]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #74666 - ssomers:btree_cleanup_1, r=Mark-Simulacrum
authorYuki Okushi <huyuumi.dev@gmail.com>
Fri, 24 Jul 2020 09:56:34 +0000 (18:56 +0900)
committerGitHub <noreply@github.com>
Fri, 24 Jul 2020 09:56:34 +0000 (18:56 +0900)
More BTreeMap test cases, some exposing undefined behaviour

Gathered from other ongoing PRs and all either blessed or ignored by Miri

r? @Mark-Simulacrum

423 files changed:
.github/workflows/ci.yml
Cargo.lock
Cargo.toml
src/bootstrap/builder.rs
src/bootstrap/dist.rs
src/bootstrap/doc.rs
src/bootstrap/install.rs
src/bootstrap/test.rs
src/bootstrap/tool.rs
src/build_helper/lib.rs
src/ci/azure-pipelines/auto.yml
src/ci/azure-pipelines/master.yml [deleted file]
src/ci/azure-pipelines/pr.yml [deleted file]
src/ci/azure-pipelines/try.yml
src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile
src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh
src/ci/docker/host-x86_64/dist-x86_64-linux/build-cmake.sh
src/ci/docker/host-x86_64/dist-x86_64-linux/build-curl.sh
src/ci/docker/host-x86_64/dist-x86_64-linux/build-gcc.sh
src/ci/github-actions/ci.yml
src/ci/run.sh
src/doc/book
src/doc/edition-guide
src/doc/reference
src/doc/rustc/src/codegen-options/index.md
src/doc/unstable-book/src/compiler-flags/sanitizer.md
src/liballoc/collections/binary_heap.rs
src/liballoc/collections/btree/map.rs
src/liballoc/collections/btree/set.rs
src/liballoc/collections/linked_list.rs
src/liballoc/collections/vec_deque.rs
src/liballoc/str.rs
src/liballoc/string.rs
src/libcore/convert/mod.rs
src/libcore/fmt/rt/v1.rs
src/libcore/hash/sip.rs
src/libcore/hint.rs
src/libcore/intrinsics.rs
src/libcore/iter/traits/iterator.rs
src/libcore/lib.rs
src/libcore/macros/mod.rs
src/libcore/mem/mod.rs
src/libcore/num/f32.rs
src/libcore/num/f64.rs
src/libcore/ops/range.rs
src/libcore/pin.rs
src/libcore/ptr/const_ptr.rs
src/libcore/ptr/mut_ptr.rs
src/libcore/ptr/non_null.rs
src/libcore/slice/mod.rs
src/libcore/slice/sort.rs
src/libcore/str/mod.rs
src/libcore/task/mod.rs
src/libcore/task/ready.rs [new file with mode: 0644]
src/libprofiler_builtins/Cargo.toml
src/libprofiler_builtins/build.rs
src/librustc_ast/build.rs [deleted file]
src/librustc_ast_passes/ast_validation.rs
src/librustc_attr/Cargo.toml
src/librustc_attr/build.rs [deleted file]
src/librustc_attr/builtin.rs
src/librustc_codegen_llvm/abi.rs
src/librustc_codegen_llvm/attributes.rs
src/librustc_codegen_llvm/base.rs
src/librustc_codegen_llvm/build.rs [deleted file]
src/librustc_codegen_llvm/builder.rs
src/librustc_codegen_llvm/callee.rs
src/librustc_codegen_llvm/common.rs
src/librustc_codegen_llvm/consts.rs
src/librustc_codegen_llvm/context.rs
src/librustc_codegen_llvm/coverageinfo/mapgen.rs [new file with mode: 0644]
src/librustc_codegen_llvm/coverageinfo/mod.rs
src/librustc_codegen_llvm/debuginfo/metadata.rs
src/librustc_codegen_llvm/debuginfo/mod.rs
src/librustc_codegen_llvm/intrinsic.rs
src/librustc_codegen_llvm/llvm/ffi.rs
src/librustc_codegen_llvm/llvm/mod.rs
src/librustc_codegen_llvm/mono_item.rs
src/librustc_codegen_llvm/type_.rs
src/librustc_codegen_llvm/type_of.rs
src/librustc_codegen_llvm/va_arg.rs
src/librustc_codegen_ssa/back/link.rs
src/librustc_codegen_ssa/back/linker.rs
src/librustc_codegen_ssa/back/symbol_export.rs
src/librustc_codegen_ssa/build.rs [deleted file]
src/librustc_codegen_ssa/coverageinfo/map.rs
src/librustc_codegen_ssa/debuginfo/type_names.rs
src/librustc_codegen_ssa/meth.rs
src/librustc_codegen_ssa/mir/analyze.rs
src/librustc_codegen_ssa/mir/block.rs
src/librustc_codegen_ssa/mir/mod.rs
src/librustc_codegen_ssa/mir/rvalue.rs
src/librustc_codegen_ssa/traits/coverageinfo.rs
src/librustc_codegen_ssa/traits/statics.rs
src/librustc_codegen_ssa/traits/type_.rs
src/librustc_data_structures/sorted_map/index_map.rs
src/librustc_data_structures/stable_hasher.rs
src/librustc_driver/build.rs [deleted file]
src/librustc_error_codes/error_codes.rs
src/librustc_error_codes/error_codes/E0724.md
src/librustc_error_codes/error_codes/E0771.md [new file with mode: 0644]
src/librustc_feature/accepted.rs
src/librustc_feature/builtin_attrs.rs
src/librustc_hir/fake_lang_items.rs [new file with mode: 0644]
src/librustc_hir/hir.rs
src/librustc_hir/lang_items.rs
src/librustc_hir/lib.rs
src/librustc_incremental/build.rs [deleted file]
src/librustc_index/bit_set.rs
src/librustc_index/lib.rs
src/librustc_infer/infer/combine.rs
src/librustc_infer/infer/error_reporting/mod.rs
src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs
src/librustc_infer/infer/error_reporting/nice_region_error/util.rs
src/librustc_infer/infer/mod.rs
src/librustc_infer/lib.rs
src/librustc_interface/build.rs [deleted file]
src/librustc_interface/tests.rs
src/librustc_llvm/Cargo.toml
src/librustc_llvm/build.rs
src/librustc_llvm/lib.rs
src/librustc_metadata/build.rs [deleted file]
src/librustc_metadata/creader.rs
src/librustc_metadata/locator.rs
src/librustc_metadata/rmeta/decoder.rs
src/librustc_metadata/rmeta/decoder/cstore_impl.rs
src/librustc_metadata/rmeta/encoder.rs
src/librustc_metadata/rmeta/mod.rs
src/librustc_middle/build.rs [deleted file]
src/librustc_middle/lib.rs
src/librustc_middle/middle/stability.rs
src/librustc_middle/mir/coverage/mod.rs
src/librustc_middle/mir/mono.rs
src/librustc_middle/mir/query.rs
src/librustc_middle/query/mod.rs
src/librustc_middle/traits/mod.rs
src/librustc_middle/traits/specialization_graph.rs
src/librustc_middle/traits/structural_impls.rs
src/librustc_middle/ty/flags.rs
src/librustc_middle/ty/instance.rs
src/librustc_middle/ty/layout.rs
src/librustc_middle/ty/mod.rs
src/librustc_middle/ty/normalize_erasing_regions.rs
src/librustc_middle/ty/print/obsolete.rs
src/librustc_middle/ty/query/mod.rs
src/librustc_middle/ty/sty.rs
src/librustc_mir/borrow_check/mod.rs
src/librustc_mir/const_eval/eval_queries.rs
src/librustc_mir/interpret/intrinsics.rs
src/librustc_mir/interpret/terminator.rs
src/librustc_mir/interpret/traits.rs
src/librustc_mir/lib.rs
src/librustc_mir/monomorphize/collector.rs
src/librustc_mir/monomorphize/mod.rs
src/librustc_mir/monomorphize/partitioning.rs
src/librustc_mir/monomorphize/polymorphize.rs [new file with mode: 0644]
src/librustc_mir/shim.rs
src/librustc_mir/transform/check_unsafety.rs
src/librustc_mir/transform/const_prop.rs
src/librustc_mir/transform/instrument_coverage.rs
src/librustc_mir/transform/mod.rs
src/librustc_mir_build/build/mod.rs
src/librustc_passes/stability.rs
src/librustc_passes/weak_lang_items.rs
src/librustc_plugin_impl/load.rs
src/librustc_resolve/diagnostics.rs
src/librustc_resolve/late.rs
src/librustc_resolve/late/diagnostics.rs
src/librustc_resolve/late/lifetimes.rs
src/librustc_resolve/lib.rs
src/librustc_resolve/macros.rs
src/librustc_session/config.rs
src/librustc_session/options.rs
src/librustc_session/session.rs
src/librustc_span/symbol.rs
src/librustc_symbol_mangling/legacy.rs
src/librustc_target/abi/mod.rs
src/librustc_target/build.rs [deleted file]
src/librustc_target/spec/aarch64_apple_darwin.rs [new file with mode: 0644]
src/librustc_target/spec/apple_base.rs
src/librustc_target/spec/freestanding_base.rs
src/librustc_target/spec/illumos_base.rs
src/librustc_target/spec/mod.rs
src/librustc_target/spec/msp430_none_elf.rs
src/librustc_target/spec/riscv32i_unknown_none_elf.rs
src/librustc_target/spec/riscv32imac_unknown_none_elf.rs
src/librustc_target/spec/riscv32imc_unknown_none_elf.rs
src/librustc_target/spec/riscv64gc_unknown_none_elf.rs
src/librustc_target/spec/riscv64imac_unknown_none_elf.rs
src/librustc_target/spec/solaris_base.rs
src/librustc_target/spec/thumbv4t_none_eabi.rs [new file with mode: 0644]
src/librustc_target/spec/windows_gnu_base.rs
src/librustc_target/spec/x86_64_apple_darwin.rs
src/librustc_trait_selection/traits/codegen/mod.rs
src/librustc_trait_selection/traits/coherence.rs
src/librustc_trait_selection/traits/error_reporting/suggestions.rs
src/librustc_trait_selection/traits/mod.rs
src/librustc_ty/instance.rs
src/librustc_typeck/astconv.rs
src/librustc_typeck/check/intrinsic.rs
src/librustc_typeck/check/method/confirm.rs
src/librustc_typeck/check/mod.rs
src/librustc_typeck/check/regionck.rs
src/librustc_typeck/check/wfcheck.rs
src/librustc_typeck/collect.rs
src/librustdoc/clean/inline.rs
src/librustdoc/clean/mod.rs
src/librustdoc/clean/types.rs
src/librustdoc/html/render.rs
src/librustdoc/html/static/rustdoc.css
src/librustdoc/html/static/themes/ayu.css
src/librustdoc/html/static/themes/dark.css
src/librustdoc/html/static/themes/light.css
src/librustdoc/passes/collect_intra_doc_links.rs
src/libstd/Cargo.toml
src/libstd/alloc.rs
src/libstd/backtrace.rs
src/libstd/build.rs
src/libstd/collections/hash/map.rs
src/libstd/collections/hash/set.rs
src/libstd/collections/mod.rs
src/libstd/f32.rs
src/libstd/f64.rs
src/libstd/ffi/c_str.rs
src/libstd/io/mod.rs
src/libstd/keyword_docs.rs
src/libstd/lib.rs
src/libstd/os/linux/fs.rs
src/libstd/os/redox/fs.rs
src/libstd/path.rs
src/libstd/sys/sgx/fd.rs
src/libstd/sys/unix/ext/fs.rs
src/libstd/sys/unix/fd.rs
src/libstd/sys/unix/fs.rs
src/libstd/sys/unix/net.rs
src/libstd/sys/unix/os.rs
src/libstd/sys/unix/pipe.rs
src/libstd/sys/unix/process/process_unix.rs
src/libstd/sys/unix/weak.rs
src/libstd/sys/vxworks/fd.rs
src/libstd/sys/vxworks/time.rs
src/libstd/sys/wasi/ext/mod.rs
src/libstd/sys/wasi/fs.rs
src/libunwind/Cargo.toml
src/rustllvm/CoverageMappingWrapper.cpp [new file with mode: 0644]
src/rustllvm/RustWrapper.cpp
src/rustllvm/rustllvm.h
src/test/codegen-units/item-collection/static-init.rs
src/test/codegen-units/item-collection/trait-method-default-impl.rs
src/test/codegen-units/polymorphization/unused_type_parameters.rs [new file with mode: 0644]
src/test/codegen/abi-efiapi.rs
src/test/codegen/avr/avr-func-addrspace.rs [new file with mode: 0644]
src/test/codegen/cfguard-checks.rs
src/test/codegen/cfguard-disabled.rs
src/test/codegen/cfguard-nochecks.rs
src/test/codegen/cfguard-non-msvc.rs
src/test/codegen/force-unwind-tables.rs
src/test/codegen/unchecked-float-casts.rs
src/test/codegen/wasm_casts_trapping.rs
src/test/compile-fail/empty-extern-arg.rs
src/test/debuginfo/function-call.rs
src/test/debuginfo/pretty-huge-vec.rs
src/test/debuginfo/pretty-std-collections.rs
src/test/debuginfo/pretty-std.rs
src/test/debuginfo/pretty-uninitialized-vec.rs
src/test/mir-opt/instrument_coverage/rustc.bar.InstrumentCoverage.diff
src/test/mir-opt/instrument_coverage/rustc.main.InstrumentCoverage.diff
src/test/run-make-fulldeps/c-link-to-rust-va-list-fn/checkrust.rs
src/test/run-make-fulldeps/c-link-to-rust-va-list-fn/test.c
src/test/run-make-fulldeps/instrument-coverage/Makefile [new file with mode: 0644]
src/test/run-make-fulldeps/instrument-coverage/expected_export_coverage.json [new file with mode: 0644]
src/test/run-make-fulldeps/instrument-coverage/main.rs [new file with mode: 0644]
src/test/run-make-fulldeps/instrument-coverage/prettify_json.py [new file with mode: 0644]
src/test/run-make-fulldeps/instrument-coverage/typical_show_coverage.txt [new file with mode: 0644]
src/test/run-make-fulldeps/tools.mk
src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr
src/test/rustdoc-ui/intra-doc-alias-ice.stderr
src/test/rustdoc-ui/intra-link-span-ice-55723.rs
src/test/rustdoc-ui/intra-link-span-ice-55723.stderr
src/test/rustdoc-ui/intra-links-anchors.rs
src/test/rustdoc-ui/intra-links-anchors.stderr
src/test/rustdoc-ui/intra-links-private.private.stderr [new file with mode: 0644]
src/test/rustdoc-ui/intra-links-private.public.stderr
src/test/rustdoc-ui/intra-links-private.rs
src/test/rustdoc-ui/intra-links-warning-crlf.rs
src/test/rustdoc-ui/intra-links-warning-crlf.stderr
src/test/rustdoc-ui/intra-links-warning.rs
src/test/rustdoc-ui/intra-links-warning.stderr
src/test/rustdoc-ui/issue-74134.private.stderr [new file with mode: 0644]
src/test/rustdoc-ui/issue-74134.public.stderr
src/test/rustdoc-ui/issue-74134.rs
src/test/rustdoc-ui/lint-group.rs
src/test/rustdoc-ui/lint-group.stderr
src/test/rustdoc/auxiliary/unstable-trait.rs [new file with mode: 0644]
src/test/rustdoc/hide-unstable-trait.rs [new file with mode: 0644]
src/test/ui-fulldeps/macro-crate-rlib.rs
src/test/ui-fulldeps/macro-crate-rlib.stderr
src/test/ui/associated-types/cache/project-fn-ret-contravariant.rs
src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr
src/test/ui/associated-types/cache/project-fn-ret-invariant.rs
src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr
src/test/ui/associated-types/issue-62200.rs [new file with mode: 0644]
src/test/ui/associated-types/issue-62200.stderr [new file with mode: 0644]
src/test/ui/async-await/issues/issue-62097.rs
src/test/ui/async-await/issues/issue-62097.stderr
src/test/ui/cfguard-run.rs
src/test/ui/const-generics/const-argument-non-static-lifetime.rs [new file with mode: 0644]
src/test/ui/const-generics/const-argument-non-static-lifetime.stderr [new file with mode: 0644]
src/test/ui/const-generics/defaults/wrong-order.rs [new file with mode: 0644]
src/test/ui/const-generics/defaults/wrong-order.stderr [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-62878.rs [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-62878.stderr [new file with mode: 0644]
src/test/ui/consts/const_unsafe_unreachable.rs [new file with mode: 0644]
src/test/ui/consts/const_unsafe_unreachable_ub.rs [new file with mode: 0644]
src/test/ui/consts/const_unsafe_unreachable_ub.stderr [new file with mode: 0644]
src/test/ui/consts/issue-73976-monomorphic.rs [new file with mode: 0644]
src/test/ui/consts/issue-73976-polymorphic.rs [new file with mode: 0644]
src/test/ui/consts/issue-73976-polymorphic.stderr [new file with mode: 0644]
src/test/ui/error-codes/E0771.rs [new file with mode: 0644]
src/test/ui/error-codes/E0771.stderr [new file with mode: 0644]
src/test/ui/extern/extern-prelude-no-speculative.rs
src/test/ui/impl-header-lifetime-elision/dyn-trait.rs
src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr
src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr
src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs
src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr
src/test/ui/impl-trait/static-return-lifetime-infered.nll.stderr
src/test/ui/impl-trait/static-return-lifetime-infered.rs
src/test/ui/impl-trait/static-return-lifetime-infered.stderr
src/test/ui/issues/issue-16922.rs
src/test/ui/issues/issue-16922.stderr
src/test/ui/issues/issue-74539.rs [new file with mode: 0644]
src/test/ui/issues/issue-74539.stderr [new file with mode: 0644]
src/test/ui/issues/issue-74614.rs [new file with mode: 0644]
src/test/ui/lint/lint-ctypes.rs
src/test/ui/lint/lint-ctypes.stderr
src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr
src/test/ui/object-lifetime/object-lifetime-default-from-box-error.rs
src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr
src/test/ui/polymorphization/const_parameters/closures.rs [new file with mode: 0644]
src/test/ui/polymorphization/const_parameters/closures.stderr [new file with mode: 0644]
src/test/ui/polymorphization/const_parameters/functions.rs [new file with mode: 0644]
src/test/ui/polymorphization/const_parameters/functions.stderr [new file with mode: 0644]
src/test/ui/polymorphization/drop_shims/simple.rs [new file with mode: 0644]
src/test/ui/polymorphization/drop_shims/transitive.rs [new file with mode: 0644]
src/test/ui/polymorphization/generators.rs [new file with mode: 0644]
src/test/ui/polymorphization/generators.stderr [new file with mode: 0644]
src/test/ui/polymorphization/lifetimes.rs [new file with mode: 0644]
src/test/ui/polymorphization/lifetimes.stderr [new file with mode: 0644]
src/test/ui/polymorphization/normalized_sig_types.rs [new file with mode: 0644]
src/test/ui/polymorphization/predicates.rs [new file with mode: 0644]
src/test/ui/polymorphization/predicates.stderr [new file with mode: 0644]
src/test/ui/polymorphization/promoted-function.rs [new file with mode: 0644]
src/test/ui/polymorphization/too-many-generic-params.rs [new file with mode: 0644]
src/test/ui/polymorphization/type_parameters/closures.rs [new file with mode: 0644]
src/test/ui/polymorphization/type_parameters/closures.stderr [new file with mode: 0644]
src/test/ui/polymorphization/type_parameters/functions.rs [new file with mode: 0644]
src/test/ui/polymorphization/type_parameters/functions.stderr [new file with mode: 0644]
src/test/ui/polymorphization/unsized_cast.rs [new file with mode: 0644]
src/test/ui/polymorphization/unsized_cast.stderr [new file with mode: 0644]
src/test/ui/print_type_sizes/niche-filling.stdout
src/test/ui/regions/region-object-lifetime-in-coercion.rs
src/test/ui/regions/region-object-lifetime-in-coercion.stderr
src/test/ui/regions/regions-addr-of-self.rs
src/test/ui/regions/regions-addr-of-self.stderr
src/test/ui/regions/regions-close-object-into-object-2.rs
src/test/ui/regions/regions-close-object-into-object-2.stderr
src/test/ui/regions/regions-close-object-into-object-4.rs
src/test/ui/regions/regions-close-object-into-object-4.stderr
src/test/ui/regions/regions-proc-bound-capture.rs
src/test/ui/regions/regions-proc-bound-capture.stderr
src/test/ui/regions/type-param-outlives-reempty-issue-74429-2.rs [new file with mode: 0644]
src/test/ui/regions/type-param-outlives-reempty-issue-74429.rs [new file with mode: 0644]
src/test/ui/rfc-2457/crate_name_nonascii_forbidden-1.rs
src/test/ui/rfc-2457/crate_name_nonascii_forbidden-1.stderr
src/test/ui/rfc-2457/crate_name_nonascii_forbidden-2.rs
src/test/ui/rfc-2457/crate_name_nonascii_forbidden-2.stderr
src/test/ui/sanitize/new-llvm-pass-manager-thin-lto.rs
src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.rs
src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr
src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.rs
src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr
src/test/ui/specialization/min_specialization/impl-on-nonexisting.rs [new file with mode: 0644]
src/test/ui/specialization/min_specialization/impl-on-nonexisting.stderr [new file with mode: 0644]
src/test/ui/stability-attribute/stability-attribute-sanity.rs
src/test/ui/stability-attribute/stability-attribute-sanity.stderr
src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.nll.stderr [new file with mode: 0644]
src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs [new file with mode: 0644]
src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr [new file with mode: 0644]
src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.fixed [new file with mode: 0644]
src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.nll.stderr [new file with mode: 0644]
src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.rs [new file with mode: 0644]
src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr [new file with mode: 0644]
src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs
src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr
src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.rs
src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.stderr
src/test/ui/traits/issue-72410.rs [new file with mode: 0644]
src/test/ui/traits/issue-72410.stderr [new file with mode: 0644]
src/test/ui/type-sizes.rs
src/test/ui/typeck/typeck_type_placeholder_item.rs
src/test/ui/typeck/typeck_type_placeholder_item.stderr
src/test/ui/underscore-lifetime/dyn-trait-underscore.rs
src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr
src/test/ui/wf/wf-foreign-fn-decl-ret.rs [new file with mode: 0644]
src/test/ui/wf/wf-foreign-fn-decl-ret.stderr [new file with mode: 0644]
src/tools/cargo
src/tools/clippy/clippy_lints/src/utils/mod.rs
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/tests.rs
src/tools/error_index_generator/Cargo.toml
src/tools/linkchecker/main.rs
src/tools/publish_toolstate.py
src/tools/rust-analyzer
src/tools/rust-demangler/Cargo.toml [new file with mode: 0644]
src/tools/rust-demangler/main.rs [new file with mode: 0644]
src/tools/tidy/src/error_codes_check.rs
triagebot.toml

index 86de37820003ae425f59eee735e23666f7099015..d83971b70bedc45bfecb79c29608d884c0d5ef79 100644 (file)
@@ -20,6 +20,7 @@ name: CI
     branches:
       - auto
       - try
+      - try-perf
       - master
   pull_request:
     branches:
@@ -32,9 +33,9 @@ jobs:
     name: PR
     env:
       CI_JOB_NAME: "${{ matrix.name }}"
-      SCCACHE_BUCKET: rust-lang-gha-caches
-      TOOLSTATE_REPO: "https://github.com/pietroalbini/rust-toolstate"
-      CACHE_DOMAIN: ci-caches-gha.rust-lang.org
+      SCCACHE_BUCKET: rust-lang-ci-sccache2
+      TOOLSTATE_REPO: "https://github.com/rust-lang-nursery/rust-toolstate"
+      CACHE_DOMAIN: ci-caches.rust-lang.org
     if: "github.event_name == 'pull_request'"
     strategy:
       matrix:
@@ -63,6 +64,11 @@ jobs:
         with:
           github_token: "${{ secrets.github_token }}"
         if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'"
+      - name: configure the PR in which the error message will be posted
+        run: "echo \"[CI_PR_NUMBER=$num]\""
+        env:
+          num: "${{ github.event.number }}"
+        if: "success() && !env.SKIP_JOBS && github.event_name == 'pull_request'"
       - name: add extra environment variables
         run: src/ci/scripts/setup-environment.sh
         env:
@@ -133,15 +139,15 @@ jobs:
     name: try
     env:
       CI_JOB_NAME: "${{ matrix.name }}"
-      SCCACHE_BUCKET: rust-lang-gha-caches
-      DEPLOY_BUCKET: rust-lang-gha
-      TOOLSTATE_REPO: "https://github.com/pietroalbini/rust-toolstate"
-      TOOLSTATE_ISSUES_API_URL: "https://api.github.com/repos/pietroalbini/rust-toolstate/issues"
+      SCCACHE_BUCKET: rust-lang-ci-sccache2
+      DEPLOY_BUCKET: rust-lang-ci2
+      TOOLSTATE_REPO: "https://github.com/rust-lang-nursery/rust-toolstate"
+      TOOLSTATE_ISSUES_API_URL: "https://api.github.com/repos/rust-lang/rust/issues"
       TOOLSTATE_PUBLISH: 1
-      CACHES_AWS_ACCESS_KEY_ID: AKIA46X5W6CZOMUQATD5
-      ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZH5AYXDVF
-      CACHE_DOMAIN: ci-caches-gha.rust-lang.org
-    if: "github.event_name == 'push' && github.ref == 'refs/heads/try' && github.repository == 'rust-lang-ci/rust'"
+      CACHES_AWS_ACCESS_KEY_ID: AKIA46X5W6CZI5DHEBFL
+      ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZN24CBO55
+      CACHE_DOMAIN: ci-caches.rust-lang.org
+    if: "github.event_name == 'push' && (github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf') && github.repository == 'rust-lang-ci/rust'"
     strategy:
       matrix:
         include:
@@ -162,6 +168,11 @@ jobs:
         with:
           github_token: "${{ secrets.github_token }}"
         if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'"
+      - name: configure the PR in which the error message will be posted
+        run: "echo \"[CI_PR_NUMBER=$num]\""
+        env:
+          num: "${{ github.event.number }}"
+        if: "success() && !env.SKIP_JOBS && github.event_name == 'pull_request'"
       - name: add extra environment variables
         run: src/ci/scripts/setup-environment.sh
         env:
@@ -232,14 +243,14 @@ jobs:
     name: auto
     env:
       CI_JOB_NAME: "${{ matrix.name }}"
-      SCCACHE_BUCKET: rust-lang-gha-caches
-      DEPLOY_BUCKET: rust-lang-gha
-      TOOLSTATE_REPO: "https://github.com/pietroalbini/rust-toolstate"
-      TOOLSTATE_ISSUES_API_URL: "https://api.github.com/repos/pietroalbini/rust-toolstate/issues"
+      SCCACHE_BUCKET: rust-lang-ci-sccache2
+      DEPLOY_BUCKET: rust-lang-ci2
+      TOOLSTATE_REPO: "https://github.com/rust-lang-nursery/rust-toolstate"
+      TOOLSTATE_ISSUES_API_URL: "https://api.github.com/repos/rust-lang/rust/issues"
       TOOLSTATE_PUBLISH: 1
-      CACHES_AWS_ACCESS_KEY_ID: AKIA46X5W6CZOMUQATD5
-      ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZH5AYXDVF
-      CACHE_DOMAIN: ci-caches-gha.rust-lang.org
+      CACHES_AWS_ACCESS_KEY_ID: AKIA46X5W6CZI5DHEBFL
+      ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZN24CBO55
+      CACHE_DOMAIN: ci-caches.rust-lang.org
     if: "github.event_name == 'push' && github.ref == 'refs/heads/auto' && github.repository == 'rust-lang-ci/rust'"
     strategy:
       matrix:
@@ -479,6 +490,11 @@ jobs:
         with:
           github_token: "${{ secrets.github_token }}"
         if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'"
+      - name: configure the PR in which the error message will be posted
+        run: "echo \"[CI_PR_NUMBER=$num]\""
+        env:
+          num: "${{ github.event.number }}"
+        if: "success() && !env.SKIP_JOBS && github.event_name == 'pull_request'"
       - name: add extra environment variables
         run: src/ci/scripts/setup-environment.sh
         env:
@@ -604,6 +620,11 @@ jobs:
         with:
           github_token: "${{ secrets.github_token }}"
         if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'"
+      - name: configure the PR in which the error message will be posted
+        run: "echo \"[CI_PR_NUMBER=$num]\""
+        env:
+          num: "${{ github.event.number }}"
+        if: "success() && !env.SKIP_JOBS && github.event_name == 'pull_request'"
       - name: add extra environment variables
         run: src/ci/scripts/setup-environment.sh
         env:
@@ -674,14 +695,14 @@ jobs:
     name: master
     runs-on: ubuntu-latest
     env:
-      SCCACHE_BUCKET: rust-lang-gha-caches
-      DEPLOY_BUCKET: rust-lang-gha
-      TOOLSTATE_REPO: "https://github.com/pietroalbini/rust-toolstate"
-      TOOLSTATE_ISSUES_API_URL: "https://api.github.com/repos/pietroalbini/rust-toolstate/issues"
+      SCCACHE_BUCKET: rust-lang-ci-sccache2
+      DEPLOY_BUCKET: rust-lang-ci2
+      TOOLSTATE_REPO: "https://github.com/rust-lang-nursery/rust-toolstate"
+      TOOLSTATE_ISSUES_API_URL: "https://api.github.com/repos/rust-lang/rust/issues"
       TOOLSTATE_PUBLISH: 1
-      CACHES_AWS_ACCESS_KEY_ID: AKIA46X5W6CZOMUQATD5
-      ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZH5AYXDVF
-      CACHE_DOMAIN: ci-caches-gha.rust-lang.org
+      CACHES_AWS_ACCESS_KEY_ID: AKIA46X5W6CZI5DHEBFL
+      ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZN24CBO55
+      CACHE_DOMAIN: ci-caches.rust-lang.org
     if: "github.event_name == 'push' && github.ref == 'refs/heads/master' && github.repository == 'rust-lang-ci/rust'"
     steps:
       - name: checkout the source code
@@ -697,7 +718,7 @@ jobs:
   try-success:
     needs:
       - try
-    if: "success() && github.event_name == 'push' && github.ref == 'refs/heads/try' && github.repository == 'rust-lang-ci/rust'"
+    if: "success() && github.event_name == 'push' && (github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf') && github.repository == 'rust-lang-ci/rust'"
     steps:
       - name: mark the job as a success
         run: exit 0
@@ -707,7 +728,7 @@ jobs:
   try-failure:
     needs:
       - try
-    if: "!success() && github.event_name == 'push' && github.ref == 'refs/heads/try' && github.repository == 'rust-lang-ci/rust'"
+    if: "!success() && github.event_name == 'push' && (github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf') && github.repository == 'rust-lang-ci/rust'"
     steps:
       - name: mark the job as a failure
         run: exit 1
index 3ee7d07900700cdc1797ecbcbc1fcb8efd98c8df..8f110403eb842311fcc3e72b72cf392be76dda80 100644 (file)
@@ -278,7 +278,7 @@ checksum = "716960a18f978640f25101b5cbf1c6f6b0d3192fab36a2d98ca96f0ecbe41010"
 
 [[package]]
 name = "cargo"
-version = "0.47.0"
+version = "0.48.0"
 dependencies = [
  "anyhow",
  "atty",
@@ -410,9 +410,9 @@ version = "0.1.0"
 
 [[package]]
 name = "cc"
-version = "1.0.57"
+version = "1.0.58"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fde55d2a2bfaa4c9668bbc63f531fbdeee3ffe188f4662511ce2c22b3eedebe"
+checksum = "f9a06fb2e53271d7c279ec1efea6ab691c35a2ae67ec0d91d7acec0caf13b518"
 dependencies = [
  "jobserver",
 ]
@@ -1563,9 +1563,9 @@ checksum = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f"
 
 [[package]]
 name = "libc"
-version = "0.2.71"
+version = "0.2.73"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49"
+checksum = "bd7d4bd64732af4bf3a67f367c27df8520ad7e230c5817b8ff485864d80242b9"
 dependencies = [
  "rustc-std-workspace-core",
 ]
@@ -2794,6 +2794,13 @@ dependencies = [
  "rls-span",
 ]
 
+[[package]]
+name = "rust-demangler"
+version = "0.0.0"
+dependencies = [
+ "rustc-demangle",
+]
+
 [[package]]
 name = "rustbook"
 version = "0.1.0"
index be15e50e2bcca07d92d6615542914b4c0ba112f7..efc6f4a0291ca6791b9088ad6f7a02bb4473106b 100644 (file)
@@ -17,6 +17,7 @@ members = [
   "src/tools/remote-test-client",
   "src/tools/remote-test-server",
   "src/tools/rust-installer",
+  "src/tools/rust-demangler",
   "src/tools/cargo",
   "src/tools/rustdoc",
   "src/tools/rls",
index a8161c9bfb85927db91f9af30d330e1d98334968..c1e56347ab1e0111ed0ff5d0bd71f1c88aead816 100644 (file)
@@ -370,6 +370,7 @@ macro_rules! describe {
                 tool::Cargo,
                 tool::Rls,
                 tool::RustAnalyzer,
+                tool::RustDemangler,
                 tool::Rustdoc,
                 tool::Clippy,
                 tool::CargoClippy,
@@ -1238,7 +1239,7 @@ pub fn cargo(
             && self.config.control_flow_guard
             && compiler.stage >= 1
         {
-            rustflags.arg("-Zcontrol-flow-guard");
+            rustflags.arg("-Ccontrol-flow-guard");
         }
 
         // For `cargo doc` invocations, make rustdoc print the Rust version into the docs
@@ -1443,6 +1444,10 @@ pub struct Cargo {
 }
 
 impl Cargo {
+    pub fn rustdocflag(&mut self, arg: &str) -> &mut Cargo {
+        self.rustdocflags.arg(arg);
+        self
+    }
     pub fn rustflag(&mut self, arg: &str) -> &mut Cargo {
         self.rustflags.arg(arg);
         self
@@ -1465,6 +1470,9 @@ pub fn args<I, S>(&mut self, args: I) -> &mut Cargo
     }
 
     pub fn env(&mut self, key: impl AsRef<OsStr>, value: impl AsRef<OsStr>) -> &mut Cargo {
+        // These are managed through rustflag/rustdocflag interfaces.
+        assert_ne!(key.as_ref(), "RUSTFLAGS");
+        assert_ne!(key.as_ref(), "RUSTDOCFLAGS");
         self.command.env(key.as_ref(), value.as_ref());
         self
     }
index af30747a9592e6dcaf4eccaa226ba34f0c1d06cb..c64934cd6c9ded20f166b32e7988f80eb94eb68c 100644 (file)
@@ -91,7 +91,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
         let name = pkgname(builder, "rust-docs");
 
         if !builder.config.docs {
-            return distdir(builder).join(format!("{}-{}.tar.gz", name, host));
+            return distdir(builder).join(format!("{}-{}.tar.gz", name, host.triple));
         }
 
         builder.default_doc(None);
@@ -99,7 +99,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
         builder.info(&format!("Dist docs ({})", host));
         let _time = timeit(builder);
 
-        let image = tmpdir(builder).join(format!("{}-{}-image", name, host));
+        let image = tmpdir(builder).join(format!("{}-{}-image", name, host.triple));
         let _ = fs::remove_dir_all(&image);
 
         let dst = image.join("share/doc/rust/html");
@@ -119,14 +119,14 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
             .arg(&tmpdir(builder))
             .arg("--output-dir")
             .arg(&distdir(builder))
-            .arg(format!("--package-name={}-{}", name, host))
+            .arg(format!("--package-name={}-{}", name, host.triple))
             .arg("--component-name=rust-docs")
             .arg("--legacy-manifest-dirs=rustlib,cargo")
             .arg("--bulk-dirs=share/doc/rust/html");
         builder.run(&mut cmd);
         builder.remove_dir(&image);
 
-        distdir(builder).join(format!("{}-{}.tar.gz", name, host))
+        distdir(builder).join(format!("{}-{}.tar.gz", name, host.triple))
     }
 }
 
@@ -154,12 +154,12 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
         let name = pkgname(builder, "rustc-docs");
 
         if !builder.config.compiler_docs {
-            return distdir(builder).join(format!("{}-{}.tar.gz", name, host));
+            return distdir(builder).join(format!("{}-{}.tar.gz", name, host.triple));
         }
 
         builder.default_doc(None);
 
-        let image = tmpdir(builder).join(format!("{}-{}-image", name, host));
+        let image = tmpdir(builder).join(format!("{}-{}-image", name, host.triple));
         let _ = fs::remove_dir_all(&image);
 
         let dst = image.join("share/doc/rust/html");
@@ -178,7 +178,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
             .arg(&tmpdir(builder))
             .arg("--output-dir")
             .arg(&distdir(builder))
-            .arg(format!("--package-name={}-{}", name, host))
+            .arg(format!("--package-name={}-{}", name, host.triple))
             .arg("--component-name=rustc-docs")
             .arg("--legacy-manifest-dirs=rustlib,cargo")
             .arg("--bulk-dirs=share/doc/rust/html");
@@ -188,7 +188,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
         builder.run(&mut cmd);
         builder.remove_dir(&image);
 
-        distdir(builder).join(format!("{}-{}.tar.gz", name, host))
+        distdir(builder).join(format!("{}-{}.tar.gz", name, host.triple))
     }
 }
 
@@ -372,7 +372,7 @@ fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
         builder.info(&format!("Dist mingw ({})", host));
         let _time = timeit(builder);
         let name = pkgname(builder, "rust-mingw");
-        let image = tmpdir(builder).join(format!("{}-{}-image", name, host));
+        let image = tmpdir(builder).join(format!("{}-{}-image", name, host.triple));
         let _ = fs::remove_dir_all(&image);
         t!(fs::create_dir_all(&image));
 
@@ -393,12 +393,12 @@ fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
             .arg(&tmpdir(builder))
             .arg("--output-dir")
             .arg(&distdir(builder))
-            .arg(format!("--package-name={}-{}", name, host))
+            .arg(format!("--package-name={}-{}", name, host.triple))
             .arg("--component-name=rust-mingw")
             .arg("--legacy-manifest-dirs=rustlib,cargo");
         builder.run(&mut cmd);
         t!(fs::remove_dir_all(&image));
-        Some(distdir(builder).join(format!("{}-{}.tar.gz", name, host)))
+        Some(distdir(builder).join(format!("{}-{}.tar.gz", name, host.triple)))
     }
 }
 
@@ -427,9 +427,9 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
         let host = self.compiler.host;
 
         let name = pkgname(builder, "rustc");
-        let image = tmpdir(builder).join(format!("{}-{}-image", name, host));
+        let image = tmpdir(builder).join(format!("{}-{}-image", name, host.triple));
         let _ = fs::remove_dir_all(&image);
-        let overlay = tmpdir(builder).join(format!("{}-{}-overlay", name, host));
+        let overlay = tmpdir(builder).join(format!("{}-{}-overlay", name, host.triple));
         let _ = fs::remove_dir_all(&overlay);
 
         // Prepare the rustc "image", what will actually end up getting installed
@@ -483,17 +483,17 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
             .arg(&distdir(builder))
             .arg("--non-installed-overlay")
             .arg(&overlay)
-            .arg(format!("--package-name={}-{}", name, host))
+            .arg(format!("--package-name={}-{}", name, host.triple))
             .arg("--component-name=rustc")
             .arg("--legacy-manifest-dirs=rustlib,cargo");
 
-        builder.info(&format!("Dist rustc stage{} ({})", compiler.stage, host));
+        builder.info(&format!("Dist rustc stage{} ({})", compiler.stage, host.triple));
         let _time = timeit(builder);
         builder.run(&mut cmd);
         builder.remove_dir(&image);
         builder.remove_dir(&overlay);
 
-        return distdir(builder).join(format!("{}-{}.tar.gz", name, host));
+        return distdir(builder).join(format!("{}-{}.tar.gz", name, host.triple));
 
         fn prepare_image(builder: &Builder<'_>, compiler: Compiler, image: &Path) {
             let host = compiler.host;
@@ -707,14 +707,14 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
         let target = self.target;
 
         let name = pkgname(builder, "rust-std");
-        let archive = distdir(builder).join(format!("{}-{}.tar.gz", name, target));
+        let archive = distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple));
         if skip_host_target_lib(builder, compiler) {
             return archive;
         }
 
         builder.ensure(compile::Std { compiler, target });
 
-        let image = tmpdir(builder).join(format!("{}-{}-image", name, target));
+        let image = tmpdir(builder).join(format!("{}-{}-image", name, target.triple));
         let _ = fs::remove_dir_all(&image);
 
         let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target);
@@ -732,8 +732,8 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
             .arg(&tmpdir(builder))
             .arg("--output-dir")
             .arg(&distdir(builder))
-            .arg(format!("--package-name={}-{}", name, target))
-            .arg(format!("--component-name=rust-std-{}", target))
+            .arg(format!("--package-name={}-{}", name, target.triple))
+            .arg(format!("--component-name=rust-std-{}", target.triple))
             .arg("--legacy-manifest-dirs=rustlib,cargo");
 
         builder
@@ -776,14 +776,14 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
         let target = self.target;
 
         let name = pkgname(builder, "rustc-dev");
-        let archive = distdir(builder).join(format!("{}-{}.tar.gz", name, target));
+        let archive = distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple));
         if skip_host_target_lib(builder, compiler) {
             return archive;
         }
 
         builder.ensure(compile::Rustc { compiler, target });
 
-        let image = tmpdir(builder).join(format!("{}-{}-image", name, target));
+        let image = tmpdir(builder).join(format!("{}-{}-image", name, target.triple));
         let _ = fs::remove_dir_all(&image);
 
         let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target);
@@ -801,8 +801,8 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
             .arg(&tmpdir(builder))
             .arg("--output-dir")
             .arg(&distdir(builder))
-            .arg(format!("--package-name={}-{}", name, target))
-            .arg(format!("--component-name=rustc-dev-{}", target))
+            .arg(format!("--package-name={}-{}", name, target.triple))
+            .arg(format!("--component-name=rustc-dev-{}", target.triple))
             .arg("--legacy-manifest-dirs=rustlib,cargo");
 
         builder.info(&format!(
@@ -853,12 +853,12 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
         let name = pkgname(builder, "rust-analysis");
 
         if compiler.host != builder.config.build {
-            return distdir(builder).join(format!("{}-{}.tar.gz", name, target));
+            return distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple));
         }
 
         builder.ensure(compile::Std { compiler, target });
 
-        let image = tmpdir(builder).join(format!("{}-{}-image", name, target));
+        let image = tmpdir(builder).join(format!("{}-{}-image", name, target.triple));
 
         let src = builder
             .stage_out(compiler, Mode::Std)
@@ -883,15 +883,15 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
             .arg(&tmpdir(builder))
             .arg("--output-dir")
             .arg(&distdir(builder))
-            .arg(format!("--package-name={}-{}", name, target))
-            .arg(format!("--component-name=rust-analysis-{}", target))
+            .arg(format!("--package-name={}-{}", name, target.triple))
+            .arg(format!("--component-name=rust-analysis-{}", target.triple))
             .arg("--legacy-manifest-dirs=rustlib,cargo");
 
         builder.info("Dist analysis");
         let _time = timeit(builder);
         builder.run(&mut cmd);
         builder.remove_dir(&image);
-        distdir(builder).join(format!("{}-{}.tar.gz", name, target))
+        distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple))
     }
 }
 
@@ -1242,14 +1242,14 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
             .arg(&distdir(builder))
             .arg("--non-installed-overlay")
             .arg(&overlay)
-            .arg(format!("--package-name={}-{}", name, target))
+            .arg(format!("--package-name={}-{}", name, target.triple))
             .arg("--component-name=cargo")
             .arg("--legacy-manifest-dirs=rustlib,cargo");
 
         builder.info(&format!("Dist cargo stage{} ({})", compiler.stage, target));
         let _time = timeit(builder);
         builder.run(&mut cmd);
-        distdir(builder).join(format!("{}-{}.tar.gz", name, target))
+        distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple))
     }
 }
 
@@ -1332,14 +1332,14 @@ fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
             .arg(&distdir(builder))
             .arg("--non-installed-overlay")
             .arg(&overlay)
-            .arg(format!("--package-name={}-{}", name, target))
+            .arg(format!("--package-name={}-{}", name, target.triple))
             .arg("--legacy-manifest-dirs=rustlib,cargo")
             .arg("--component-name=rls-preview");
 
-        builder.info(&format!("Dist RLS stage{} ({})", compiler.stage, target));
+        builder.info(&format!("Dist RLS stage{} ({})", compiler.stage, target.triple));
         let _time = timeit(builder);
         builder.run(&mut cmd);
-        Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target)))
+        Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple)))
     }
 }
 
@@ -1419,14 +1419,14 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
             .arg(&distdir(builder))
             .arg("--non-installed-overlay")
             .arg(&overlay)
-            .arg(format!("--package-name={}-{}", name, target))
+            .arg(format!("--package-name={}-{}", name, target.triple))
             .arg("--legacy-manifest-dirs=rustlib,cargo")
             .arg("--component-name=rust-analyzer-preview");
 
         builder.info(&format!("Dist rust-analyzer stage{} ({})", compiler.stage, target));
         let _time = timeit(builder);
         builder.run(&mut cmd);
-        distdir(builder).join(format!("{}-{}.tar.gz", name, target))
+        distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple))
     }
 }
 
@@ -1510,14 +1510,14 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
             .arg(&distdir(builder))
             .arg("--non-installed-overlay")
             .arg(&overlay)
-            .arg(format!("--package-name={}-{}", name, target))
+            .arg(format!("--package-name={}-{}", name, target.triple))
             .arg("--legacy-manifest-dirs=rustlib,cargo")
             .arg("--component-name=clippy-preview");
 
         builder.info(&format!("Dist clippy stage{} ({})", compiler.stage, target));
         let _time = timeit(builder);
         builder.run(&mut cmd);
-        distdir(builder).join(format!("{}-{}.tar.gz", name, target))
+        distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple))
     }
 }
 
@@ -1607,14 +1607,14 @@ fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
             .arg(&distdir(builder))
             .arg("--non-installed-overlay")
             .arg(&overlay)
-            .arg(format!("--package-name={}-{}", name, target))
+            .arg(format!("--package-name={}-{}", name, target.triple))
             .arg("--legacy-manifest-dirs=rustlib,cargo")
             .arg("--component-name=miri-preview");
 
         builder.info(&format!("Dist miri stage{} ({})", compiler.stage, target));
         let _time = timeit(builder);
         builder.run(&mut cmd);
-        Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target)))
+        Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple)))
     }
 }
 
@@ -1701,14 +1701,14 @@ fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
             .arg(&distdir(builder))
             .arg("--non-installed-overlay")
             .arg(&overlay)
-            .arg(format!("--package-name={}-{}", name, target))
+            .arg(format!("--package-name={}-{}", name, target.triple))
             .arg("--legacy-manifest-dirs=rustlib,cargo")
             .arg("--component-name=rustfmt-preview");
 
         builder.info(&format!("Dist Rustfmt stage{} ({})", compiler.stage, target));
         let _time = timeit(builder);
         builder.run(&mut cmd);
-        Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target)))
+        Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple)))
     }
 }
 
@@ -1813,7 +1813,7 @@ fn run(self, builder: &Builder<'_>) {
             .arg(&work)
             .arg("--output-dir")
             .arg(&distdir(builder))
-            .arg(format!("--package-name={}-{}", pkgname(builder, "rust"), target))
+            .arg(format!("--package-name={}-{}", pkgname(builder, "rust"), target.triple))
             .arg("--legacy-manifest-dirs=rustlib,cargo")
             .arg("--input-tarballs")
             .arg(input_tarballs)
@@ -1893,7 +1893,7 @@ fn filter(contents: &str, marker: &str) -> String {
             let prepare = |name: &str| {
                 builder.create_dir(&pkg.join(name));
                 builder.cp_r(
-                    &work.join(&format!("{}-{}", pkgname(builder, name), target)),
+                    &work.join(&format!("{}-{}", pkgname(builder, name), target.triple)),
                     &pkg.join(name),
                 );
                 builder.install(&etc.join("pkg/postinstall"), &pkg.join(name), 0o755);
@@ -1926,7 +1926,11 @@ fn filter(contents: &str, marker: &str) -> String {
                 .arg(xform(&etc.join("pkg/Distribution.xml")))
                 .arg("--resources")
                 .arg(pkg.join("res"))
-                .arg(distdir(builder).join(format!("{}-{}.pkg", pkgname(builder, "rust"), target)))
+                .arg(distdir(builder).join(format!(
+                    "{}-{}.pkg",
+                    pkgname(builder, "rust"),
+                    target.triple
+                )))
                 .arg("--package-path")
                 .arg(&pkg);
             let _time = timeit(builder);
@@ -1940,7 +1944,7 @@ fn filter(contents: &str, marker: &str) -> String {
             let prepare = |name: &str| {
                 builder.create_dir(&exe.join(name));
                 let dir = if name == "rust-std" || name == "rust-analysis" {
-                    format!("{}-{}", name, target)
+                    format!("{}-{}", name, target.triple)
                 } else if name == "rls" {
                     "rls-preview".to_string()
                 } else if name == "rust-analyzer" {
@@ -1953,7 +1957,7 @@ fn filter(contents: &str, marker: &str) -> String {
                     name.to_string()
                 };
                 builder.cp_r(
-                    &work.join(&format!("{}-{}", pkgname(builder, name), target)).join(dir),
+                    &work.join(&format!("{}-{}", pkgname(builder, name), target.triple)).join(dir),
                     &exe.join(name),
                 );
                 builder.remove(&exe.join(name).join("manifest.in"));
@@ -2212,7 +2216,7 @@ fn filter(contents: &str, marker: &str) -> String {
             builder.install(&etc.join("gfx/dialogbg.bmp"), &exe, 0o644);
 
             builder.info(&format!("building `msi` installer with {:?}", light));
-            let filename = format!("{}-{}.msi", pkgname(builder, "rust"), target);
+            let filename = format!("{}-{}.msi", pkgname(builder, "rust"), target.triple);
             let mut cmd = Command::new(&light);
             cmd.arg("-nologo")
                 .arg("-ext")
@@ -2461,11 +2465,11 @@ fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
             .arg(&distdir(builder))
             .arg("--non-installed-overlay")
             .arg(&overlay)
-            .arg(format!("--package-name={}-{}", name, target))
+            .arg(format!("--package-name={}-{}", name, target.triple))
             .arg("--legacy-manifest-dirs=rustlib,cargo")
             .arg("--component-name=llvm-tools-preview");
 
         builder.run(&mut cmd);
-        Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target)))
+        Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple)))
     }
 }
index b051390fc2671f73b7fe1f134717b5e8a4bc4dec..f8a549afc88fb81da408d64ca8c9f7519fee8bf8 100644 (file)
@@ -527,11 +527,9 @@ fn run(self, builder: &Builder<'_>) {
 
         // Build cargo command.
         let mut cargo = builder.cargo(compiler, Mode::Rustc, SourceType::InTree, target, "doc");
-        cargo.env(
-            "RUSTDOCFLAGS",
-            "--document-private-items \
-            --enable-index-page -Zunstable-options",
-        );
+        cargo.rustdocflag("--document-private-items");
+        cargo.rustdocflag("--enable-index-page");
+        cargo.rustdocflag("-Zunstable-options");
         compile::rustc_cargo(builder, &mut cargo, target);
 
         // Only include compiler crates, no dependencies of those, such as `libc`.
@@ -624,7 +622,7 @@ fn run(self, builder: &Builder<'_>) {
         cargo.arg("--no-deps");
         cargo.arg("-p").arg("rustdoc");
 
-        cargo.env("RUSTDOCFLAGS", "--document-private-items");
+        cargo.rustdocflag("--document-private-items");
         builder.run(&mut cargo.into());
     }
 }
index dcdc681e87dbb010e75ee5c34eee6951bd990da1..1316f95dd41770b7b1cd0217924de8a11ff52c46 100644 (file)
@@ -107,7 +107,7 @@ fn install_sh(
 
     t!(fs::create_dir_all(&empty_dir));
     let package_name = if let Some(host) = host {
-        format!("{}-{}", pkgname(builder, name), host)
+        format!("{}-{}", pkgname(builder, name), host.triple)
     } else {
         pkgname(builder, name)
     };
index b6641180c92c0fb9c421223c247637d406f1c0b2..b76d80aa509a5c6d353c3f48df176177b714d62c 100644 (file)
@@ -1022,6 +1022,10 @@ fn run(self, builder: &Builder<'_>) {
             cmd.arg("--rustdoc-path").arg(builder.rustdoc(compiler));
         }
 
+        if mode == "run-make" && suite.ends_with("fulldeps") {
+            cmd.arg("--rust-demangler-path").arg(builder.tool_exe(Tool::RustDemangler));
+        }
+
         cmd.arg("--src-base").arg(builder.src.join("src/test").join(suite));
         cmd.arg("--build-base").arg(testdir(builder, compiler.host).join(suite));
         cmd.arg("--stage-id").arg(format!("stage{}-{}", compiler.stage, target));
index f66061975d64d1ecb8ef7e8d432f9e21de81987c..fe3f1e78029d7679aa9983b1ee5e334a61b76c79 100644 (file)
@@ -361,6 +361,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
     Compiletest, "src/tools/compiletest", "compiletest", is_unstable_tool = true;
     BuildManifest, "src/tools/build-manifest", "build-manifest";
     RemoteTestClient, "src/tools/remote-test-client", "remote-test-client";
+    RustDemangler, "src/tools/rust-demangler", "rust-demangler";
     RustInstaller, "src/tools/rust-installer", "fabricate", is_external_tool = true;
     RustdocTheme, "src/tools/rustdoc-themes", "rustdoc-themes";
     ExpandYamlAnchors, "src/tools/expand-yaml-anchors", "expand-yaml-anchors";
index 43c3c5773ce5b2d45cd32ee1157cf2d8ce0dc1b2..e30da8d56e10fca3ebb0fb3e289f07665e4e27e0 100644 (file)
@@ -1,3 +1,5 @@
+use std::ffi::{OsStr, OsString};
+use std::fmt::Display;
 use std::path::{Path, PathBuf};
 use std::process::{Command, Stdio};
 use std::time::{SystemTime, UNIX_EPOCH};
@@ -28,6 +30,14 @@ macro_rules! t {
     };
 }
 
+/// Reads an environment variable and adds it to dependencies.
+/// Supposed to be used for all variables except those set for build scripts by cargo
+/// https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts
+pub fn tracked_env_var_os<K: AsRef<OsStr> + Display>(key: K) -> Option<OsString> {
+    println!("cargo:rerun-if-env-changed={}", key);
+    env::var_os(key)
+}
+
 // Because Cargo adds the compiler's dylib path to our library search path, llvm-config may
 // break: the dylib path for the compiler, as of this writing, contains a copy of the LLVM
 // shared library, which means that when our freshly built llvm-config goes to load it's
@@ -37,10 +47,8 @@ macro_rules! t {
 // perfect -- we might actually want to see something from Cargo's added library paths -- but
 // for now it works.
 pub fn restore_library_path() {
-    println!("cargo:rerun-if-env-changed=REAL_LIBRARY_PATH_VAR");
-    println!("cargo:rerun-if-env-changed=REAL_LIBRARY_PATH");
-    let key = env::var_os("REAL_LIBRARY_PATH_VAR").expect("REAL_LIBRARY_PATH_VAR");
-    if let Some(env) = env::var_os("REAL_LIBRARY_PATH") {
+    let key = tracked_env_var_os("REAL_LIBRARY_PATH_VAR").expect("REAL_LIBRARY_PATH_VAR");
+    if let Some(env) = tracked_env_var_os("REAL_LIBRARY_PATH") {
         env::set_var(&key, &env);
     } else {
         env::remove_var(&key);
index 1786baa0278b9896df976494b3051a9eedfc972f..06e284c763c1509f7c34b38d3edc5e0198ff158c 100644 (file)
 #####################################
 
 #
-# Azure Pipelines "auto" branch build for Rust on Linux, macOS, and Windows.
+# Azure Pipelines "auto" branch build for Rust on macOS
 #
 
 pr: none
 trigger:
   - auto
 
-variables:
-- group: prod-credentials
-
 jobs:
-- job: Linux
-  timeoutInMinutes: 600
-  pool:
-    vmImage: ubuntu-16.04
-  steps:
-  - template: steps/run.yml
-  strategy:
-    matrix:
-      x86_64-gnu-llvm-8:
-        RUST_BACKTRACE: 1
-      dist-x86_64-linux: {}
-      dist-x86_64-linux-alt:
-        IMAGE: dist-x86_64-linux
-      arm-android: {}
-      armhf-gnu: {}
-      dist-various-1: {}
-      dist-various-2: {}
-      dist-aarch64-linux: {}
-      dist-android: {}
-      dist-arm-linux: {}
-      dist-armhf-linux: {}
-      dist-armv7-linux: {}
-      dist-i586-gnu-i586-i686-musl: {}
-      dist-i686-freebsd: {}
-      dist-i686-linux: {}
-      dist-mips-linux: {}
-      dist-mips64-linux: {}
-      dist-mips64el-linux: {}
-      dist-mipsel-linux: {}
-      dist-powerpc-linux: {}
-      dist-powerpc64-linux: {}
-      dist-powerpc64le-linux: {}
-      dist-riscv64-linux: {}
-      dist-s390x-linux: {}
-      dist-x86_64-freebsd: {}
-      dist-x86_64-illumos: {}
-      dist-x86_64-musl: {}
-      dist-x86_64-netbsd: {}
-      i686-gnu: {}
-      i686-gnu-nopt: {}
-      test-various: {}
-      wasm32: {}
-      x86_64-gnu: {}
-      x86_64-gnu-full-bootstrap: {}
-      x86_64-gnu-aux: {}
-      x86_64-gnu-tools:
-        DEPLOY_TOOLSTATES_JSON: toolstates-linux.json
-      x86_64-gnu-debug: {}
-      x86_64-gnu-nopt: {}
-      x86_64-gnu-distcheck: {}
-      mingw-check: {}
-
 - job: macOS
   timeoutInMinutes: 600
   pool:
     vmImage: macos-10.15
   steps:
   - template: steps/run.yml
+  variables:
+    # We're still uploading macOS builds from Azure Pipelines.
+    - group: prod-credentials
   strategy:
     matrix:
       # OSX builders running tests, these run the full test suite.
@@ -112,115 +60,3 @@ jobs:
         MACOSX_DEPLOYMENT_TARGET: 10.7
         NO_LLVM_ASSERTIONS: 1
         NO_DEBUG_ASSERTIONS: 1
-
-
-- job: Windows
-  timeoutInMinutes: 600
-  pool:
-    vmImage: 'vs2017-win2016'
-  steps:
-  - template: steps/run.yml
-  strategy:
-    matrix:
-      # 32/64 bit MSVC tests
-      x86_64-msvc-1:
-        INITIAL_RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-profiler
-        SCRIPT: make ci-subset-1
-        # FIXME(#59637)
-        NO_DEBUG_ASSERTIONS: 1
-        NO_LLVM_ASSERTIONS: 1
-      x86_64-msvc-2:
-        INITIAL_RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-profiler
-        SCRIPT: make ci-subset-2
-      i686-msvc-1:
-        INITIAL_RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc
-        SCRIPT: make ci-subset-1
-        # FIXME(#59637)
-        NO_DEBUG_ASSERTIONS: 1
-        NO_LLVM_ASSERTIONS: 1
-      i686-msvc-2:
-        INITIAL_RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc
-        SCRIPT: make ci-subset-2
-        # FIXME(#59637)
-        NO_DEBUG_ASSERTIONS: 1
-        NO_LLVM_ASSERTIONS: 1
-      x86_64-msvc-cargo:
-        SCRIPT: python x.py test src/tools/cargotest src/tools/cargo
-        INITIAL_RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-lld
-        VCVARS_BAT: vcvars64.bat
-        # FIXME(#59637)
-        NO_DEBUG_ASSERTIONS: 1
-        NO_LLVM_ASSERTIONS: 1
-      # MSVC tools tests
-      x86_64-msvc-tools:
-        SCRIPT: src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh x.py
-        INITIAL_RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --save-toolstates=/tmp/toolstate/toolstates.json
-
-      # 32/64-bit MinGW builds.
-      #
-      # We are using MinGW with posix threads since LLVM does not compile with
-      # the win32 threads version due to missing support for C++'s std::thread.
-      #
-      # Instead of relying on the MinGW version installed on appveryor we download
-      # and install one ourselves so we won't be surprised by changes to appveyor's
-      # build image.
-      #
-      # Finally, note that the downloads below are all in the `rust-lang-ci` S3
-      # bucket, but they cleraly didn't originate there! The downloads originally
-      # came from the mingw-w64 SourceForge download site. Unfortunately
-      # SourceForge is notoriously flaky, so we mirror it on our own infrastructure.
-      i686-mingw-1:
-        INITIAL_RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu
-        SCRIPT: make ci-mingw-subset-1
-        CUSTOM_MINGW: 1
-        # FIXME(#59637)
-        NO_DEBUG_ASSERTIONS: 1
-        NO_LLVM_ASSERTIONS: 1
-      i686-mingw-2:
-        INITIAL_RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu
-        SCRIPT: make ci-mingw-subset-2
-        CUSTOM_MINGW: 1
-      x86_64-mingw-1:
-        SCRIPT: make ci-mingw-subset-1
-        INITIAL_RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu
-        CUSTOM_MINGW: 1
-        # FIXME(#59637)
-        NO_DEBUG_ASSERTIONS: 1
-        NO_LLVM_ASSERTIONS: 1
-      x86_64-mingw-2:
-        SCRIPT: make ci-mingw-subset-2
-        INITIAL_RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu
-        CUSTOM_MINGW: 1
-
-      # 32/64 bit MSVC and GNU deployment
-      dist-x86_64-msvc:
-        INITIAL_RUST_CONFIGURE_ARGS: >-
-          --build=x86_64-pc-windows-msvc
-          --target=x86_64-pc-windows-msvc,aarch64-pc-windows-msvc
-          --enable-full-tools
-          --enable-profiler
-        SCRIPT: python x.py dist
-        DIST_REQUIRE_ALL_TOOLS: 1
-      dist-i686-msvc:
-        INITIAL_RUST_CONFIGURE_ARGS: >-
-          --build=i686-pc-windows-msvc
-          --target=i586-pc-windows-msvc
-          --enable-full-tools
-          --enable-profiler
-        SCRIPT: python x.py dist
-        DIST_REQUIRE_ALL_TOOLS: 1
-      dist-i686-mingw:
-        INITIAL_RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-full-tools --enable-profiler
-        SCRIPT: python x.py dist
-        CUSTOM_MINGW: 1
-        DIST_REQUIRE_ALL_TOOLS: 1
-      dist-x86_64-mingw:
-        SCRIPT: python x.py dist
-        INITIAL_RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-full-tools --enable-profiler
-        CUSTOM_MINGW: 1
-        DIST_REQUIRE_ALL_TOOLS: 1
-
-      # "alternate" deployment, see .travis.yml for more info
-      dist-x86_64-msvc-alt:
-        INITIAL_RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-extended --enable-profiler
-        SCRIPT: python x.py dist
diff --git a/src/ci/azure-pipelines/master.yml b/src/ci/azure-pipelines/master.yml
deleted file mode 100644 (file)
index 485b803..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-#####################################
-##    READ BEFORE CHANGING THIS    ##
-#####################################
-
-# We're in the process of evaluating GitHub Actions as a possible replacement
-# for Azure Pipelines, and at the moment the configuration is duplicated
-# between the two CI providers. Be sure to also change the configuration in
-# src/ci/github-actions when changing this file.
-
-#####################################
-
-#
-# Azure Pipelines job to publish toolstate. Only triggers on pushes to master.
-#
-
-pr: none
-trigger:
-  - master
-
-variables:
-- group: prod-credentials
-
-pool:
-  vmImage: ubuntu-16.04
-
-steps:
-- checkout: self
-  fetchDepth: 2
-
-- script: src/ci/publish_toolstate.sh
-  displayName: Publish toolstate
-  env:
-    TOOLSTATE_REPO_ACCESS_TOKEN: $(TOOLSTATE_REPO_ACCESS_TOKEN)
diff --git a/src/ci/azure-pipelines/pr.yml b/src/ci/azure-pipelines/pr.yml
deleted file mode 100644 (file)
index 1fc8d18..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-#####################################
-##    READ BEFORE CHANGING THIS    ##
-#####################################
-
-# We're in the process of evaluating GitHub Actions as a possible replacement
-# for Azure Pipelines, and at the moment the configuration is duplicated
-# between the two CI providers. Be sure to also change the configuration in
-# src/ci/github-actions when changing this file.
-
-#####################################
-
-#
-# Azure Pipelines pull request build for Rust
-#
-
-trigger: none
-pr:
-- master
-
-variables:
-- group: public-credentials
-
-jobs:
-- job: Linux
-  timeoutInMinutes: 600
-  pool:
-    vmImage: ubuntu-16.04
-  steps:
-    - template: steps/run.yml
-  strategy:
-    matrix:
-      x86_64-gnu-llvm-8: {}
-      mingw-check: {}
-      x86_64-gnu-tools:
-        CI_ONLY_WHEN_SUBMODULES_CHANGED: 1
index 818306a00922986ab4fe3c3f8ceb079b574a3acd..62bb6f47334123f79f34d6d77bd552ba99ea2900 100644 (file)
@@ -13,70 +13,10 @@ pr: none
 trigger:
 - try
 
-variables:
-- group: prod-credentials
-
 jobs:
-- job: Linux
+- job: Dummy
   timeoutInMinutes: 600
   pool:
     vmImage: ubuntu-16.04
   steps:
-  - template: steps/run.yml
-  strategy:
-    matrix:
-      dist-x86_64-linux: {}
-
-# The macOS and Windows builds here are currently disabled due to them not being
-# overly necessary on `try` builds. We also don't actually have anything that
-# consumes the artifacts currently. Perhaps one day we can re-enable, but for now
-# it helps free up capacity on Azure.
-# - job: macOS
-#   timeoutInMinutes: 600
-#   pool:
-#     vmImage: macos-10.15
-#   steps:
-#   - template: steps/run.yml
-#   strategy:
-#     matrix:
-#       dist-x86_64-apple:
-#         SCRIPT: ./x.py dist
-#         INITIAL_RUST_CONFIGURE_ARGS: --target=aarch64-apple-ios,armv7-apple-ios,armv7s-apple-ios,i386-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc
-#         DEPLOY: 1
-#         RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
-#         MACOSX_DEPLOYMENT_TARGET: 10.7
-#         NO_LLVM_ASSERTIONS: 1
-#         NO_DEBUG_ASSERTIONS: 1
-#         DIST_REQUIRE_ALL_TOOLS: 1
-#
-#       dist-x86_64-apple-alt:
-#         SCRIPT: ./x.py dist
-#         INITIAL_RUST_CONFIGURE_ARGS: --enable-extended --enable-profiler --set rust.jemalloc
-#         DEPLOY_ALT: 1
-#         RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
-#         MACOSX_DEPLOYMENT_TARGET: 10.7
-#         NO_LLVM_ASSERTIONS: 1
-#         NO_DEBUG_ASSERTIONS: 1
-#
-# - job: Windows
-#   timeoutInMinutes: 600
-#   pool:
-#     vmImage: 'vs2017-win2016'
-#   steps:
-#   - template: steps/run.yml
-#   strategy:
-#     matrix:
-#       dist-x86_64-msvc:
-#         INITIAL_RUST_CONFIGURE_ARGS: >
-#           --build=x86_64-pc-windows-msvc
-#           --target=x86_64-pc-windows-msvc,aarch64-pc-windows-msvc
-#           --enable-full-tools
-#           --enable-profiler
-#         SCRIPT: python x.py dist
-#         DIST_REQUIRE_ALL_TOOLS: 1
-#         DEPLOY: 1
-#
-#       dist-x86_64-msvc-alt:
-#         INITIAL_RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-extended --enable-profiler
-#         SCRIPT: python x.py dist
-#         DEPLOY_ALT: 1
+  - bash: echo "We're running this job since bors is still gating on Azure"
index eac0ed24d509e94a0be5377eab1af980702bd1a8..9a051caa0667881dc49ee425bf295a4cde1d3c5f 100644 (file)
@@ -1,34 +1,44 @@
-FROM centos:5
+# We use Debian 6 (glibc 2.11, kernel 2.6.32) as a common base for other
+# distros that still need Rust support: RHEL 6 (glibc 2.12, kernel 2.6.32) and
+# SLES 11 SP4 (glibc 2.11, kernel 3.0).
+FROM debian:6
 
 WORKDIR /build
 
-# Centos 5 is EOL and is no longer available from the usual mirrors, so switch
-# to http://vault.centos.org/
-RUN sed -i 's/enabled=1/enabled=0/' /etc/yum/pluginconf.d/fastestmirror.conf
-RUN sed -i 's/mirrorlist/#mirrorlist/' /etc/yum.repos.d/*.repo
-RUN sed -i 's|#\(baseurl.*\)mirror.centos.org/centos/$releasever|\1vault.centos.org/5.11|' /etc/yum.repos.d/*.repo
+# Debian 6 is EOL and no longer available from the usual mirrors,
+# so we'll need to switch to http://archive.debian.org/
+RUN sed -i '/updates/d' /etc/apt/sources.list && \
+    sed -i 's/httpredir/archive/' /etc/apt/sources.list
 
-RUN yum upgrade -y && yum install -y \
-      curl \
+RUN apt-get update && \
+    apt-get install --allow-unauthenticated -y --no-install-recommends \
+      automake \
       bzip2 \
+      ca-certificates \
+      curl \
+      file \
+      g++ \
+      g++-multilib \
       gcc \
-      gcc-c++ \
+      gcc-multilib \
+      git \
+      lib32z1-dev \
+      libedit-dev \
+      libncurses-dev \
       make \
-      glibc-devel \
+      patch \
       perl \
-      zlib-devel \
-      file \
-      xz \
-      which \
-      pkgconfig \
+      pkg-config \
+      unzip \
       wget \
-      autoconf \
-      gettext
+      xz-utils \
+      zlib1g-dev
 
 ENV PATH=/rustroot/bin:$PATH
-ENV LD_LIBRARY_PATH=/rustroot/lib64:/rustroot/lib
+ENV LD_LIBRARY_PATH=/rustroot/lib64:/rustroot/lib32:/rustroot/lib
 ENV PKG_CONFIG_PATH=/rustroot/lib/pkgconfig
 WORKDIR /tmp
+RUN mkdir /home/user
 COPY host-x86_64/dist-x86_64-linux/shared.sh /tmp/
 
 # We need a build of openssl which supports SNI to download artifacts from
@@ -38,14 +48,14 @@ COPY host-x86_64/dist-x86_64-linux/shared.sh /tmp/
 COPY host-x86_64/dist-x86_64-linux/build-openssl.sh /tmp/
 RUN ./build-openssl.sh
 
-# The `curl` binary on CentOS doesn't support SNI which is needed for fetching
+# The `curl` binary on Debian 6 doesn't support SNI which is needed for fetching
 # some https urls we have, so install a new version of libcurl + curl which is
 # using the openssl we just built previously.
 #
 # Note that we also disable a bunch of optional features of curl that we don't
 # really need.
 COPY host-x86_64/dist-x86_64-linux/build-curl.sh /tmp/
-RUN ./build-curl.sh
+RUN ./build-curl.sh && apt-get remove -y curl
 
 # binutils < 2.22 has a bug where the 32-bit executables it generates
 # immediately segfault in Rust, so we need to install our own binutils.
@@ -54,40 +64,24 @@ RUN ./build-curl.sh
 COPY host-x86_64/dist-x86_64-linux/build-binutils.sh /tmp/
 RUN ./build-binutils.sh
 
-# libssh2 (a dependency of Cargo) requires cmake 2.8.11 or higher but CentOS
-# only has 2.6.4, so build our own
-COPY host-x86_64/dist-x86_64-linux/build-cmake.sh /tmp/
-RUN ./build-cmake.sh
-
-# Need a newer version of gcc than centos has to compile LLVM nowadays
+# Need at least GCC 5.1 to compile LLVM nowadays
 COPY host-x86_64/dist-x86_64-linux/build-gcc.sh /tmp/
-RUN ./build-gcc.sh
+RUN ./build-gcc.sh && apt-get remove -y gcc g++
 
-# CentOS 5.5 has Python 2.4 by default, but LLVM needs 2.7+
+# Debian 6 has Python 2.6 by default, but LLVM needs 2.7+
 COPY host-x86_64/dist-x86_64-linux/build-python.sh /tmp/
 RUN ./build-python.sh
 
-# Now build LLVM+Clang 7, afterwards configuring further compilations to use the
+# LLVM needs cmake 3.4.3 or higher, and is planning to raise to 3.13.4.
+COPY host-x86_64/dist-x86_64-linux/build-cmake.sh /tmp/
+RUN ./build-cmake.sh
+
+# Now build LLVM+Clang, afterwards configuring further compilations to use the
 # clang/clang++ compilers.
-COPY host-x86_64/dist-x86_64-linux/build-clang.sh host-x86_64/dist-x86_64-linux/llvm-project-centos.patch /tmp/
+COPY host-x86_64/dist-x86_64-linux/build-clang.sh /tmp/
 RUN ./build-clang.sh
 ENV CC=clang CXX=clang++
 
-# Apparently CentOS 5.5 desn't have `git` in yum, but we're gonna need it for
-# cloning, so download and build it here.
-COPY host-x86_64/dist-x86_64-linux/build-git.sh /tmp/
-RUN ./build-git.sh
-
-# for sanitizers, we need kernel headers files newer than the ones CentOS ships
-# with so we install newer ones here
-COPY host-x86_64/dist-x86_64-linux/build-headers.sh /tmp/
-RUN ./build-headers.sh
-
-# OpenSSL requires a more recent version of perl
-# with so we install newer ones here
-COPY host-x86_64/dist-x86_64-linux/build-perl.sh /tmp/
-RUN ./build-perl.sh
-
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
@@ -117,4 +111,11 @@ ENV CFLAGS -mstackrealign
 # libcurl, instead it should compile its own.
 ENV LIBCURL_NO_PKG_CONFIG 1
 
+# There was a bad interaction between "old" 32-bit binaries on current 64-bit
+# kernels with selinux enabled, where ASLR mmap would sometimes choose a low
+# address and then block it for being below `vm.mmap_min_addr` -> `EACCES`.
+# This is probably a kernel bug, but setting `ulimit -Hs` works around it.
+# See also `src/ci/run.sh` where this takes effect.
+ENV SET_HARD_RLIMIT_STACK 1
+
 ENV DIST_REQUIRE_ALL_TOOLS 1
index 8b78214fbdd146138dcca92b622c5e51da17c5ed..1f0978c0082c5898166955a5dba385dc8deb62f4 100644 (file)
@@ -1,34 +1,44 @@
-FROM centos:5
+# We use Debian 6 (glibc 2.11, kernel 2.6.32) as a common base for other
+# distros that still need Rust support: RHEL 6 (glibc 2.12, kernel 2.6.32) and
+# SLES 11 SP4 (glibc 2.11, kernel 3.0).
+FROM debian:6
 
 WORKDIR /build
 
-# Centos 5 is EOL and is no longer available from the usual mirrors, so switch
-# to http://vault.centos.org/
-RUN sed -i 's/enabled=1/enabled=0/' /etc/yum/pluginconf.d/fastestmirror.conf
-RUN sed -i 's/mirrorlist/#mirrorlist/' /etc/yum.repos.d/*.repo
-RUN sed -i 's|#\(baseurl.*\)mirror.centos.org/centos/$releasever|\1vault.centos.org/5.11|' /etc/yum.repos.d/*.repo
+# Debian 6 is EOL and no longer available from the usual mirrors,
+# so we'll need to switch to http://archive.debian.org/
+RUN sed -i '/updates/d' /etc/apt/sources.list && \
+    sed -i 's/httpredir/archive/' /etc/apt/sources.list
 
-RUN yum upgrade -y && yum install -y \
-      curl \
+RUN apt-get update && \
+    apt-get install --allow-unauthenticated -y --no-install-recommends \
+      automake \
       bzip2 \
+      ca-certificates \
+      curl \
+      file \
+      g++ \
+      g++-multilib \
       gcc \
-      gcc-c++ \
+      gcc-multilib \
+      git \
+      lib32z1-dev \
+      libedit-dev \
+      libncurses-dev \
       make \
-      glibc-devel \
+      patch \
       perl \
-      zlib-devel \
-      file \
-      xz \
-      which \
-      pkgconfig \
+      pkg-config \
+      unzip \
       wget \
-      autoconf \
-      gettext
+      xz-utils \
+      zlib1g-dev
 
 ENV PATH=/rustroot/bin:$PATH
-ENV LD_LIBRARY_PATH=/rustroot/lib64:/rustroot/lib
+ENV LD_LIBRARY_PATH=/rustroot/lib64:/rustroot/lib32:/rustroot/lib
 ENV PKG_CONFIG_PATH=/rustroot/lib/pkgconfig
 WORKDIR /tmp
+RUN mkdir /home/user
 COPY host-x86_64/dist-x86_64-linux/shared.sh /tmp/
 
 # We need a build of openssl which supports SNI to download artifacts from
@@ -38,14 +48,14 @@ COPY host-x86_64/dist-x86_64-linux/shared.sh /tmp/
 COPY host-x86_64/dist-x86_64-linux/build-openssl.sh /tmp/
 RUN ./build-openssl.sh
 
-# The `curl` binary on CentOS doesn't support SNI which is needed for fetching
+# The `curl` binary on Debian 6 doesn't support SNI which is needed for fetching
 # some https urls we have, so install a new version of libcurl + curl which is
 # using the openssl we just built previously.
 #
 # Note that we also disable a bunch of optional features of curl that we don't
 # really need.
 COPY host-x86_64/dist-x86_64-linux/build-curl.sh /tmp/
-RUN ./build-curl.sh
+RUN ./build-curl.sh && apt-get remove -y curl
 
 # binutils < 2.22 has a bug where the 32-bit executables it generates
 # immediately segfault in Rust, so we need to install our own binutils.
@@ -54,40 +64,24 @@ RUN ./build-curl.sh
 COPY host-x86_64/dist-x86_64-linux/build-binutils.sh /tmp/
 RUN ./build-binutils.sh
 
-# libssh2 (a dependency of Cargo) requires cmake 2.8.11 or higher but CentOS
-# only has 2.6.4, so build our own
-COPY host-x86_64/dist-x86_64-linux/build-cmake.sh /tmp/
-RUN ./build-cmake.sh
-
-# Build a version of gcc capable of building LLVM 6
+# Need at least GCC 5.1 to compile LLVM nowadays
 COPY host-x86_64/dist-x86_64-linux/build-gcc.sh /tmp/
-RUN ./build-gcc.sh
+RUN ./build-gcc.sh && apt-get remove -y gcc g++
 
-# CentOS 5.5 has Python 2.4 by default, but LLVM needs 2.7+
+# Debian 6 has Python 2.6 by default, but LLVM needs 2.7+
 COPY host-x86_64/dist-x86_64-linux/build-python.sh /tmp/
 RUN ./build-python.sh
 
-# Now build LLVM+Clang 7, afterwards configuring further compilations to use the
+# LLVM needs cmake 3.4.3 or higher, and is planning to raise to 3.13.4.
+COPY host-x86_64/dist-x86_64-linux/build-cmake.sh /tmp/
+RUN ./build-cmake.sh
+
+# Now build LLVM+Clang, afterwards configuring further compilations to use the
 # clang/clang++ compilers.
-COPY host-x86_64/dist-x86_64-linux/build-clang.sh host-x86_64/dist-x86_64-linux/llvm-project-centos.patch /tmp/
+COPY host-x86_64/dist-x86_64-linux/build-clang.sh /tmp/
 RUN ./build-clang.sh
 ENV CC=clang CXX=clang++
 
-# Apparently CentOS 5.5 desn't have `git` in yum, but we're gonna need it for
-# cloning, so download and build it here.
-COPY host-x86_64/dist-x86_64-linux/build-git.sh /tmp/
-RUN ./build-git.sh
-
-# for sanitizers, we need kernel headers files newer than the ones CentOS ships
-# with so we install newer ones here
-COPY host-x86_64/dist-x86_64-linux/build-headers.sh /tmp/
-RUN ./build-headers.sh
-
-# OpenSSL requires a more recent version of perl
-# with so we install newer ones here
-COPY host-x86_64/dist-x86_64-linux/build-perl.sh /tmp/
-RUN ./build-perl.sh
-
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
index 518f6ef9b701dc249c0924788856f2d78905192e..2c00a628a1d350e764dbd51b534167a808e98c00 100755 (executable)
@@ -12,9 +12,6 @@ cd llvm-project
 curl -L https://github.com/llvm/llvm-project/archive/$LLVM.tar.gz | \
   tar xzf - --strip-components=1
 
-yum install -y patch
-patch -Np1 < ../llvm-project-centos.patch
-
 mkdir clang-build
 cd clang-build
 
index 84522a7b87a4b194d8f0531b82eb8d636057a959..e17831a1afee56da93229799ff3ac6ae2113c005 100755 (executable)
@@ -3,14 +3,15 @@
 set -ex
 source shared.sh
 
-curl https://cmake.org/files/v3.6/cmake-3.6.3.tar.gz | tar xzf -
+CMAKE=3.13.4
+curl -L https://github.com/Kitware/CMake/releases/download/v$CMAKE/cmake-$CMAKE.tar.gz | tar xzf -
 
 mkdir cmake-build
 cd cmake-build
-hide_output ../cmake-3.6.3/configure --prefix=/rustroot
+hide_output ../cmake-$CMAKE/configure --prefix=/rustroot
 hide_output make -j10
 hide_output make install
 
 cd ..
 rm -rf cmake-build
-rm -rf cmake-3.6.3
+rm -rf cmake-$CMAKE
index 0c7eb5fdac9bea0425b92a8c4a8f31375546b3eb..a60c6be9f322211ad3be6371c2809dc1169236cc 100755 (executable)
@@ -36,4 +36,3 @@ hide_output make install
 cd ..
 rm -rf curl-build
 rm -rf curl-$VERSION
-yum erase -y curl
index ddc2066537cefa7f69d0b6599695a7da8defa5df..9d7461ebee32b4a86de019254bf6eab3ed9497aa 100755 (executable)
@@ -37,4 +37,3 @@ ln -s gcc /rustroot/bin/cc
 cd ..
 rm -rf gcc-build
 rm -rf gcc-$GCC
-yum erase -y gcc gcc-c++ binutils
index 5573d87aa2e55c278399a8f0e0c1b6a12bf11600..0aeb6a04e5f773ec8d12ef17351ba9ef77f5d88f 100644 (file)
@@ -35,11 +35,26 @@ x--expand-yaml-anchors--remove:
     CI_JOB_NAME: ${{ matrix.name }}
 
   - &public-variables
-    SCCACHE_BUCKET: rust-lang-gha-caches
-    TOOLSTATE_REPO: https://github.com/pietroalbini/rust-toolstate
-    CACHE_DOMAIN: ci-caches-gha.rust-lang.org
+    SCCACHE_BUCKET: rust-lang-ci-sccache2
+    TOOLSTATE_REPO: https://github.com/rust-lang-nursery/rust-toolstate
+    CACHE_DOMAIN: ci-caches.rust-lang.org
 
   - &prod-variables
+    SCCACHE_BUCKET: rust-lang-ci-sccache2
+    DEPLOY_BUCKET: rust-lang-ci2
+    TOOLSTATE_REPO: https://github.com/rust-lang-nursery/rust-toolstate
+    TOOLSTATE_ISSUES_API_URL: https://api.github.com/repos/rust-lang/rust/issues
+    TOOLSTATE_PUBLISH: 1
+    # AWS_SECRET_ACCESS_KEYs are stored in GitHub's secrets storage, named
+    # AWS_SECRET_ACCESS_KEY_<keyid>. Including the key id in the name allows to
+    # rotate them in a single branch while keeping the old key in another
+    # branch, which wouldn't be possible if the key was named with the kind
+    # (caches, artifacts...).
+    CACHES_AWS_ACCESS_KEY_ID: AKIA46X5W6CZI5DHEBFL
+    ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZN24CBO55
+    CACHE_DOMAIN: ci-caches.rust-lang.org
+
+  - &dummy-variables
     SCCACHE_BUCKET: rust-lang-gha-caches
     DEPLOY_BUCKET: rust-lang-gha
     TOOLSTATE_REPO: https://github.com/pietroalbini/rust-toolstate
@@ -92,6 +107,15 @@ x--expand-yaml-anchors--remove:
         if: success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'
         <<: *step
 
+      # Rust Log Analyzer can't currently detect the PR number of a GitHub
+      # Actions build on its own, so a hint in the log message is needed to
+      # point it in the right direction.
+      - name: configure the PR in which the error message will be posted
+        run: echo "[CI_PR_NUMBER=$num]"
+        env:
+          num: ${{ github.event.number }}
+        if: success() && !env.SKIP_JOBS && github.event_name == 'pull_request'
+
       - name: add extra environment variables
         run: src/ci/scripts/setup-environment.sh
         env:
@@ -223,6 +247,7 @@ on:
     branches:
       - auto
       - try
+      - try-perf
       - master
   pull_request:
     branches:
@@ -261,7 +286,7 @@ jobs:
     name: try
     env:
       <<: [*shared-ci-variables, *prod-variables]
-    if: github.event_name == 'push' && github.ref == 'refs/heads/try' && github.repository == 'rust-lang-ci/rust'
+    if: github.event_name == 'push' && (github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf') && github.repository == 'rust-lang-ci/rust'
     strategy:
       matrix:
         include:
@@ -556,7 +581,7 @@ jobs:
     <<: *base-ci-job
     name: auto-fallible
     env:
-      <<: [*shared-ci-variables, *prod-variables]
+      <<: [*shared-ci-variables, *dummy-variables]
     if: github.event_name == 'push' && github.ref == 'refs/heads/auto' && github.repository == 'rust-lang-ci/rust'
     strategy:
       matrix:
@@ -621,11 +646,11 @@ jobs:
   # successful listening to webhooks only.
   try-success:
     needs: [try]
-    if: "success() && github.event_name == 'push' && github.ref == 'refs/heads/try' && github.repository == 'rust-lang-ci/rust'"
+    if: "success() && github.event_name == 'push' && (github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf') && github.repository == 'rust-lang-ci/rust'"
     <<: *base-success-job
   try-failure:
     needs: [try]
-    if: "!success() && github.event_name == 'push' && github.ref == 'refs/heads/try' && github.repository == 'rust-lang-ci/rust'"
+    if: "!success() && github.event_name == 'push' && (github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf') && github.repository == 'rust-lang-ci/rust'"
     <<: *base-failure-job
   auto-success:
     needs: [auto]
index 59f2736cbd406b05e11bfebd35e97dd66218258e..5231aa2e7661979f0ff006deeb5093682900311e 100755 (executable)
@@ -20,6 +20,18 @@ if [ -f /proc/sys/kernel/core_pattern ]; then
   ulimit -c unlimited
 fi
 
+# There was a bad interaction between "old" 32-bit binaries on current 64-bit
+# kernels with selinux enabled, where ASLR mmap would sometimes choose a low
+# address and then block it for being below `vm.mmap_min_addr` -> `EACCES`.
+# This is probably a kernel bug, but setting `ulimit -Hs` works around it.
+# See also `dist-i686-linux` where this setting is enabled.
+if [ "$SET_HARD_RLIMIT_STACK" = "1" ]; then
+  rlimit_stack=$(ulimit -Ss)
+  if [ "$rlimit_stack" != "" ]; then
+    ulimit -Hs "$rlimit_stack"
+  fi
+fi
+
 ci_dir=`cd $(dirname $0) && pwd`
 source "$ci_dir/shared.sh"
 
index 84a31397b34f9d405df44f2899ff17a4828dba18..a914f2c7e5cdb771fa465de142381a51c53b580e 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 84a31397b34f9d405df44f2899ff17a4828dba18
+Subproject commit a914f2c7e5cdb771fa465de142381a51c53b580e
index 82bec5877c77cfad530ca11095db4456d757f668..bd6e4a9f59c5c1545f572266af77f5c7a5bad6d1 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 82bec5877c77cfad530ca11095db4456d757f668
+Subproject commit bd6e4a9f59c5c1545f572266af77f5c7a5bad6d1
index 0ea7bc494f1289234d8800bb9185021e0ad946f0..b329ce37424874ad4db94f829a55807c6e21d2cb 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 0ea7bc494f1289234d8800bb9185021e0ad946f0
+Subproject commit b329ce37424874ad4db94f829a55807c6e21d2cb
index 0b4bb05c1db23e66ead131d085b9ced6d7bf9141..35904e15d3feeaa596f58772a70bcd92fb1cd848 100644 (file)
@@ -42,6 +42,18 @@ generated code, but may be slower to compile.
 The default value, if not specified, is 16 for non-incremental builds. For
 incremental builds the default is 256 which allows caching to be more granular.
 
+## control-flow-guard
+
+This flag controls whether LLVM enables the Windows [Control Flow 
+Guard](https://docs.microsoft.com/en-us/windows/win32/secbp/control-flow-guard) 
+platform security feature. This flag is currently ignored for non-Windows targets. 
+It takes one of the following values:
+
+* `y`, `yes`, `on`, `checks`, or no value: enable Control Flow Guard.
+* `nochecks`: emit Control Flow Guard metadata without runtime enforcement checks (this 
+should only be used for testing purposes as it does not provide security enforcement).
+* `n`, `no`, `off`: do not enable Control Flow Guard (the default).
+
 ## debug-assertions
 
 This flag lets you turn `cfg(debug_assertions)` [conditional
index 5e2e04c063bc483abff4700462958c6791e9573a..93908e9190e6436af2fdc6290aec711543fe252e 100644 (file)
@@ -26,6 +26,9 @@ of bugs:
 * Double-free, invalid free
 * Memory leaks
 
+The memory leak detection is enabled by default on Linux, and can be enabled
+with runtime flag `ASAN_OPTIONS=detect_leaks=1` on macOS.
+
 AddressSanitizer is supported on the following targets:
 
 * `x86_64-apple-darwin`
@@ -196,10 +199,6 @@ fn main() {
 
 ```shell
 $ export \
-  CC=clang \
-  CXX=clang++ \
-  CFLAGS='-fsanitize=memory -fsanitize-memory-track-origins' \
-  CXXFLAGS='-fsanitize=memory -fsanitize-memory-track-origins' \
   RUSTFLAGS='-Zsanitizer=memory -Zsanitizer-memory-track-origins' \
   RUSTDOCFLAGS='-Zsanitizer=memory -Zsanitizer-memory-track-origins'
 $ cargo clean
index 15313e333ce732a876646d5fe533b77a58f4d0bf..8398cfa3bd34e2ea07fbca98e3ce7ec9a7d1f1ed 100644 (file)
@@ -1,9 +1,9 @@
 //! A priority queue implemented with a binary heap.
 //!
-//! Insertion and popping the largest element have `O(log(n))` time complexity.
-//! Checking the largest element is `O(1)`. Converting a vector to a binary heap
-//! can be done in-place, and has `O(n)` complexity. A binary heap can also be
-//! converted to a sorted vector in-place, allowing it to be used for an `O(n * log(n))`
+//! Insertion and popping the largest element have *O*(log(*n*)) time complexity.
+//! Checking the largest element is *O*(1). Converting a vector to a binary heap
+//! can be done in-place, and has *O*(*n*) complexity. A binary heap can also be
+//! converted to a sorted vector in-place, allowing it to be used for an *O*(*n* \* log(*n*))
 //! in-place heapsort.
 //!
 //! # Examples
 ///
 /// | [push] | [pop]     | [peek]/[peek\_mut] |
 /// |--------|-----------|--------------------|
-/// | O(1)~  | O(log(n)) | O(1)               |
+/// | O(1)~  | *O*(log(*n*)) | *O*(1)               |
 ///
 /// The value for `push` is an expected cost; the method documentation gives a
 /// more detailed analysis.
@@ -398,7 +398,7 @@ pub fn with_capacity(capacity: usize) -> BinaryHeap<T> {
     ///
     /// # Time complexity
     ///
-    /// Cost is `O(1)` in the worst case.
+    /// Cost is *O*(1) in the worst case.
     #[stable(feature = "binary_heap_peek_mut", since = "1.12.0")]
     pub fn peek_mut(&mut self) -> Option<PeekMut<'_, T>> {
         if self.is_empty() { None } else { Some(PeekMut { heap: self, sift: true }) }
@@ -422,7 +422,7 @@ pub fn peek_mut(&mut self) -> Option<PeekMut<'_, T>> {
     ///
     /// # Time complexity
     ///
-    /// The worst case cost of `pop` on a heap containing *n* elements is `O(log(n))`.
+    /// The worst case cost of `pop` on a heap containing *n* elements is *O*(log(*n*)).
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn pop(&mut self) -> Option<T> {
         self.data.pop().map(|mut item| {
@@ -455,15 +455,15 @@ pub fn pop(&mut self) -> Option<T> {
     ///
     /// The expected cost of `push`, averaged over every possible ordering of
     /// the elements being pushed, and over a sufficiently large number of
-    /// pushes, is `O(1)`. This is the most meaningful cost metric when pushing
+    /// pushes, is *O*(1). This is the most meaningful cost metric when pushing
     /// elements that are *not* already in any sorted pattern.
     ///
     /// The time complexity degrades if elements are pushed in predominantly
     /// ascending order. In the worst case, elements are pushed in ascending
-    /// sorted order and the amortized cost per push is `O(log(n))` against a heap
+    /// sorted order and the amortized cost per push is *O*(log(*n*)) against a heap
     /// containing *n* elements.
     ///
-    /// The worst case cost of a *single* call to `push` is `O(n)`. The worst case
+    /// The worst case cost of a *single* call to `push` is *O*(*n*). The worst case
     /// occurs when capacity is exhausted and needs a resize. The resize cost
     /// has been amortized in the previous figures.
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -643,7 +643,7 @@ fn better_to_rebuild(len1: usize, len2: usize) -> bool {
     /// The remaining elements will be removed on drop in heap order.
     ///
     /// Note:
-    /// * `.drain_sorted()` is `O(n * log(n))`; much slower than `.drain()`.
+    /// * `.drain_sorted()` is *O*(*n* \* log(*n*)); much slower than `.drain()`.
     ///   You should use the latter for most cases.
     ///
     /// # Examples
@@ -756,7 +756,7 @@ pub fn into_iter_sorted(self) -> IntoIterSorted<T> {
     ///
     /// # Time complexity
     ///
-    /// Cost is `O(1)` in the worst case.
+    /// Cost is *O*(1) in the worst case.
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn peek(&self) -> Option<&T> {
         self.data.get(0)
@@ -1312,7 +1312,7 @@ unsafe impl<T: Ord> TrustedLen for DrainSorted<'_, T> {}
 impl<T: Ord> From<Vec<T>> for BinaryHeap<T> {
     /// Converts a `Vec<T>` into a `BinaryHeap<T>`.
     ///
-    /// This conversion happens in-place, and has `O(n)` time complexity.
+    /// This conversion happens in-place, and has *O*(*n*) time complexity.
     fn from(vec: Vec<T>) -> BinaryHeap<T> {
         let mut heap = BinaryHeap { data: vec };
         heap.rebuild();
index bf5748739d470422e0d110770812baf6bc9a1bbc..d2f4278d0d0e0a817d51246c971265c4056c6103 100644 (file)
@@ -47,9 +47,9 @@
 /// any other key, as determined by the [`Ord`] trait, changes while it is in the map. This is
 /// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code.
 ///
-/// [`Ord`]: ../../std/cmp/trait.Ord.html
-/// [`Cell`]: ../../std/cell/struct.Cell.html
-/// [`RefCell`]: ../../std/cell/struct.RefCell.html
+/// [`Ord`]: core::cmp::Ord
+/// [`Cell`]: core::cell::Cell
+/// [`RefCell`]: core::cell::RefCell
 ///
 /// # Examples
 ///
@@ -256,8 +256,7 @@ fn replace(&mut self, key: K) -> Option<K> {
 /// This `struct` is created by the [`iter`] method on [`BTreeMap`]. See its
 /// documentation for more.
 ///
-/// [`iter`]: struct.BTreeMap.html#method.iter
-/// [`BTreeMap`]: struct.BTreeMap.html
+/// [`iter`]: BTreeMap::iter
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Iter<'a, K: 'a, V: 'a> {
     range: Range<'a, K, V>,
@@ -276,8 +275,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 /// This `struct` is created by the [`iter_mut`] method on [`BTreeMap`]. See its
 /// documentation for more.
 ///
-/// [`iter_mut`]: struct.BTreeMap.html#method.iter_mut
-/// [`BTreeMap`]: struct.BTreeMap.html
+/// [`iter_mut`]: BTreeMap::iter_mut
 #[stable(feature = "rust1", since = "1.0.0")]
 #[derive(Debug)]
 pub struct IterMut<'a, K: 'a, V: 'a> {
@@ -290,8 +288,7 @@ pub struct IterMut<'a, K: 'a, V: 'a> {
 /// This `struct` is created by the [`into_iter`] method on [`BTreeMap`]
 /// (provided by the `IntoIterator` trait). See its documentation for more.
 ///
-/// [`into_iter`]: struct.BTreeMap.html#method.into_iter
-/// [`BTreeMap`]: struct.BTreeMap.html
+/// [`into_iter`]: IntoIterator::into_iter
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct IntoIter<K, V> {
     front: Option<Handle<NodeRef<marker::Owned, K, V, marker::Leaf>, marker::Edge>>,
@@ -315,8 +312,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 /// This `struct` is created by the [`keys`] method on [`BTreeMap`]. See its
 /// documentation for more.
 ///
-/// [`keys`]: struct.BTreeMap.html#method.keys
-/// [`BTreeMap`]: struct.BTreeMap.html
+/// [`keys`]: BTreeMap::keys
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Keys<'a, K: 'a, V: 'a> {
     inner: Iter<'a, K, V>,
@@ -334,8 +330,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 /// This `struct` is created by the [`values`] method on [`BTreeMap`]. See its
 /// documentation for more.
 ///
-/// [`values`]: struct.BTreeMap.html#method.values
-/// [`BTreeMap`]: struct.BTreeMap.html
+/// [`values`]: BTreeMap::values
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Values<'a, K: 'a, V: 'a> {
     inner: Iter<'a, K, V>,
@@ -353,8 +348,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 /// This `struct` is created by the [`values_mut`] method on [`BTreeMap`]. See its
 /// documentation for more.
 ///
-/// [`values_mut`]: struct.BTreeMap.html#method.values_mut
-/// [`BTreeMap`]: struct.BTreeMap.html
+/// [`values_mut`]: BTreeMap::values_mut
 #[stable(feature = "map_values_mut", since = "1.10.0")]
 #[derive(Debug)]
 pub struct ValuesMut<'a, K: 'a, V: 'a> {
@@ -366,8 +360,7 @@ pub struct ValuesMut<'a, K: 'a, V: 'a> {
 /// This `struct` is created by the [`range`] method on [`BTreeMap`]. See its
 /// documentation for more.
 ///
-/// [`range`]: struct.BTreeMap.html#method.range
-/// [`BTreeMap`]: struct.BTreeMap.html
+/// [`range`]: BTreeMap::range
 #[stable(feature = "btree_range", since = "1.17.0")]
 pub struct Range<'a, K: 'a, V: 'a> {
     front: Option<Handle<NodeRef<marker::Immut<'a>, K, V, marker::Leaf>, marker::Edge>>,
@@ -386,8 +379,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 /// This `struct` is created by the [`range_mut`] method on [`BTreeMap`]. See its
 /// documentation for more.
 ///
-/// [`range_mut`]: struct.BTreeMap.html#method.range_mut
-/// [`BTreeMap`]: struct.BTreeMap.html
+/// [`range_mut`]: BTreeMap::range_mut
 #[stable(feature = "btree_range", since = "1.17.0")]
 pub struct RangeMut<'a, K: 'a, V: 'a> {
     front: Option<Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>>,
@@ -412,8 +404,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 ///
 /// This `enum` is constructed from the [`entry`] method on [`BTreeMap`].
 ///
-/// [`BTreeMap`]: struct.BTreeMap.html
-/// [`entry`]: struct.BTreeMap.html#method.entry
+/// [`entry`]: BTreeMap::entry
 #[stable(feature = "rust1", since = "1.0.0")]
 pub enum Entry<'a, K: 'a, V: 'a> {
     /// A vacant entry.
index 530cb0c91b8e314894a198802100ad04873f792d..35f4ef1d9b4c7a3750e15cd76bfe714833b632a2 100644 (file)
@@ -22,9 +22,9 @@
 /// to any other item, as determined by the [`Ord`] trait, changes while it is in the set. This is
 /// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code.
 ///
-/// [`Ord`]: ../../std/cmp/trait.Ord.html
-/// [`Cell`]: ../../std/cell/struct.Cell.html
-/// [`RefCell`]: ../../std/cell/struct.RefCell.html
+/// [`Ord`]: core::cmp::Ord
+/// [`Cell`]: core::cell::Cell
+/// [`RefCell`]: core::cell::RefCell
 ///
 /// # Examples
 ///
index 36b5785fdf6c5ed930340eb4b38d772d7dd21f4a..1f875f6c5217f4897cb67711b05670b9dfae509a 100644 (file)
@@ -404,7 +404,7 @@ pub const fn new() -> Self {
     /// This reuses all the nodes from `other` and moves them into `self`. After
     /// this operation, `other` becomes empty.
     ///
-    /// This operation should compute in `O(1)` time and `O(1)` memory.
+    /// This operation should compute in *O*(1) time and *O*(1) memory.
     ///
     /// # Examples
     ///
@@ -561,7 +561,7 @@ pub fn cursor_back_mut(&mut self) -> CursorMut<'_, T> {
 
     /// Returns `true` if the `LinkedList` is empty.
     ///
-    /// This operation should compute in `O(1)` time.
+    /// This operation should compute in *O*(1) time.
     ///
     /// # Examples
     ///
@@ -582,7 +582,7 @@ pub fn is_empty(&self) -> bool {
 
     /// Returns the length of the `LinkedList`.
     ///
-    /// This operation should compute in `O(1)` time.
+    /// This operation should compute in *O*(1) time.
     ///
     /// # Examples
     ///
@@ -608,7 +608,7 @@ pub fn len(&self) -> usize {
 
     /// Removes all elements from the `LinkedList`.
     ///
-    /// This operation should compute in `O(n)` time.
+    /// This operation should compute in *O*(*n*) time.
     ///
     /// # Examples
     ///
@@ -751,7 +751,7 @@ pub fn back_mut(&mut self) -> Option<&mut T> {
 
     /// Adds an element first in the list.
     ///
-    /// This operation should compute in `O(1)` time.
+    /// This operation should compute in *O*(1) time.
     ///
     /// # Examples
     ///
@@ -774,7 +774,7 @@ pub fn push_front(&mut self, elt: T) {
     /// Removes the first element and returns it, or `None` if the list is
     /// empty.
     ///
-    /// This operation should compute in `O(1)` time.
+    /// This operation should compute in *O*(1) time.
     ///
     /// # Examples
     ///
@@ -797,7 +797,7 @@ pub fn pop_front(&mut self) -> Option<T> {
 
     /// Appends an element to the back of a list.
     ///
-    /// This operation should compute in `O(1)` time.
+    /// This operation should compute in *O*(1) time.
     ///
     /// # Examples
     ///
@@ -817,7 +817,7 @@ pub fn push_back(&mut self, elt: T) {
     /// Removes the last element from a list and returns it, or `None` if
     /// it is empty.
     ///
-    /// This operation should compute in `O(1)` time.
+    /// This operation should compute in *O*(1) time.
     ///
     /// # Examples
     ///
@@ -838,7 +838,7 @@ pub fn pop_back(&mut self) -> Option<T> {
     /// Splits the list into two at the given index. Returns everything after the given index,
     /// including the index.
     ///
-    /// This operation should compute in `O(n)` time.
+    /// This operation should compute in *O*(*n*) time.
     ///
     /// # Panics
     ///
@@ -894,7 +894,7 @@ pub fn split_off(&mut self, at: usize) -> LinkedList<T> {
 
     /// Removes the element at the given index and returns it.
     ///
-    /// This operation should compute in `O(n)` time.
+    /// This operation should compute in *O*(*n*) time.
     ///
     /// # Panics
     /// Panics if at >= len
index 2efb94e8afe57731485f7bca4665a93e235abf1e..fa65d6ce8d725bba49eb2da48829b79d85accfca 100644 (file)
@@ -1,7 +1,7 @@
 //! A double-ended queue implemented with a growable ring buffer.
 //!
-//! This queue has `O(1)` amortized inserts and removals from both ends of the
-//! container. It also has `O(1)` indexing like a vector. The contained elements
+//! This queue has *O*(1) amortized inserts and removals from both ends of the
+//! container. It also has *O*(1) indexing like a vector. The contained elements
 //! are not required to be copyable, and the queue will be sendable if the
 //! contained type is sendable.
 
@@ -1512,7 +1512,7 @@ fn is_contiguous(&self) -> bool {
     /// Removes an element from anywhere in the `VecDeque` and returns it,
     /// replacing it with the first element.
     ///
-    /// This does not preserve ordering, but is `O(1)`.
+    /// This does not preserve ordering, but is *O*(1).
     ///
     /// Returns `None` if `index` is out of bounds.
     ///
@@ -1547,7 +1547,7 @@ pub fn swap_remove_front(&mut self, index: usize) -> Option<T> {
     /// Removes an element from anywhere in the `VecDeque` and returns it, replacing it with the
     /// last element.
     ///
-    /// This does not preserve ordering, but is `O(1)`.
+    /// This does not preserve ordering, but is *O*(1).
     ///
     /// Returns `None` if `index` is out of bounds.
     ///
@@ -2331,7 +2331,7 @@ pub fn make_contiguous(&mut self) -> &mut [T] {
     ///
     /// # Complexity
     ///
-    /// Takes `O(min(mid, len() - mid))` time and no extra space.
+    /// Takes `*O*(min(mid, len() - mid))` time and no extra space.
     ///
     /// # Examples
     ///
@@ -2374,7 +2374,7 @@ pub fn rotate_left(&mut self, mid: usize) {
     ///
     /// # Complexity
     ///
-    /// Takes `O(min(k, len() - k))` time and no extra space.
+    /// Takes `*O*(min(k, len() - k))` time and no extra space.
     ///
     /// # Examples
     ///
@@ -3076,7 +3076,7 @@ impl<T> From<VecDeque<T>> for Vec<T> {
     /// [`Vec<T>`]: crate::vec::Vec
     /// [`VecDeque<T>`]: crate::collections::VecDeque
     ///
-    /// This never needs to re-allocate, but does need to do `O(n)` data movement if
+    /// This never needs to re-allocate, but does need to do *O*(*n*) data movement if
     /// the circular buffer doesn't happen to be at the beginning of the allocation.
     ///
     /// # Examples
@@ -3084,7 +3084,7 @@ impl<T> From<VecDeque<T>> for Vec<T> {
     /// ```
     /// use std::collections::VecDeque;
     ///
-    /// // This one is O(1).
+    /// // This one is *O*(1).
     /// let deque: VecDeque<_> = (1..5).collect();
     /// let ptr = deque.as_slices().0.as_ptr();
     /// let vec = Vec::from(deque);
index 57927c688479b5f72746d6220b271f58dd2c7e41..339592728ac24b012451fb6ce5999afcfe458c28 100644 (file)
@@ -240,8 +240,6 @@ pub fn into_boxed_bytes(self: Box<str>) -> Box<[u8]> {
     /// While doing so, it attempts to find matches of a pattern. If it finds any, it
     /// replaces them with the replacement string slice.
     ///
-    /// [`String`]: string/struct.String.html
-    ///
     /// # Examples
     ///
     /// Basic usage:
@@ -280,8 +278,6 @@ pub fn replace<'a, P: Pattern<'a>>(&'a self, from: P, to: &str) -> String {
     /// While doing so, it attempts to find matches of a pattern. If it finds any, it
     /// replaces them with the replacement string slice at most `count` times.
     ///
-    /// [`String`]: string/struct.String.html
-    ///
     /// # Examples
     ///
     /// Basic usage:
@@ -324,8 +320,6 @@ pub fn replacen<'a, P: Pattern<'a>>(&'a self, pat: P, to: &str, count: usize) ->
     /// the case, this function returns a [`String`] instead of modifying the
     /// parameter in-place.
     ///
-    /// [`String`]: string/struct.String.html
-    ///
     /// # Examples
     ///
     /// Basic usage:
@@ -411,8 +405,6 @@ fn case_ignoreable_then_cased<I: Iterator<Item = char>>(iter: I) -> bool {
     /// the case, this function returns a [`String`] instead of modifying the
     /// parameter in-place.
     ///
-    /// [`String`]: string/struct.String.html
-    ///
     /// # Examples
     ///
     /// Basic usage:
@@ -459,8 +451,7 @@ pub fn to_uppercase(&self) -> String {
 
     /// Converts a [`Box<str>`] into a [`String`] without copying or allocating.
     ///
-    /// [`String`]: string/struct.String.html
-    /// [`Box<str>`]: boxed/struct.Box.html
+    /// [`Box<str>`]: Box
     ///
     /// # Examples
     ///
@@ -485,8 +476,6 @@ pub fn into_string(self: Box<str>) -> String {
     ///
     /// This function will panic if the capacity would overflow.
     ///
-    /// [`String`]: string/struct.String.html
-    ///
     /// # Examples
     ///
     /// Basic usage:
@@ -525,7 +514,7 @@ pub fn repeat(&self, n: usize) -> String {
     /// assert_eq!("GRüßE, JüRGEN ❤", s.to_ascii_uppercase());
     /// ```
     ///
-    /// [`make_ascii_uppercase`]: #method.make_ascii_uppercase
+    /// [`make_ascii_uppercase`]: str::make_ascii_uppercase
     /// [`to_uppercase`]: #method.to_uppercase
     #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
     #[inline]
@@ -555,7 +544,7 @@ pub fn to_ascii_uppercase(&self) -> String {
     /// assert_eq!("grüße, jürgen ❤", s.to_ascii_lowercase());
     /// ```
     ///
-    /// [`make_ascii_lowercase`]: #method.make_ascii_lowercase
+    /// [`make_ascii_lowercase`]: str::make_ascii_lowercase
     /// [`to_lowercase`]: #method.to_lowercase
     #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
     #[inline]
index 5b671b41b5bf673f12f5d27ad9d4d3e6ede22db6..f41c8c5a5591054c6c89d6ecc1e6108c94acd7c1 100644 (file)
@@ -4,8 +4,6 @@
 //! [`ToString`]s, and several error types that may result from working with
 //! [`String`]s.
 //!
-//! [`ToString`]: trait.ToString.html
-//!
 //! # Examples
 //!
 //! There are multiple ways to create a new [`String`] from a string literal:
@@ -20,8 +18,6 @@
 //! You can create a new [`String`] from an existing one by concatenating with
 //! `+`:
 //!
-//! [`String`]: struct.String.html
-//!
 //! ```
 //! let s = "Hello".to_string();
 //!
 /// contents of the string. It has a close relationship with its borrowed
 /// counterpart, the primitive [`str`].
 ///
-/// [`str`]: ../../std/primitive.str.html
-///
 /// # Examples
 ///
-/// You can create a `String` from a literal string with [`String::from`]:
+/// You can create a `String` from [a literal string][`str`] with [`String::from`]:
+///
+/// [`String::from`]: From::from
 ///
 /// ```
 /// let hello = String::from("Hello, world!");
 /// hello.push_str("orld!");
 /// ```
 ///
-/// [`String::from`]: #method.from
-/// [`char`]: ../../std/primitive.char.html
-/// [`push`]: #method.push
-/// [`push_str`]: #method.push_str
+/// [`push`]: String::push
+/// [`push_str`]: String::push_str
 ///
 /// If you have a vector of UTF-8 bytes, you can create a `String` from it with
 /// the [`from_utf8`] method:
 /// assert_eq!("💖", sparkle_heart);
 /// ```
 ///
-/// [`from_utf8`]: #method.from_utf8
+/// [`from_utf8`]: String::from_utf8
 ///
 /// # UTF-8
 ///
 /// The [`bytes`] and [`chars`] methods return iterators over the first
 /// two, respectively.
 ///
-/// [`bytes`]: #method.bytes
-/// [`chars`]: #method.chars
+/// [`bytes`]: str::bytes
+/// [`chars`]: str::chars
 ///
 /// # Deref
 ///
 /// assert_eq!(String::from("Once upon a time..."), s);
 /// ```
 ///
-/// [`as_ptr`]: #method.as_ptr
-/// [`len`]: #method.len
-/// [`capacity`]: #method.capacity
+/// [`as_ptr`]: str::as_ptr
+/// [`len`]: String::len
+/// [`capacity`]: String::capacity
 ///
 /// If a `String` has enough capacity, adding elements to it will not
 /// re-allocate. For example, consider this program:
 /// }
 /// ```
 ///
-/// [`with_capacity`]: #method.with_capacity
+/// [`with_capacity`]: String::with_capacity
 ///
 /// We end up with a different output:
 ///
 ///
 /// Here, there's no need to allocate more memory inside the loop.
 ///
-/// [`&str`]: ../../std/primitive.str.html
-/// [`Deref`]: ../../std/ops/trait.Deref.html
-/// [`as_str()`]: struct.String.html#method.as_str
+/// [`str`]: type@str
+/// [`&str`]: type@str
+/// [`Deref`]: core::ops::Deref
+/// [`as_str()`]: String::as_str
 #[derive(PartialOrd, Eq, Ord)]
 #[cfg_attr(not(test), rustc_diagnostic_item = "string_type")]
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -291,20 +286,18 @@ pub struct String {
 /// [`into_bytes`] method will give back the byte vector that was used in the
 /// conversion attempt.
 ///
-/// [`from_utf8`]: struct.String.html#method.from_utf8
-/// [`String`]: struct.String.html
-/// [`into_bytes`]: struct.FromUtf8Error.html#method.into_bytes
+/// [`from_utf8`]: String::from_utf8
+/// [`into_bytes`]: FromUtf8Error::into_bytes
 ///
 /// The [`Utf8Error`] type provided by [`std::str`] represents an error that may
 /// occur when converting a slice of [`u8`]s to a [`&str`]. In this sense, it's
 /// an analogue to `FromUtf8Error`, and you can get one from a `FromUtf8Error`
 /// through the [`utf8_error`] method.
 ///
-/// [`Utf8Error`]: ../../std/str/struct.Utf8Error.html
-/// [`std::str`]: ../../std/str/index.html
-/// [`u8`]: ../../std/primitive.u8.html
-/// [`&str`]: ../../std/primitive.str.html
-/// [`utf8_error`]: #method.utf8_error
+/// [`Utf8Error`]: core::str::Utf8Error
+/// [`std::str`]: core::str
+/// [`&str`]: str
+/// [`utf8_error`]: Self::utf8_error
 ///
 /// # Examples
 ///
@@ -330,9 +323,7 @@ pub struct FromUtf8Error {
 ///
 /// This type is the error type for the [`from_utf16`] method on [`String`].
 ///
-/// [`from_utf16`]: struct.String.html#method.from_utf16
-/// [`String`]: struct.String.html
-///
+/// [`from_utf16`]: String::from_utf16
 /// # Examples
 ///
 /// Basic usage:
@@ -358,7 +349,7 @@ impl String {
     /// consider the [`with_capacity`] method to prevent excessive
     /// re-allocation.
     ///
-    /// [`with_capacity`]: #method.with_capacity
+    /// [`with_capacity`]: String::with_capacity
     ///
     /// # Examples
     ///
@@ -383,12 +374,12 @@ pub const fn new() -> String {
     /// appending a bunch of data to the `String`, reducing the number of
     /// reallocations it needs to do.
     ///
-    /// [`capacity`]: #method.capacity
+    /// [`capacity`]: String::capacity
     ///
     /// If the given capacity is `0`, no allocation will occur, and this method
     /// is identical to the [`new`] method.
     ///
-    /// [`new`]: #method.new
+    /// [`new`]: String::new
     ///
     /// # Examples
     ///
@@ -479,15 +470,10 @@ pub fn from_str(_: &str) -> String {
     /// See the docs for [`FromUtf8Error`] for more details on what you can do
     /// with this error.
     ///
-    /// [`from_utf8_unchecked`]: struct.String.html#method.from_utf8_unchecked
-    /// [`String`]: struct.String.html
-    /// [`u8`]: ../../std/primitive.u8.html
-    /// [`Vec<u8>`]: ../../std/vec/struct.Vec.html
-    /// [`&str`]: ../../std/primitive.str.html
-    /// [`str::from_utf8`]: ../../std/str/fn.from_utf8.html
-    /// [`into_bytes`]: struct.String.html#method.into_bytes
-    /// [`FromUtf8Error`]: struct.FromUtf8Error.html
-    /// [`Err`]: ../../std/result/enum.Result.html#variant.Err
+    /// [`from_utf8_unchecked`]: String::from_utf8_unchecked
+    /// [`Vec<u8>`]: crate::vec::Vec
+    /// [`&str`]: str
+    /// [`into_bytes`]: String::into_bytes
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn from_utf8(vec: Vec<u8>) -> Result<String, FromUtf8Error> {
@@ -506,16 +492,15 @@ pub fn from_utf8(vec: Vec<u8>) -> Result<String, FromUtf8Error> {
     /// `from_utf8_lossy()` will replace any invalid UTF-8 sequences with
     /// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD], which looks like this: �
     ///
-    /// [`u8`]: ../../std/primitive.u8.html
     /// [byteslice]: ../../std/primitive.slice.html
-    /// [U+FFFD]: ../char/constant.REPLACEMENT_CHARACTER.html
+    /// [U+FFFD]: core::char::REPLACEMENT_CHARACTER
     ///
     /// If you are sure that the byte slice is valid UTF-8, and you don't want
     /// to incur the overhead of the conversion, there is an unsafe version
     /// of this function, [`from_utf8_unchecked`], which has the same behavior
     /// but skips the checks.
     ///
-    /// [`from_utf8_unchecked`]: struct.String.html#method.from_utf8_unchecked
+    /// [`from_utf8_unchecked`]: String::from_utf8_unchecked
     ///
     /// This function returns a [`Cow<'a, str>`]. If our byte slice is invalid
     /// UTF-8, then we need to insert the replacement characters, which will
@@ -523,7 +508,7 @@ pub fn from_utf8(vec: Vec<u8>) -> Result<String, FromUtf8Error> {
     /// it's already valid UTF-8, we don't need a new allocation. This return
     /// type allows us to handle both cases.
     ///
-    /// [`Cow<'a, str>`]: ../../std/borrow/enum.Cow.html
+    /// [`Cow<'a, str>`]: crate::borrow::Cow
     ///
     /// # Examples
     ///
@@ -583,8 +568,6 @@ pub fn from_utf8_lossy(v: &[u8]) -> Cow<'_, str> {
     /// Decode a UTF-16 encoded vector `v` into a `String`, returning [`Err`]
     /// if `v` contains any invalid data.
     ///
-    /// [`Err`]: ../../std/result/enum.Result.html#variant.Err
-    ///
     /// # Examples
     ///
     /// Basic usage:
@@ -623,9 +606,9 @@ pub fn from_utf16(v: &[u16]) -> Result<String, FromUtf16Error> {
     /// `from_utf16_lossy` returns a `String` since the UTF-16 to UTF-8
     /// conversion requires a memory allocation.
     ///
-    /// [`from_utf8_lossy`]: #method.from_utf8_lossy
-    /// [`Cow<'a, str>`]: ../borrow/enum.Cow.html
-    /// [U+FFFD]: ../char/constant.REPLACEMENT_CHARACTER.html
+    /// [`from_utf8_lossy`]: String::from_utf8_lossy
+    /// [`Cow<'a, str>`]: crate::borrow::Cow
+    /// [U+FFFD]: core::char::REPLACEMENT_CHARACTER
     ///
     /// # Examples
     ///
@@ -659,7 +642,7 @@ pub fn from_utf16_lossy(v: &[u16]) -> String {
     /// into a `String` with the [`from_raw_parts`] function, allowing
     /// the destructor to perform the cleanup.
     ///
-    /// [`from_raw_parts`]: #method.from_raw_parts
+    /// [`from_raw_parts`]: String::from_raw_parts
     ///
     /// # Examples
     ///
@@ -732,7 +715,7 @@ pub unsafe fn from_raw_parts(buf: *mut u8, length: usize, capacity: usize) -> St
     ///
     /// See the safe version, [`from_utf8`], for more details.
     ///
-    /// [`from_utf8`]: struct.String.html#method.from_utf8
+    /// [`from_utf8`]: String::from_utf8
     ///
     /// # Safety
     ///
@@ -867,8 +850,7 @@ pub fn capacity(&self) -> usize {
     ///
     /// Panics if the new capacity overflows [`usize`].
     ///
-    /// [`reserve_exact`]: struct.String.html#method.reserve_exact
-    /// [`usize`]: ../../std/primitive.usize.html
+    /// [`reserve_exact`]: String::reserve_exact
     ///
     /// # Examples
     ///
@@ -911,7 +893,7 @@ pub fn reserve(&mut self, additional: usize) {
     /// Consider using the [`reserve`] method unless you absolutely know
     /// better than the allocator.
     ///
-    /// [`reserve`]: #method.reserve
+    /// [`reserve`]: String::reserve
     ///
     /// # Panics
     ///
@@ -1076,8 +1058,6 @@ pub fn shrink_to(&mut self, min_capacity: usize) {
 
     /// Appends the given [`char`] to the end of this `String`.
     ///
-    /// [`char`]: ../../std/primitive.char.html
-    ///
     /// # Examples
     ///
     /// Basic usage:
@@ -1104,7 +1084,7 @@ pub fn push(&mut self, ch: char) {
     ///
     /// The inverse of this method is [`from_utf8`].
     ///
-    /// [`from_utf8`]: #method.from_utf8
+    /// [`from_utf8`]: String::from_utf8
     ///
     /// # Examples
     ///
@@ -1133,8 +1113,6 @@ pub fn as_bytes(&self) -> &[u8] {
     ///
     /// Panics if `new_len` does not lie on a [`char`] boundary.
     ///
-    /// [`char`]: ../../std/primitive.char.html
-    ///
     /// # Examples
     ///
     /// Basic usage:
@@ -1159,8 +1137,6 @@ pub fn truncate(&mut self, new_len: usize) {
     ///
     /// Returns [`None`] if this `String` is empty.
     ///
-    /// [`None`]: ../../std/option/enum.Option.html#variant.None
-    ///
     /// # Examples
     ///
     /// Basic usage:
@@ -1187,7 +1163,7 @@ pub fn pop(&mut self) -> Option<char> {
 
     /// Removes a [`char`] from this `String` at a byte position and returns it.
     ///
-    /// This is an `O(n)` operation, as it requires copying every element in the
+    /// This is an *O*(*n*) operation, as it requires copying every element in the
     /// buffer.
     ///
     /// # Panics
@@ -1195,8 +1171,6 @@ pub fn pop(&mut self) -> Option<char> {
     /// Panics if `idx` is larger than or equal to the `String`'s length,
     /// or if it does not lie on a [`char`] boundary.
     ///
-    /// [`char`]: ../../std/primitive.char.html
-    ///
     /// # Examples
     ///
     /// Basic usage:
@@ -1289,7 +1263,7 @@ pub fn retain<F>(&mut self, mut f: F)
 
     /// Inserts a character into this `String` at a byte position.
     ///
-    /// This is an `O(n)` operation as it requires copying every element in the
+    /// This is an *O*(*n*) operation as it requires copying every element in the
     /// buffer.
     ///
     /// # Panics
@@ -1297,8 +1271,6 @@ pub fn retain<F>(&mut self, mut f: F)
     /// Panics if `idx` is larger than the `String`'s length, or if it does not
     /// lie on a [`char`] boundary.
     ///
-    /// [`char`]: ../../std/primitive.char.html
-    ///
     /// # Examples
     ///
     /// Basic usage:
@@ -1338,7 +1310,7 @@ unsafe fn insert_bytes(&mut self, idx: usize, bytes: &[u8]) {
 
     /// Inserts a string slice into this `String` at a byte position.
     ///
-    /// This is an `O(n)` operation as it requires copying every element in the
+    /// This is an *O*(*n*) operation as it requires copying every element in the
     /// buffer.
     ///
     /// # Panics
@@ -1346,8 +1318,6 @@ unsafe fn insert_bytes(&mut self, idx: usize, bytes: &[u8]) {
     /// Panics if `idx` is larger than the `String`'s length, or if it does not
     /// lie on a [`char`] boundary.
     ///
-    /// [`char`]: ../../std/primitive.char.html
-    ///
     /// # Examples
     ///
     /// Basic usage:
@@ -1507,8 +1477,6 @@ pub fn clear(&mut self) {
     /// Panics if the starting point or end point do not lie on a [`char`]
     /// boundary, or if they're out of bounds.
     ///
-    /// [`char`]: ../../std/primitive.char.html
-    ///
     /// # Examples
     ///
     /// Basic usage:
@@ -1567,9 +1535,6 @@ pub fn drain<R>(&mut self, range: R) -> Drain<'_>
     /// Panics if the starting point or end point do not lie on a [`char`]
     /// boundary, or if they're out of bounds.
     ///
-    /// [`char`]: ../../std/primitive.char.html
-    /// [`Vec::splice`]: ../../std/vec/struct.Vec.html#method.splice
-    ///
     /// # Examples
     ///
     /// Basic usage:
@@ -1610,9 +1575,6 @@ pub fn replace_range<R>(&mut self, range: R, replace_with: &str)
     ///
     /// This will drop any excess capacity.
     ///
-    /// [`Box`]: ../../std/boxed/struct.Box.html
-    /// [`str`]: ../../std/primitive.str.html
-    ///
     /// # Examples
     ///
     /// Basic usage:
@@ -1680,10 +1642,8 @@ pub fn into_bytes(self) -> Vec<u8> {
     /// an analogue to `FromUtf8Error`. See its documentation for more details
     /// on using it.
     ///
-    /// [`Utf8Error`]: ../../std/str/struct.Utf8Error.html
-    /// [`std::str`]: ../../std/str/index.html
-    /// [`u8`]: ../../std/primitive.u8.html
-    /// [`&str`]: ../../std/primitive.str.html
+    /// [`std::str`]: core::str
+    /// [`&str`]: str
     ///
     /// # Examples
     ///
@@ -2012,7 +1972,7 @@ fn hash<H: hash::Hasher>(&self, hasher: &mut H) {
 ///
 /// This consumes the `String` on the left-hand side and re-uses its buffer (growing it if
 /// necessary). This is done to avoid allocating a new `String` and copying the entire contents on
-/// every operation, which would lead to `O(n^2)` running time when building an `n`-byte string by
+/// every operation, which would lead to *O*(*n*^2) running time when building an *n*-byte string by
 /// repeated concatenation.
 ///
 /// The string on the right-hand side is only borrowed; its contents are copied into the returned
@@ -2187,7 +2147,7 @@ fn deref_mut(&mut self) -> &mut str {
 ///
 /// This alias exists for backwards compatibility, and may be eventually deprecated.
 ///
-/// [`Infallible`]: ../../core/convert/enum.Infallible.html
+/// [`Infallible`]: core::convert::Infallible
 #[stable(feature = "str_parse_error", since = "1.5.0")]
 pub type ParseError = core::convert::Infallible;
 
@@ -2207,7 +2167,7 @@ fn from_str(s: &str) -> Result<String, Self::Err> {
 /// [`Display`] should be implemented instead, and you get the `ToString`
 /// implementation for free.
 ///
-/// [`Display`]: ../../std/fmt/trait.Display.html
+/// [`Display`]: fmt::Display
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait ToString {
     /// Converts the given value to a `String`.
@@ -2465,8 +2425,7 @@ fn write_char(&mut self, c: char) -> fmt::Result {
 /// This struct is created by the [`drain`] method on [`String`]. See its
 /// documentation for more.
 ///
-/// [`drain`]: struct.String.html#method.drain
-/// [`String`]: struct.String.html
+/// [`drain`]: String::drain
 #[stable(feature = "drain", since = "1.6.0")]
 pub struct Drain<'a> {
     /// Will be used as &'a mut String in the destructor
index 94f7ff5c1f7fe7864f6bf1fd0399ae7d8b568eef..03b798d57db9bcf37ba50b1ba515730782f2e7bd 100644 (file)
@@ -677,7 +677,7 @@ fn as_ref(&self) -> &str {
 ///
 ///
 /// However there is one case where `!` syntax can be used
-/// before `!` is stabilized as a full-fleged type: in the position of a function’s return type.
+/// before `!` is stabilized as a full-fledged type: in the position of a function’s return type.
 /// Specifically, it is possible implementations for two different function pointer types:
 ///
 /// ```
index f6460470bfe18e5e3aec17b90cbf39b1351835ec..37202b2774dc63d95086c9d7ef6d7fa3f6231742 100644 (file)
@@ -33,9 +33,13 @@ pub enum Alignment {
     Unknown,
 }
 
+/// Used by [width](https://doc.rust-lang.org/std/fmt/#width) and [precision](https://doc.rust-lang.org/std/fmt/#precision) specifiers.
 #[derive(Copy, Clone)]
 pub enum Count {
+    /// Specified with a literal number, stores the value
     Is(usize),
+    /// Specified using `$` and `*` syntaxes, stores the index into `args`
     Param(usize),
+    /// Not specified
     Implied,
 }
index f2bbf646f3272b87d1c5beb7e8b22721f985abce..a9882d54de4f18b3e47d86ce132d760c852e2ab6 100644 (file)
@@ -43,7 +43,7 @@ struct SipHasher24 {
 ///
 /// SipHash is a general-purpose hashing function: it runs at a good
 /// speed (competitive with Spooky and City) and permits strong _keyed_
-/// hashing. This lets you key your hashtables from a strong RNG, such as
+/// hashing. This lets you key your hash tables from a strong RNG, such as
 /// [`rand::os::OsRng`](https://doc.rust-lang.org/rand/rand/os/struct.OsRng.html).
 ///
 /// Although the SipHash algorithm is considered to be generally strong,
index 9ebcde79b633d3ea0492f5c90991a1d803e15e0f..3116815f5d655a03461d6cfbc19f19a056aa78ec 100644 (file)
@@ -45,7 +45,8 @@
 /// ```
 #[inline]
 #[stable(feature = "unreachable", since = "1.27.0")]
-pub unsafe fn unreachable_unchecked() -> ! {
+#[rustc_const_unstable(feature = "const_unreachable_unchecked", issue = "53188")]
+pub const unsafe fn unreachable_unchecked() -> ! {
     // SAFETY: the safety contract for `intrinsics::unreachable` must
     // be upheld by the caller.
     unsafe { intrinsics::unreachable() }
index 080760aa81f30013d37fd6f2f2ee7764530577be..1af4f1009d1ac86e94d3c2d49e62d3db44a93a25 100644 (file)
@@ -15,7 +15,7 @@
 //!
 //! If an intrinsic is supposed to be used from a `const fn` with a `rustc_const_stable` attribute,
 //! the intrinsic's attribute must be `rustc_const_stable`, too. Such a change should not be done
-//! without T-lang consulation, because it bakes a feature into the language that cannot be
+//! without T-lang consultation, because it bakes a feature into the language that cannot be
 //! replicated in user code without compiler support.
 //!
 //! # Volatiles
     ///
     /// The stabilized version of this intrinsic is
     /// [`std::hint::unreachable_unchecked`](../../std/hint/fn.unreachable_unchecked.html).
+    #[rustc_const_unstable(feature = "const_unreachable_unchecked", issue = "53188")]
     pub fn unreachable() -> !;
 
     /// Informs the optimizer that a condition is always true.
     /// [`std::mem::align_of`](../../std/mem/fn.align_of.html).
     #[rustc_const_stable(feature = "const_min_align_of", since = "1.40.0")]
     pub fn min_align_of<T>() -> usize;
-    /// The prefered alignment of a type.
+    /// The preferred alignment of a type.
     ///
     /// This intrinsic does not have a stable counterpart.
     #[rustc_const_unstable(feature = "const_pref_align_of", issue = "none")]
     ///     assert!(mid <= len);
     ///     unsafe {
     ///         let slice2 = mem::transmute::<&mut [T], &mut [T]>(slice);
-    ///         // first: transmute is not typesafe; all it checks is that T and
+    ///         // first: transmute is not type safe; all it checks is that T and
     ///         // U are of the same size. Second, right here, you have two
     ///         // mutable references pointing to the same memory.
     ///         (&mut slice[0..mid], &mut slice2[mid..len])
     ///     }
     /// }
     ///
-    /// // This gets rid of the typesafety problems; `&mut *` will *only* give
+    /// // This gets rid of the type safety problems; `&mut *` will *only* give
     /// // you an `&mut T` from an `&mut T` or `*mut T`.
     /// fn split_at_mut_casts<T>(slice: &mut [T], mid: usize)
     ///                          -> (&mut [T], &mut [T]) {
     /// Internal placeholder for injecting code coverage counters when the "instrument-coverage"
     /// option is enabled. The placeholder is replaced with `llvm.instrprof.increment` during code
     /// generation.
+    #[cfg(not(bootstrap))]
     #[lang = "count_code_region"]
-    pub fn count_code_region(index: u32, start_byte_pos: u32, end_byte_pos: u32);
+    pub fn count_code_region(
+        function_source_hash: u64,
+        index: u32,
+        start_byte_pos: u32,
+        end_byte_pos: u32,
+    );
 
     /// Internal marker for code coverage expressions, injected into the MIR when the
     /// "instrument-coverage" option is enabled. This intrinsic is not converted into a
     /// "coverage map", which is injected into the generated code, as additional data.
     /// This marker identifies a code region and two other counters or counter expressions
     /// whose sum is the number of times the code region was executed.
+    #[cfg(not(bootstrap))]
+    #[lang = "coverage_counter_add"]
     pub fn coverage_counter_add(
         index: u32,
         left_index: u32,
@@ -1977,6 +1986,8 @@ pub fn coverage_counter_add(
     /// This marker identifies a code region and two other counters or counter expressions
     /// whose difference is the number of times the code region was executed.
     /// (See `coverage_counter_add` for more information.)
+    #[cfg(not(bootstrap))]
+    #[lang = "coverage_counter_subtract"]
     pub fn coverage_counter_subtract(
         index: u32,
         left_index: u32,
index b8faeb488e72d3cf776f324498c170d1cc6f319d..3ea3eeed6b0434f3f4f5fc7b3b5569051a255249 100644 (file)
@@ -1069,7 +1069,7 @@ fn take_while<P>(self, predicate: P) -> TakeWhile<Self, P>
     /// let vec = iter.collect::<Vec<_>>();
     ///
     /// // We have more elements which could fit in u32 (4, 5), but `map_while` returned `None` for `-3`
-    /// // (as the `predicate` returned `None`) and `collect` stops at the first `None` entcountered.
+    /// // (as the `predicate` returned `None`) and `collect` stops at the first `None` encountered.
     /// assert_eq!(vec, vec![0, 1, 2]);
     /// ```
     ///
index 1621cf79751665fe32d70efda4bea36a44f8afed..2e443064706d239117b7890ee3f74ff07daaa3bd 100644 (file)
@@ -92,6 +92,7 @@
 #![feature(const_slice_ptr_len)]
 #![feature(const_type_name)]
 #![feature(const_likely)]
+#![feature(const_unreachable_unchecked)]
 #![feature(custom_inner_attributes)]
 #![feature(decl_macro)]
 #![feature(doc_cfg)]
index 4ac366ab16408eb3de7c8d60359a9cd5fb8dbd05..3b9057b7e8377911feec5d30b98e163a787d0fab 100644 (file)
@@ -1047,7 +1047,7 @@ macro_rules! stringify {
         };
     }
 
-    /// Includes a utf8-encoded file as a string.
+    /// Includes a UTF-8 encoded file as a string.
     ///
     /// The file is located relative to the current file (similarly to how
     /// modules are found). The provided path is interpreted in a platform-specific
index d62de7617a00df5de0e4161462237247644e6a36..6ff7baab70f61eee903dde10278c4e06dcdeabe1 100644 (file)
@@ -348,11 +348,11 @@ pub fn size_of_val<T: ?Sized>(val: &T) -> usize {
 ///
 /// - If `T` is `Sized`, this function is always safe to call.
 /// - If the unsized tail of `T` is:
-///     - a [slice], then the length of the slice tail must be an intialized
+///     - a [slice], then the length of the slice tail must be an initialized
 ///       integer, and the size of the *entire value*
 ///       (dynamic tail length + statically sized prefix) must fit in `isize`.
 ///     - a [trait object], then the vtable part of the pointer must point
-///       to a valid vtable acquired by an unsizing coersion, and the size
+///       to a valid vtable acquired by an unsizing coercion, and the size
 ///       of the *entire value* (dynamic tail length + statically sized prefix)
 ///       must fit in `isize`.
 ///     - an (unstable) [extern type], then this function is always safe to
@@ -483,11 +483,11 @@ pub fn align_of_val<T: ?Sized>(val: &T) -> usize {
 ///
 /// - If `T` is `Sized`, this function is always safe to call.
 /// - If the unsized tail of `T` is:
-///     - a [slice], then the length of the slice tail must be an intialized
+///     - a [slice], then the length of the slice tail must be an initialized
 ///       integer, and the size of the *entire value*
 ///       (dynamic tail length + statically sized prefix) must fit in `isize`.
 ///     - a [trait object], then the vtable part of the pointer must point
-///       to a valid vtable acquired by an unsizing coersion, and the size
+///       to a valid vtable acquired by an unsizing coercion, and the size
 ///       of the *entire value* (dynamic tail length + statically sized prefix)
 ///       must fit in `isize`.
 ///     - an (unstable) [extern type], then this function is always safe to
index 061d1ea6b1c46974ffe7f7e11d3c3a6a878c8842..9fb7296ce31cc32d873d7eb0e91ff21fe9929318 100644 (file)
@@ -242,7 +242,7 @@ pub mod consts {
     /// The full circle constant (τ)
     ///
     /// Equal to 2π.
-    #[unstable(feature = "tau_constant", issue = "66770")]
+    #[stable(feature = "tau_constant", since = "1.47.0")]
     pub const TAU: f32 = 6.28318530717958647692528676655900577_f32;
 
     /// π/2
index b0df4d64f6ee1880583c42f5bc83c8a5a6dbd9d2..a5b1eb3f1fd67c61adcc65d041319bc7b88f6f29 100644 (file)
@@ -242,7 +242,7 @@ pub mod consts {
     /// The full circle constant (τ)
     ///
     /// Equal to 2π.
-    #[unstable(feature = "tau_constant", issue = "66770")]
+    #[stable(feature = "tau_constant", since = "1.47.0")]
     pub const TAU: f64 = 6.28318530717958647692528676655900577_f64;
 
     /// π/2
@@ -687,7 +687,7 @@ pub fn to_bits(self) -> u64 {
     /// signaling NaNs on MIPS are quiet NaNs on x86, and vice-versa.
     ///
     /// Rather than trying to preserve signaling-ness cross-platform, this
-    /// implementation favours preserving the exact bits. This means that
+    /// implementation favors preserving the exact bits. This means that
     /// any payloads encoded in NaNs will be preserved even if the result of
     /// this method is sent over the network from an x86 machine to a MIPS one.
     ///
@@ -696,7 +696,7 @@ pub fn to_bits(self) -> u64 {
     ///
     /// If the input isn't NaN, then there is no portability concern.
     ///
-    /// If you don't care about signalingness (very likely), then there is no
+    /// If you don't care about signaling-ness (very likely), then there is no
     /// portability concern.
     ///
     /// Note that this function is distinct from `as` casting, which attempts to
index d86f39c4550c843fc3aa8f5212ccc5c633710e46..179038d1977c86ada516b1fce43454eb335c0fb5 100644 (file)
@@ -39,7 +39,7 @@
 /// [`Iterator`]: ../iter/trait.IntoIterator.html
 /// [slicing index]: ../slice/trait.SliceIndex.html
 #[doc(alias = "..")]
-#[derive(Copy, Clone, PartialEq, Eq, Hash)]
+#[derive(Copy, Clone, Default, PartialEq, Eq, Hash)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct RangeFull;
 
@@ -71,7 +71,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
 /// assert_eq!(arr[1..=3], [  1,2,3  ]);
 /// ```
 #[doc(alias = "..")]
-#[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186
+#[derive(Clone, Default, PartialEq, Eq, Hash)] // not Copy -- see #27186
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Range<Idx> {
     /// The lower bound of the range (inclusive).
index da299f026f8f16c87f0d7dd4f64fe3e62f37491b..9bcacd8ddcf77ee54bb950f8a9dcff1d280fbf6d 100644 (file)
 //!
 //! Crucially, we have to be able to rely on [`drop`] being called. If an element
 //! could be deallocated or otherwise invalidated without calling [`drop`], the pointers into it
-//! from its neighbouring elements would become invalid, which would break the data structure.
+//! from its neighboring elements would become invalid, which would break the data structure.
 //!
 //! Therefore, pinning also comes with a [`drop`]-related guarantee.
 //!
index 896ad740e1e692424a695f23fc0ca04576d326a8..a2acc239bd38f942da26c334b1254e4a6a24db00 100644 (file)
@@ -331,13 +331,13 @@ pub const fn guaranteed_eq(self, other: *const T) -> bool
         intrinsics::ptr_guaranteed_eq(self, other)
     }
 
-    /// Returns whether two pointers are guaranteed to be inequal.
+    /// Returns whether two pointers are guaranteed to be unequal.
     ///
     /// At runtime this function behaves like `self != other`.
     /// However, in some contexts (e.g., compile-time evaluation),
     /// it is not always possible to determine the inequality of two pointers, so this function may
-    /// spuriously return `false` for pointers that later actually turn out to be inequal.
-    /// But when it returns `true`, the pointers are guaranteed to be inequal.
+    /// spuriously return `false` for pointers that later actually turn out to be unequal.
+    /// But when it returns `true`, the pointers are guaranteed to be unequal.
     ///
     /// This function is the mirror of [`guaranteed_eq`], but not its inverse. There are pointer
     /// comparisons for which both functions return `false`.
index 96856e7512cabdcf5cad84e732ad9de4f30c543c..17fa90ecc08b5c81acc3e672bf9f3a6db429178d 100644 (file)
@@ -47,17 +47,22 @@ pub const fn cast<U>(self) -> *mut U {
     /// operation because the returned value could be pointing to invalid
     /// memory.
     ///
-    /// When calling this method, you have to ensure that if the pointer is
-    /// non-NULL, then it is properly aligned, dereferenceable (for the whole
-    /// size of `T`) and points to an initialized instance of `T`. This applies
-    /// even if the result of this method is unused!
+    /// When calling this method, you have to ensure that *either* the pointer is NULL *or*
+    /// all of the following is true:
+    /// - it is properly aligned
+    /// - it must point to an initialized instance of T; in particular, the pointer must be
+    ///   "dereferencable" in the sense defined [here].
+    ///
+    /// This applies even if the result of this method is unused!
     /// (The part about being initialized is not yet fully decided, but until
     /// it is, the only safe approach is to ensure that they are indeed initialized.)
     ///
     /// Additionally, the lifetime `'a` returned is arbitrarily chosen and does
-    /// not necessarily reflect the actual lifetime of the data. It is up to the
-    /// caller to ensure that for the duration of this lifetime, the memory this
-    /// pointer points to does not get written to outside of `UnsafeCell<U>`.
+    /// not necessarily reflect the actual lifetime of the data. *You* must enforce
+    /// Rust's aliasing rules. In particular, for the duration of this lifetime,
+    /// the memory the pointer points to must not get mutated (except inside `UnsafeCell`).
+    ///
+    /// [here]: crate::ptr#safety
     ///
     /// # Examples
     ///
@@ -312,13 +317,13 @@ pub const fn guaranteed_eq(self, other: *mut T) -> bool
         intrinsics::ptr_guaranteed_eq(self as *const _, other as *const _)
     }
 
-    /// Returns whether two pointers are guaranteed to be inequal.
+    /// Returns whether two pointers are guaranteed to be unequal.
     ///
     /// At runtime this function behaves like `self != other`.
     /// However, in some contexts (e.g., compile-time evaluation),
     /// it is not always possible to determine the inequality of two pointers, so this function may
-    /// spuriously return `false` for pointers that later actually turn out to be inequal.
-    /// But when it returns `true`, the pointers are guaranteed to be inequal.
+    /// spuriously return `false` for pointers that later actually turn out to be unequal.
+    /// But when it returns `true`, the pointers are guaranteed to be unequal.
     ///
     /// This function is the mirror of [`guaranteed_eq`], but not its inverse. There are pointer
     /// comparisons for which both functions return `false`.
index b362a49d604e7ffd2a3ccdecee89c4f33c17f440..9f843a570990d615b795f7233734686b42675ed2 100644 (file)
@@ -172,7 +172,7 @@ impl<T> NonNull<[T]> {
     /// assert_eq!(unsafe { slice.as_ref()[2] }, 7);
     /// ```
     ///
-    /// (Note that this example artifically demonstrates a use of this method,
+    /// (Note that this example artificially demonstrates a use of this method,
     /// but `let slice = NonNull::from(&x[..]);` would be a better way to write code like this.)
     #[unstable(feature = "nonnull_slice_from_raw_parts", issue = "71941")]
     #[rustc_const_unstable(feature = "const_nonnull_slice_from_raw_parts", issue = "71941")]
index 20b2c3d3c965a8eb2c4cbc7d5de1e2891492cd1b..210ac078b4fe70a667d998ddce972b5e8d751dd3 100644 (file)
@@ -1672,7 +1672,7 @@ pub fn binary_search_by_key<'a, B, F>(&'a self, b: &B, mut f: F) -> Result<usize
     /// Sorts the slice, but may not preserve the order of equal elements.
     ///
     /// This sort is unstable (i.e., may reorder equal elements), in-place
-    /// (i.e., does not allocate), and `O(n * log(n))` worst-case.
+    /// (i.e., does not allocate), and *O*(*n* \* log(*n*)) worst-case.
     ///
     /// # Current implementation
     ///
@@ -1708,7 +1708,7 @@ pub fn sort_unstable(&mut self)
     /// elements.
     ///
     /// This sort is unstable (i.e., may reorder equal elements), in-place
-    /// (i.e., does not allocate), and `O(n * log(n))` worst-case.
+    /// (i.e., does not allocate), and *O*(*n* \* log(*n*)) worst-case.
     ///
     /// The comparator function must define a total ordering for the elements in the slice. If
     /// the ordering is not total, the order of the elements is unspecified. An order is a
@@ -1763,8 +1763,8 @@ pub fn sort_unstable_by<F>(&mut self, mut compare: F)
     /// elements.
     ///
     /// This sort is unstable (i.e., may reorder equal elements), in-place
-    /// (i.e., does not allocate), and `O(m * n * log(n))` worst-case, where the key function is
-    /// `O(m)`.
+    /// (i.e., does not allocate), and *O*(m \* *n* \* log(*n*)) worst-case, where the key function is
+    /// *O*(*m*).
     ///
     /// # Current implementation
     ///
@@ -1803,7 +1803,7 @@ pub fn sort_unstable_by_key<K, F>(&mut self, mut f: F)
     /// This reordering has the additional property that any value at position `i < index` will be
     /// less than or equal to any value at a position `j > index`. Additionally, this reordering is
     /// unstable (i.e. any number of equal elements may end up at position `index`), in-place
-    /// (i.e. does not allocate), and `O(n)` worst-case. This function is also/ known as "kth
+    /// (i.e. does not allocate), and *O*(*n*) worst-case. This function is also/ known as "kth
     /// element" in other libraries. It returns a triplet of the following values: all elements less
     /// than the one at the given index, the value at the given index, and all elements greater than
     /// the one at the given index.
@@ -1852,7 +1852,7 @@ pub fn partition_at_index(&mut self, index: usize) -> (&mut [T], &mut T, &mut [T
     /// This reordering has the additional property that any value at position `i < index` will be
     /// less than or equal to any value at a position `j > index` using the comparator function.
     /// Additionally, this reordering is unstable (i.e. any number of equal elements may end up at
-    /// position `index`), in-place (i.e. does not allocate), and `O(n)` worst-case. This function
+    /// position `index`), in-place (i.e. does not allocate), and *O*(*n*) worst-case. This function
     /// is also known as "kth element" in other libraries. It returns a triplet of the following
     /// values: all elements less than the one at the given index, the value at the given index,
     /// and all elements greater than the one at the given index, using the provided comparator
@@ -1906,7 +1906,7 @@ pub fn partition_at_index_by<F>(
     /// This reordering has the additional property that any value at position `i < index` will be
     /// less than or equal to any value at a position `j > index` using the key extraction function.
     /// Additionally, this reordering is unstable (i.e. any number of equal elements may end up at
-    /// position `index`), in-place (i.e. does not allocate), and `O(n)` worst-case. This function
+    /// position `index`), in-place (i.e. does not allocate), and *O*(*n*) worst-case. This function
     /// is also known as "kth element" in other libraries. It returns a triplet of the following
     /// values: all elements less than the one at the given index, the value at the given index, and
     /// all elements greater than the one at the given index, using the provided key extraction
index 8b2ac294764ff5aa49fc17796b45a1a8f651910d..972a33d6489e986919558cfcd15f1bfaac392f02 100644 (file)
@@ -121,7 +121,7 @@ fn shift_tail<T, F>(v: &mut [T], is_less: &mut F)
 
 /// Partially sorts a slice by shifting several out-of-order elements around.
 ///
-/// Returns `true` if the slice is sorted at the end. This function is `O(n)` worst-case.
+/// Returns `true` if the slice is sorted at the end. This function is *O*(*n*) worst-case.
 #[cold]
 fn partial_insertion_sort<T, F>(v: &mut [T], is_less: &mut F) -> bool
 where
@@ -168,7 +168,7 @@ fn partial_insertion_sort<T, F>(v: &mut [T], is_less: &mut F) -> bool
     false
 }
 
-/// Sorts a slice using insertion sort, which is `O(n^2)` worst-case.
+/// Sorts a slice using insertion sort, which is *O*(*n*^2) worst-case.
 fn insertion_sort<T, F>(v: &mut [T], is_less: &mut F)
 where
     F: FnMut(&T, &T) -> bool,
@@ -178,7 +178,7 @@ fn insertion_sort<T, F>(v: &mut [T], is_less: &mut F)
     }
 }
 
-/// Sorts `v` using heapsort, which guarantees `O(n * log(n))` worst-case.
+/// Sorts `v` using heapsort, which guarantees *O*(*n* \* log(*n*)) worst-case.
 #[cold]
 pub fn heapsort<T, F>(v: &mut [T], is_less: &mut F)
 where
@@ -751,7 +751,7 @@ fn recurse<'a, T, F>(mut v: &'a mut [T], is_less: &mut F, mut pred: Option<&'a T
     }
 }
 
-/// Sorts `v` using pattern-defeating quicksort, which is `O(n * log(n))` worst-case.
+/// Sorts `v` using pattern-defeating quicksort, which is *O*(*n* \* log(*n*)) worst-case.
 pub fn quicksort<T, F>(v: &mut [T], mut is_less: F)
 where
     F: FnMut(&T, &T) -> bool,
index faf58cafbb70b626d582c91b31822a316800d807..790ec4bd24f8dcab225c7a3c52ee4550f497e270 100644 (file)
@@ -4,7 +4,7 @@
 //!
 //! For more details, see the [`std::str`] module.
 //!
-//! [`std::str`]: ../../std/str/index.html
+//! [`std::str`]: self
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
@@ -163,13 +163,11 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 /// Errors which can occur when attempting to interpret a sequence of [`u8`]
 /// as a string.
 ///
-/// [`u8`]: ../../std/primitive.u8.html
-///
 /// As such, the `from_utf8` family of functions and methods for both [`String`]s
 /// and [`&str`]s make use of this error, for example.
 ///
 /// [`String`]: ../../std/string/struct.String.html#method.from_utf8
-/// [`&str`]: ../../std/str/fn.from_utf8.html
+/// [`&str`]: from_utf8
 ///
 /// # Examples
 ///
index 27760749c1d4b63ddca3afbf14d25da6d2c5ef3e..3d6f4f5971a62db2a88b3657a26008ade27732c4 100644 (file)
@@ -9,3 +9,7 @@
 mod wake;
 #[stable(feature = "futures_api", since = "1.36.0")]
 pub use self::wake::{Context, RawWaker, RawWakerVTable, Waker};
+
+mod ready;
+#[unstable(feature = "ready_macro", issue = "70922")]
+pub use ready::ready;
diff --git a/src/libcore/task/ready.rs b/src/libcore/task/ready.rs
new file mode 100644 (file)
index 0000000..d4e733e
--- /dev/null
@@ -0,0 +1,60 @@
+/// Extracts the successful type of a `Poll<T>`.
+///
+/// This macro bakes in propagation of `Pending` signals by returning early.
+///
+/// # Examples
+///
+/// ```
+/// #![feature(future_readiness_fns)]
+/// #![feature(ready_macro)]
+///
+/// use core::task::{ready, Context, Poll};
+/// use core::future::{self, Future};
+/// use core::pin::Pin;
+///
+/// pub fn do_poll(cx: &mut Context<'_>) -> Poll<()> {
+///     let mut fut = future::ready(42);
+///     let fut = Pin::new(&mut fut);
+///
+///     let num = ready!(fut.poll(cx));
+///     # drop(num);
+///     // ... use num
+///
+///     Poll::Ready(())
+/// }
+/// ```
+///
+/// The `ready!` call expands to:
+///
+/// ```
+/// # #![feature(future_readiness_fns)]
+/// # #![feature(ready_macro)]
+/// #
+/// # use core::task::{Context, Poll};
+/// # use core::future::{self, Future};
+/// # use core::pin::Pin;
+/// #
+/// # pub fn do_poll(cx: &mut Context<'_>) -> Poll<()> {
+///     # let mut fut = future::ready(42);
+///     # let fut = Pin::new(&mut fut);
+///     #
+/// let num = match fut.poll(cx) {
+///     Poll::Ready(t) => t,
+///     Poll::Pending => return Poll::Pending,
+/// };
+///     # drop(num);
+///     # // ... use num
+///     #
+///     # Poll::Ready(())
+/// # }
+/// ```
+#[unstable(feature = "ready_macro", issue = "70922")]
+#[rustc_macro_transparency = "semitransparent"]
+pub macro ready($e:expr) {
+    match $e {
+        $crate::task::Poll::Ready(t) => t,
+        $crate::task::Poll::Pending => {
+            return $crate::task::Poll::Pending;
+        }
+    }
+}
index 0d36bd0b39d76b69a3f7e835e5e5c579828425f4..899f923b957fe3af07644fe48f79a65d5adc53dc 100644 (file)
@@ -1,6 +1,5 @@
 [package]
 authors = ["The Rust Project Developers"]
-build = "build.rs"
 name = "profiler_builtins"
 version = "0.0.0"
 edition = "2018"
index bb7d59e113c08a29fc9c61e26383c668adb577e7..d2cb873058c282f14f04317fe77e4cc6e46554b1 100644 (file)
@@ -9,6 +9,8 @@ fn main() {
     let target = env::var("TARGET").expect("TARGET was not set");
     let cfg = &mut cc::Build::new();
 
+    // FIXME: `rerun-if-changed` directives are not currently emitted and the build script
+    // will not rerun on changes in these source files or headers included into them.
     let mut profile_sources = vec![
         "GCDAProfiling.c",
         "InstrProfiling.c",
diff --git a/src/librustc_ast/build.rs b/src/librustc_ast/build.rs
deleted file mode 100644 (file)
index 9b861f9..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-fn main() {
-    println!("cargo:rerun-if-changed=build.rs");
-    println!("cargo:rerun-if-env-changed=CFG_RELEASE_CHANNEL");
-    println!("cargo:rerun-if-env-changed=CFG_DISABLE_UNSTABLE_FEATURES");
-}
index 975881d9a0ac0c898895c5318320f3dd6f9660a0..daf3e23d6a1234c2196fe76286000f792f60976c 100644 (file)
@@ -1118,13 +1118,26 @@ fn visit_generic_args(&mut self, _: Span, generic_args: &'a GenericArgs) {
     fn visit_generics(&mut self, generics: &'a Generics) {
         let mut prev_ty_default = None;
         for param in &generics.params {
-            if let GenericParamKind::Type { ref default, .. } = param.kind {
-                if default.is_some() {
+            match param.kind {
+                GenericParamKind::Lifetime => (),
+                GenericParamKind::Type { default: Some(_), .. } => {
                     prev_ty_default = Some(param.ident.span);
-                } else if let Some(span) = prev_ty_default {
-                    self.err_handler()
-                        .span_err(span, "type parameters with a default must be trailing");
-                    break;
+                }
+                GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
+                    if let Some(span) = prev_ty_default {
+                        let mut err = self.err_handler().struct_span_err(
+                            span,
+                            "type parameters with a default must be trailing",
+                        );
+                        if matches!(param.kind, GenericParamKind::Const { .. }) {
+                            err.note(
+                                "using type defaults and const parameters \
+                                 in the same parameter list is currently not permitted",
+                            );
+                        }
+                        err.emit();
+                        break;
+                    }
                 }
             }
         }
index 677796a8df0b37a89cc427c8754d7b8b190df517..496becb8f1b5948235438afe758fdc9db0282829 100644 (file)
@@ -3,7 +3,6 @@ authors = ["The Rust Project Developers"]
 name = "rustc_attr"
 version = "0.0.0"
 edition = "2018"
-build = "build.rs"
 
 [lib]
 name = "rustc_attr"
diff --git a/src/librustc_attr/build.rs b/src/librustc_attr/build.rs
deleted file mode 100644 (file)
index 863f2b7..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-fn main() {
-    println!("cargo:rerun-if-changed=build.rs");
-    println!("cargo:rerun-if-env-changed=CFG_RELEASE");
-    println!("cargo:rerun-if-env-changed=CFG_RELEASE_CHANNEL");
-}
index 0606fac2fe748f17aa13ee7e078ab363f146ecb6..1e088b52dcc35b5fffb03d09cde40843b6801e81 100644 (file)
@@ -124,13 +124,11 @@ pub fn find_unwind_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> Op
 ///
 /// - `#[stable]`
 /// - `#[unstable]`
-/// - `#[rustc_deprecated]`
 #[derive(RustcEncodable, RustcDecodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
 #[derive(HashStable_Generic)]
 pub struct Stability {
     pub level: StabilityLevel,
     pub feature: Symbol,
-    pub rustc_depr: Option<RustcDeprecation>,
 }
 
 /// Represents the `#[rustc_const_unstable]` and `#[rustc_const_stable]` attributes.
@@ -163,15 +161,6 @@ pub fn is_stable(&self) -> bool {
     }
 }
 
-#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Copy, Clone, Debug, Eq, Hash)]
-#[derive(HashStable_Generic)]
-pub struct RustcDeprecation {
-    pub since: Symbol,
-    pub reason: Symbol,
-    /// A text snippet used to completely replace any use of the deprecated item in an expression.
-    pub suggestion: Option<Symbol>,
-}
-
 /// Checks if `attrs` contains an attribute like `#![feature(feature_name)]`.
 /// This will not perform any "sanity checks" on the form of the attributes.
 pub fn contains_feature_attr(attrs: &[Attribute], feature_name: Symbol) -> bool {
@@ -205,7 +194,6 @@ fn find_stability_generic<'a, I>(
     use StabilityLevel::*;
 
     let mut stab: Option<Stability> = None;
-    let mut rustc_depr: Option<RustcDeprecation> = None;
     let mut const_stab: Option<ConstStability> = None;
     let mut promotable = false;
     let mut allow_const_fn_ptr = false;
@@ -213,7 +201,6 @@ fn find_stability_generic<'a, I>(
 
     'outer: for attr in attrs_iter {
         if ![
-            sym::rustc_deprecated,
             sym::rustc_const_unstable,
             sym::rustc_const_stable,
             sym::unstable,
@@ -258,76 +245,8 @@ fn find_stability_generic<'a, I>(
                 }
             };
 
-            macro_rules! get_meta {
-                ($($name:ident),+) => {
-                    $(
-                        let mut $name = None;
-                    )+
-                    for meta in metas {
-                        if let Some(mi) = meta.meta_item() {
-                            match mi.name_or_empty() {
-                                $(
-                                    sym::$name => if !get(mi, &mut $name) { continue 'outer },
-                                )+
-                                _ => {
-                                    let expected = &[ $( stringify!($name) ),+ ];
-                                    handle_errors(
-                                        sess,
-                                        mi.span,
-                                        AttrError::UnknownMetaItem(
-                                            pprust::path_to_string(&mi.path),
-                                            expected,
-                                        ),
-                                    );
-                                    continue 'outer
-                                }
-                            }
-                        } else {
-                            handle_errors(
-                                sess,
-                                meta.span(),
-                                AttrError::UnsupportedLiteral(
-                                    "unsupported literal",
-                                    false,
-                                ),
-                            );
-                            continue 'outer
-                        }
-                    }
-                }
-            }
-
             let meta_name = meta.name_or_empty();
             match meta_name {
-                sym::rustc_deprecated => {
-                    if rustc_depr.is_some() {
-                        struct_span_err!(
-                            diagnostic,
-                            item_sp,
-                            E0540,
-                            "multiple rustc_deprecated attributes"
-                        )
-                        .emit();
-                        continue 'outer;
-                    }
-
-                    get_meta!(since, reason, suggestion);
-
-                    match (since, reason) {
-                        (Some(since), Some(reason)) => {
-                            rustc_depr = Some(RustcDeprecation { since, reason, suggestion })
-                        }
-                        (None, _) => {
-                            handle_errors(sess, attr.span, AttrError::MissingSince);
-                            continue;
-                        }
-                        _ => {
-                            struct_span_err!(diagnostic, attr.span, E0543, "missing 'reason'")
-                                .emit();
-                            continue;
-                        }
-                    }
-                }
                 sym::rustc_const_unstable | sym::unstable => {
                     if meta_name == sym::unstable && stab.is_some() {
                         handle_errors(sess, attr.span, AttrError::MultipleStabilityLevels);
@@ -429,7 +348,7 @@ macro_rules! get_meta {
                         (Some(feature), reason, Some(_)) => {
                             let level = Unstable { reason, issue: issue_num, is_soft };
                             if sym::unstable == meta_name {
-                                stab = Some(Stability { level, feature, rustc_depr: None });
+                                stab = Some(Stability { level, feature });
                             } else {
                                 const_stab = Some(ConstStability {
                                     level,
@@ -501,7 +420,7 @@ macro_rules! get_meta {
                         (Some(feature), Some(since)) => {
                             let level = Stable { since };
                             if sym::stable == meta_name {
-                                stab = Some(Stability { level, feature, rustc_depr: None });
+                                stab = Some(Stability { level, feature });
                             } else {
                                 const_stab = Some(ConstStability {
                                     level,
@@ -526,22 +445,6 @@ macro_rules! get_meta {
         }
     }
 
-    // Merge the deprecation info into the stability info
-    if let Some(rustc_depr) = rustc_depr {
-        if let Some(ref mut stab) = stab {
-            stab.rustc_depr = Some(rustc_depr);
-        } else {
-            struct_span_err!(
-                diagnostic,
-                item_sp,
-                E0549,
-                "rustc_deprecated attribute must be paired with \
-                       either stable or unstable attribute"
-            )
-            .emit();
-        }
-    }
-
     // Merge the const-unstable info into the stability info
     if promotable || allow_const_fn_ptr {
         if let Some(ref mut stab) = const_stab {
@@ -714,7 +617,16 @@ pub fn eval_condition(
 #[derive(RustcEncodable, RustcDecodable, Clone, HashStable_Generic)]
 pub struct Deprecation {
     pub since: Option<Symbol>,
+    /// The note to issue a reason.
     pub note: Option<Symbol>,
+    /// A text snippet used to completely replace any use of the deprecated item in an expression.
+    ///
+    /// This is currently unstable.
+    pub suggestion: Option<Symbol>,
+
+    /// Whether to treat the since attribute as being a Rust version identifier
+    /// (rather than an opaque string).
+    pub is_since_rustc_version: bool,
 }
 
 /// Finds the deprecation attribute. `None` if none exists.
@@ -738,7 +650,7 @@ fn find_deprecation_generic<'a, I>(
     let diagnostic = &sess.span_diagnostic;
 
     'outer: for attr in attrs_iter {
-        if !attr.check_name(sym::deprecated) {
+        if !(attr.check_name(sym::deprecated) || attr.check_name(sym::rustc_deprecated)) {
             continue;
         }
 
@@ -751,11 +663,12 @@ fn find_deprecation_generic<'a, I>(
             Some(meta) => meta,
             None => continue,
         };
-        depr = match &meta.kind {
-            MetaItemKind::Word => Some(Deprecation { since: None, note: None }),
-            MetaItemKind::NameValue(..) => {
-                meta.value_str().map(|note| Deprecation { since: None, note: Some(note) })
-            }
+        let mut since = None;
+        let mut note = None;
+        let mut suggestion = None;
+        match &meta.kind {
+            MetaItemKind::Word => {}
+            MetaItemKind::NameValue(..) => note = meta.value_str(),
             MetaItemKind::List(list) => {
                 let get = |meta: &MetaItem, item: &mut Option<Symbol>| {
                     if item.is_some() {
@@ -789,8 +702,6 @@ fn find_deprecation_generic<'a, I>(
                     }
                 };
 
-                let mut since = None;
-                let mut note = None;
                 for meta in list {
                     match meta {
                         NestedMetaItem::MetaItem(mi) => match mi.name_or_empty() {
@@ -799,18 +710,32 @@ fn find_deprecation_generic<'a, I>(
                                     continue 'outer;
                                 }
                             }
-                            sym::note => {
+                            sym::note if attr.check_name(sym::deprecated) => {
+                                if !get(mi, &mut note) {
+                                    continue 'outer;
+                                }
+                            }
+                            sym::reason if attr.check_name(sym::rustc_deprecated) => {
                                 if !get(mi, &mut note) {
                                     continue 'outer;
                                 }
                             }
+                            sym::suggestion if attr.check_name(sym::rustc_deprecated) => {
+                                if !get(mi, &mut suggestion) {
+                                    continue 'outer;
+                                }
+                            }
                             _ => {
                                 handle_errors(
                                     sess,
                                     meta.span(),
                                     AttrError::UnknownMetaItem(
                                         pprust::path_to_string(&mi.path),
-                                        &["since", "note"],
+                                        if attr.check_name(sym::deprecated) {
+                                            &["since", "note"]
+                                        } else {
+                                            &["since", "reason", "suggestion"]
+                                        },
                                     ),
                                 );
                                 continue 'outer;
@@ -829,10 +754,29 @@ fn find_deprecation_generic<'a, I>(
                         }
                     }
                 }
+            }
+        }
+
+        if suggestion.is_some() && attr.check_name(sym::deprecated) {
+            unreachable!("only allowed on rustc_deprecated")
+        }
 
-                Some(Deprecation { since, note })
+        if attr.check_name(sym::rustc_deprecated) {
+            if since.is_none() {
+                handle_errors(sess, attr.span, AttrError::MissingSince);
+                continue;
             }
-        };
+
+            if note.is_none() {
+                struct_span_err!(diagnostic, attr.span, E0543, "missing 'reason'").emit();
+                continue;
+            }
+        }
+
+        mark_used(&attr);
+
+        let is_since_rustc_version = attr.check_name(sym::rustc_deprecated);
+        depr = Some(Deprecation { since, note, suggestion, is_since_rustc_version });
     }
 
     depr
index 099c402703d09f44260df9feab87947654dadcf5..7857ccb613bf8abd7fe212b11576986f80e49c7d 100644 (file)
@@ -366,7 +366,7 @@ fn ptr_to_llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type {
         unsafe {
             llvm::LLVMPointerType(
                 self.llvm_type(cx),
-                cx.data_layout().instruction_address_space as c_uint,
+                cx.data_layout().instruction_address_space.0 as c_uint,
             )
         }
     }
index 89b548a9c5ab23a36300b97ac13e7d19141755d9..227a87ff8199495c2b8a9549c2bd44a1b827c777 100644 (file)
@@ -133,6 +133,9 @@ fn set_probestack(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
         return;
     }
 
+    // FIXME(richkadel): Make sure probestack plays nice with `-Z instrument-coverage`
+    // or disable it if not, similar to above early exits.
+
     // Flag our internal `__rust_probestack` function as the stack probe symbol.
     // This is defined in the `compiler-builtins` crate for each architecture.
     llvm::AddFunctionAttrStringValue(
index d5e0d7d36ee7a010e2d257c42f5ca7e9ecbee62b..b19199b9cfabd5bc80beb7dbc6fc167f3af7e0df 100644 (file)
@@ -144,17 +144,18 @@ fn module_codegen(tcx: TyCtxt<'_>, cgu_name: Symbol) -> ModuleCodegen<ModuleLlvm
                 }
             }
 
+            // Finalize code coverage by injecting the coverage map. Note, the coverage map will
+            // also be added to the `llvm.used` variable, created next.
+            if cx.sess().opts.debugging_opts.instrument_coverage {
+                cx.coverageinfo_finalize();
+            }
+
             // Create the llvm.used variable
             // This variable has type [N x i8*] and is stored in the llvm.metadata section
             if !cx.used_statics().borrow().is_empty() {
                 cx.create_used_variable()
             }
 
-            // Finalize code coverage by injecting the coverage map
-            if cx.sess().opts.debugging_opts.instrument_coverage {
-                cx.coverageinfo_finalize();
-            }
-
             // Finalize debuginfo
             if cx.sess().opts.debuginfo != DebugInfo::None {
                 cx.debuginfo_finalize();
diff --git a/src/librustc_codegen_llvm/build.rs b/src/librustc_codegen_llvm/build.rs
deleted file mode 100644 (file)
index d1fc624..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-fn main() {
-    println!("cargo:rerun-if-changed=build.rs");
-    println!("cargo:rerun-if-env-changed=CFG_VERSION");
-    println!("cargo:rerun-if-env-changed=CFG_PREFIX");
-    println!("cargo:rerun-if-env-changed=CFG_LLVM_ROOT");
-}
index 6a38323f7ca9ef343748173860ee4049ec4e8b30..8a1bb258d4274480afd58fa175e64fd129fcdd8a 100644 (file)
@@ -1060,7 +1060,7 @@ fn instrprof_increment(
             fn_name, hash, num_counters, index
         );
 
-        let llfn = unsafe { llvm::LLVMRustGetInstrprofIncrementIntrinsic(self.cx().llmod) };
+        let llfn = unsafe { llvm::LLVMRustGetInstrProfIncrementIntrinsic(self.cx().llmod) };
         let args = &[fn_name, hash, num_counters, index];
         let args = self.check_call("call", llfn, args);
 
@@ -1330,7 +1330,12 @@ fn call_lifetime_intrinsic(&mut self, intrinsic: &str, ptr: &'ll Value, size: Si
         self.call(lifetime_intrinsic, &[self.cx.const_u64(size), ptr], None);
     }
 
-    fn phi(&mut self, ty: &'ll Type, vals: &[&'ll Value], bbs: &[&'ll BasicBlock]) -> &'ll Value {
+    pub(crate) fn phi(
+        &mut self,
+        ty: &'ll Type,
+        vals: &[&'ll Value],
+        bbs: &[&'ll BasicBlock],
+    ) -> &'ll Value {
         assert_eq!(vals.len(), bbs.len());
         let phi = unsafe { llvm::LLVMBuildPhi(self.llbuilder, ty, UNNAMED) };
         unsafe {
index 7b341651adf3dec5d0de0ef748257b44047b3cd9..75b4f2e3ca5a55aa0e4bb6dd79d3ccc6f76f4495 100644 (file)
@@ -13,7 +13,7 @@
 use rustc_codegen_ssa::traits::*;
 
 use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt};
-use rustc_middle::ty::{Instance, TypeFoldable};
+use rustc_middle::ty::{self, Instance, TypeFoldable};
 
 /// Codegens a reference to a fn/method item, monomorphizing and
 /// inlining as it goes.
@@ -29,14 +29,18 @@ pub fn get_fn(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) -> &'ll Value
 
     assert!(!instance.substs.needs_infer());
     assert!(!instance.substs.has_escaping_bound_vars());
-    assert!(!instance.substs.has_param_types_or_consts());
 
     if let Some(&llfn) = cx.instances.borrow().get(&instance) {
         return llfn;
     }
 
     let sym = tcx.symbol_name(instance).name;
-    debug!("get_fn({:?}: {:?}) => {}", instance, instance.monomorphic_ty(cx.tcx()), sym);
+    debug!(
+        "get_fn({:?}: {:?}) => {}",
+        instance,
+        instance.ty(cx.tcx(), ty::ParamEnv::reveal_all()),
+        sym
+    );
 
     let fn_abi = FnAbi::of_instance(cx, instance, &[]);
 
index 64140747871fec68ca8b27a2ebdb516ad2f004e7..2a50d4a46d279436ade2897007f8615097f59b7a 100644 (file)
@@ -16,7 +16,7 @@
 use rustc_middle::mir::interpret::{Allocation, GlobalAlloc, Scalar};
 use rustc_middle::ty::layout::TyAndLayout;
 use rustc_span::symbol::Symbol;
-use rustc_target::abi::{self, HasDataLayout, LayoutOf, Pointer, Size};
+use rustc_target::abi::{self, AddressSpace, HasDataLayout, LayoutOf, Pointer, Size};
 
 use libc::{c_char, c_uint};
 use log::debug;
@@ -244,7 +244,7 @@ fn scalar_to_backend(&self, cv: Scalar, layout: &abi::Scalar, llty: &'ll Type) -
                 }
             }
             Scalar::Ptr(ptr) => {
-                let base_addr = match self.tcx.global_alloc(ptr.alloc_id) {
+                let (base_addr, base_addr_space) = match self.tcx.global_alloc(ptr.alloc_id) {
                     GlobalAlloc::Memory(alloc) => {
                         let init = const_alloc_to_llvm(self, alloc);
                         let value = match alloc.mutability {
@@ -254,18 +254,21 @@ fn scalar_to_backend(&self, cv: Scalar, layout: &abi::Scalar, llty: &'ll Type) -
                         if !self.sess().fewer_names() {
                             llvm::set_value_name(value, format!("{:?}", ptr.alloc_id).as_bytes());
                         }
-                        value
+                        (value, AddressSpace::DATA)
                     }
-                    GlobalAlloc::Function(fn_instance) => self.get_fn_addr(fn_instance),
+                    GlobalAlloc::Function(fn_instance) => (
+                        self.get_fn_addr(fn_instance.polymorphize(self.tcx)),
+                        self.data_layout().instruction_address_space,
+                    ),
                     GlobalAlloc::Static(def_id) => {
                         assert!(self.tcx.is_static(def_id));
                         assert!(!self.tcx.is_thread_local_static(def_id));
-                        self.get_static(def_id)
+                        (self.get_static(def_id), AddressSpace::DATA)
                     }
                 };
                 let llval = unsafe {
                     llvm::LLVMConstInBoundsGEP(
-                        self.const_bitcast(base_addr, self.type_i8p()),
+                        self.const_bitcast(base_addr, self.type_i8p_ext(base_addr_space)),
                         &self.const_usize(ptr.offset.bytes()),
                         1,
                     )
index 90887b760fb7d20c53fb1b38b0dbb68c09c0f62c..3e9e5d9c8c1f44e059030d9397441ca8b31feb44 100644 (file)
 use rustc_hir::Node;
 use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
 use rustc_middle::mir::interpret::{
-    read_target_uint, Allocation, ConstValue, ErrorHandled, Pointer,
+    read_target_uint, Allocation, ConstValue, ErrorHandled, GlobalAlloc, Pointer,
 };
 use rustc_middle::mir::mono::MonoItem;
 use rustc_middle::ty::{self, Instance, Ty};
 use rustc_middle::{bug, span_bug};
 use rustc_span::symbol::sym;
 use rustc_span::Span;
-use rustc_target::abi::{Align, HasDataLayout, LayoutOf, Primitive, Scalar, Size};
+use rustc_target::abi::{AddressSpace, Align, HasDataLayout, LayoutOf, Primitive, Scalar, Size};
 
 use std::ffi::CStr;
 
@@ -53,10 +53,16 @@ pub fn const_alloc_to_llvm(cx: &CodegenCx<'ll, '_>, alloc: &Allocation) -> &'ll
         )
         .expect("const_alloc_to_llvm: could not read relocation pointer")
             as u64;
+
+        let address_space = match cx.tcx.global_alloc(alloc_id) {
+            GlobalAlloc::Function(..) => cx.data_layout().instruction_address_space,
+            GlobalAlloc::Static(..) | GlobalAlloc::Memory(..) => AddressSpace::DATA,
+        };
+
         llvals.push(cx.scalar_to_backend(
             Pointer::new(alloc_id, Size::from_bytes(ptr_offset)).into(),
             &Scalar { value: Primitive::Pointer, valid_range: 0..=!0 },
-            cx.type_i8p(),
+            cx.type_i8p_ext(address_space),
         ));
         next_offset = offset + pointer_size;
     }
@@ -203,7 +209,7 @@ impl CodegenCx<'ll, 'tcx> {
             def_id
         );
 
-        let ty = instance.monomorphic_ty(self.tcx);
+        let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all());
         let sym = self.tcx.symbol_name(instance).name;
 
         debug!("get_static: sym={} instance={:?}", sym, instance);
@@ -361,7 +367,7 @@ fn codegen_static(&self, def_id: DefId, is_mutable: bool) {
             };
 
             let instance = Instance::mono(self.tcx, def_id);
-            let ty = instance.monomorphic_ty(self.tcx);
+            let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all());
             let llty = self.layout_of(ty).llvm_type(self);
             let g = if val_llty == llty {
                 g
@@ -493,10 +499,14 @@ fn codegen_static(&self, def_id: DefId, is_mutable: bool) {
             }
 
             if attrs.flags.contains(CodegenFnAttrFlags::USED) {
-                // This static will be stored in the llvm.used variable which is an array of i8*
-                let cast = llvm::LLVMConstPointerCast(g, self.type_i8p());
-                self.used_statics.borrow_mut().push(cast);
+                self.add_used_global(g);
             }
         }
     }
+
+    /// Add a global value to a list to be stored in the `llvm.used` variable, an array of i8*.
+    fn add_used_global(&self, global: &'ll Value) {
+        let cast = unsafe { llvm::LLVMConstPointerCast(global, self.type_i8p()) };
+        self.used_statics.borrow_mut().push(cast);
+    }
 }
index 21ba97d15a485776362716ed8b84b6c946cd1f8d..33a3cdbfa9b443ff638b5e51d4f9c6bd3b851450 100644 (file)
@@ -190,7 +190,7 @@ pub unsafe fn create_module(
 
     // Control Flow Guard is currently only supported by the MSVC linker on Windows.
     if sess.target.target.options.is_like_msvc {
-        match sess.opts.debugging_opts.control_flow_guard {
+        match sess.opts.cg.control_flow_guard {
             CFGuard::Disabled => {}
             CFGuard::NoChecks => {
                 // Set `cfguard=1` module flag to emit metadata only.
@@ -510,6 +510,14 @@ macro_rules! vector_types {
         ifn!("llvm.wasm.trunc.saturate.signed.i32.f64", fn(t_f64) -> t_i32);
         ifn!("llvm.wasm.trunc.saturate.signed.i64.f32", fn(t_f32) -> t_i64);
         ifn!("llvm.wasm.trunc.saturate.signed.i64.f64", fn(t_f64) -> t_i64);
+        ifn!("llvm.wasm.trunc.unsigned.i32.f32", fn(t_f32) -> t_i32);
+        ifn!("llvm.wasm.trunc.unsigned.i32.f64", fn(t_f64) -> t_i32);
+        ifn!("llvm.wasm.trunc.unsigned.i64.f32", fn(t_f32) -> t_i64);
+        ifn!("llvm.wasm.trunc.unsigned.i64.f64", fn(t_f64) -> t_i64);
+        ifn!("llvm.wasm.trunc.signed.i32.f32", fn(t_f32) -> t_i32);
+        ifn!("llvm.wasm.trunc.signed.i32.f64", fn(t_f64) -> t_i32);
+        ifn!("llvm.wasm.trunc.signed.i64.f32", fn(t_f32) -> t_i64);
+        ifn!("llvm.wasm.trunc.signed.i64.f64", fn(t_f64) -> t_i64);
 
         ifn!("llvm.trap", fn() -> void);
         ifn!("llvm.debugtrap", fn() -> void);
diff --git a/src/librustc_codegen_llvm/coverageinfo/mapgen.rs b/src/librustc_codegen_llvm/coverageinfo/mapgen.rs
new file mode 100644 (file)
index 0000000..7f48b1d
--- /dev/null
@@ -0,0 +1,274 @@
+use crate::llvm;
+
+use crate::common::CodegenCx;
+use crate::coverageinfo;
+
+use log::debug;
+use rustc_codegen_ssa::coverageinfo::map::*;
+use rustc_codegen_ssa::traits::{BaseTypeMethods, ConstMethods, MiscMethods};
+use rustc_data_structures::fx::FxHashMap;
+use rustc_llvm::RustString;
+use rustc_middle::ty::Instance;
+use rustc_middle::{bug, mir};
+
+use std::collections::BTreeMap;
+use std::ffi::CString;
+use std::path::PathBuf;
+
+// FIXME(richkadel): Complete all variations of generating and exporting the coverage map to LLVM.
+// The current implementation is an initial foundation with basic capabilities (Counters, but not
+// CounterExpressions, etc.).
+
+/// Generates and exports the Coverage Map.
+///
+/// This Coverage Map complies with Coverage Mapping Format version 3 (zero-based encoded as 2),
+/// as defined at [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/llvmorg-8.0.0/llvm/docs/CoverageMappingFormat.rst#llvm-code-coverage-mapping-format)
+/// and published in Rust's current (July 2020) fork of LLVM. This version is supported by the
+/// LLVM coverage tools (`llvm-profdata` and `llvm-cov`) bundled with Rust's fork of LLVM.
+///
+/// Consequently, Rust's bundled version of Clang also generates Coverage Maps compliant with
+/// version 3. Clang's implementation of Coverage Map generation was referenced when implementing
+/// this Rust version, and though the format documentation is very explicit and detailed, some
+/// undocumented details in Clang's implementation (that may or may not be important) were also
+/// replicated for Rust's Coverage Map.
+pub fn finalize<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) {
+    let mut coverage_writer = CoverageMappingWriter::new(cx);
+
+    let function_coverage_map = cx.coverage_context().take_function_coverage_map();
+
+    // Encode coverage mappings and generate function records
+    let mut function_records = Vec::<&'ll llvm::Value>::new();
+    let coverage_mappings_buffer = llvm::build_byte_buffer(|coverage_mappings_buffer| {
+        for (instance, function_coverage) in function_coverage_map.into_iter() {
+            if let Some(function_record) = coverage_writer.write_function_mappings_and_record(
+                instance,
+                function_coverage,
+                coverage_mappings_buffer,
+            ) {
+                function_records.push(function_record);
+            }
+        }
+    });
+
+    // Encode all filenames covered in this module, ordered by `file_id`
+    let filenames_buffer = llvm::build_byte_buffer(|filenames_buffer| {
+        coverageinfo::write_filenames_section_to_buffer(
+            &coverage_writer.filenames,
+            filenames_buffer,
+        );
+    });
+
+    if coverage_mappings_buffer.len() > 0 {
+        // Generate the LLVM IR representation of the coverage map and store it in a well-known
+        // global constant.
+        coverage_writer.write_coverage_map(
+            function_records,
+            filenames_buffer,
+            coverage_mappings_buffer,
+        );
+    }
+}
+
+struct CoverageMappingWriter<'a, 'll, 'tcx> {
+    cx: &'a CodegenCx<'ll, 'tcx>,
+    filenames: Vec<CString>,
+    filename_to_index: FxHashMap<CString, u32>,
+}
+
+impl<'a, 'll, 'tcx> CoverageMappingWriter<'a, 'll, 'tcx> {
+    fn new(cx: &'a CodegenCx<'ll, 'tcx>) -> Self {
+        Self { cx, filenames: Vec::new(), filename_to_index: FxHashMap::<CString, u32>::default() }
+    }
+
+    /// For the given function, get the coverage region data, stream it to the given buffer, and
+    /// then generate and return a new function record.
+    fn write_function_mappings_and_record(
+        &mut self,
+        instance: Instance<'tcx>,
+        mut function_coverage: FunctionCoverage,
+        coverage_mappings_buffer: &RustString,
+    ) -> Option<&'ll llvm::Value> {
+        let cx = self.cx;
+        let coverageinfo: &mir::CoverageInfo = cx.tcx.coverageinfo(instance.def_id());
+        debug!(
+            "Generate coverage map for: {:?}, num_counters: {}, num_expressions: {}",
+            instance, coverageinfo.num_counters, coverageinfo.num_expressions
+        );
+        debug_assert!(coverageinfo.num_counters > 0);
+
+        let regions_in_file_order = function_coverage.regions_in_file_order(cx.sess().source_map());
+        if regions_in_file_order.len() == 0 {
+            return None;
+        }
+
+        // Stream the coverage mapping regions for the function (`instance`) to the buffer, and
+        // compute the data byte size used.
+        let old_len = coverage_mappings_buffer.len();
+        self.regions_to_mappings(regions_in_file_order, coverage_mappings_buffer);
+        let mapping_data_size = coverage_mappings_buffer.len() - old_len;
+        debug_assert!(mapping_data_size > 0);
+
+        let mangled_function_name = cx.tcx.symbol_name(instance).to_string();
+        let name_ref = coverageinfo::compute_hash(&mangled_function_name);
+        let function_source_hash = function_coverage.source_hash();
+
+        // Generate and return the function record
+        let name_ref_val = cx.const_u64(name_ref);
+        let mapping_data_size_val = cx.const_u32(mapping_data_size as u32);
+        let func_hash_val = cx.const_u64(function_source_hash);
+        Some(cx.const_struct(
+            &[name_ref_val, mapping_data_size_val, func_hash_val],
+            /*packed=*/ true,
+        ))
+    }
+
+    /// For each coverage region, extract its coverage data from the earlier coverage analysis.
+    /// Use LLVM APIs to convert the data into buffered bytes compliant with the LLVM Coverage
+    /// Mapping format.
+    fn regions_to_mappings(
+        &mut self,
+        regions_in_file_order: BTreeMap<PathBuf, BTreeMap<CoverageLoc, (usize, CoverageKind)>>,
+        coverage_mappings_buffer: &RustString,
+    ) {
+        let mut virtual_file_mapping = Vec::new();
+        let mut mapping_regions = coverageinfo::SmallVectorCounterMappingRegion::new();
+        let mut expressions = coverageinfo::SmallVectorCounterExpression::new();
+
+        for (file_id, (file_path, file_coverage_regions)) in
+            regions_in_file_order.into_iter().enumerate()
+        {
+            let file_id = file_id as u32;
+            let filename = CString::new(file_path.to_string_lossy().to_string())
+                .expect("null error converting filename to C string");
+            debug!("  file_id: {} = '{:?}'", file_id, filename);
+            let filenames_index = match self.filename_to_index.get(&filename) {
+                Some(index) => *index,
+                None => {
+                    let index = self.filenames.len() as u32;
+                    self.filenames.push(filename.clone());
+                    self.filename_to_index.insert(filename, index);
+                    index
+                }
+            };
+            virtual_file_mapping.push(filenames_index);
+
+            let mut mapping_indexes = vec![0 as u32; file_coverage_regions.len()];
+            for (mapping_index, (region_id, _)) in file_coverage_regions.values().enumerate() {
+                mapping_indexes[*region_id] = mapping_index as u32;
+            }
+
+            for (region_loc, (region_id, region_kind)) in file_coverage_regions.into_iter() {
+                let mapping_index = mapping_indexes[region_id];
+                match region_kind {
+                    CoverageKind::Counter => {
+                        debug!(
+                            "  Counter {}, file_id: {}, region_loc: {}",
+                            mapping_index, file_id, region_loc
+                        );
+                        mapping_regions.push_from(
+                            mapping_index,
+                            file_id,
+                            region_loc.start_line,
+                            region_loc.start_col,
+                            region_loc.end_line,
+                            region_loc.end_col,
+                        );
+                    }
+                    CoverageKind::CounterExpression(lhs, op, rhs) => {
+                        debug!(
+                            "  CounterExpression {} = {} {:?} {}, file_id: {}, region_loc: {:?}",
+                            mapping_index, lhs, op, rhs, file_id, region_loc,
+                        );
+                        mapping_regions.push_from(
+                            mapping_index,
+                            file_id,
+                            region_loc.start_line,
+                            region_loc.start_col,
+                            region_loc.end_line,
+                            region_loc.end_col,
+                        );
+                        expressions.push_from(op, lhs, rhs);
+                    }
+                    CoverageKind::Unreachable => {
+                        debug!(
+                            "  Unreachable region, file_id: {}, region_loc: {:?}",
+                            file_id, region_loc,
+                        );
+                        bug!("Unreachable region not expected and not yet handled!")
+                        // FIXME(richkadel): implement and call
+                        //   mapping_regions.push_from(...) for unreachable regions
+                    }
+                }
+            }
+        }
+
+        // Encode and append the current function's coverage mapping data
+        coverageinfo::write_mapping_to_buffer(
+            virtual_file_mapping,
+            expressions,
+            mapping_regions,
+            coverage_mappings_buffer,
+        );
+    }
+
+    fn write_coverage_map(
+        self,
+        function_records: Vec<&'ll llvm::Value>,
+        filenames_buffer: Vec<u8>,
+        mut coverage_mappings_buffer: Vec<u8>,
+    ) {
+        let cx = self.cx;
+
+        // Concatenate the encoded filenames and encoded coverage mappings, and add additional zero
+        // bytes as-needed to ensure 8-byte alignment.
+        let mut coverage_size = coverage_mappings_buffer.len();
+        let filenames_size = filenames_buffer.len();
+        let remaining_bytes =
+            (filenames_size + coverage_size) % coverageinfo::COVMAP_VAR_ALIGN_BYTES;
+        if remaining_bytes > 0 {
+            let pad = coverageinfo::COVMAP_VAR_ALIGN_BYTES - remaining_bytes;
+            coverage_mappings_buffer.append(&mut [0].repeat(pad));
+            coverage_size += pad;
+        }
+        let filenames_and_coverage_mappings = [filenames_buffer, coverage_mappings_buffer].concat();
+        let filenames_and_coverage_mappings_val =
+            cx.const_bytes(&filenames_and_coverage_mappings[..]);
+
+        debug!(
+            "cov map: n_records = {}, filenames_size = {}, coverage_size = {}, 0-based version = {}",
+            function_records.len(),
+            filenames_size,
+            coverage_size,
+            coverageinfo::mapping_version()
+        );
+
+        // Create the coverage data header
+        let n_records_val = cx.const_u32(function_records.len() as u32);
+        let filenames_size_val = cx.const_u32(filenames_size as u32);
+        let coverage_size_val = cx.const_u32(coverage_size as u32);
+        let version_val = cx.const_u32(coverageinfo::mapping_version());
+        let cov_data_header_val = cx.const_struct(
+            &[n_records_val, filenames_size_val, coverage_size_val, version_val],
+            /*packed=*/ false,
+        );
+
+        // Create the function records array
+        let name_ref_from_u64 = cx.type_i64();
+        let mapping_data_size_from_u32 = cx.type_i32();
+        let func_hash_from_u64 = cx.type_i64();
+        let function_record_ty = cx.type_struct(
+            &[name_ref_from_u64, mapping_data_size_from_u32, func_hash_from_u64],
+            /*packed=*/ true,
+        );
+        let function_records_val = cx.const_array(function_record_ty, &function_records[..]);
+
+        // Create the complete LLVM coverage data value to add to the LLVM IR
+        let cov_data_val = cx.const_struct(
+            &[cov_data_header_val, function_records_val, filenames_and_coverage_mappings_val],
+            /*packed=*/ false,
+        );
+
+        // Save the coverage data value to LLVM IR
+        coverageinfo::save_map_to_mod(cx, cov_data_val);
+    }
+}
index ff9f8f7aeaa544ec591697a2528c5383edc037bd..76894bcd6c1b1c4a63c8b1bcc8c0ef859a629b58 100644 (file)
@@ -1,67 +1,44 @@
+use crate::llvm;
+
 use crate::builder::Builder;
 use crate::common::CodegenCx;
+
+use libc::c_uint;
 use log::debug;
 use rustc_codegen_ssa::coverageinfo::map::*;
-use rustc_codegen_ssa::traits::{CoverageInfoBuilderMethods, CoverageInfoMethods};
+use rustc_codegen_ssa::traits::{
+    BaseTypeMethods, CoverageInfoBuilderMethods, CoverageInfoMethods, StaticMethods,
+};
 use rustc_data_structures::fx::FxHashMap;
+use rustc_llvm::RustString;
 use rustc_middle::ty::Instance;
 
 use std::cell::RefCell;
+use std::ffi::CString;
+
+pub mod mapgen;
+
+const COVMAP_VAR_ALIGN_BYTES: usize = 8;
 
 /// A context object for maintaining all state needed by the coverageinfo module.
 pub struct CrateCoverageContext<'tcx> {
     // Coverage region data for each instrumented function identified by DefId.
-    pub(crate) coverage_regions: RefCell<FxHashMap<Instance<'tcx>, FunctionCoverageRegions>>,
+    pub(crate) function_coverage_map: RefCell<FxHashMap<Instance<'tcx>, FunctionCoverage>>,
 }
 
 impl<'tcx> CrateCoverageContext<'tcx> {
     pub fn new() -> Self {
-        Self { coverage_regions: Default::default() }
+        Self { function_coverage_map: Default::default() }
     }
-}
 
-/// Generates and exports the Coverage Map.
-// FIXME(richkadel): Actually generate and export the coverage map to LLVM.
-// The current implementation is actually just debug messages to show the data is available.
-pub fn finalize(cx: &CodegenCx<'_, '_>) {
-    let coverage_regions = &*cx.coverage_context().coverage_regions.borrow();
-    for instance in coverage_regions.keys() {
-        let coverageinfo = cx.tcx.coverageinfo(instance.def_id());
-        debug_assert!(coverageinfo.num_counters > 0);
-        debug!(
-            "Generate coverage map for: {:?}, hash: {}, num_counters: {}",
-            instance, coverageinfo.hash, coverageinfo.num_counters
-        );
-        let function_coverage_regions = &coverage_regions[instance];
-        for (index, region) in function_coverage_regions.indexed_regions() {
-            match region.kind {
-                CoverageKind::Counter => debug!(
-                    "  Counter {}, for {}..{}",
-                    index, region.coverage_span.start_byte_pos, region.coverage_span.end_byte_pos
-                ),
-                CoverageKind::CounterExpression(lhs, op, rhs) => debug!(
-                    "  CounterExpression {} = {} {:?} {}, for {}..{}",
-                    index,
-                    lhs,
-                    op,
-                    rhs,
-                    region.coverage_span.start_byte_pos,
-                    region.coverage_span.end_byte_pos
-                ),
-            }
-        }
-        for unreachable in function_coverage_regions.unreachable_regions() {
-            debug!(
-                "  Unreachable code region: {}..{}",
-                unreachable.start_byte_pos, unreachable.end_byte_pos
-            );
-        }
+    pub fn take_function_coverage_map(&self) -> FxHashMap<Instance<'tcx>, FunctionCoverage> {
+        self.function_coverage_map.replace(FxHashMap::default())
     }
 }
 
 impl CoverageInfoMethods for CodegenCx<'ll, 'tcx> {
     fn coverageinfo_finalize(&self) {
-        finalize(self)
+        mapgen::finalize(self)
     }
 }
 
@@ -69,20 +46,22 @@ impl CoverageInfoBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
     fn add_counter_region(
         &mut self,
         instance: Instance<'tcx>,
+        function_source_hash: u64,
         index: u32,
         start_byte_pos: u32,
         end_byte_pos: u32,
     ) {
         debug!(
-            "adding counter to coverage map: instance={:?}, index={}, byte range {}..{}",
-            instance, index, start_byte_pos, end_byte_pos,
-        );
-        let mut coverage_regions = self.coverage_context().coverage_regions.borrow_mut();
-        coverage_regions.entry(instance).or_default().add_counter(
-            index,
-            start_byte_pos,
-            end_byte_pos,
+            "adding counter to coverage_regions: instance={:?}, function_source_hash={}, index={}, byte range {}..{}",
+            instance, function_source_hash, index, start_byte_pos, end_byte_pos,
         );
+        let mut coverage_regions = self.coverage_context().function_coverage_map.borrow_mut();
+        coverage_regions
+            .entry(instance)
+            .or_insert_with(|| {
+                FunctionCoverage::with_coverageinfo(self.tcx.coverageinfo(instance.def_id()))
+            })
+            .add_counter(function_source_hash, index, start_byte_pos, end_byte_pos);
     }
 
     fn add_counter_expression_region(
@@ -96,18 +75,16 @@ fn add_counter_expression_region(
         end_byte_pos: u32,
     ) {
         debug!(
-            "adding counter expression to coverage map: instance={:?}, index={}, {} {:?} {}, byte range {}..{}",
+            "adding counter expression to coverage_regions: instance={:?}, index={}, {} {:?} {}, byte range {}..{}",
             instance, index, lhs, op, rhs, start_byte_pos, end_byte_pos,
         );
-        let mut coverage_regions = self.coverage_context().coverage_regions.borrow_mut();
-        coverage_regions.entry(instance).or_default().add_counter_expression(
-            index,
-            lhs,
-            op,
-            rhs,
-            start_byte_pos,
-            end_byte_pos,
-        );
+        let mut coverage_regions = self.coverage_context().function_coverage_map.borrow_mut();
+        coverage_regions
+            .entry(instance)
+            .or_insert_with(|| {
+                FunctionCoverage::with_coverageinfo(self.tcx.coverageinfo(instance.def_id()))
+            })
+            .add_counter_expression(index, lhs, op, rhs, start_byte_pos, end_byte_pos);
     }
 
     fn add_unreachable_region(
@@ -117,10 +94,175 @@ fn add_unreachable_region(
         end_byte_pos: u32,
     ) {
         debug!(
-            "adding unreachable code to coverage map: instance={:?}, byte range {}..{}",
+            "adding unreachable code to coverage_regions: instance={:?}, byte range {}..{}",
             instance, start_byte_pos, end_byte_pos,
         );
-        let mut coverage_regions = self.coverage_context().coverage_regions.borrow_mut();
-        coverage_regions.entry(instance).or_default().add_unreachable(start_byte_pos, end_byte_pos);
+        let mut coverage_regions = self.coverage_context().function_coverage_map.borrow_mut();
+        coverage_regions
+            .entry(instance)
+            .or_insert_with(|| {
+                FunctionCoverage::with_coverageinfo(self.tcx.coverageinfo(instance.def_id()))
+            })
+            .add_unreachable(start_byte_pos, end_byte_pos);
+    }
+}
+
+/// This struct wraps an opaque reference to the C++ template instantiation of
+/// `llvm::SmallVector<coverage::CounterExpression>`. Each `coverage::CounterExpression` object is
+/// constructed from primative-typed arguments, and pushed to the `SmallVector`, in the C++
+/// implementation of `LLVMRustCoverageSmallVectorCounterExpressionAdd()` (see
+/// `src/rustllvm/CoverageMappingWrapper.cpp`).
+pub struct SmallVectorCounterExpression<'a> {
+    pub raw: &'a mut llvm::coverageinfo::SmallVectorCounterExpression<'a>,
+}
+
+impl SmallVectorCounterExpression<'a> {
+    pub fn new() -> Self {
+        SmallVectorCounterExpression {
+            raw: unsafe { llvm::LLVMRustCoverageSmallVectorCounterExpressionCreate() },
+        }
+    }
+
+    pub fn as_ptr(&self) -> *const llvm::coverageinfo::SmallVectorCounterExpression<'a> {
+        self.raw
+    }
+
+    pub fn push_from(
+        &mut self,
+        kind: rustc_codegen_ssa::coverageinfo::CounterOp,
+        left_index: u32,
+        right_index: u32,
+    ) {
+        unsafe {
+            llvm::LLVMRustCoverageSmallVectorCounterExpressionAdd(
+                &mut *(self.raw as *mut _),
+                kind,
+                left_index,
+                right_index,
+            )
+        }
+    }
+}
+
+impl Drop for SmallVectorCounterExpression<'a> {
+    fn drop(&mut self) {
+        unsafe {
+            llvm::LLVMRustCoverageSmallVectorCounterExpressionDispose(&mut *(self.raw as *mut _));
+        }
+    }
+}
+
+/// This struct wraps an opaque reference to the C++ template instantiation of
+/// `llvm::SmallVector<coverage::CounterMappingRegion>`. Each `coverage::CounterMappingRegion`
+/// object is constructed from primative-typed arguments, and pushed to the `SmallVector`, in the
+/// C++ implementation of `LLVMRustCoverageSmallVectorCounterMappingRegionAdd()` (see
+/// `src/rustllvm/CoverageMappingWrapper.cpp`).
+pub struct SmallVectorCounterMappingRegion<'a> {
+    pub raw: &'a mut llvm::coverageinfo::SmallVectorCounterMappingRegion<'a>,
+}
+
+impl SmallVectorCounterMappingRegion<'a> {
+    pub fn new() -> Self {
+        SmallVectorCounterMappingRegion {
+            raw: unsafe { llvm::LLVMRustCoverageSmallVectorCounterMappingRegionCreate() },
+        }
+    }
+
+    pub fn as_ptr(&self) -> *const llvm::coverageinfo::SmallVectorCounterMappingRegion<'a> {
+        self.raw
+    }
+
+    pub fn push_from(
+        &mut self,
+        index: u32,
+        file_id: u32,
+        line_start: u32,
+        column_start: u32,
+        line_end: u32,
+        column_end: u32,
+    ) {
+        unsafe {
+            llvm::LLVMRustCoverageSmallVectorCounterMappingRegionAdd(
+                &mut *(self.raw as *mut _),
+                index,
+                file_id,
+                line_start,
+                column_start,
+                line_end,
+                column_end,
+            )
+        }
+    }
+}
+
+impl Drop for SmallVectorCounterMappingRegion<'a> {
+    fn drop(&mut self) {
+        unsafe {
+            llvm::LLVMRustCoverageSmallVectorCounterMappingRegionDispose(
+                &mut *(self.raw as *mut _),
+            );
+        }
+    }
+}
+
+pub(crate) fn write_filenames_section_to_buffer(filenames: &Vec<CString>, buffer: &RustString) {
+    let c_str_vec = filenames.iter().map(|cstring| cstring.as_ptr()).collect::<Vec<_>>();
+    unsafe {
+        llvm::LLVMRustCoverageWriteFilenamesSectionToBuffer(
+            c_str_vec.as_ptr(),
+            c_str_vec.len(),
+            buffer,
+        );
+    }
+}
+
+pub(crate) fn write_mapping_to_buffer(
+    virtual_file_mapping: Vec<u32>,
+    expressions: SmallVectorCounterExpression<'_>,
+    mapping_regions: SmallVectorCounterMappingRegion<'_>,
+    buffer: &RustString,
+) {
+    unsafe {
+        llvm::LLVMRustCoverageWriteMappingToBuffer(
+            virtual_file_mapping.as_ptr(),
+            virtual_file_mapping.len() as c_uint,
+            expressions.as_ptr(),
+            mapping_regions.as_ptr(),
+            buffer,
+        );
     }
 }
+
+pub(crate) fn compute_hash(name: &str) -> u64 {
+    let name = CString::new(name).expect("null error converting hashable name to C string");
+    unsafe { llvm::LLVMRustCoverageComputeHash(name.as_ptr()) }
+}
+
+pub(crate) fn mapping_version() -> u32 {
+    unsafe { llvm::LLVMRustCoverageMappingVersion() }
+}
+
+pub(crate) fn save_map_to_mod<'ll, 'tcx>(
+    cx: &CodegenCx<'ll, 'tcx>,
+    cov_data_val: &'ll llvm::Value,
+) {
+    let covmap_var_name = llvm::build_string(|s| unsafe {
+        llvm::LLVMRustCoverageWriteMappingVarNameToString(s);
+    })
+    .expect("Rust Coverage Mapping var name failed UTF-8 conversion");
+    debug!("covmap var name: {:?}", covmap_var_name);
+
+    let covmap_section_name = llvm::build_string(|s| unsafe {
+        llvm::LLVMRustCoverageWriteSectionNameToString(cx.llmod, s);
+    })
+    .expect("Rust Coverage section name failed UTF-8 conversion");
+    debug!("covmap section name: {:?}", covmap_section_name);
+
+    let llglobal = llvm::add_global(cx.llmod, cx.val_ty(cov_data_val), &covmap_var_name);
+    llvm::set_initializer(llglobal, cov_data_val);
+    llvm::set_global_constant(llglobal, true);
+    llvm::set_linkage(llglobal, llvm::Linkage::InternalLinkage);
+    llvm::set_section(llglobal, &covmap_section_name);
+    llvm::set_alignment(llglobal, COVMAP_VAR_ALIGN_BYTES);
+    cx.add_used_global(llglobal);
+}
index ef9d42968ae2e0a1ae27a2fe6c92f9ffbea48405..6ae7c7efaee62b4933c33d8d578493e348a9fa55 100644 (file)
@@ -700,6 +700,8 @@ pub fn type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>, usage_site_span: Sp
             prepare_tuple_metadata(cx, t, &tys, unique_type_id, usage_site_span, NO_SCOPE_METADATA)
                 .finalize(cx)
         }
+        // Type parameters from polymorphized functions.
+        ty::Param(_) => MetadataCreationResult::new(param_type_metadata(cx, t), false),
         _ => bug!("debuginfo: unexpected type in type_metadata: {:?}", t),
     };
 
@@ -955,6 +957,20 @@ fn pointer_type_metadata(
     }
 }
 
+fn param_type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType {
+    debug!("param_type_metadata: {:?}", t);
+    let name = format!("{:?}", t);
+    return unsafe {
+        llvm::LLVMRustDIBuilderCreateBasicType(
+            DIB(cx),
+            name.as_ptr().cast(),
+            name.len(),
+            Size::ZERO.bits(),
+            DW_ATE_unsigned,
+        )
+    };
+}
+
 pub fn compile_unit_metadata(
     tcx: TyCtxt<'_>,
     codegen_unit_name: &str,
@@ -2465,7 +2481,7 @@ pub fn create_global_var_metadata(cx: &CodegenCx<'ll, '_>, def_id: DefId, global
     };
 
     let is_local_to_unit = is_node_local_to_unit(cx, def_id);
-    let variable_type = Instance::mono(cx.tcx, def_id).monomorphic_ty(cx.tcx);
+    let variable_type = Instance::mono(cx.tcx, def_id).ty(cx.tcx, ty::ParamEnv::reveal_all());
     let type_metadata = type_metadata(cx, variable_type, span);
     let var_name = tcx.item_name(def_id).as_str();
     let linkage_name = mangled_name_of_instance(cx, Instance::mono(tcx, def_id)).name;
index 44993d7602fe6e89ca9f16c0dce53391b527a88d..a01b8553721290697e789f760c95cc084718a72a 100644 (file)
@@ -26,7 +26,7 @@
 use rustc_middle::mir;
 use rustc_middle::ty::layout::HasTyCtxt;
 use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
-use rustc_middle::ty::{self, Instance, ParamEnv, Ty};
+use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TypeFoldable};
 use rustc_session::config::{self, DebugInfo};
 use rustc_span::symbol::Symbol;
 use rustc_span::{self, BytePos, Span};
@@ -470,7 +470,9 @@ fn get_containing_scope<'ll, 'tcx>(
                     match impl_self_ty.kind {
                         ty::Adt(def, ..) if !def.is_box() => {
                             // Again, only create type information if full debuginfo is enabled
-                            if cx.sess().opts.debuginfo == DebugInfo::Full {
+                            if cx.sess().opts.debuginfo == DebugInfo::Full
+                                && !impl_self_ty.needs_subst()
+                            {
                                 Some(type_metadata(cx, impl_self_ty, rustc_span::DUMMY_SP))
                             } else {
                                 Some(namespace::item_namespace(cx, def.did))
index d095587a1e8cb81d9cecd25fae428e132e538f24..11b1c95c58b3e14e10dfb341bb1ccea0752fe4a5 100644 (file)
@@ -90,45 +90,64 @@ fn is_codegen_intrinsic(
         args: &Vec<Operand<'tcx>>,
         caller_instance: ty::Instance<'tcx>,
     ) -> bool {
-        match intrinsic {
-            sym::count_code_region => {
-                use coverage::count_code_region_args::*;
-                self.add_counter_region(
-                    caller_instance,
-                    op_to_u32(&args[COUNTER_INDEX]),
-                    op_to_u32(&args[START_BYTE_POS]),
-                    op_to_u32(&args[END_BYTE_POS]),
-                );
-                true // Also inject the counter increment in the backend
-            }
-            sym::coverage_counter_add | sym::coverage_counter_subtract => {
-                use coverage::coverage_counter_expression_args::*;
-                self.add_counter_expression_region(
-                    caller_instance,
-                    op_to_u32(&args[COUNTER_EXPRESSION_INDEX]),
-                    op_to_u32(&args[LEFT_INDEX]),
-                    if intrinsic == sym::coverage_counter_add {
-                        CounterOp::Add
-                    } else {
-                        CounterOp::Subtract
-                    },
-                    op_to_u32(&args[RIGHT_INDEX]),
-                    op_to_u32(&args[START_BYTE_POS]),
-                    op_to_u32(&args[END_BYTE_POS]),
-                );
-                false // Does not inject backend code
-            }
-            sym::coverage_unreachable => {
-                use coverage::coverage_unreachable_args::*;
-                self.add_unreachable_region(
-                    caller_instance,
-                    op_to_u32(&args[START_BYTE_POS]),
-                    op_to_u32(&args[END_BYTE_POS]),
-                );
-                false // Does not inject backend code
+        if self.tcx.sess.opts.debugging_opts.instrument_coverage {
+            // Add the coverage information from the MIR to the Codegen context. Some coverage
+            // intrinsics are used only to pass along the coverage information (returns `false`
+            // for `is_codegen_intrinsic()`), but `count_code_region` is also converted into an
+            // LLVM intrinsic to increment a coverage counter.
+            match intrinsic {
+                sym::count_code_region => {
+                    use coverage::count_code_region_args::*;
+                    self.add_counter_region(
+                        caller_instance,
+                        op_to_u64(&args[FUNCTION_SOURCE_HASH]),
+                        op_to_u32(&args[COUNTER_INDEX]),
+                        op_to_u32(&args[START_BYTE_POS]),
+                        op_to_u32(&args[END_BYTE_POS]),
+                    );
+                    return true; // Also inject the counter increment in the backend
+                }
+                sym::coverage_counter_add | sym::coverage_counter_subtract => {
+                    use coverage::coverage_counter_expression_args::*;
+                    self.add_counter_expression_region(
+                        caller_instance,
+                        op_to_u32(&args[COUNTER_EXPRESSION_INDEX]),
+                        op_to_u32(&args[LEFT_INDEX]),
+                        if intrinsic == sym::coverage_counter_add {
+                            CounterOp::Add
+                        } else {
+                            CounterOp::Subtract
+                        },
+                        op_to_u32(&args[RIGHT_INDEX]),
+                        op_to_u32(&args[START_BYTE_POS]),
+                        op_to_u32(&args[END_BYTE_POS]),
+                    );
+                    return false; // Does not inject backend code
+                }
+                sym::coverage_unreachable => {
+                    use coverage::coverage_unreachable_args::*;
+                    self.add_unreachable_region(
+                        caller_instance,
+                        op_to_u32(&args[START_BYTE_POS]),
+                        op_to_u32(&args[END_BYTE_POS]),
+                    );
+                    return false; // Does not inject backend code
+                }
+                _ => {}
+            }
+        } else {
+            // NOT self.tcx.sess.opts.debugging_opts.instrument_coverage
+            if intrinsic == sym::count_code_region {
+                // An external crate may have been pre-compiled with coverage instrumentation, and
+                // some references from the current crate to the external crate might carry along
+                // the call terminators to coverage intrinsics, like `count_code_region` (for
+                // example, when instantiating a generic function). If the current crate has
+                // `instrument_coverage` disabled, the `count_code_region` call terminators should
+                // be ignored.
+                return false; // Do not inject coverage counters inlined from external crates
             }
-            _ => true, // Unhandled intrinsics should be passed to `codegen_intrinsic_call()`
         }
+        true // Unhandled intrinsics should be passed to `codegen_intrinsic_call()`
     }
 
     fn codegen_intrinsic_call(
@@ -141,7 +160,7 @@ fn codegen_intrinsic_call(
         caller_instance: ty::Instance<'tcx>,
     ) {
         let tcx = self.tcx;
-        let callee_ty = instance.monomorphic_ty(tcx);
+        let callee_ty = instance.ty(tcx, ty::ParamEnv::reveal_all());
 
         let (def_id, substs) = match callee_ty.kind {
             ty::FnDef(def_id, substs) => (def_id, substs),
@@ -197,12 +216,13 @@ fn codegen_intrinsic_call(
                 let coverageinfo = tcx.coverageinfo(caller_instance.def_id());
                 let mangled_fn = tcx.symbol_name(caller_instance);
                 let (mangled_fn_name, _len_val) = self.const_str(Symbol::intern(mangled_fn.name));
-                let hash = self.const_u64(coverageinfo.hash);
                 let num_counters = self.const_u32(coverageinfo.num_counters);
                 use coverage::count_code_region_args::*;
+                let hash = args[FUNCTION_SOURCE_HASH].immediate();
                 let index = args[COUNTER_INDEX].immediate();
                 debug!(
-                    "count_code_region to LLVM intrinsic instrprof.increment(fn_name={}, hash={:?}, num_counters={:?}, index={:?})",
+                    "translating Rust intrinsic `count_code_region()` to LLVM intrinsic: \
+                    instrprof.increment(fn_name={}, hash={:?}, num_counters={:?}, index={:?})",
                     mangled_fn.name, hash, num_counters, index,
                 );
                 self.instrprof_increment(mangled_fn_name, hash, num_counters, index)
@@ -609,27 +629,24 @@ fn codegen_intrinsic_call(
             }
 
             sym::float_to_int_unchecked => {
-                if float_type_width(arg_tys[0]).is_none() {
-                    span_invalid_monomorphization_error(
-                        tcx.sess,
-                        span,
-                        &format!(
-                            "invalid monomorphization of `float_to_int_unchecked` \
+                let float_width = match float_type_width(arg_tys[0]) {
+                    Some(width) => width,
+                    None => {
+                        span_invalid_monomorphization_error(
+                            tcx.sess,
+                            span,
+                            &format!(
+                                "invalid monomorphization of `float_to_int_unchecked` \
                                   intrinsic: expected basic float type, \
                                   found `{}`",
-                            arg_tys[0]
-                        ),
-                    );
-                    return;
-                }
-                match int_type_width_signed(ret_ty, self.cx) {
-                    Some((width, signed)) => {
-                        if signed {
-                            self.fptosi(args[0].immediate(), self.cx.type_ix(width))
-                        } else {
-                            self.fptoui(args[0].immediate(), self.cx.type_ix(width))
-                        }
+                                arg_tys[0]
+                            ),
+                        );
+                        return;
                     }
+                };
+                let (width, signed) = match int_type_width_signed(ret_ty, self.cx) {
+                    Some(pair) => pair,
                     None => {
                         span_invalid_monomorphization_error(
                             tcx.sess,
@@ -643,7 +660,49 @@ fn codegen_intrinsic_call(
                         );
                         return;
                     }
+                };
+
+                // The LLVM backend can reorder and speculate `fptosi` and
+                // `fptoui`, so on WebAssembly the codegen for this instruction
+                // is quite heavyweight. To avoid this heavyweight codegen we
+                // instead use the raw wasm intrinsics which will lower to one
+                // instruction in WebAssembly (`iNN.trunc_fMM_{s,u}`). This one
+                // instruction will trap if the operand is out of bounds, but
+                // that's ok since this intrinsic is UB if the operands are out
+                // of bounds, so the behavior can be different on WebAssembly
+                // than other targets.
+                //
+                // Note, however, that when the `nontrapping-fptoint` feature is
+                // enabled in LLVM then LLVM will lower `fptosi` to
+                // `iNN.trunc_sat_fMM_{s,u}`, so if that's the case we don't
+                // bother with intrinsics.
+                let mut result = None;
+                if self.sess().target.target.arch == "wasm32"
+                    && !self.sess().target_features.contains(&sym::nontrapping_dash_fptoint)
+                {
+                    let name = match (width, float_width, signed) {
+                        (32, 32, true) => Some("llvm.wasm.trunc.signed.i32.f32"),
+                        (32, 64, true) => Some("llvm.wasm.trunc.signed.i32.f64"),
+                        (64, 32, true) => Some("llvm.wasm.trunc.signed.i64.f32"),
+                        (64, 64, true) => Some("llvm.wasm.trunc.signed.i64.f64"),
+                        (32, 32, false) => Some("llvm.wasm.trunc.unsigned.i32.f32"),
+                        (32, 64, false) => Some("llvm.wasm.trunc.unsigned.i32.f64"),
+                        (64, 32, false) => Some("llvm.wasm.trunc.unsigned.i64.f32"),
+                        (64, 64, false) => Some("llvm.wasm.trunc.unsigned.i64.f64"),
+                        _ => None,
+                    };
+                    if let Some(name) = name {
+                        let intrinsic = self.get_intrinsic(name);
+                        result = Some(self.call(intrinsic, &[args[0].immediate()], None));
+                    }
                 }
+                result.unwrap_or_else(|| {
+                    if signed {
+                        self.fptosi(args[0].immediate(), self.cx.type_ix(width))
+                    } else {
+                        self.fptoui(args[0].immediate(), self.cx.type_ix(width))
+                    }
+                })
             }
 
             sym::discriminant_value => {
@@ -2222,3 +2281,7 @@ fn float_type_width(ty: Ty<'_>) -> Option<u64> {
 fn op_to_u32<'tcx>(op: &Operand<'tcx>) -> u32 {
     Operand::scalar_from_const(op).to_u32().expect("Scalar is u32")
 }
+
+fn op_to_u64<'tcx>(op: &Operand<'tcx>) -> u64 {
+    Operand::scalar_from_const(op).to_u64().expect("Scalar is u64")
+}
index 64f5e103f0b0dbd5f06c46f84042e3a0fdbf4086..9784beaa079de7f2b892b710ad730ec129fc325e 100644 (file)
@@ -1,6 +1,8 @@
 #![allow(non_camel_case_types)]
 #![allow(non_upper_case_globals)]
 
+use super::coverageinfo::{SmallVectorCounterExpression, SmallVectorCounterMappingRegion};
+
 use super::debuginfo::{
     DIArray, DIBasicType, DIBuilder, DICompositeType, DIDerivedType, DIDescriptor, DIEnumerator,
     DIFile, DIFlags, DIGlobalVariableExpression, DILexicalBlock, DINameSpace, DISPFlags, DIScope,
@@ -650,6 +652,16 @@ struct InvariantOpaque<'a> {
 pub type DiagnosticHandler = unsafe extern "C" fn(&DiagnosticInfo, *mut c_void);
 pub type InlineAsmDiagHandler = unsafe extern "C" fn(&SMDiagnostic, *const c_void, c_uint);
 
+pub mod coverageinfo {
+    use super::InvariantOpaque;
+
+    #[repr(C)]
+    pub struct SmallVectorCounterExpression<'a>(InvariantOpaque<'a>);
+
+    #[repr(C)]
+    pub struct SmallVectorCounterMappingRegion<'a>(InvariantOpaque<'a>);
+}
+
 pub mod debuginfo {
     use super::{InvariantOpaque, Metadata};
     use bitflags::bitflags;
@@ -1365,7 +1377,7 @@ pub fn LLVMBuildFCmp(
 
     // Miscellaneous instructions
     pub fn LLVMBuildPhi(B: &Builder<'a>, Ty: &'a Type, Name: *const c_char) -> &'a Value;
-    pub fn LLVMRustGetInstrprofIncrementIntrinsic(M: &Module) -> &'a Value;
+    pub fn LLVMRustGetInstrProfIncrementIntrinsic(M: &Module) -> &'a Value;
     pub fn LLVMRustBuildCall(
         B: &Builder<'a>,
         Fn: &'a Value,
@@ -1633,6 +1645,58 @@ pub fn LLVMRustInlineAsmVerify(
         ConstraintsLen: size_t,
     ) -> bool;
 
+    pub fn LLVMRustCoverageSmallVectorCounterExpressionCreate()
+    -> &'a mut SmallVectorCounterExpression<'a>;
+    pub fn LLVMRustCoverageSmallVectorCounterExpressionDispose(
+        Container: &'a mut SmallVectorCounterExpression<'a>,
+    );
+    pub fn LLVMRustCoverageSmallVectorCounterExpressionAdd(
+        Container: &mut SmallVectorCounterExpression<'a>,
+        Kind: rustc_codegen_ssa::coverageinfo::CounterOp,
+        LeftIndex: c_uint,
+        RightIndex: c_uint,
+    );
+
+    pub fn LLVMRustCoverageSmallVectorCounterMappingRegionCreate()
+    -> &'a mut SmallVectorCounterMappingRegion<'a>;
+    pub fn LLVMRustCoverageSmallVectorCounterMappingRegionDispose(
+        Container: &'a mut SmallVectorCounterMappingRegion<'a>,
+    );
+    pub fn LLVMRustCoverageSmallVectorCounterMappingRegionAdd(
+        Container: &mut SmallVectorCounterMappingRegion<'a>,
+        Index: c_uint,
+        FileID: c_uint,
+        LineStart: c_uint,
+        ColumnStart: c_uint,
+        LineEnd: c_uint,
+        ColumnEnd: c_uint,
+    );
+
+    #[allow(improper_ctypes)]
+    pub fn LLVMRustCoverageWriteFilenamesSectionToBuffer(
+        Filenames: *const *const c_char,
+        FilenamesLen: size_t,
+        BufferOut: &RustString,
+    );
+
+    #[allow(improper_ctypes)]
+    pub fn LLVMRustCoverageWriteMappingToBuffer(
+        VirtualFileMappingIDs: *const c_uint,
+        NumVirtualFileMappingIDs: c_uint,
+        Expressions: *const SmallVectorCounterExpression<'_>,
+        MappingRegions: *const SmallVectorCounterMappingRegion<'_>,
+        BufferOut: &RustString,
+    );
+
+    pub fn LLVMRustCoverageComputeHash(Name: *const c_char) -> u64;
+
+    #[allow(improper_ctypes)]
+    pub fn LLVMRustCoverageWriteSectionNameToString(M: &Module, Str: &RustString);
+
+    #[allow(improper_ctypes)]
+    pub fn LLVMRustCoverageWriteMappingVarNameToString(Str: &RustString);
+
+    pub fn LLVMRustCoverageMappingVersion() -> u32;
     pub fn LLVMRustDebugMetadataVersion() -> u32;
     pub fn LLVMRustVersionMajor() -> u32;
     pub fn LLVMRustVersionMinor() -> u32;
index b7f1e1789c9e2cd0c8ced4247a2cdd8bf9c7b986..c09e3659f80a20053b6819df530bee4d783b78f8 100644 (file)
@@ -12,7 +12,7 @@
 use rustc_data_structures::small_c_str::SmallCStr;
 use rustc_llvm::RustString;
 use std::cell::RefCell;
-use std::ffi::CStr;
+use std::ffi::{CStr, CString};
 use std::str::FromStr;
 use std::string::FromUtf8Error;
 
@@ -189,6 +189,42 @@ 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 {
+        LLVMSetSection(llglobal, section_name_cstr.as_ptr());
+    }
+}
+
+pub fn add_global<'a>(llmod: &'a Module, ty: &'a Type, name: &str) -> &'a Value {
+    let name_cstr = CString::new(name).expect("unexpected CString error");
+    unsafe { LLVMAddGlobal(llmod, ty, name_cstr.as_ptr()) }
+}
+
+pub fn set_initializer(llglobal: &Value, constant_val: &Value) {
+    unsafe {
+        LLVMSetInitializer(llglobal, constant_val);
+    }
+}
+
+pub fn set_global_constant(llglobal: &Value, is_constant: bool) {
+    unsafe {
+        LLVMSetGlobalConstant(llglobal, if is_constant { ffi::True } else { ffi::False });
+    }
+}
+
+pub fn set_linkage(llglobal: &Value, linkage: Linkage) {
+    unsafe {
+        LLVMRustSetLinkage(llglobal, linkage);
+    }
+}
+
+pub fn set_alignment(llglobal: &Value, bytes: usize) {
+    unsafe {
+        ffi::LLVMSetAlignment(llglobal, bytes as c_uint);
+    }
+}
+
 /// Safe wrapper around `LLVMGetParam`, because segfaults are no fun.
 pub fn get_param(llfn: &Value, index: c_uint) -> &Value {
     unsafe {
@@ -225,6 +261,12 @@ pub fn build_string(f: impl FnOnce(&RustString)) -> Result<String, FromUtf8Error
     String::from_utf8(sr.bytes.into_inner())
 }
 
+pub fn build_byte_buffer(f: impl FnOnce(&RustString)) -> Vec<u8> {
+    let sr = RustString { bytes: RefCell::new(Vec::new()) };
+    f(&sr);
+    sr.bytes.into_inner()
+}
+
 pub fn twine_to_string(tr: &Twine) -> String {
     unsafe {
         build_string(|s| LLVMRustWriteTwineToString(tr, s)).expect("got a non-UTF8 Twine from LLVM")
index 486ea7f22dfffb1c968607e57fc60682ece68f11..0936deb7bb5a9c26d916e2a088d4e2cf5b98bd82 100644 (file)
@@ -10,7 +10,7 @@
 pub use rustc_middle::mir::mono::MonoItem;
 use rustc_middle::mir::mono::{Linkage, Visibility};
 use rustc_middle::ty::layout::FnAbiExt;
-use rustc_middle::ty::{Instance, TypeFoldable};
+use rustc_middle::ty::{self, Instance, TypeFoldable};
 use rustc_target::abi::LayoutOf;
 
 impl PreDefineMethods<'tcx> for CodegenCx<'ll, 'tcx> {
@@ -22,7 +22,7 @@ fn predefine_static(
         symbol_name: &str,
     ) {
         let instance = Instance::mono(self.tcx, def_id);
-        let ty = instance.monomorphic_ty(self.tcx);
+        let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all());
         let llty = self.layout_of(ty).llvm_type(self);
 
         let g = self.define_global(symbol_name, llty).unwrap_or_else(|| {
@@ -47,7 +47,7 @@ fn predefine_fn(
         visibility: Visibility,
         symbol_name: &str,
     ) {
-        assert!(!instance.substs.needs_infer() && !instance.substs.has_param_types_or_consts());
+        assert!(!instance.substs.needs_infer());
 
         let fn_abi = FnAbi::of_instance(self, instance, &[]);
         let lldecl = self.declare_fn(symbol_name, &fn_abi);
index 854eff31733805e349062e7876efd4889b756cc9..05e364884f66dcd66fac3e1b2d5e3fa8d7e89ce6 100644 (file)
@@ -15,7 +15,7 @@
 use rustc_middle::ty::layout::TyAndLayout;
 use rustc_middle::ty::Ty;
 use rustc_target::abi::call::{CastTarget, FnAbi, Reg};
-use rustc_target::abi::{Align, Integer, Size};
+use rustc_target::abi::{AddressSpace, Align, Integer, Size};
 
 use std::fmt;
 use std::ptr;
@@ -198,9 +198,13 @@ fn type_ptr_to(&self, ty: &'ll Type) -> &'ll Type {
         assert_ne!(
             self.type_kind(ty),
             TypeKind::Function,
-            "don't call ptr_to on function types, use ptr_to_llvm_type on FnAbi instead"
+            "don't call ptr_to on function types, use ptr_to_llvm_type on FnAbi instead or explicitly specify an address space if it makes sense"
         );
-        ty.ptr_to()
+        ty.ptr_to(AddressSpace::DATA)
+    }
+
+    fn type_ptr_to_ext(&self, ty: &'ll Type, address_space: AddressSpace) -> &'ll Type {
+        ty.ptr_to(address_space)
     }
 
     fn element_type(&self, ty: &'ll Type) -> &'ll Type {
@@ -241,11 +245,11 @@ pub fn ix_llcx(llcx: &llvm::Context, num_bits: u64) -> &Type {
     }
 
     pub fn i8p_llcx(llcx: &llvm::Context) -> &Type {
-        Type::i8_llcx(llcx).ptr_to()
+        Type::i8_llcx(llcx).ptr_to(AddressSpace::DATA)
     }
 
-    fn ptr_to(&self) -> &Type {
-        unsafe { llvm::LLVMPointerType(&self, 0) }
+    fn ptr_to(&self, address_space: AddressSpace) -> &Type {
+        unsafe { llvm::LLVMPointerType(&self, address_space.0) }
     }
 }
 
index 5a0da6be5980ed8d1192e63bf7eae7d189df5762..1d0adc5783f3d74dc99836108f59889fe23d1ce9 100644 (file)
@@ -7,7 +7,7 @@
 use rustc_middle::ty::layout::{FnAbiExt, TyAndLayout};
 use rustc_middle::ty::print::obsolete::DefPathBasedNames;
 use rustc_middle::ty::{self, Ty, TypeFoldable};
-use rustc_target::abi::{Abi, Align, FieldsShape};
+use rustc_target::abi::{Abi, AddressSpace, Align, FieldsShape};
 use rustc_target::abi::{Int, Pointer, F32, F64};
 use rustc_target::abi::{LayoutOf, PointeeInfo, Scalar, Size, TyAndLayoutMethods, Variants};
 
@@ -310,12 +310,13 @@ fn scalar_llvm_type_at<'a>(
             F64 => cx.type_f64(),
             Pointer => {
                 // If we know the alignment, pick something better than i8.
-                let pointee = if let Some(pointee) = self.pointee_info_at(cx, offset) {
-                    cx.type_pointee_for_align(pointee.align)
-                } else {
-                    cx.type_i8()
-                };
-                cx.type_ptr_to(pointee)
+                let (pointee, address_space) =
+                    if let Some(pointee) = self.pointee_info_at(cx, offset) {
+                        (cx.type_pointee_for_align(pointee.align), pointee.address_space)
+                    } else {
+                        (cx.type_i8(), AddressSpace::DATA)
+                    };
+                cx.type_ptr_to_ext(pointee, address_space)
             }
         }
     }
index 8bc3579800ea81380214b01e823161a28bb8454b..54efa05aee81e315ea619eebb3b2bc827603f15d 100644 (file)
@@ -3,8 +3,9 @@
 use crate::type_of::LayoutLlvmExt;
 use crate::value::Value;
 use rustc_codegen_ssa::mir::operand::OperandRef;
-use rustc_codegen_ssa::traits::{
-    BaseTypeMethods, BuilderMethods, ConstMethods, DerivedTypeMethods,
+use rustc_codegen_ssa::{
+    common::IntPredicate,
+    traits::{BaseTypeMethods, BuilderMethods, ConstMethods, DerivedTypeMethods},
 };
 use rustc_middle::ty::layout::HasTyCtxt;
 use rustc_middle::ty::Ty;
@@ -89,6 +90,81 @@ fn emit_ptr_va_arg(
     }
 }
 
+fn emit_aapcs_va_arg(
+    bx: &mut Builder<'a, 'll, 'tcx>,
+    list: OperandRef<'tcx, &'ll Value>,
+    target_ty: Ty<'tcx>,
+) -> &'ll Value {
+    // Implementation of the AAPCS64 calling convention for va_args see
+    // https://github.com/ARM-software/abi-aa/blob/master/aapcs64/aapcs64.rst
+    let va_list_addr = list.immediate();
+    let layout = bx.cx.layout_of(target_ty);
+
+    let mut maybe_reg = bx.build_sibling_block("va_arg.maybe_reg");
+    let mut in_reg = bx.build_sibling_block("va_arg.in_reg");
+    let mut on_stack = bx.build_sibling_block("va_arg.on_stack");
+    let mut end = bx.build_sibling_block("va_arg.end");
+    let zero = bx.const_i32(0);
+    let offset_align = Align::from_bytes(4).unwrap();
+    assert!(&*bx.tcx().sess.target.target.target_endian == "little");
+
+    let gr_type = target_ty.is_any_ptr() || target_ty.is_integral();
+    let (reg_off, reg_top_index, slot_size) = if gr_type {
+        let gr_offs = bx.struct_gep(va_list_addr, 7);
+        let nreg = (layout.size.bytes() + 7) / 8;
+        (gr_offs, 3, nreg * 8)
+    } else {
+        let vr_off = bx.struct_gep(va_list_addr, 9);
+        let nreg = (layout.size.bytes() + 15) / 16;
+        (vr_off, 5, nreg * 16)
+    };
+
+    // if the offset >= 0 then the value will be on the stack
+    let mut reg_off_v = bx.load(reg_off, offset_align);
+    let use_stack = bx.icmp(IntPredicate::IntSGE, reg_off_v, zero);
+    bx.cond_br(use_stack, &on_stack.llbb(), &maybe_reg.llbb());
+
+    // The value at this point might be in a register, but there is a chance that
+    // it could be on the stack so we have to update the offset and then check
+    // the offset again.
+
+    if gr_type && layout.align.abi.bytes() > 8 {
+        reg_off_v = maybe_reg.add(reg_off_v, bx.const_i32(15));
+        reg_off_v = maybe_reg.and(reg_off_v, bx.const_i32(-16));
+    }
+    let new_reg_off_v = maybe_reg.add(reg_off_v, bx.const_i32(slot_size as i32));
+
+    maybe_reg.store(new_reg_off_v, reg_off, offset_align);
+
+    // Check to see if we have overflowed the registers as a result of this.
+    // If we have then we need to use the stack for this value
+    let use_stack = maybe_reg.icmp(IntPredicate::IntSGT, new_reg_off_v, zero);
+    maybe_reg.cond_br(use_stack, &on_stack.llbb(), &in_reg.llbb());
+
+    let top = in_reg.struct_gep(va_list_addr, reg_top_index);
+    let top = in_reg.load(top, bx.tcx().data_layout.pointer_align.abi);
+
+    // reg_value = *(@top + reg_off_v);
+    let top = in_reg.gep(top, &[reg_off_v]);
+    let top = in_reg.bitcast(top, bx.cx.type_ptr_to(layout.llvm_type(bx)));
+    let reg_value = in_reg.load(top, layout.align.abi);
+    in_reg.br(&end.llbb());
+
+    // On Stack block
+    let stack_value =
+        emit_ptr_va_arg(&mut on_stack, list, target_ty, false, Align::from_bytes(8).unwrap(), true);
+    on_stack.br(&end.llbb());
+
+    let val = end.phi(
+        layout.immediate_llvm_type(bx),
+        &[reg_value, stack_value],
+        &[&in_reg.llbb(), &on_stack.llbb()],
+    );
+
+    *bx = end;
+    val
+}
+
 pub(super) fn emit_va_arg(
     bx: &mut Builder<'a, 'll, 'tcx>,
     addr: OperandRef<'tcx, &'ll Value>,
@@ -115,6 +191,7 @@ pub(super) fn emit_va_arg(
         ("aarch64", _) if target.target_os == "ios" => {
             emit_ptr_va_arg(bx, addr, target_ty, false, Align::from_bytes(8).unwrap(), true)
         }
+        ("aarch64", _) => emit_aapcs_va_arg(bx, addr, target_ty),
         // Windows x86_64
         ("x86_64", true) => {
             let target_ty_size = bx.cx.size_of(target_ty).bytes();
index 3adaa07db91b012c054e80fa1a274fbf53db9184..9191c68d4537aac7f7a43a8596d5adaa3d505680 100644 (file)
@@ -1598,7 +1598,9 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
     }
 
     // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
-    cmd.add_eh_frame_header();
+    if sess.target.target.options.eh_frame_header {
+        cmd.add_eh_frame_header();
+    }
 
     // NO-OPT-OUT, OBJECT-FILES-NO
     if crt_objects_fallback {
@@ -1659,7 +1661,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
     // FIXME: Order dependent, applies to the following objects. Where should it be placed?
     // Try to strip as much out of the generated object by removing unused
     // sections if possible. See more comments in linker.rs
-    if !sess.opts.cg.link_dead_code {
+    if sess.opts.cg.link_dead_code != Some(true) {
         let keep_metadata = crate_type == CrateType::Dylib;
         cmd.gc_sections(keep_metadata);
     }
@@ -1695,12 +1697,12 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
     );
 
     // OBJECT-FILES-NO, AUDIT-ORDER
-    if sess.opts.cg.profile_generate.enabled() {
+    if sess.opts.cg.profile_generate.enabled() || sess.opts.debugging_opts.instrument_coverage {
         cmd.pgo_gen();
     }
 
     // OBJECT-FILES-NO, AUDIT-ORDER
-    if sess.opts.debugging_opts.control_flow_guard != CFGuard::Disabled {
+    if sess.opts.cg.control_flow_guard != CFGuard::Disabled {
         cmd.control_flow_guard();
     }
 
index 6f40aac83eb9c7b7a1da4fbbd0867eaace7c3d63..d1ae9e372695fded7ad77293f052f541368ca746 100644 (file)
@@ -28,9 +28,7 @@
 pub fn disable_localization(linker: &mut Command) {
     // No harm in setting both env vars simultaneously.
     // Unix-style linkers.
-    // We use an UTF-8 locale, as the generic C locale disables support for non-ASCII
-    // bytes in filenames on some platforms.
-    linker.env("LC_ALL", "en_US.UTF-8");
+    linker.env("LC_ALL", "C");
     // MSVC's `link.exe`.
     linker.env("VSLANG", "1033");
 }
@@ -621,13 +619,7 @@ fn linker_plugin_lto(&mut self) {
     // Some versions of `gcc` add it implicitly, some (e.g. `musl-gcc`) don't,
     // so we just always add it.
     fn add_eh_frame_header(&mut self) {
-        if !self.sess.target.target.options.is_like_osx
-            && !self.sess.target.target.options.is_like_windows
-            && !self.sess.target.target.options.is_like_solaris
-            && self.sess.target.target.target_os != "uefi"
-        {
-            self.linker_arg("--eh-frame-hdr");
-        }
+        self.linker_arg("--eh-frame-hdr");
     }
 }
 
index 3287e7b856a37df75ec6d3bb762a8ece1abae421..7d742e7a7afd2b35a613fb20f1b9569f2133507b 100644 (file)
@@ -203,6 +203,17 @@ fn exported_symbols_provider_local(
         }));
     }
 
+    if tcx.sess.opts.debugging_opts.instrument_coverage {
+        // Similar to PGO profiling, preserve symbols used by LLVM InstrProf coverage profiling.
+        const COVERAGE_WEAK_SYMBOLS: [&str; 3] =
+            ["__llvm_profile_filename", "__llvm_coverage_mapping", "__llvm_covmap"];
+
+        symbols.extend(COVERAGE_WEAK_SYMBOLS.iter().map(|sym| {
+            let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, sym));
+            (exported_symbol, SymbolExportLevel::C)
+        }));
+    }
+
     if tcx.sess.opts.debugging_opts.sanitizer.contains(SanitizerSet::MEMORY) {
         // Similar to profiling, preserve weak msan symbol during LTO.
         const MSAN_WEAK_SYMBOLS: [&str; 2] = ["__msan_track_origins", "__msan_keep_going"];
diff --git a/src/librustc_codegen_ssa/build.rs b/src/librustc_codegen_ssa/build.rs
deleted file mode 100644 (file)
index ea2af6e..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-fn main() {
-    println!("cargo:rerun-if-changed=build.rs");
-    println!("cargo:rerun-if-env-changed=CFG_RELEASE_CHANNEL");
-}
index 3bd262cf2b21374915a0b2ff9c9bc82cf2cd82cd..a8ffef8bc5b6b2fae298aac14e5cdd8509bc45e9 100644 (file)
-use rustc_data_structures::fx::FxHashMap;
-use std::collections::hash_map;
-use std::slice;
+use rustc_data_structures::sync::Lrc;
+use rustc_middle::mir;
+use rustc_span::source_map::{Pos, SourceFile, SourceMap};
+use rustc_span::{BytePos, FileName, RealFileName};
+
+use std::cmp::{Ord, Ordering};
+use std::collections::BTreeMap;
+use std::fmt;
+use std::path::PathBuf;
 
 #[derive(Copy, Clone, Debug)]
+#[repr(C)]
 pub enum CounterOp {
-    Add,
+    // Note the order (and therefore the default values) is important. With the attribute
+    // `#[repr(C)]`, this enum matches the layout of the LLVM enum defined for the nested enum,
+    // `llvm::coverage::CounterExpression::ExprKind`, as shown in the following source snippet:
+    // https://github.com/rust-lang/llvm-project/blob/f208b70fbc4dee78067b3c5bd6cb92aa3ba58a1e/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L146
     Subtract,
+    Add,
 }
 
+#[derive(Copy, Clone, Debug)]
 pub enum CoverageKind {
     Counter,
     CounterExpression(u32, CounterOp, u32),
+    Unreachable,
 }
 
-pub struct CoverageSpan {
+#[derive(Clone, Debug)]
+pub struct CoverageRegion {
+    pub kind: CoverageKind,
     pub start_byte_pos: u32,
     pub end_byte_pos: u32,
 }
 
-pub struct CoverageRegion {
-    pub kind: CoverageKind,
-    pub coverage_span: CoverageSpan,
+impl CoverageRegion {
+    pub fn source_loc(&self, source_map: &SourceMap) -> Option<(Lrc<SourceFile>, CoverageLoc)> {
+        let (start_file, start_line, start_col) =
+            lookup_file_line_col(source_map, BytePos::from_u32(self.start_byte_pos));
+        let (end_file, end_line, end_col) =
+            lookup_file_line_col(source_map, BytePos::from_u32(self.end_byte_pos));
+        let start_file_path = match &start_file.name {
+            FileName::Real(RealFileName::Named(path)) => path,
+            _ => {
+                bug!("start_file_path should be a RealFileName, but it was: {:?}", start_file.name)
+            }
+        };
+        let end_file_path = match &end_file.name {
+            FileName::Real(RealFileName::Named(path)) => path,
+            _ => bug!("end_file_path should be a RealFileName, but it was: {:?}", end_file.name),
+        };
+        if start_file_path == end_file_path {
+            Some((start_file, CoverageLoc { start_line, start_col, end_line, end_col }))
+        } else {
+            None
+            // FIXME(richkadel): There seems to be a problem computing the file location in
+            // some cases. I need to investigate this more. When I generate and show coverage
+            // for the example binary in the crates.io crate `json5format`, I had a couple of
+            // notable problems:
+            //
+            //   1. I saw a lot of coverage spans in `llvm-cov show` highlighting regions in
+            //      various comments (not corresponding to rustdoc code), indicating a possible
+            //      problem with the byte_pos-to-source-map implementation.
+            //
+            //   2. And (perhaps not related) when I build the aforementioned example binary with:
+            //      `RUST_FLAGS="-Zinstrument-coverage" cargo build --example formatjson5`
+            //      and then run that binary with
+            //      `LLVM_PROFILE_FILE="formatjson5.profraw" ./target/debug/examples/formatjson5 \
+            //      some.json5` for some reason the binary generates *TWO* `.profraw` files. One
+            //      named `default.profraw` and the other named `formatjson5.profraw` (the expected
+            //      name, in this case).
+            //
+            // If the byte range conversion is wrong, fix it. But if it
+            // is right, then it is possible for the start and end to be in different files.
+            // Can I do something other than ignore coverages that span multiple files?
+            //
+            // If I can resolve this, remove the "Option<>" result type wrapper
+            // `regions_in_file_order()` accordingly.
+        }
+    }
+}
+
+impl Default for CoverageRegion {
+    fn default() -> Self {
+        Self {
+            // The default kind (Unreachable) is a placeholder that will be overwritten before
+            // backend codegen.
+            kind: CoverageKind::Unreachable,
+            start_byte_pos: 0,
+            end_byte_pos: 0,
+        }
+    }
+}
+
+/// A source code region used with coverage information.
+#[derive(Debug, Eq, PartialEq)]
+pub struct CoverageLoc {
+    /// The (1-based) line number of the region start.
+    pub start_line: u32,
+    /// The (1-based) column number of the region start.
+    pub start_col: u32,
+    /// The (1-based) line number of the region end.
+    pub end_line: u32,
+    /// The (1-based) column number of the region end.
+    pub end_col: u32,
+}
+
+impl Ord for CoverageLoc {
+    fn cmp(&self, other: &Self) -> Ordering {
+        (self.start_line, &self.start_col, &self.end_line, &self.end_col).cmp(&(
+            other.start_line,
+            &other.start_col,
+            &other.end_line,
+            &other.end_col,
+        ))
+    }
+}
+
+impl PartialOrd for CoverageLoc {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+impl fmt::Display for CoverageLoc {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        // Customize debug format, and repeat the file name, so generated location strings are
+        // "clickable" in many IDEs.
+        write!(f, "{}:{} - {}:{}", self.start_line, self.start_col, self.end_line, self.end_col)
+    }
+}
+
+fn lookup_file_line_col(source_map: &SourceMap, byte_pos: BytePos) -> (Lrc<SourceFile>, u32, u32) {
+    let found = source_map
+        .lookup_line(byte_pos)
+        .expect("should find coverage region byte position in source");
+    let file = found.sf;
+    let line_pos = file.line_begin_pos(byte_pos);
+
+    // Use 1-based indexing.
+    let line = (found.line + 1) as u32;
+    let col = (byte_pos - line_pos).to_u32() + 1;
+
+    (file, line, col)
 }
 
 /// Collects all of the coverage regions associated with (a) injected counters, (b) counter
 /// expressions (additions or subtraction), and (c) unreachable regions (always counted as zero),
 /// for a given Function. Counters and counter expressions are indexed because they can be operands
-/// in an expression.
+/// in an expression. This struct also stores the `function_source_hash`, computed during
+/// instrumentation and forwarded with counters.
 ///
 /// Note, it's important to distinguish the `unreachable` region type from what LLVM's refers to as
 /// a "gap region" (or "gap area"). A gap region is a code region within a counted region (either
@@ -34,50 +156,134 @@ pub struct CoverageRegion {
 /// lines with 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(Default)]
-pub struct FunctionCoverageRegions {
-    indexed: FxHashMap<u32, CoverageRegion>,
-    unreachable: Vec<CoverageSpan>,
+pub struct FunctionCoverage {
+    source_hash: u64,
+    counters: Vec<CoverageRegion>,
+    expressions: Vec<CoverageRegion>,
+    unreachable: Vec<CoverageRegion>,
+    translated: bool,
 }
 
-impl FunctionCoverageRegions {
-    pub fn add_counter(&mut self, index: u32, start_byte_pos: u32, end_byte_pos: u32) {
-        self.indexed.insert(
-            index,
-            CoverageRegion {
-                kind: CoverageKind::Counter,
-                coverage_span: CoverageSpan { start_byte_pos, end_byte_pos },
-            },
-        );
+impl FunctionCoverage {
+    pub fn with_coverageinfo<'tcx>(coverageinfo: &'tcx mir::CoverageInfo) -> Self {
+        Self {
+            source_hash: 0, // will be set with the first `add_counter()`
+            counters: vec![CoverageRegion::default(); coverageinfo.num_counters as usize],
+            expressions: vec![CoverageRegion::default(); coverageinfo.num_expressions as usize],
+            unreachable: Vec::new(),
+            translated: false,
+        }
     }
 
-    pub fn add_counter_expression(
+    /// Adds a code region to be counted by an injected counter intrinsic. Return a counter ID
+    /// for the call.
+    pub fn add_counter(
         &mut self,
+        source_hash: u64,
         index: u32,
+        start_byte_pos: u32,
+        end_byte_pos: u32,
+    ) {
+        self.source_hash = source_hash;
+        self.counters[index as usize] =
+            CoverageRegion { kind: CoverageKind::Counter, start_byte_pos, end_byte_pos };
+    }
+
+    pub fn add_counter_expression(
+        &mut self,
+        translated_index: u32,
         lhs: u32,
         op: CounterOp,
         rhs: u32,
         start_byte_pos: u32,
         end_byte_pos: u32,
     ) {
-        self.indexed.insert(
-            index,
-            CoverageRegion {
-                kind: CoverageKind::CounterExpression(lhs, op, rhs),
-                coverage_span: CoverageSpan { start_byte_pos, end_byte_pos },
-            },
-        );
+        let index = u32::MAX - translated_index;
+        // Counter expressions start with "translated indexes", descending from `u32::MAX`, so
+        // the range of expression indexes is disjoint from the range of counter indexes. This way,
+        // both counters and expressions can be operands in other expressions.
+        //
+        // Once all counters have been added, the final "region index" for an expression is
+        // `counters.len() + expression_index` (where `expression_index` is its index in
+        // `self.expressions`), and the expression operands (`lhs` and `rhs`) can be converted to
+        // final "region index" references by the same conversion, after subtracting from
+        // `u32::MAX`.
+        self.expressions[index as usize] = CoverageRegion {
+            kind: CoverageKind::CounterExpression(lhs, op, rhs),
+            start_byte_pos,
+            end_byte_pos,
+        };
     }
 
     pub fn add_unreachable(&mut self, start_byte_pos: u32, end_byte_pos: u32) {
-        self.unreachable.push(CoverageSpan { start_byte_pos, end_byte_pos });
+        self.unreachable.push(CoverageRegion {
+            kind: CoverageKind::Unreachable,
+            start_byte_pos,
+            end_byte_pos,
+        });
+    }
+
+    pub fn source_hash(&self) -> u64 {
+        self.source_hash
+    }
+
+    fn regions(&'a mut self) -> impl Iterator<Item = &'a CoverageRegion> {
+        assert!(self.source_hash != 0);
+        self.ensure_expressions_translated();
+        self.counters.iter().chain(self.expressions.iter().chain(self.unreachable.iter()))
     }
 
-    pub fn indexed_regions(&self) -> hash_map::Iter<'_, u32, CoverageRegion> {
-        self.indexed.iter()
+    pub fn regions_in_file_order(
+        &'a mut self,
+        source_map: &SourceMap,
+    ) -> BTreeMap<PathBuf, BTreeMap<CoverageLoc, (usize, CoverageKind)>> {
+        let mut regions_in_file_order = BTreeMap::new();
+        for (region_id, region) in self.regions().enumerate() {
+            if let Some((source_file, region_loc)) = region.source_loc(source_map) {
+                // FIXME(richkadel): `region.source_loc()` sometimes fails with two different
+                // filenames for the start and end byte position. This seems wrong, but for
+                // now, if encountered, the region is skipped. If resolved, convert the result
+                // to a non-option value so regions are never skipped.
+                let real_file_path = match &(*source_file).name {
+                    FileName::Real(RealFileName::Named(path)) => path.clone(),
+                    _ => bug!("coverage mapping expected only real, named files"),
+                };
+                let file_coverage_regions =
+                    regions_in_file_order.entry(real_file_path).or_insert_with(|| BTreeMap::new());
+                file_coverage_regions.insert(region_loc, (region_id, region.kind));
+            }
+        }
+        regions_in_file_order
     }
 
-    pub fn unreachable_regions(&self) -> slice::Iter<'_, CoverageSpan> {
-        self.unreachable.iter()
+    /// A one-time translation of expression operands is needed, for any operands referencing
+    /// other CounterExpressions. CounterExpression operands get an initial operand ID that is
+    /// computed by the simple translation: `u32::max - expression_index` because, when created,
+    /// the total number of Counters is not yet known. This function recomputes region indexes
+    /// for expressions so they start with the next region index after the last counter index.
+    fn ensure_expressions_translated(&mut self) {
+        if !self.translated {
+            self.translated = true;
+            let start = self.counters.len() as u32;
+            assert!(
+                (start as u64 + self.expressions.len() as u64) < u32::MAX as u64,
+                "the number of counters and counter expressions in a single function exceeds {}",
+                u32::MAX
+            );
+            for region in self.expressions.iter_mut() {
+                match region.kind {
+                    CoverageKind::CounterExpression(lhs, op, rhs) => {
+                        let lhs = to_region_index(start, lhs);
+                        let rhs = to_region_index(start, rhs);
+                        region.kind = CoverageKind::CounterExpression(lhs, op, rhs);
+                    }
+                    _ => bug!("expressions must only contain CounterExpression kinds"),
+                }
+            }
+        }
     }
 }
+
+fn to_region_index(start: u32, index: u32) -> u32 {
+    if index < start { index } else { start + (u32::MAX - index) }
+}
index 20d440433cbb0bc4f5b27bc3f4490aabadecd39f..fb8f5a6298911f23584790e9cf62b39db5ec189d 100644 (file)
@@ -205,14 +205,17 @@ pub fn push_debuginfo_type_name<'tcx>(
                 tcx.def_key(def_id).disambiguated_data.disambiguator
             ));
         }
+        // Type parameters from polymorphized functions.
+        ty::Param(_) => {
+            output.push_str(&format!("{:?}", t));
+        }
         ty::Error(_)
         | ty::Infer(_)
         | ty::Placeholder(..)
         | ty::Projection(..)
         | ty::Bound(..)
         | ty::Opaque(..)
-        | ty::GeneratorWitness(..)
-        | ty::Param(_) => {
+        | ty::GeneratorWitness(..) => {
             bug!(
                 "debuginfo: Trying to create type name for \
                   unexpected type: {:?}",
index 199dd8c7df42fd7d0be1e33acb752b6d652b210e..bcc19c6a44bd829ffff227b9c606938cb26da6b5 100644 (file)
@@ -75,7 +75,7 @@ pub fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>(
     }
 
     // Not in the cache; build it.
-    let nullptr = cx.const_null(cx.type_i8p());
+    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 {
@@ -94,7 +94,8 @@ pub fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>(
                     def_id,
                     substs,
                 )
-                .unwrap(),
+                .unwrap()
+                .polymorphize(cx.tcx()),
             )
         })
     });
index db935c2b3e2658a027ba7525da21a38e90146a44..2e386c1e5946bf141e409900e7eaba4a88338c19 100644 (file)
@@ -124,8 +124,7 @@ fn process_place(
                 let base_ty = self.fx.monomorphize(&base_ty);
 
                 // ZSTs don't require any actual memory access.
-                let elem_ty = base_ty.projection_ty(cx.tcx(), elem).ty;
-                let elem_ty = self.fx.monomorphize(&elem_ty);
+                let elem_ty = base_ty.projection_ty(cx.tcx(), self.fx.monomorphize(&elem)).ty;
                 let span = self.fx.mir.local_decls[place_ref.local].source_info.span;
                 if cx.spanned_layout_of(elem_ty, span).is_zst() {
                     return;
index 7116bb8c92517d3fbf1fba318f5db2e30700ac9e..e1de9677f807a4fb312c2c245854583bee726ce4 100644 (file)
@@ -543,7 +543,8 @@ fn codegen_call_terminator(
                 Some(
                     ty::Instance::resolve(bx.tcx(), ty::ParamEnv::reveal_all(), def_id, substs)
                         .unwrap()
-                        .unwrap(),
+                        .unwrap()
+                        .polymorphize(bx.tcx()),
                 ),
                 None,
             ),
index 00b4bf96afa594b75e55115647bb84b9410c6179..f4d83e87710822836ccab73f7674d4bc417aef08 100644 (file)
@@ -6,6 +6,7 @@
 use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt, TyAndLayout};
 use rustc_middle::ty::{self, Instance, Ty, TypeFoldable};
 use rustc_target::abi::call::{FnAbi, PassMode};
+use rustc_target::abi::HasDataLayout;
 
 use std::iter;
 
@@ -323,7 +324,9 @@ fn create_funclets<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
                     // C++ personality function, but `catch (...)` has no type so
                     // it's null. The 64 here is actually a bitfield which
                     // represents that this is a catch-all block.
-                    let null = bx.const_null(bx.type_i8p());
+                    let null = bx.const_null(
+                        bx.type_i8p_ext(bx.cx().data_layout().instruction_address_space),
+                    );
                     let sixty_four = bx.const_i32(64);
                     funclet = cp_bx.catch_pad(cs, &[null, sixty_four, null]);
                     cp_bx.br(llbb);
index 4b2be7b5321ff8aec4cc808b133461cd6c3f88c9..9c108998bc9078928827a8114789a56b0f474e97 100644 (file)
@@ -190,17 +190,15 @@ pub fn codegen_rvalue_operand(
                                 if bx.cx().tcx().has_attr(def_id, sym::rustc_args_required_const) {
                                     bug!("reifying a fn ptr that requires const arguments");
                                 }
-                                OperandValue::Immediate(
-                                    bx.get_fn_addr(
-                                        ty::Instance::resolve_for_fn_ptr(
-                                            bx.tcx(),
-                                            ty::ParamEnv::reveal_all(),
-                                            def_id,
-                                            substs,
-                                        )
-                                        .unwrap(),
-                                    ),
+                                let instance = ty::Instance::resolve_for_fn_ptr(
+                                    bx.tcx(),
+                                    ty::ParamEnv::reveal_all(),
+                                    def_id,
+                                    substs,
                                 )
+                                .unwrap()
+                                .polymorphize(bx.cx().tcx());
+                                OperandValue::Immediate(bx.get_fn_addr(instance))
                             }
                             _ => bug!("{} cannot be reified to a fn ptr", operand.layout.ty),
                         }
@@ -213,7 +211,8 @@ pub fn codegen_rvalue_operand(
                                     def_id,
                                     substs,
                                     ty::ClosureKind::FnOnce,
-                                );
+                                )
+                                .polymorphize(bx.cx().tcx());
                                 OperandValue::Immediate(bx.cx().get_fn_addr(instance))
                             }
                             _ => bug!("{} cannot be cast to a fn ptr", operand.layout.ty),
index d80f90fa4fa0d7eb6412b83aa7ef387c2d58ae4c..1b9faa42484f1ad536a21b3ccdc35e9a5b9f70d4 100644 (file)
@@ -10,6 +10,7 @@ pub trait CoverageInfoBuilderMethods<'tcx>: BackendTypes {
     fn add_counter_region(
         &mut self,
         instance: Instance<'tcx>,
+        function_source_hash: u64,
         index: u32,
         start_byte_pos: u32,
         end_byte_pos: u32,
index a6462b358347b3111a0c009662ac9a10867452f8..817fc02d166a35ba9dff5e61e3087e9628d59c3b 100644 (file)
@@ -5,6 +5,18 @@
 pub trait StaticMethods: BackendTypes {
     fn static_addr_of(&self, cv: Self::Value, align: Align, kind: Option<&str>) -> Self::Value;
     fn codegen_static(&self, def_id: DefId, is_mutable: bool);
+
+    /// Mark the given global value as "used", to prevent a backend from potentially removing a
+    /// static variable that may otherwise appear unused.
+    ///
+    /// Static variables in Rust can be annotated with the `#[used]` attribute to direct the `rustc`
+    /// compiler to mark the variable as a "used global".
+    ///
+    /// ```no_run
+    /// #[used]
+    /// static FOO: u32 = 0;
+    /// ```
+    fn add_used_global(&self, global: Self::Value);
 }
 
 pub trait StaticBuilderMethods: BackendTypes {
index c55bf9858b972450c4cd607ee630221dacb23f38..726d948cfd40cf483be1e705af99a8412f59abd4 100644 (file)
@@ -7,7 +7,7 @@
 use rustc_middle::ty::{self, Ty};
 use rustc_span::DUMMY_SP;
 use rustc_target::abi::call::{ArgAbi, CastTarget, FnAbi, Reg};
-use rustc_target::abi::Integer;
+use rustc_target::abi::{AddressSpace, Integer};
 
 // This depends on `Backend` and not `BackendTypes`, because consumers will probably want to use
 // `LayoutOf` or `HasTyCtxt`. This way, they don't have to add a constraint on it themselves.
@@ -27,6 +27,7 @@ pub trait BaseTypeMethods<'tcx>: Backend<'tcx> {
     fn type_struct(&self, els: &[Self::Type], packed: bool) -> Self::Type;
     fn type_kind(&self, ty: Self::Type) -> TypeKind;
     fn type_ptr_to(&self, ty: Self::Type) -> Self::Type;
+    fn type_ptr_to_ext(&self, ty: Self::Type, address_space: AddressSpace) -> Self::Type;
     fn element_type(&self, ty: Self::Type) -> Self::Type;
 
     /// Returns the number of elements in `self` if it is a LLVM vector type.
@@ -42,7 +43,11 @@ pub trait BaseTypeMethods<'tcx>: Backend<'tcx> {
 
 pub trait DerivedTypeMethods<'tcx>: BaseTypeMethods<'tcx> + MiscMethods<'tcx> {
     fn type_i8p(&self) -> Self::Type {
-        self.type_ptr_to(self.type_i8())
+        self.type_i8p_ext(AddressSpace::DATA)
+    }
+
+    fn type_i8p_ext(&self, address_space: AddressSpace) -> Self::Type {
+        self.type_ptr_to_ext(self.type_i8(), address_space)
     }
 
     fn type_int(&self) -> Self::Type {
index b7005ccdc998be72cb0276c20d2de5917e211a7d..2bb421a47efa689632dcc42dc445a584c0a8f845 100644 (file)
@@ -7,8 +7,8 @@
 use crate::stable_hasher::{HashStable, StableHasher};
 use rustc_index::vec::{Idx, IndexVec};
 
-/// An indexed multi-map that preserves insertion order while permitting both `O(log n)` lookup of
-/// an item by key and `O(1)` lookup by index.
+/// An indexed multi-map that preserves insertion order while permitting both *O*(log *n*) lookup of
+/// an item by key and *O*(1) lookup by index.
 ///
 /// This data structure is a hybrid of an [`IndexVec`] and a [`SortedMap`]. Like `IndexVec`,
 /// `SortedIndexMultiMap` assigns a typed index to each item while preserving insertion order.
@@ -20,7 +20,7 @@
 /// items will be yielded in insertion order.
 ///
 /// Unlike a general-purpose map like `BTreeSet` or `HashSet`, `SortedMap` and
-/// `SortedIndexMultiMap` require `O(n)` time to insert a single item. This is because we may need
+/// `SortedIndexMultiMap` require *O*(*n*) time to insert a single item. This is because we may need
 /// to insert into the middle of the sorted array. Users should avoid mutating this data structure
 /// in-place.
 ///
index 97b02eaef35d0732b0c4ce8ab9a19cf30ba66147..c1c79b174f415e93d4637ca0f684f54856a6871f 100644 (file)
@@ -469,6 +469,15 @@ fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
     }
 }
 
+impl<T, CTX> HashStable<CTX> for bit_set::FiniteBitSet<T>
+where
+    T: HashStable<CTX> + bit_set::FiniteBitSetTy,
+{
+    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
+        self.0.hash_stable(hcx, hasher);
+    }
+}
+
 impl_stable_hash_via_hash!(::std::path::Path);
 impl_stable_hash_via_hash!(::std::path::PathBuf);
 
diff --git a/src/librustc_driver/build.rs b/src/librustc_driver/build.rs
deleted file mode 100644 (file)
index 414d134..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-fn main() {
-    println!("cargo:rerun-if-changed=build.rs");
-    println!("cargo:rerun-if-env-changed=CFG_RELEASE");
-    println!("cargo:rerun-if-env-changed=CFG_VERSION");
-    println!("cargo:rerun-if-env-changed=CFG_VER_DATE");
-    println!("cargo:rerun-if-env-changed=CFG_VER_HASH");
-}
index 6160450d766769fe4f0169b7317ed528d33f12f7..4e5e77f80c28a1208c4f0121777816cd98cbf24f 100644 (file)
 E0768: include_str!("./error_codes/E0768.md"),
 E0769: include_str!("./error_codes/E0769.md"),
 E0770: include_str!("./error_codes/E0770.md"),
+E0771: include_str!("./error_codes/E0771.md"),
 ;
 //  E0006, // merged with E0005
 //  E0008, // cannot bind by-move into a pattern guard
 //  E0420, merged into 532
 //  E0421, merged into 531
 //  E0427, merged into 530
-    E0456, // plugin `..` is not available for triple `..`
+//  E0456, // plugin `..` is not available for triple `..`
     E0457, // plugin `..` only found in rlib format, but must be available...
     E0460, // found possibly newer version of crate `..`
     E0461, // couldn't find crate `..` with expected target triple ..
     E0521, // borrowed data escapes outside of closure
     E0523,
 //  E0526, // shuffle indices are not constant
-    E0540, // multiple rustc_deprecated attributes
+//  E0540, // multiple rustc_deprecated attributes
     E0542, // missing 'since'
     E0543, // missing 'reason'
     E0544, // multiple stability levels
     E0755, // `#[ffi_pure]` is only allowed on foreign functions
     E0756, // `#[ffi_const]` is only allowed on foreign functions
     E0757, // `#[ffi_const]` functions cannot be `#[ffi_pure]`
+    E0772, // `'static' obligation coming from `impl dyn Trait {}` or `impl Foo for dyn Bar {}`.
 }
index 7a7ba15485434836c9754da42db925d1a098a5d8..e8f84d0fc7d508deb202e5b1515149806bc83546 100644 (file)
@@ -1,4 +1,5 @@
-`#[ffi_returns_twice]` was used on non-foreign function.
+`#[ffi_returns_twice]` was used on something other than a foreign function
+declaration.
 
 Erroneous code example:
 
diff --git a/src/librustc_error_codes/error_codes/E0771.md b/src/librustc_error_codes/error_codes/E0771.md
new file mode 100644 (file)
index 0000000..824a955
--- /dev/null
@@ -0,0 +1,23 @@
+A non-`'static` lifetime was used in a const generic. This is currently not
+allowed.
+
+Erroneous code example:
+
+```compile_fail,E0771
+#![feature(const_generics)]
+
+fn function_with_str<'a, const STRING: &'a str>() {} // error!
+```
+
+To fix this issue, the lifetime in the const generic need to be changed to
+`'static`:
+
+```
+#![feature(const_generics)]
+
+fn function_with_str<const STRING: &'static str>() {} // ok!
+```
+
+For more information, see [GitHub issue #74052].
+
+[GitHub issue #74052]: https://github.com/rust-lang/rust/issues/74052
index d93c17b05b498c02baa6225f0173191cc519cca3..d16f023c00a6216109be48ace5e222590dcf5c10 100644 (file)
@@ -262,9 +262,9 @@ macro_rules! declare_features {
     /// Allows using subslice patterns, `[a, .., b]` and `[a, xs @ .., b]`.
     (accepted, slice_patterns, "1.42.0", Some(62254), None),
     /// Allows the use of `if` and `match` in constants.
-    (accepted, const_if_match, "1.45.0", Some(49146), None),
+    (accepted, const_if_match, "1.46.0", Some(49146), None),
     /// Allows the use of `loop` and `while` in constants.
-    (accepted, const_loop, "1.45.0", Some(52000), None),
+    (accepted, const_loop, "1.46.0", Some(52000), None),
     /// Allows `#[track_caller]` to be used which provides
     /// accurate caller location reporting during panic (RFC 2091).
     (accepted, track_caller, "1.46.0", Some(47809), None),
index 4e2aea34fe7fb713d5eab44c83de0faea28ac7f0..879f06f89a70a8a92bc55be479634edb854578b3 100644 (file)
@@ -568,6 +568,7 @@ macro_rules! experimental {
     ),
     rustc_attr!(TEST, rustc_synthetic, AssumedUsed, template!(Word)),
     rustc_attr!(TEST, rustc_symbol_name, AssumedUsed, template!(Word)),
+    rustc_attr!(TEST, rustc_polymorphize_error, AssumedUsed, template!(Word)),
     rustc_attr!(TEST, rustc_def_path, AssumedUsed, template!(Word)),
     rustc_attr!(TEST, rustc_mir, AssumedUsed, template!(List: "arg1, arg2, ...")),
     rustc_attr!(TEST, rustc_dump_program_clauses, AssumedUsed, template!(Word)),
diff --git a/src/librustc_hir/fake_lang_items.rs b/src/librustc_hir/fake_lang_items.rs
new file mode 100644 (file)
index 0000000..91db580
--- /dev/null
@@ -0,0 +1,37 @@
+//! Validity checking for fake lang items
+
+use crate::def_id::DefId;
+use crate::{lang_items, LangItem, LanguageItems};
+
+use rustc_data_structures::fx::FxHashMap;
+use rustc_span::symbol::{sym, Symbol};
+
+use lazy_static::lazy_static;
+
+macro_rules! fake_lang_items {
+    ($($item:ident, $name:ident, $method:ident;)*) => (
+
+lazy_static! {
+    pub static ref FAKE_ITEMS_REFS: FxHashMap<Symbol, LangItem> = {
+        let mut map = FxHashMap::default();
+        $(map.insert(sym::$name, lang_items::$item);)*
+        map
+    };
+}
+
+impl LanguageItems {
+    pub fn is_fake_lang_item(&self, item_def_id: DefId) -> bool {
+        let did = Some(item_def_id);
+
+        $(self.$method() == did)||*
+    }
+}
+
+) }
+
+fake_lang_items! {
+//  Variant name,                      Symbol,                    Method name,
+    CountCodeRegionFnLangItem,         count_code_region,         count_code_region_fn;
+    CoverageCounterAddFnLangItem,      coverage_counter_add,      coverage_counter_add_fn;
+    CoverageCounterSubtractFnLangItem, coverage_counter_subtract, coverage_counter_subtract_fn;
+}
index f56522406b0a707f36cda83862b4bc684f47fb6b..6474dc318d329f73854c2c0526b8f075589c7f0b 100644 (file)
@@ -2198,7 +2198,17 @@ pub enum IsAsync {
     NotAsync,
 }
 
-#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(
+    Copy,
+    Clone,
+    PartialEq,
+    RustcEncodable,
+    RustcDecodable,
+    Debug,
+    HashStable_Generic,
+    Eq,
+    Hash
+)]
 pub enum Defaultness {
     Default { has_value: bool },
     Final,
index 88c97d874bed6f3c9a849b8f6cc309bddaef21ea..4b71407acfb8cf44c57f7b202dd6900b13174326 100644 (file)
@@ -276,8 +276,6 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
 
     StartFnLangItem,               sym::start,              start_fn,                Target::Fn;
 
-    CountCodeRegionFnLangItem,     sym::count_code_region,  count_code_region_fn,    Target::Fn;
-
     EhPersonalityLangItem,         sym::eh_personality,     eh_personality,          Target::Fn;
     EhCatchTypeinfoLangItem,       sym::eh_catch_typeinfo,  eh_catch_typeinfo,       Target::Static;
 
@@ -295,4 +293,9 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
     TerminationTraitLangItem,      sym::termination,        termination,             Target::Trait;
 
     TryTraitLangItem,              kw::Try,                 try_trait,               Target::Trait;
+
+    // language items related to source code coverage instrumentation (-Zinstrument-coverage)
+    CountCodeRegionFnLangItem,         sym::count_code_region,         count_code_region_fn,         Target::Fn;
+    CoverageCounterAddFnLangItem,      sym::coverage_counter_add,      coverage_counter_add_fn,      Target::Fn;
+    CoverageCounterSubtractFnLangItem, sym::coverage_counter_subtract, coverage_counter_subtract_fn, Target::Fn;
 }
index 37041923890cd3bf720dff2334b0d59c9b1ceeef..52131cb3d3d4cab03a12ae46f2ef769aaa9b93f0 100644 (file)
@@ -17,6 +17,7 @@
 pub mod def;
 pub mod definitions;
 pub use rustc_span::def_id;
+pub mod fake_lang_items;
 mod hir;
 pub mod hir_id;
 pub mod intravisit;
diff --git a/src/librustc_incremental/build.rs b/src/librustc_incremental/build.rs
deleted file mode 100644 (file)
index d230ba9..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-fn main() {
-    println!("cargo:rerun-if-changed=build.rs");
-    println!("cargo:rerun-if-env-changed=CFG_VERSION");
-}
index 3e1d4b68c6fa104f1184d1908c8740009174ceaf..b369be252185b378319eca659abce5966c96b855 100644 (file)
@@ -4,6 +4,7 @@
 use std::iter;
 use std::marker::PhantomData;
 use std::mem;
+use std::ops::{BitAnd, BitAndAssign, BitOrAssign, Not, Range, Shl};
 use std::slice;
 
 #[cfg(test)]
@@ -772,7 +773,7 @@ pub fn contains(&self, row: R, column: C) -> bool {
     }
 
     /// Returns those indices that are true in rows `a` and `b`. This
-    /// is an O(n) operation where `n` is the number of elements
+    /// is an *O*(*n*) operation where *n* is the number of elements
     /// (somewhat independent from the actual size of the
     /// intersection, in particular).
     pub fn intersect_rows(&self, row1: R, row2: R) -> Vec<C> {
@@ -1001,3 +1002,137 @@ fn word_index_and_mask<T: Idx>(elem: T) -> (usize, Word) {
     let mask = 1 << (elem % WORD_BITS);
     (word_index, mask)
 }
+
+/// Integral type used to represent the bit set.
+pub trait FiniteBitSetTy:
+    BitAnd<Output = Self>
+    + BitAndAssign
+    + BitOrAssign
+    + Clone
+    + Copy
+    + Shl
+    + Not<Output = Self>
+    + PartialEq
+    + Sized
+{
+    /// Size of the domain representable by this type, e.g. 64 for `u64`.
+    const DOMAIN_SIZE: u32;
+
+    /// Value which represents the `FiniteBitSet` having every bit set.
+    const FILLED: Self;
+    /// Value which represents the `FiniteBitSet` having no bits set.
+    const EMPTY: Self;
+
+    /// Value for one as the integral type.
+    const ONE: Self;
+    /// Value for zero as the integral type.
+    const ZERO: Self;
+
+    /// Perform a checked left shift on the integral type.
+    fn checked_shl(self, rhs: u32) -> Option<Self>;
+    /// Perform a checked right shift on the integral type.
+    fn checked_shr(self, rhs: u32) -> Option<Self>;
+}
+
+impl FiniteBitSetTy for u64 {
+    const DOMAIN_SIZE: u32 = 64;
+
+    const FILLED: Self = Self::MAX;
+    const EMPTY: Self = Self::MIN;
+
+    const ONE: Self = 1u64;
+    const ZERO: Self = 0u64;
+
+    fn checked_shl(self, rhs: u32) -> Option<Self> {
+        self.checked_shl(rhs)
+    }
+
+    fn checked_shr(self, rhs: u32) -> Option<Self> {
+        self.checked_shr(rhs)
+    }
+}
+
+impl std::fmt::Debug for FiniteBitSet<u64> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{:064b}", self.0)
+    }
+}
+
+impl FiniteBitSetTy for u128 {
+    const DOMAIN_SIZE: u32 = 128;
+
+    const FILLED: Self = Self::MAX;
+    const EMPTY: Self = Self::MIN;
+
+    const ONE: Self = 1u128;
+    const ZERO: Self = 0u128;
+
+    fn checked_shl(self, rhs: u32) -> Option<Self> {
+        self.checked_shl(rhs)
+    }
+
+    fn checked_shr(self, rhs: u32) -> Option<Self> {
+        self.checked_shr(rhs)
+    }
+}
+
+impl std::fmt::Debug for FiniteBitSet<u128> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{:0128b}", self.0)
+    }
+}
+
+/// A fixed-sized bitset type represented by an integer type. Indices outwith than the range
+/// representable by `T` are considered set.
+#[derive(Copy, Clone, Eq, PartialEq, RustcDecodable, RustcEncodable)]
+pub struct FiniteBitSet<T: FiniteBitSetTy>(pub T);
+
+impl<T: FiniteBitSetTy> FiniteBitSet<T> {
+    /// Creates a new, empty bitset.
+    pub fn new_empty() -> Self {
+        Self(T::EMPTY)
+    }
+
+    /// Sets the `index`th bit.
+    pub fn set(&mut self, index: u32) {
+        self.0 |= T::ONE.checked_shl(index).unwrap_or(T::ZERO);
+    }
+
+    /// Unsets the `index`th bit.
+    pub fn clear(&mut self, index: u32) {
+        self.0 &= !T::ONE.checked_shl(index).unwrap_or(T::ZERO);
+    }
+
+    /// Sets the `i`th to `j`th bits.
+    pub fn set_range(&mut self, range: Range<u32>) {
+        let bits = T::FILLED
+            .checked_shl(range.end - range.start)
+            .unwrap_or(T::ZERO)
+            .not()
+            .checked_shl(range.start)
+            .unwrap_or(T::ZERO);
+        self.0 |= bits;
+    }
+
+    /// Is the set empty?
+    pub fn is_empty(&self) -> bool {
+        self.0 == T::EMPTY
+    }
+
+    /// Returns the domain size of the bitset.
+    pub fn within_domain(&self, index: u32) -> bool {
+        index < T::DOMAIN_SIZE
+    }
+
+    /// Returns if the `index`th bit is set.
+    pub fn contains(&self, index: u32) -> Option<bool> {
+        self.within_domain(index)
+            .then(|| ((self.0.checked_shr(index).unwrap_or(T::ONE)) & T::ONE) == T::ONE)
+    }
+}
+
+impl<T: FiniteBitSetTy> Default for FiniteBitSet<T> {
+    fn default() -> Self {
+        Self::new_empty()
+    }
+}
index eaef4c7b54a625d05f72ce44e88acd074481f30d..7ee881b0639daf53f363e82d6878fc12e0a1735c 100644 (file)
@@ -1,4 +1,5 @@
 #![feature(allow_internal_unstable)]
+#![feature(bool_to_option)]
 #![feature(const_fn)]
 #![feature(const_panic)]
 #![feature(extend_one)]
index 3b564e03d9a94e91ff1fe11b78e4ff7505147402..c63464e5baec9e3b1a71409ad0402cc1a710684e 100644 (file)
 
 use rustc_ast::ast;
 use rustc_hir::def_id::DefId;
+use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::{self, InferConst, ToPredicate, Ty, TyCtxt, TypeFoldable};
 use rustc_middle::ty::{IntType, UintType};
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::DUMMY_SP;
 
 #[derive(Clone)]
 pub struct CombineFields<'infcx, 'tcx> {
@@ -367,10 +368,11 @@ fn generalize(
         };
 
         debug!("generalize: for_universe = {:?}", for_universe);
+        debug!("generalize: trace = {:?}", self.trace);
 
         let mut generalize = Generalizer {
             infcx: self.infcx,
-            span: self.trace.cause.span,
+            cause: &self.trace.cause,
             for_vid_sub_root: self.infcx.inner.borrow_mut().type_variables().sub_root_var(for_vid),
             for_universe,
             ambient_variance,
@@ -414,7 +416,7 @@ struct Generalizer<'cx, 'tcx> {
     infcx: &'cx InferCtxt<'cx, 'tcx>,
 
     /// The span, used when creating new type variables and things.
-    span: Span,
+    cause: &'cx ObligationCause<'tcx>,
 
     /// The vid of the type variable that is in the process of being
     /// instantiated; if we find this within the type we are folding,
@@ -639,7 +641,7 @@ fn regions(
 
         // FIXME: This is non-ideal because we don't give a
         // very descriptive origin for this region variable.
-        Ok(self.infcx.next_region_var_in_universe(MiscVariable(self.span), self.for_universe))
+        Ok(self.infcx.next_region_var_in_universe(MiscVariable(self.cause.span), self.for_universe))
     }
 
     fn consts(
index 633589db2704cd7e37ed882b7d3f64b64bfcb997..ff905faa95a9fe627e85e4b433c303218f5ef493 100644 (file)
@@ -2010,7 +2010,7 @@ fn report_inference_failure(
             infer::MiscVariable(_) => String::new(),
             infer::PatternRegion(_) => " for pattern".to_string(),
             infer::AddrOfRegion(_) => " for borrow expression".to_string(),
-            infer::Autoref(_) => " for autoref".to_string(),
+            infer::Autoref(_, _) => " for autoref".to_string(),
             infer::Coercion(_) => " for automatic coercion".to_string(),
             infer::LateBoundRegion(_, br, infer::FnCall) => {
                 format!(" for lifetime parameter {}in function call", br_string(br))
index b6e971feb0e5fdc4043f45411baa2264ea13cc19..4fa6d9d2394242cb56b69ad0ad19f5b3e4b4e745 100644 (file)
 
 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
 use crate::infer::lexical_region_resolve::RegionResolutionError;
-use rustc_errors::{struct_span_err, Applicability, ErrorReported};
-use rustc_hir::{GenericBound, ItemKind, Lifetime, LifetimeName, TyKind};
-use rustc_middle::ty::RegionKind;
+use crate::infer::{SubregionOrigin, TypeTrace};
+use crate::traits::{ObligationCauseCode, UnifyReceiverContext};
+use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported};
+use rustc_hir::def_id::DefId;
+use rustc_hir::intravisit::{walk_ty, ErasedMap, NestedVisitorMap, Visitor};
+use rustc_hir::{
+    self as hir, GenericBound, ImplItem, Item, ItemKind, Lifetime, LifetimeName, Node, TraitItem,
+    TyKind,
+};
+use rustc_middle::ty::{self, AssocItemContainer, RegionKind, Ty, TypeFoldable, TypeVisitor};
+use rustc_span::symbol::Ident;
+use rustc_span::{MultiSpan, Span};
 
 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
-    /// Print the error message for lifetime errors when the return type is a static impl Trait.
+    /// Print the error message for lifetime errors when the return type is a static `impl Trait`,
+    /// `dyn Trait` or if a method call on a trait object introduces a static requirement.
     pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorReported> {
         debug!("try_report_static_impl_trait(error={:?})", self.error);
-        if let Some(RegionResolutionError::SubSupConflict(
-            _,
-            var_origin,
-            ref sub_origin,
-            sub_r,
-            ref sup_origin,
-            sup_r,
-        )) = self.error
-        {
-            debug!(
-                "try_report_static_impl_trait(var={:?}, sub={:?} {:?} sup={:?} {:?})",
-                var_origin, sub_origin, sub_r, sup_origin, sup_r
-            );
-            let anon_reg_sup = self.tcx().is_suitable_region(sup_r)?;
-            debug!("try_report_static_impl_trait: anon_reg_sup={:?}", anon_reg_sup);
-            let fn_returns = self.tcx().return_type_impl_or_dyn_traits(anon_reg_sup.def_id);
-            if fn_returns.is_empty() {
+        let tcx = self.tcx();
+        let (var_origin, sub_origin, sub_r, sup_origin, sup_r) = match self.error.as_ref()? {
+            RegionResolutionError::SubSupConflict(
+                _,
+                var_origin,
+                sub_origin,
+                sub_r,
+                sup_origin,
+                sup_r,
+            ) if **sub_r == RegionKind::ReStatic => {
+                (var_origin, sub_origin, sub_r, sup_origin, sup_r)
+            }
+            RegionResolutionError::ConcreteFailure(
+                SubregionOrigin::Subtype(box TypeTrace { cause, .. }),
+                sub_r,
+                sup_r,
+            ) if **sub_r == RegionKind::ReStatic => {
+                // This is for an implicit `'static` requirement coming from `impl dyn Trait {}`.
+                if let ObligationCauseCode::UnifyReceiver(ctxt) = &cause.code {
+                    let param = self.find_param_with_region(sup_r, sub_r)?;
+                    let lifetime = if sup_r.has_name() {
+                        format!("lifetime `{}`", sup_r)
+                    } else {
+                        "an anonymous lifetime `'_`".to_string()
+                    };
+                    let mut err = struct_span_err!(
+                        tcx.sess,
+                        cause.span,
+                        E0772,
+                        "{} has {} but calling `{}` introduces an implicit `'static` lifetime \
+                         requirement",
+                        param
+                            .param
+                            .pat
+                            .simple_ident()
+                            .map(|s| format!("`{}`", s))
+                            .unwrap_or_else(|| "`fn` parameter".to_string()),
+                        lifetime,
+                        ctxt.assoc_item.ident,
+                    );
+                    err.span_label(param.param_ty_span, &format!("this data with {}...", lifetime));
+                    err.span_label(
+                        cause.span,
+                        &format!(
+                            "...is captured and required to live as long as `'static` here \
+                             because of an implicit lifetime bound on the {}",
+                            match ctxt.assoc_item.container {
+                                AssocItemContainer::TraitContainer(id) =>
+                                    format!("`impl` of `{}`", tcx.def_path_str(id)),
+                                AssocItemContainer::ImplContainer(_) =>
+                                    "inherent `impl`".to_string(),
+                            },
+                        ),
+                    );
+                    if self.find_impl_on_dyn_trait(&mut err, param.param_ty, &ctxt) {
+                        err.emit();
+                        return Some(ErrorReported);
+                    } else {
+                        err.cancel();
+                    }
+                }
                 return None;
             }
-            debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns);
-            if *sub_r == RegionKind::ReStatic {
-                let sp = var_origin.span();
-                let return_sp = sub_origin.span();
-                let param_info = self.find_param_with_region(sup_r, sub_r)?;
-                let (lifetime_name, lifetime) = if sup_r.has_name() {
-                    (sup_r.to_string(), format!("lifetime `{}`", sup_r))
-                } else {
-                    ("'_".to_owned(), "an anonymous lifetime `'_`".to_string())
-                };
-                let mut err = struct_span_err!(
-                    self.tcx().sess,
-                    sp,
-                    E0759,
-                    "cannot infer an appropriate lifetime"
-                );
+            _ => return None,
+        };
+        debug!(
+            "try_report_static_impl_trait(var={:?}, sub={:?} {:?} sup={:?} {:?})",
+            var_origin, sub_origin, sub_r, sup_origin, sup_r
+        );
+        let anon_reg_sup = tcx.is_suitable_region(sup_r)?;
+        debug!("try_report_static_impl_trait: anon_reg_sup={:?}", anon_reg_sup);
+        let sp = var_origin.span();
+        let return_sp = sub_origin.span();
+        let param = self.find_param_with_region(sup_r, sub_r)?;
+        let (lifetime_name, lifetime) = if sup_r.has_name() {
+            (sup_r.to_string(), format!("lifetime `{}`", sup_r))
+        } else {
+            ("'_".to_owned(), "an anonymous lifetime `'_`".to_string())
+        };
+        let param_name = param
+            .param
+            .pat
+            .simple_ident()
+            .map(|s| format!("`{}`", s))
+            .unwrap_or_else(|| "`fn` parameter".to_string());
+        let mut err = struct_span_err!(
+            tcx.sess,
+            sp,
+            E0759,
+            "{} has {} but it needs to satisfy a `'static` lifetime requirement",
+            param_name,
+            lifetime,
+        );
+        err.span_label(param.param_ty_span, &format!("this data with {}...", lifetime));
+        debug!("try_report_static_impl_trait: param_info={:?}", param);
+
+        // We try to make the output have fewer overlapping spans if possible.
+        if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span()))
+            && sup_origin.span() != return_sp
+        {
+            // FIXME: account for `async fn` like in `async-await/issues/issue-62097.rs`
+
+            // Customize the spans and labels depending on their relative order so
+            // that split sentences flow correctly.
+            if sup_origin.span().overlaps(return_sp) && sp == sup_origin.span() {
+                // Avoid the following:
+                //
+                // error: cannot infer an appropriate lifetime
+                //   --> $DIR/must_outlive_least_region_or_bound.rs:18:50
+                //    |
+                // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }
+                //    |           ----                      ---------^-
+                //
+                // and instead show:
+                //
+                // error: cannot infer an appropriate lifetime
+                //   --> $DIR/must_outlive_least_region_or_bound.rs:18:50
+                //    |
+                // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }
+                //    |           ----                               ^
                 err.span_label(
-                    param_info.param_ty_span,
-                    &format!("this data with {}...", lifetime),
+                    sup_origin.span(),
+                    "...is captured here, requiring it to live as long as `'static`",
                 );
-                debug!("try_report_static_impl_trait: param_info={:?}", param_info);
+            } else {
+                err.span_label(sup_origin.span(), "...is captured here...");
+                if return_sp < sup_origin.span() {
+                    err.span_note(
+                        return_sp,
+                        "...and is required to live as long as `'static` here",
+                    );
+                } else {
+                    err.span_label(
+                        return_sp,
+                        "...and is required to live as long as `'static` here",
+                    );
+                }
+            }
+        } else {
+            err.span_label(
+                return_sp,
+                "...is captured and required to live as long as `'static` here",
+            );
+        }
+
+        let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.def_id);
 
-                // We try to make the output have fewer overlapping spans if possible.
-                if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span()))
-                    && sup_origin.span() != return_sp
+        let mut override_error_code = None;
+        if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = &sup_origin {
+            if let ObligationCauseCode::UnifyReceiver(ctxt) = &cause.code {
+                // Handle case of `impl Foo for dyn Bar { fn qux(&self) {} }` introducing a
+                // `'static` lifetime when called as a method on a binding: `bar.qux()`.
+                if self.find_impl_on_dyn_trait(&mut err, param.param_ty, &ctxt) {
+                    override_error_code = Some(ctxt.assoc_item.ident);
+                }
+            }
+        }
+        if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = &sub_origin {
+            if let ObligationCauseCode::ItemObligation(item_def_id) = cause.code {
+                // Same case of `impl Foo for dyn Bar { fn qux(&self) {} }` introducing a `'static`
+                // lifetime as above, but called using a fully-qualified path to the method:
+                // `Foo::qux(bar)`.
+                let mut v = TraitObjectVisitor(vec![]);
+                v.visit_ty(param.param_ty);
+                if let Some((ident, self_ty)) =
+                    self.get_impl_ident_and_self_ty_from_trait(item_def_id, &v.0[..])
                 {
-                    // FIXME: account for `async fn` like in `async-await/issues/issue-62097.rs`
-
-                    // Customize the spans and labels depending on their relative order so
-                    // that split sentences flow correctly.
-                    if sup_origin.span().overlaps(return_sp) && sp == sup_origin.span() {
-                        // Avoid the following:
-                        //
-                        // error: cannot infer an appropriate lifetime
-                        //   --> $DIR/must_outlive_least_region_or_bound.rs:18:50
-                        //    |
-                        // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }
-                        //    |           ----                      ---------^-
-                        //
-                        // and instead show:
-                        //
-                        // error: cannot infer an appropriate lifetime
-                        //   --> $DIR/must_outlive_least_region_or_bound.rs:18:50
-                        //    |
-                        // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }
-                        //    |           ----                               ^
-                        err.span_label(
-                            sup_origin.span(),
-                            "...is captured here, requiring it to live as long as `'static`",
+                    if self.suggest_constrain_dyn_trait_in_impl(&mut err, &v.0[..], ident, self_ty)
+                    {
+                        override_error_code = Some(ident);
+                    }
+                }
+            }
+        }
+        if let (Some(ident), true) = (override_error_code, fn_returns.is_empty()) {
+            // Provide a more targetted error code and description.
+            err.code(rustc_errors::error_code!(E0772));
+            err.set_primary_message(&format!(
+                "{} has {} but calling `{}` introduces an implicit `'static` lifetime \
+                requirement",
+                param_name, lifetime, ident,
+            ));
+        }
+
+        debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns);
+        // FIXME: account for the need of parens in `&(dyn Trait + '_)`
+        let consider = "consider changing the";
+        let declare = "to declare that the";
+        let arg = match param.param.pat.simple_ident() {
+            Some(simple_ident) => format!("argument `{}`", simple_ident),
+            None => "the argument".to_string(),
+        };
+        let explicit = format!("you can add an explicit `{}` lifetime bound", lifetime_name);
+        let explicit_static = format!("explicit `'static` bound to the lifetime of {}", arg);
+        let captures = format!("captures data from {}", arg);
+        let add_static_bound = "alternatively, add an explicit `'static` bound to this reference";
+        let plus_lt = format!(" + {}", lifetime_name);
+        for fn_return in fn_returns {
+            if fn_return.span.desugaring_kind().is_some() {
+                // Skip `async` desugaring `impl Future`.
+                continue;
+            }
+            match fn_return.kind {
+                TyKind::OpaqueDef(item_id, _) => {
+                    let item = tcx.hir().item(item_id.id);
+                    let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind {
+                        opaque
+                    } else {
+                        err.emit();
+                        return Some(ErrorReported);
+                    };
+
+                    if let Some(span) = opaque
+                        .bounds
+                        .iter()
+                        .filter_map(|arg| match arg {
+                            GenericBound::Outlives(Lifetime {
+                                name: LifetimeName::Static,
+                                span,
+                                ..
+                            }) => Some(*span),
+                            _ => None,
+                        })
+                        .next()
+                    {
+                        err.span_suggestion_verbose(
+                            span,
+                            &format!("{} `impl Trait`'s {}", consider, explicit_static),
+                            lifetime_name.clone(),
+                            Applicability::MaybeIncorrect,
+                        );
+                        err.span_suggestion_verbose(
+                            param.param_ty_span,
+                            add_static_bound,
+                            param.param_ty.to_string(),
+                            Applicability::MaybeIncorrect,
                         );
+                    } else if let Some(_) = opaque
+                        .bounds
+                        .iter()
+                        .filter_map(|arg| match arg {
+                            GenericBound::Outlives(Lifetime { name, span, .. })
+                                if name.ident().to_string() == lifetime_name =>
+                            {
+                                Some(*span)
+                            }
+                            _ => None,
+                        })
+                        .next()
+                    {
                     } else {
-                        err.span_label(sup_origin.span(), "...is captured here...");
-                        if return_sp < sup_origin.span() {
-                            err.span_note(
-                                return_sp,
-                                "...and is required to live as long as `'static` here",
-                            );
-                        } else {
-                            err.span_label(
-                                return_sp,
-                                "...and is required to live as long as `'static` here",
-                            );
-                        }
+                        err.span_suggestion_verbose(
+                            fn_return.span.shrink_to_hi(),
+                            &format!(
+                                "{declare} `impl Trait` {captures}, {explicit}",
+                                declare = declare,
+                                captures = captures,
+                                explicit = explicit,
+                            ),
+                            plus_lt.clone(),
+                            Applicability::MaybeIncorrect,
+                        );
                     }
-                } else {
-                    err.span_label(
-                        return_sp,
-                        "...is captured and required to live as long as `'static` here",
-                    );
                 }
+                TyKind::TraitObject(_, lt) => match lt.name {
+                    LifetimeName::ImplicitObjectLifetimeDefault => {
+                        err.span_suggestion_verbose(
+                            fn_return.span.shrink_to_hi(),
+                            &format!(
+                                "{declare} trait object {captures}, {explicit}",
+                                declare = declare,
+                                captures = captures,
+                                explicit = explicit,
+                            ),
+                            plus_lt.clone(),
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                    name if name.ident().to_string() != lifetime_name => {
+                        // With this check we avoid suggesting redundant bounds. This
+                        // would happen if there are nested impl/dyn traits and only
+                        // one of them has the bound we'd suggest already there, like
+                        // in `impl Foo<X = dyn Bar> + '_`.
+                        err.span_suggestion_verbose(
+                            lt.span,
+                            &format!("{} trait object's {}", consider, explicit_static),
+                            lifetime_name.clone(),
+                            Applicability::MaybeIncorrect,
+                        );
+                        err.span_suggestion_verbose(
+                            param.param_ty_span,
+                            add_static_bound,
+                            param.param_ty.to_string(),
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                    _ => {}
+                },
+                _ => {}
+            }
+        }
+        err.emit();
+        Some(ErrorReported)
+    }
 
-                // FIXME: account for the need of parens in `&(dyn Trait + '_)`
-                let consider = "consider changing the";
-                let declare = "to declare that the";
-                let arg = match param_info.param.pat.simple_ident() {
-                    Some(simple_ident) => format!("argument `{}`", simple_ident),
-                    None => "the argument".to_string(),
-                };
-                let explicit =
-                    format!("you can add an explicit `{}` lifetime bound", lifetime_name);
-                let explicit_static =
-                    format!("explicit `'static` bound to the lifetime of {}", arg);
-                let captures = format!("captures data from {}", arg);
-                let add_static_bound =
-                    "alternatively, add an explicit `'static` bound to this reference";
-                let plus_lt = format!(" + {}", lifetime_name);
-                for fn_return in fn_returns {
-                    if fn_return.span.desugaring_kind().is_some() {
-                        // Skip `async` desugaring `impl Future`.
-                        continue;
+    fn get_impl_ident_and_self_ty_from_trait(
+        &self,
+        def_id: DefId,
+        trait_objects: &[DefId],
+    ) -> Option<(Ident, &'tcx hir::Ty<'tcx>)> {
+        let tcx = self.tcx();
+        match tcx.hir().get_if_local(def_id) {
+            Some(Node::ImplItem(ImplItem { ident, hir_id, .. })) => {
+                match tcx.hir().find(tcx.hir().get_parent_item(*hir_id)) {
+                    Some(Node::Item(Item { kind: ItemKind::Impl { self_ty, .. }, .. })) => {
+                        Some((*ident, self_ty))
                     }
-                    match fn_return.kind {
-                        TyKind::OpaqueDef(item_id, _) => {
-                            let item = self.tcx().hir().item(item_id.id);
-                            let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind {
-                                opaque
-                            } else {
-                                err.emit();
-                                return Some(ErrorReported);
-                            };
-
-                            if let Some(span) = opaque
-                                .bounds
-                                .iter()
-                                .filter_map(|arg| match arg {
-                                    GenericBound::Outlives(Lifetime {
-                                        name: LifetimeName::Static,
-                                        span,
+                    _ => None,
+                }
+            }
+            Some(Node::TraitItem(TraitItem { ident, hir_id, .. })) => {
+                let parent_id = tcx.hir().get_parent_item(*hir_id);
+                match tcx.hir().find(parent_id) {
+                    Some(Node::Item(Item { kind: ItemKind::Trait(..), .. })) => {
+                        // The method being called is defined in the `trait`, but the `'static`
+                        // obligation comes from the `impl`. Find that `impl` so that we can point
+                        // at it in the suggestion.
+                        let trait_did = tcx.hir().local_def_id(parent_id).to_def_id();
+                        match tcx
+                            .hir()
+                            .trait_impls(trait_did)
+                            .iter()
+                            .filter_map(|impl_node| {
+                                let impl_did = tcx.hir().local_def_id(*impl_node);
+                                match tcx.hir().get_if_local(impl_did.to_def_id()) {
+                                    Some(Node::Item(Item {
+                                        kind: ItemKind::Impl { self_ty, .. },
                                         ..
-                                    }) => Some(*span),
-                                    _ => None,
-                                })
-                                .next()
-                            {
-                                err.span_suggestion_verbose(
-                                    span,
-                                    &format!("{} `impl Trait`'s {}", consider, explicit_static),
-                                    lifetime_name.clone(),
-                                    Applicability::MaybeIncorrect,
-                                );
-                                err.span_suggestion_verbose(
-                                    param_info.param_ty_span,
-                                    add_static_bound,
-                                    param_info.param_ty.to_string(),
-                                    Applicability::MaybeIncorrect,
-                                );
-                            } else if let Some(_) = opaque
-                                .bounds
-                                .iter()
-                                .filter_map(|arg| match arg {
-                                    GenericBound::Outlives(Lifetime { name, span, .. })
-                                        if name.ident().to_string() == lifetime_name =>
+                                    })) if trait_objects.iter().all(|did| {
+                                        // FIXME: we should check `self_ty` against the receiver
+                                        // type in the `UnifyReceiver` context, but for now, use
+                                        // this imperfect proxy. This will fail if there are
+                                        // multiple `impl`s for the same trait like
+                                        // `impl Foo for Box<dyn Bar>` and `impl Foo for dyn Bar`.
+                                        // In that case, only the first one will get suggestions.
+                                        let mut hir_v = HirTraitObjectVisitor(vec![], *did);
+                                        hir_v.visit_ty(self_ty);
+                                        !hir_v.0.is_empty()
+                                    }) =>
                                     {
-                                        Some(*span)
+                                        Some(self_ty)
                                     }
                                     _ => None,
-                                })
-                                .next()
-                            {
-                            } else {
-                                err.span_suggestion_verbose(
-                                    fn_return.span.shrink_to_hi(),
-                                    &format!(
-                                        "{declare} `impl Trait` {captures}, {explicit}",
-                                        declare = declare,
-                                        captures = captures,
-                                        explicit = explicit,
-                                    ),
-                                    plus_lt.clone(),
-                                    Applicability::MaybeIncorrect,
-                                );
-                            }
+                                }
+                            })
+                            .next()
+                        {
+                            Some(self_ty) => Some((*ident, self_ty)),
+                            _ => None,
                         }
-                        TyKind::TraitObject(_, lt) => match lt.name {
-                            LifetimeName::ImplicitObjectLifetimeDefault => {
-                                err.span_suggestion_verbose(
-                                    fn_return.span.shrink_to_hi(),
-                                    &format!(
-                                        "{declare} trait object {captures}, {explicit}",
-                                        declare = declare,
-                                        captures = captures,
-                                        explicit = explicit,
-                                    ),
-                                    plus_lt.clone(),
-                                    Applicability::MaybeIncorrect,
-                                );
-                            }
-                            name if name.ident().to_string() != lifetime_name => {
-                                // With this check we avoid suggesting redundant bounds. This
-                                // would happen if there are nested impl/dyn traits and only
-                                // one of them has the bound we'd suggest already there, like
-                                // in `impl Foo<X = dyn Bar> + '_`.
-                                err.span_suggestion_verbose(
-                                    lt.span,
-                                    &format!("{} trait object's {}", consider, explicit_static),
-                                    lifetime_name.clone(),
-                                    Applicability::MaybeIncorrect,
-                                );
-                                err.span_suggestion_verbose(
-                                    param_info.param_ty_span,
-                                    add_static_bound,
-                                    param_info.param_ty.to_string(),
-                                    Applicability::MaybeIncorrect,
-                                );
-                            }
-                            _ => {}
-                        },
-                        _ => {}
+                    }
+                    _ => None,
+                }
+            }
+            _ => None,
+        }
+    }
+
+    /// When we call a method coming from an `impl Foo for dyn Bar`, `dyn Bar` introduces a default
+    /// `'static` obligation. Suggest relaxing that implicit bound.
+    fn find_impl_on_dyn_trait(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        ty: Ty<'_>,
+        ctxt: &UnifyReceiverContext<'tcx>,
+    ) -> bool {
+        let tcx = self.tcx();
+
+        // Find the method being called.
+        let instance = match ty::Instance::resolve(
+            tcx,
+            ctxt.param_env,
+            ctxt.assoc_item.def_id,
+            self.infcx.resolve_vars_if_possible(&ctxt.substs),
+        ) {
+            Ok(Some(instance)) => instance,
+            _ => return false,
+        };
+
+        let mut v = TraitObjectVisitor(vec![]);
+        v.visit_ty(ty);
+
+        // Get the `Ident` of the method being called and the corresponding `impl` (to point at
+        // `Bar` in `impl Foo for dyn Bar {}` and the definition of the method being called).
+        let (ident, self_ty) =
+            match self.get_impl_ident_and_self_ty_from_trait(instance.def_id(), &v.0[..]) {
+                Some((ident, self_ty)) => (ident, self_ty),
+                None => return false,
+            };
+
+        // Find the trait object types in the argument, so we point at *only* the trait object.
+        self.suggest_constrain_dyn_trait_in_impl(err, &v.0[..], ident, self_ty)
+    }
+
+    fn suggest_constrain_dyn_trait_in_impl(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        found_dids: &[DefId],
+        ident: Ident,
+        self_ty: &hir::Ty<'_>,
+    ) -> bool {
+        let mut suggested = false;
+        for found_did in found_dids {
+            let mut hir_v = HirTraitObjectVisitor(vec![], *found_did);
+            hir_v.visit_ty(&self_ty);
+            for span in &hir_v.0 {
+                let mut multi_span: MultiSpan = vec![*span].into();
+                multi_span.push_span_label(
+                    *span,
+                    "this has an implicit `'static` lifetime requirement".to_string(),
+                );
+                multi_span.push_span_label(
+                    ident.span,
+                    "calling this method introduces the `impl`'s 'static` requirement".to_string(),
+                );
+                err.span_note(multi_span, "the used `impl` has a `'static` requirement");
+                err.span_suggestion_verbose(
+                    span.shrink_to_hi(),
+                    "consider relaxing the implicit `'static` requirement",
+                    " + '_".to_string(),
+                    Applicability::MaybeIncorrect,
+                );
+                suggested = true;
+            }
+        }
+        suggested
+    }
+}
+
+/// Collect all the trait objects in a type that could have received an implicit `'static` lifetime.
+struct TraitObjectVisitor(Vec<DefId>);
+
+impl TypeVisitor<'_> for TraitObjectVisitor {
+    fn visit_ty(&mut self, t: Ty<'_>) -> bool {
+        match t.kind {
+            ty::Dynamic(preds, RegionKind::ReStatic) => {
+                if let Some(def_id) = preds.principal_def_id() {
+                    self.0.push(def_id);
+                }
+                false
+            }
+            _ => t.super_visit_with(self),
+        }
+    }
+}
+
+/// Collect all `hir::Ty<'_>` `Span`s for trait objects with an implicit lifetime.
+struct HirTraitObjectVisitor(Vec<Span>, DefId);
+
+impl<'tcx> Visitor<'tcx> for HirTraitObjectVisitor {
+    type Map = ErasedMap<'tcx>;
+
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+        NestedVisitorMap::None
+    }
+
+    fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) {
+        match t.kind {
+            TyKind::TraitObject(
+                poly_trait_refs,
+                Lifetime { name: LifetimeName::ImplicitObjectLifetimeDefault, .. },
+            ) => {
+                for ptr in poly_trait_refs {
+                    if Some(self.1) == ptr.trait_ref.trait_def_id() {
+                        self.0.push(ptr.span);
                     }
                 }
-                err.emit();
-                return Some(ErrorReported);
             }
+            _ => {}
         }
-        None
+        walk_ty(self, t);
     }
 }
index fa999abb1a86c46b672c88b81b49d1efc36f5fea..28e9dd90cfd674531eafece5122db6f3410fa2f5 100644 (file)
@@ -7,20 +7,18 @@
 use rustc_middle::ty::{self, DefIdTree, Region, Ty};
 use rustc_span::Span;
 
-// The struct contains the information about the anonymous region
-// we are searching for.
+/// Information about the anonymous region we are searching for.
 #[derive(Debug)]
 pub(super) struct AnonymousParamInfo<'tcx> {
-    // the parameter corresponding to the anonymous region
+    /// The parameter corresponding to the anonymous region.
     pub param: &'tcx hir::Param<'tcx>,
-    // the type corresponding to the anonymopus region parameter
+    /// The type corresponding to the anonymous region parameter.
     pub param_ty: Ty<'tcx>,
-    // the ty::BoundRegion corresponding to the anonymous region
+    /// The ty::BoundRegion corresponding to the anonymous region.
     pub bound_region: ty::BoundRegion,
-    // param_ty_span contains span of parameter type
+    /// The `Span` of the parameter type.
     pub param_ty_span: Span,
-    // corresponds to id the argument is the first parameter
-    // in the declaration
+    /// Signals that the argument is the first parameter in the declaration.
     pub is_first: bool,
 }
 
index 37883fcb07468e7256f7e50b7fe2b671695860e2..3744ad5d0324a59ebd145ae16ca0537210feb11d 100644 (file)
@@ -463,7 +463,7 @@ pub enum RegionVariableOrigin {
     AddrOfRegion(Span),
 
     /// Regions created as part of an autoref of a method receiver
-    Autoref(Span),
+    Autoref(Span, ty::AssocItem),
 
     /// Regions created as part of an automatic coercion
     Coercion(Span),
@@ -1800,15 +1800,15 @@ pub fn from_obligation_cause<F>(cause: &traits::ObligationCause<'tcx>, default:
 impl RegionVariableOrigin {
     pub fn span(&self) -> Span {
         match *self {
-            MiscVariable(a) => a,
-            PatternRegion(a) => a,
-            AddrOfRegion(a) => a,
-            Autoref(a) => a,
-            Coercion(a) => a,
-            EarlyBoundRegion(a, ..) => a,
-            LateBoundRegion(a, ..) => a,
+            MiscVariable(a)
+            | PatternRegion(a)
+            | AddrOfRegion(a)
+            | Autoref(a, _)
+            | Coercion(a)
+            | EarlyBoundRegion(a, ..)
+            | LateBoundRegion(a, ..)
+            | UpvarRegion(_, a) => a,
             BoundRegionInCoherence(_) => rustc_span::DUMMY_SP,
-            UpvarRegion(_, a) => a,
             NLL(..) => bug!("NLL variable used with `span`"),
         }
     }
index 0cd6585163c4e9ce2a6df197881ded29be98563e..bacb7fa153e43b1a0cca8d8f5272ec5c71d749f5 100644 (file)
@@ -13,6 +13,7 @@
 //! This API is completely unstable and subject to change.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
+#![feature(bindings_after_at)]
 #![feature(bool_to_option)]
 #![feature(box_patterns)]
 #![feature(box_syntax)]
diff --git a/src/librustc_interface/build.rs b/src/librustc_interface/build.rs
deleted file mode 100644 (file)
index 79a343e..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-fn main() {
-    println!("cargo:rerun-if-changed=build.rs");
-    println!("cargo:rerun-if-env-changed=RUSTC_INSTALL_BINDIR");
-}
index 651a77912c6d046ebff69a3a7f674fc0b3122849..22197a66530ddddb7d1eaba67444109707e5ba2f 100644 (file)
@@ -401,7 +401,7 @@ macro_rules! untracked {
     untracked!(incremental, Some(String::from("abc")));
     // `link_arg` is omitted because it just forwards to `link_args`.
     untracked!(link_args, vec![String::from("abc"), String::from("def")]);
-    untracked!(link_dead_code, true);
+    untracked!(link_dead_code, Some(true));
     untracked!(linker, Some(PathBuf::from("linker")));
     untracked!(linker_flavor, Some(LinkerFlavor::Gcc));
     untracked!(no_stack_check, true);
@@ -420,6 +420,7 @@ macro_rules! tracked {
     // Make sure that changing a [TRACKED] option changes the hash.
     // This list is in alphabetical order.
     tracked!(code_model, Some(CodeModel::Large));
+    tracked!(control_flow_guard, CFGuard::Checks);
     tracked!(debug_assertions, Some(true));
     tracked!(debuginfo, 0xdeadbeef);
     tracked!(embed_bitcode, false);
@@ -537,7 +538,6 @@ macro_rules! tracked {
     tracked!(binary_dep_depinfo, true);
     tracked!(chalk, true);
     tracked!(codegen_backend, Some("abc".to_string()));
-    tracked!(control_flow_guard, CFGuard::Checks);
     tracked!(crate_attr, vec!["abc".to_string()]);
     tracked!(debug_macros, true);
     tracked!(dep_info_omit_d_target, true);
index 4fc02e348f64637a61aeff09833cd5a561fa9fef..9f2711eec10acb26b7d1e004bbb103e034daa6c9 100644 (file)
@@ -2,7 +2,6 @@
 authors = ["The Rust Project Developers"]
 name = "rustc_llvm"
 version = "0.0.0"
-build = "build.rs"
 edition = "2018"
 
 [lib]
@@ -14,8 +13,8 @@ static-libstdcpp = []
 emscripten = []
 
 [dependencies]
-libc = "0.2"
+libc = "0.2.73"
 
 [build-dependencies]
 build_helper = { path = "../build_helper" }
-cc = "1.0.1"
+cc = "1.0.58"
index 5145b3b5e6fcc9cf423c52a0d250a8183213f9c1..21b8080714c1744ca54130adbb6325ece0082bff 100644 (file)
@@ -2,12 +2,12 @@
 use std::path::{Path, PathBuf};
 use std::process::Command;
 
-use build_helper::output;
+use build_helper::{output, tracked_env_var_os};
 
 fn detect_llvm_link() -> (&'static str, &'static str) {
     // Force the link mode we want, preferring static by default, but
     // possibly overridden by `configure --enable-llvm-link-shared`.
-    if env::var_os("LLVM_LINK_SHARED").is_some() {
+    if tracked_env_var_os("LLVM_LINK_SHARED").is_some() {
         ("dylib", "--link-shared")
     } else {
         ("static", "--link-static")
@@ -15,8 +15,7 @@ fn detect_llvm_link() -> (&'static str, &'static str) {
 }
 
 fn main() {
-    println!("cargo:rerun-if-env-changed=RUST_CHECK");
-    if env::var_os("RUST_CHECK").is_some() {
+    if tracked_env_var_os("RUST_CHECK").is_some() {
         // If we're just running `check`, there's no need for LLVM to be built.
         return;
     }
@@ -25,8 +24,8 @@ fn main() {
 
     let target = env::var("TARGET").expect("TARGET was not set");
     let llvm_config =
-        env::var_os("LLVM_CONFIG").map(|x| Some(PathBuf::from(x))).unwrap_or_else(|| {
-            if let Some(dir) = env::var_os("CARGO_TARGET_DIR").map(PathBuf::from) {
+        tracked_env_var_os("LLVM_CONFIG").map(|x| Some(PathBuf::from(x))).unwrap_or_else(|| {
+            if let Some(dir) = tracked_env_var_os("CARGO_TARGET_DIR").map(PathBuf::from) {
                 let to_test = dir
                     .parent()
                     .unwrap()
@@ -46,8 +45,6 @@ fn main() {
     }
     let llvm_config = llvm_config.unwrap_or_else(|| PathBuf::from("llvm-config"));
 
-    println!("cargo:rerun-if-env-changed=LLVM_CONFIG");
-
     // Test whether we're cross-compiling LLVM. This is a pretty rare case
     // currently where we're producing an LLVM for a different platform than
     // what this build script is currently running on.
@@ -104,8 +101,16 @@ fn main() {
         optional_components.push("riscv");
     }
 
-    let required_components =
-        &["ipo", "bitreader", "bitwriter", "linker", "asmparser", "lto", "instrumentation"];
+    let required_components = &[
+        "ipo",
+        "bitreader",
+        "bitwriter",
+        "linker",
+        "asmparser",
+        "lto",
+        "coverage",
+        "instrumentation",
+    ];
 
     let components = output(Command::new(&llvm_config).arg("--components"));
     let mut components = components.split_whitespace().collect::<Vec<_>>();
@@ -155,12 +160,11 @@ fn main() {
         cfg.define(&flag, None);
     }
 
-    println!("cargo:rerun-if-changed-env=LLVM_RUSTLLVM");
-    if env::var_os("LLVM_RUSTLLVM").is_some() {
+    if tracked_env_var_os("LLVM_RUSTLLVM").is_some() {
         cfg.define("LLVM_RUSTLLVM", None);
     }
 
-    if env::var_os("LLVM_NDEBUG").is_some() {
+    if tracked_env_var_os("LLVM_NDEBUG").is_some() {
         cfg.define("NDEBUG", None);
         cfg.debug(false);
     }
@@ -169,6 +173,7 @@ fn main() {
     cfg.file("../rustllvm/PassWrapper.cpp")
         .file("../rustllvm/RustWrapper.cpp")
         .file("../rustllvm/ArchiveWrapper.cpp")
+        .file("../rustllvm/CoverageMappingWrapper.cpp")
         .file("../rustllvm/Linker.cpp")
         .cpp(true)
         .cpp_link_stdlib(None) // we handle this below
@@ -246,7 +251,7 @@ fn main() {
     // librustc_llvm, for example when using static libc++, we may need to
     // manually specify the library search path and -ldl -lpthread as link
     // dependencies.
-    let llvm_linker_flags = env::var_os("LLVM_LINKER_FLAGS");
+    let llvm_linker_flags = tracked_env_var_os("LLVM_LINKER_FLAGS");
     if let Some(s) = llvm_linker_flags {
         for lib in s.into_string().unwrap().split_whitespace() {
             if lib.starts_with("-l") {
@@ -257,8 +262,8 @@ fn main() {
         }
     }
 
-    let llvm_static_stdcpp = env::var_os("LLVM_STATIC_STDCPP");
-    let llvm_use_libcxx = env::var_os("LLVM_USE_LIBCXX");
+    let llvm_static_stdcpp = tracked_env_var_os("LLVM_STATIC_STDCPP");
+    let llvm_use_libcxx = tracked_env_var_os("LLVM_USE_LIBCXX");
 
     let stdcppname = if target.contains("openbsd") {
         if target.contains("sparc64") { "estdc++" } else { "c++" }
index 36300d9efee7f8f76a132f500c2474607c9104e5..9d23397ade08e80e170bd9b41ebce4e72c5c7982 100644 (file)
@@ -13,6 +13,12 @@ pub struct RustString {
     pub bytes: RefCell<Vec<u8>>,
 }
 
+impl RustString {
+    pub fn len(&self) -> usize {
+        self.bytes.borrow().len()
+    }
+}
+
 /// Appending to a Rust string -- used by RawRustStringOstream.
 #[no_mangle]
 #[allow(improper_ctypes_definitions)]
diff --git a/src/librustc_metadata/build.rs b/src/librustc_metadata/build.rs
deleted file mode 100644 (file)
index 7d5c58e..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-fn main() {
-    println!("cargo:rerun-if-changed=build.rs");
-    println!("cargo:rerun-if-env-changed=CFG_VERSION");
-    println!("cargo:rerun-if-env-changed=CFG_VIRTUAL_RUST_SOURCE_BASE_DIR");
-}
index 0563894e6348d718f631127b776a40d04b521951..0d2101cb2cb0821f5bec673e3580f00f6291f4b1 100644 (file)
@@ -1,6 +1,7 @@
 //! Validates all used crates and extern libraries and loads their metadata
 
-use crate::locator::{CrateLocator, CratePaths};
+use crate::dynamic_lib::DynamicLibrary;
+use crate::locator::{CrateError, CrateLocator, CratePaths};
 use crate::rmeta::{CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob};
 
 use rustc_ast::expand::allocator::{global_allocator_spans, AllocatorKind};
@@ -8,15 +9,12 @@
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::svh::Svh;
 use rustc_data_structures::sync::Lrc;
-use rustc_errors::struct_span_err;
 use rustc_expand::base::SyntaxExtension;
 use rustc_hir::def_id::{CrateNum, LocalDefId, LOCAL_CRATE};
 use rustc_hir::definitions::Definitions;
 use rustc_index::vec::IndexVec;
-use rustc_middle::middle::cstore::DepKind;
-use rustc_middle::middle::cstore::{
-    CrateSource, ExternCrate, ExternCrateSource, MetadataLoaderDyn,
-};
+use rustc_middle::middle::cstore::{CrateSource, DepKind, ExternCrate};
+use rustc_middle::middle::cstore::{ExternCrateSource, MetadataLoaderDyn};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::{self, CrateType, ExternLocation};
 use rustc_session::lint;
@@ -31,7 +29,7 @@
 use log::{debug, info, log_enabled};
 use proc_macro::bridge::client::ProcMacro;
 use std::path::Path;
-use std::{cmp, fs};
+use std::{cmp, env, fs};
 
 #[derive(Clone)]
 pub struct CStore {
@@ -69,18 +67,6 @@ enum LoadResult {
     Loaded(Library),
 }
 
-enum LoadError<'a> {
-    LocatorError(CrateLocator<'a>),
-}
-
-impl<'a> LoadError<'a> {
-    fn report(self) -> ! {
-        match self {
-            LoadError::LocatorError(locator) => locator.report_errs(),
-        }
-    }
-}
-
 /// A reference to `CrateMetadata` that can also give access to whole crate store when necessary.
 #[derive(Clone, Copy)]
 crate struct CrateMetadataRef<'a> {
@@ -280,60 +266,43 @@ fn existing_match(&self, name: Symbol, hash: Option<Svh>, kind: PathKind) -> Opt
         ret
     }
 
-    fn verify_no_symbol_conflicts(&self, span: Span, root: &CrateRoot<'_>) {
+    fn verify_no_symbol_conflicts(&self, root: &CrateRoot<'_>) -> Result<(), CrateError> {
         // Check for (potential) conflicts with the local crate
         if self.local_crate_name == root.name()
             && self.sess.local_crate_disambiguator() == root.disambiguator()
         {
-            struct_span_err!(
-                self.sess,
-                span,
-                E0519,
-                "the current crate is indistinguishable from one of its \
-                         dependencies: it has the same crate-name `{}` and was \
-                         compiled with the same `-C metadata` arguments. This \
-                         will result in symbol conflicts between the two.",
-                root.name()
-            )
-            .emit()
+            return Err(CrateError::SymbolConflictsCurrent(root.name()));
         }
 
         // Check for conflicts with any crate loaded so far
+        let mut res = Ok(());
         self.cstore.iter_crate_data(|_, other| {
             if other.name() == root.name() && // same crate-name
-               other.disambiguator() == root.disambiguator() &&  // same crate-disambiguator
+               other.disambiguator() == root.disambiguator() && // same crate-disambiguator
                other.hash() != root.hash()
             {
                 // but different SVH
-                struct_span_err!(
-                    self.sess,
-                    span,
-                    E0523,
-                    "found two different crates with name `{}` that are \
-                         not distinguished by differing `-C metadata`. This \
-                         will result in symbol conflicts between the two.",
-                    root.name()
-                )
-                .emit();
+                res = Err(CrateError::SymbolConflictsOthers(root.name()));
             }
         });
+
+        res
     }
 
     fn register_crate(
         &mut self,
         host_lib: Option<Library>,
         root: Option<&CratePaths>,
-        span: Span,
         lib: Library,
         dep_kind: DepKind,
         name: Symbol,
-    ) -> CrateNum {
+    ) -> Result<CrateNum, CrateError> {
         let _prof_timer = self.sess.prof.generic_activity("metadata_register_crate");
 
         let Library { source, metadata } = lib;
         let crate_root = metadata.get_root();
         let host_hash = host_lib.as_ref().map(|lib| lib.metadata.get_root().hash());
-        self.verify_no_symbol_conflicts(span, &crate_root);
+        self.verify_no_symbol_conflicts(&crate_root)?;
 
         let private_dep =
             self.sess.opts.externs.get(&name.as_str()).map(|e| e.is_private_dep).unwrap_or(false);
@@ -353,7 +322,7 @@ fn register_crate(
             &crate_paths
         };
 
-        let cnum_map = self.resolve_crate_deps(root, &crate_root, &metadata, cnum, span, dep_kind);
+        let cnum_map = self.resolve_crate_deps(root, &crate_root, &metadata, cnum, dep_kind)?;
 
         let raw_proc_macros = if crate_root.is_proc_macro_crate() {
             let temp_root;
@@ -365,7 +334,7 @@ fn register_crate(
                 None => (&source, &crate_root),
             };
             let dlsym_dylib = dlsym_source.dylib.as_ref().expect("no dylib for a proc-macro crate");
-            Some(self.dlsym_proc_macros(&dlsym_dylib.0, dlsym_root.disambiguator(), span))
+            Some(self.dlsym_proc_macros(&dlsym_dylib.0, dlsym_root.disambiguator())?)
         } else {
             None
         };
@@ -386,14 +355,14 @@ fn register_crate(
             ),
         );
 
-        cnum
+        Ok(cnum)
     }
 
     fn load_proc_macro<'b>(
         &self,
         locator: &mut CrateLocator<'b>,
         path_kind: PathKind,
-    ) -> Option<(LoadResult, Option<Library>)>
+    ) -> Result<Option<(LoadResult, Option<Library>)>, CrateError>
     where
         'a: 'b,
     {
@@ -408,8 +377,11 @@ fn load_proc_macro<'b>(
         let (locator, target_result) = if self.sess.opts.debugging_opts.dual_proc_macros {
             proc_macro_locator.reset();
             let result = match self.load(&mut proc_macro_locator)? {
-                LoadResult::Previous(cnum) => return Some((LoadResult::Previous(cnum), None)),
-                LoadResult::Loaded(library) => Some(LoadResult::Loaded(library)),
+                Some(LoadResult::Previous(cnum)) => {
+                    return Ok(Some((LoadResult::Previous(cnum), None)));
+                }
+                Some(LoadResult::Loaded(library)) => Some(LoadResult::Loaded(library)),
+                None => return Ok(None),
             };
             locator.hash = locator.host_hash;
             // Use the locator when looking for the host proc macro crate, as that is required
@@ -427,9 +399,12 @@ fn load_proc_macro<'b>(
         locator.triple = TargetTriple::from_triple(config::host_triple());
         locator.filesearch = self.sess.host_filesearch(path_kind);
 
-        let host_result = self.load(locator)?;
+        let host_result = match self.load(locator)? {
+            Some(host_result) => host_result,
+            None => return Ok(None),
+        };
 
-        Some(if self.sess.opts.debugging_opts.dual_proc_macros {
+        Ok(Some(if self.sess.opts.debugging_opts.dual_proc_macros {
             let host_result = match host_result {
                 LoadResult::Previous(..) => {
                     panic!("host and target proc macros must be loaded in lock-step")
@@ -439,7 +414,7 @@ fn load_proc_macro<'b>(
             (target_result.unwrap(), Some(host_result))
         } else {
             (host_result, None)
-        })
+        }))
     }
 
     fn resolve_crate<'b>(
@@ -452,25 +427,20 @@ fn resolve_crate<'b>(
         if dep.is_none() {
             self.used_extern_options.insert(name);
         }
-        if !name.as_str().is_ascii() {
-            self.sess
-                .struct_span_err(
-                    span,
-                    &format!("cannot load a crate with a non-ascii name `{}`", name,),
-                )
-                .emit();
-        }
-        self.maybe_resolve_crate(name, span, dep_kind, dep).unwrap_or_else(|err| err.report())
+        self.maybe_resolve_crate(name, dep_kind, dep)
+            .unwrap_or_else(|err| err.report(self.sess, span))
     }
 
     fn maybe_resolve_crate<'b>(
         &'b mut self,
         name: Symbol,
-        span: Span,
         mut dep_kind: DepKind,
         dep: Option<(&'b CratePaths, &'b CrateDep)>,
-    ) -> Result<CrateNum, LoadError<'b>> {
+    ) -> Result<CrateNum, CrateError> {
         info!("resolving crate `{}`", name);
+        if !name.as_str().is_ascii() {
+            return Err(CrateError::NonAsciiName(name));
+        }
         let (root, hash, host_hash, extra_filename, path_kind) = match dep {
             Some((root, dep)) => (
                 Some(root),
@@ -494,18 +464,20 @@ fn maybe_resolve_crate<'b>(
                 extra_filename,
                 false, // is_host
                 path_kind,
-                span,
                 root,
                 Some(false), // is_proc_macro
             );
 
-            self.load(&mut locator)
-                .map(|r| (r, None))
-                .or_else(|| {
+            match self.load(&mut locator)? {
+                Some(res) => (res, None),
+                None => {
                     dep_kind = DepKind::MacrosOnly;
-                    self.load_proc_macro(&mut locator, path_kind)
-                })
-                .ok_or_else(move || LoadError::LocatorError(locator))?
+                    match self.load_proc_macro(&mut locator, path_kind)? {
+                        Some(res) => res,
+                        None => return Err(locator.into_error()),
+                    }
+                }
+            }
         };
 
         match result {
@@ -518,14 +490,17 @@ fn maybe_resolve_crate<'b>(
                 Ok(cnum)
             }
             (LoadResult::Loaded(library), host_library) => {
-                Ok(self.register_crate(host_library, root, span, library, dep_kind, name))
+                self.register_crate(host_library, root, library, dep_kind, name)
             }
             _ => panic!(),
         }
     }
 
-    fn load(&self, locator: &mut CrateLocator<'_>) -> Option<LoadResult> {
-        let library = locator.maybe_load_library_crate()?;
+    fn load(&self, locator: &mut CrateLocator<'_>) -> Result<Option<LoadResult>, CrateError> {
+        let library = match locator.maybe_load_library_crate()? {
+            Some(library) => library,
+            None => return Ok(None),
+        };
 
         // In the case that we're loading a crate, but not matching
         // against a hash, we could load a crate which has the same hash
@@ -536,7 +511,7 @@ fn load(&self, locator: &mut CrateLocator<'_>) -> Option<LoadResult> {
         // don't want to match a host crate against an equivalent target one
         // already loaded.
         let root = library.metadata.get_root();
-        if locator.triple == self.sess.opts.target_triple {
+        Ok(Some(if locator.triple == self.sess.opts.target_triple {
             let mut result = LoadResult::Loaded(library);
             self.cstore.iter_crate_data(|cnum, data| {
                 if data.name() == root.name() && root.hash() == data.hash() {
@@ -545,10 +520,10 @@ fn load(&self, locator: &mut CrateLocator<'_>) -> Option<LoadResult> {
                     result = LoadResult::Previous(cnum);
                 }
             });
-            Some(result)
+            result
         } else {
-            Some(LoadResult::Loaded(library))
-        }
+            LoadResult::Loaded(library)
+        }))
     }
 
     fn update_extern_crate(&self, cnum: CrateNum, extern_crate: ExternCrate) {
@@ -569,53 +544,51 @@ fn resolve_crate_deps(
         crate_root: &CrateRoot<'_>,
         metadata: &MetadataBlob,
         krate: CrateNum,
-        span: Span,
         dep_kind: DepKind,
-    ) -> CrateNumMap {
+    ) -> Result<CrateNumMap, CrateError> {
         debug!("resolving deps of external crate");
         if crate_root.is_proc_macro_crate() {
-            return CrateNumMap::new();
+            return Ok(CrateNumMap::new());
         }
 
         // The map from crate numbers in the crate we're resolving to local crate numbers.
         // We map 0 and all other holes in the map to our parent crate. The "additional"
         // self-dependencies should be harmless.
-        std::iter::once(krate)
-            .chain(crate_root.decode_crate_deps(metadata).map(|dep| {
-                info!(
-                    "resolving dep crate {} hash: `{}` extra filename: `{}`",
-                    dep.name, dep.hash, dep.extra_filename
-                );
-                let dep_kind = match dep_kind {
-                    DepKind::MacrosOnly => DepKind::MacrosOnly,
-                    _ => dep.kind,
-                };
-                self.resolve_crate(dep.name, span, dep_kind, Some((root, &dep)))
-            }))
-            .collect()
+        let deps = crate_root.decode_crate_deps(metadata);
+        let mut crate_num_map = CrateNumMap::with_capacity(1 + deps.len());
+        crate_num_map.push(krate);
+        for dep in deps {
+            info!(
+                "resolving dep crate {} hash: `{}` extra filename: `{}`",
+                dep.name, dep.hash, dep.extra_filename
+            );
+            let dep_kind = match dep_kind {
+                DepKind::MacrosOnly => DepKind::MacrosOnly,
+                _ => dep.kind,
+            };
+            let cnum = self.maybe_resolve_crate(dep.name, dep_kind, Some((root, &dep)))?;
+            crate_num_map.push(cnum);
+        }
+        Ok(crate_num_map)
     }
 
     fn dlsym_proc_macros(
         &self,
         path: &Path,
         disambiguator: CrateDisambiguator,
-        span: Span,
-    ) -> &'static [ProcMacro] {
-        use crate::dynamic_lib::DynamicLibrary;
-        use std::env;
-
+    ) -> Result<&'static [ProcMacro], CrateError> {
         // Make sure the path contains a / or the linker will search for it.
         let path = env::current_dir().unwrap().join(path);
         let lib = match DynamicLibrary::open(&path) {
             Ok(lib) => lib,
-            Err(err) => self.sess.span_fatal(span, &err),
+            Err(s) => return Err(CrateError::DlOpen(s)),
         };
 
         let sym = self.sess.generate_proc_macro_decls_symbol(disambiguator);
         let decls = unsafe {
             let sym = match lib.symbol(&sym) {
                 Ok(f) => f,
-                Err(err) => self.sess.span_fatal(span, &err),
+                Err(s) => return Err(CrateError::DlSym(s)),
             };
             *(sym as *const &[ProcMacro])
         };
@@ -624,7 +597,7 @@ fn dlsym_proc_macros(
         // since the library can make things that will live arbitrarily long.
         std::mem::forget(lib);
 
-        decls
+        Ok(decls)
     }
 
     fn inject_panic_runtime(&mut self, krate: &ast::Crate) {
@@ -952,7 +925,7 @@ pub fn process_path_extern(&mut self, name: Symbol, span: Span) -> CrateNum {
         cnum
     }
 
-    pub fn maybe_process_path_extern(&mut self, name: Symbol, span: Span) -> Option<CrateNum> {
-        self.maybe_resolve_crate(name, span, DepKind::Explicit, None).ok()
+    pub fn maybe_process_path_extern(&mut self, name: Symbol) -> Option<CrateNum> {
+        self.maybe_resolve_crate(name, DepKind::Explicit, None).ok()
     }
 }
index 1bdac1039b55a48e07bb179599993968857b0fdf..371ec4cd91148686345129677de65ed4b2735503 100644 (file)
 use crate::rmeta::{rustc_version, MetadataBlob, METADATA_HEADER};
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::owning_ref::OwningRef;
 use rustc_data_structures::svh::Svh;
 use rustc_data_structures::sync::MetadataRef;
-use rustc_errors::{struct_span_err, DiagnosticBuilder};
+use rustc_errors::struct_span_err;
 use rustc_middle::middle::cstore::{CrateSource, MetadataLoader};
 use rustc_session::config::{self, CrateType};
 use rustc_session::filesearch::{FileDoesntMatch, FileMatches, FileSearch};
 use rustc_span::Span;
 use rustc_target::spec::{Target, TargetTriple};
 
-use std::cmp;
-use std::fmt;
-use std::fs;
-use std::io::{self, Read};
-use std::ops::Deref;
-use std::path::{Path, PathBuf};
-use std::time::Instant;
-
 use flate2::read::DeflateDecoder;
-
-use rustc_data_structures::owning_ref::OwningRef;
-
 use log::{debug, info, warn};
-
-#[derive(Clone)]
-struct CrateMismatch {
-    path: PathBuf,
-    got: String,
-}
+use std::io::{Read, Result as IoResult, Write};
+use std::ops::Deref;
+use std::path::{Path, PathBuf};
+use std::{cmp, fmt, fs};
 
 #[derive(Clone)]
 crate struct CrateLocator<'a> {
@@ -263,7 +251,6 @@ struct CrateMismatch {
     pub target: &'a Target,
     pub triple: TargetTriple,
     pub filesearch: FileSearch<'a>,
-    span: Span,
     root: Option<&'a CratePaths>,
     pub is_proc_macro: Option<bool>,
 
@@ -275,6 +262,7 @@ struct CrateMismatch {
     rejected_via_filename: Vec<CrateMismatch>,
 }
 
+#[derive(Clone)]
 crate struct CratePaths {
     name: Symbol,
     source: CrateSource,
@@ -287,7 +275,7 @@ impl CratePaths {
 }
 
 #[derive(Copy, Clone, PartialEq)]
-enum CrateFlavor {
+crate enum CrateFlavor {
     Rlib,
     Rmeta,
     Dylib,
@@ -313,7 +301,6 @@ impl<'a> CrateLocator<'a> {
         extra_filename: Option<&'a str>,
         is_host: bool,
         path_kind: PathKind,
-        span: Span,
         root: Option<&'a CratePaths>,
         is_proc_macro: Option<bool>,
     ) -> CrateLocator<'a> {
@@ -349,7 +336,6 @@ impl<'a> CrateLocator<'a> {
             } else {
                 sess.target_filesearch(path_kind)
             },
-            span,
             root,
             is_proc_macro,
             rejected_via_hash: Vec::new(),
@@ -368,166 +354,30 @@ impl<'a> CrateLocator<'a> {
         self.rejected_via_filename.clear();
     }
 
-    crate fn maybe_load_library_crate(&mut self) -> Option<Library> {
+    crate fn maybe_load_library_crate(&mut self) -> Result<Option<Library>, CrateError> {
         if !self.exact_paths.is_empty() {
             return self.find_commandline_library();
         }
         let mut seen_paths = FxHashSet::default();
-        match self.extra_filename {
-            Some(s) => self
-                .find_library_crate(s, &mut seen_paths)
-                .or_else(|| self.find_library_crate("", &mut seen_paths)),
-            None => self.find_library_crate("", &mut seen_paths),
-        }
-    }
-
-    crate fn report_errs(self) -> ! {
-        let add = match self.root {
-            None => String::new(),
-            Some(r) => format!(" which `{}` depends on", r.name),
-        };
-        let mut msg = "the following crate versions were found:".to_string();
-        let mut err = if !self.rejected_via_hash.is_empty() {
-            let mut err = struct_span_err!(
-                self.sess,
-                self.span,
-                E0460,
-                "found possibly newer version of crate `{}`{}",
-                self.crate_name,
-                add
-            );
-            err.note("perhaps that crate needs to be recompiled?");
-            let mismatches = self.rejected_via_hash.iter();
-            for &CrateMismatch { ref path, .. } in mismatches {
-                msg.push_str(&format!("\ncrate `{}`: {}", self.crate_name, path.display()));
-            }
-            match self.root {
-                None => {}
-                Some(r) => {
-                    for path in r.source.paths() {
-                        msg.push_str(&format!("\ncrate `{}`: {}", r.name, path.display()));
-                    }
-                }
-            }
-            err.note(&msg);
-            err
-        } else if !self.rejected_via_triple.is_empty() {
-            let mut err = struct_span_err!(
-                self.sess,
-                self.span,
-                E0461,
-                "couldn't find crate `{}` \
-                                            with expected target triple {}{}",
-                self.crate_name,
-                self.triple,
-                add
-            );
-            let mismatches = self.rejected_via_triple.iter();
-            for &CrateMismatch { ref path, ref got } in mismatches {
-                msg.push_str(&format!(
-                    "\ncrate `{}`, target triple {}: {}",
-                    self.crate_name,
-                    got,
-                    path.display()
-                ));
-            }
-            err.note(&msg);
-            err
-        } else if !self.rejected_via_kind.is_empty() {
-            let mut err = struct_span_err!(
-                self.sess,
-                self.span,
-                E0462,
-                "found staticlib `{}` instead of rlib or dylib{}",
-                self.crate_name,
-                add
-            );
-            err.help("please recompile that crate using --crate-type lib");
-            let mismatches = self.rejected_via_kind.iter();
-            for &CrateMismatch { ref path, .. } in mismatches {
-                msg.push_str(&format!("\ncrate `{}`: {}", self.crate_name, path.display()));
-            }
-            err.note(&msg);
-            err
-        } else if !self.rejected_via_version.is_empty() {
-            let mut err = struct_span_err!(
-                self.sess,
-                self.span,
-                E0514,
-                "found crate `{}` compiled by an incompatible version \
-                                            of rustc{}",
-                self.crate_name,
-                add
-            );
-            err.help(&format!(
-                "please recompile that crate using this compiler ({})",
-                rustc_version()
-            ));
-            let mismatches = self.rejected_via_version.iter();
-            for &CrateMismatch { ref path, ref got } in mismatches {
-                msg.push_str(&format!(
-                    "\ncrate `{}` compiled by {}: {}",
-                    self.crate_name,
-                    got,
-                    path.display()
-                ));
-            }
-            err.note(&msg);
-            err
-        } else {
-            let mut err = struct_span_err!(
-                self.sess,
-                self.span,
-                E0463,
-                "can't find crate for `{}`{}",
-                self.crate_name,
-                add
-            );
-
-            if (self.crate_name == sym::std || self.crate_name == sym::core)
-                && self.triple != TargetTriple::from_triple(config::host_triple())
-            {
-                err.note(&format!("the `{}` target may not be installed", self.triple));
-            } else if self.crate_name == sym::profiler_builtins {
-                err.note(&"the compiler may have been built without the profiler runtime");
-            }
-            err.span_label(self.span, "can't find crate");
-            err
-        };
-
-        if !self.rejected_via_filename.is_empty() {
-            let dylibname = self.dylibname();
-            let mismatches = self.rejected_via_filename.iter();
-            for &CrateMismatch { ref path, .. } in mismatches {
-                err.note(&format!(
-                    "extern location for {} is of an unknown type: {}",
-                    self.crate_name,
-                    path.display()
-                ))
-                .help(&format!(
-                    "file name should be lib*.rlib or {}*.{}",
-                    dylibname.0, dylibname.1
-                ));
+        if let Some(extra_filename) = self.extra_filename {
+            if let library @ Some(_) = self.find_library_crate(extra_filename, &mut seen_paths)? {
+                return Ok(library);
             }
         }
-
-        err.emit();
-        self.sess.abort_if_errors();
-        unreachable!();
+        self.find_library_crate("", &mut seen_paths)
     }
 
     fn find_library_crate(
         &mut self,
         extra_prefix: &str,
         seen_paths: &mut FxHashSet<PathBuf>,
-    ) -> Option<Library> {
-        let dypair = self.dylibname();
-        let staticpair = self.staticlibname();
-
+    ) -> Result<Option<Library>, CrateError> {
         // want: crate_name.dir_part() + prefix + crate_name.file_part + "-"
-        let dylib_prefix = format!("{}{}{}", dypair.0, self.crate_name, extra_prefix);
+        let dylib_prefix =
+            format!("{}{}{}", self.target.options.dll_prefix, self.crate_name, extra_prefix);
         let rlib_prefix = format!("lib{}{}", self.crate_name, extra_prefix);
-        let staticlib_prefix = format!("{}{}{}", staticpair.0, self.crate_name, extra_prefix);
+        let staticlib_prefix =
+            format!("{}{}{}", self.target.options.staticlib_prefix, self.crate_name, extra_prefix);
 
         let mut candidates: FxHashMap<_, (FxHashMap<_, _>, FxHashMap<_, _>, FxHashMap<_, _>)> =
             Default::default();
@@ -555,10 +405,18 @@ fn find_library_crate(
                 (&file[(rlib_prefix.len())..(file.len() - ".rlib".len())], CrateFlavor::Rlib)
             } else if file.starts_with(&rlib_prefix) && file.ends_with(".rmeta") {
                 (&file[(rlib_prefix.len())..(file.len() - ".rmeta".len())], CrateFlavor::Rmeta)
-            } else if file.starts_with(&dylib_prefix) && file.ends_with(&dypair.1) {
-                (&file[(dylib_prefix.len())..(file.len() - dypair.1.len())], CrateFlavor::Dylib)
+            } else if file.starts_with(&dylib_prefix)
+                && file.ends_with(&self.target.options.dll_suffix)
+            {
+                (
+                    &file
+                        [(dylib_prefix.len())..(file.len() - self.target.options.dll_suffix.len())],
+                    CrateFlavor::Dylib,
+                )
             } else {
-                if file.starts_with(&staticlib_prefix) && file.ends_with(&staticpair.1) {
+                if file.starts_with(&staticlib_prefix)
+                    && file.ends_with(&self.target.options.staticlib_suffix)
+                {
                     staticlibs
                         .push(CrateMismatch { path: spf.path.clone(), got: "static".to_string() });
                 }
@@ -567,9 +425,7 @@ fn find_library_crate(
 
             info!("lib candidate: {}", spf.path.display());
 
-            let hash_str = hash.to_string();
-            let slot = candidates.entry(hash_str).or_default();
-            let (ref mut rlibs, ref mut rmetas, ref mut dylibs) = *slot;
+            let (rlibs, rmetas, dylibs) = candidates.entry(hash.to_string()).or_default();
             fs::canonicalize(&spf.path)
                 .map(|p| {
                     if seen_paths.contains(&p) {
@@ -577,16 +433,10 @@ fn find_library_crate(
                     };
                     seen_paths.insert(p.clone());
                     match found_kind {
-                        CrateFlavor::Rlib => {
-                            rlibs.insert(p, kind);
-                        }
-                        CrateFlavor::Rmeta => {
-                            rmetas.insert(p, kind);
-                        }
-                        CrateFlavor::Dylib => {
-                            dylibs.insert(p, kind);
-                        }
-                    }
+                        CrateFlavor::Rlib => rlibs.insert(p, kind),
+                        CrateFlavor::Rmeta => rmetas.insert(p, kind),
+                        CrateFlavor::Dylib => dylibs.insert(p, kind),
+                    };
                     FileMatches
                 })
                 .unwrap_or(FileDoesntMatch)
@@ -603,7 +453,7 @@ fn find_library_crate(
         // search is being performed for.
         let mut libraries = FxHashMap::default();
         for (_hash, (rlibs, rmetas, dylibs)) in candidates {
-            if let Some((svh, lib)) = self.extract_lib(rlibs, rmetas, dylibs) {
+            if let Some((svh, lib)) = self.extract_lib(rlibs, rmetas, dylibs)? {
                 libraries.insert(svh, lib);
             }
         }
@@ -612,39 +462,9 @@ fn find_library_crate(
         // what we've got and figure out if we found multiple candidates for
         // libraries or not.
         match libraries.len() {
-            0 => None,
-            1 => Some(libraries.into_iter().next().unwrap().1),
-            _ => {
-                let mut err = struct_span_err!(
-                    self.sess,
-                    self.span,
-                    E0464,
-                    "multiple matching crates for `{}`",
-                    self.crate_name
-                );
-                let candidates = libraries
-                    .iter()
-                    .filter_map(|(_, lib)| {
-                        let crate_name = &lib.metadata.get_root().name().as_str();
-                        match &(&lib.source.dylib, &lib.source.rlib) {
-                            &(&Some((ref pd, _)), &Some((ref pr, _))) => Some(format!(
-                                "\ncrate `{}`: {}\n{:>padding$}",
-                                crate_name,
-                                pd.display(),
-                                pr.display(),
-                                padding = 8 + crate_name.len()
-                            )),
-                            &(&Some((ref p, _)), &None) | &(&None, &Some((ref p, _))) => {
-                                Some(format!("\ncrate `{}`: {}", crate_name, p.display()))
-                            }
-                            &(&None, &None) => None,
-                        }
-                    })
-                    .collect::<String>();
-                err.note(&format!("candidates:{}", candidates));
-                err.emit();
-                None
-            }
+            0 => Ok(None),
+            1 => Ok(Some(libraries.into_iter().next().unwrap().1)),
+            _ => Err(CrateError::MultipleMatchingCrates(self.crate_name, libraries)),
         }
     }
 
@@ -653,16 +473,16 @@ fn extract_lib(
         rlibs: FxHashMap<PathBuf, PathKind>,
         rmetas: FxHashMap<PathBuf, PathKind>,
         dylibs: FxHashMap<PathBuf, PathKind>,
-    ) -> Option<(Svh, Library)> {
+    ) -> Result<Option<(Svh, Library)>, CrateError> {
         let mut slot = None;
         // Order here matters, rmeta should come first. See comment in
         // `extract_one` below.
         let source = CrateSource {
-            rmeta: self.extract_one(rmetas, CrateFlavor::Rmeta, &mut slot),
-            rlib: self.extract_one(rlibs, CrateFlavor::Rlib, &mut slot),
-            dylib: self.extract_one(dylibs, CrateFlavor::Dylib, &mut slot),
+            rmeta: self.extract_one(rmetas, CrateFlavor::Rmeta, &mut slot)?,
+            rlib: self.extract_one(rlibs, CrateFlavor::Rlib, &mut slot)?,
+            dylib: self.extract_one(dylibs, CrateFlavor::Dylib, &mut slot)?,
         };
-        slot.map(|(svh, metadata)| (svh, Library { source, metadata }))
+        Ok(slot.map(|(svh, metadata)| (svh, Library { source, metadata })))
     }
 
     fn needs_crate_flavor(&self, flavor: CrateFlavor) -> bool {
@@ -698,10 +518,7 @@ fn extract_one(
         m: FxHashMap<PathBuf, PathKind>,
         flavor: CrateFlavor,
         slot: &mut Option<(Svh, MetadataBlob)>,
-    ) -> Option<(PathBuf, PathKind)> {
-        let mut ret: Option<(PathBuf, PathKind)> = None;
-        let mut error = 0;
-
+    ) -> Result<Option<(PathBuf, PathKind)>, CrateError> {
         // If we are producing an rlib, and we've already loaded metadata, then
         // we should not attempt to discover further crate sources (unless we're
         // locating a proc macro; exact logic is in needs_crate_flavor). This means
@@ -718,13 +535,14 @@ fn extract_one(
         // from the other crate sources.
         if slot.is_some() {
             if m.is_empty() || !self.needs_crate_flavor(flavor) {
-                return None;
+                return Ok(None);
             } else if m.len() == 1 {
-                return Some(m.into_iter().next().unwrap());
+                return Ok(Some(m.into_iter().next().unwrap()));
             }
         }
 
-        let mut err: Option<DiagnosticBuilder<'_>> = None;
+        let mut ret: Option<(PathBuf, PathKind)> = None;
+        let mut err_data: Option<Vec<PathBuf>> = None;
         for (lib, kind) in m {
             info!("{} reading metadata from: {}", flavor, lib.display());
             let (hash, metadata) =
@@ -744,30 +562,18 @@ fn extract_one(
                 };
             // If we see multiple hashes, emit an error about duplicate candidates.
             if slot.as_ref().map_or(false, |s| s.0 != hash) {
-                let mut e = struct_span_err!(
-                    self.sess,
-                    self.span,
-                    E0465,
-                    "multiple {} candidates for `{}` found",
-                    flavor,
-                    self.crate_name
-                );
-                e.span_note(
-                    self.span,
-                    &format!(r"candidate #1: {}", ret.as_ref().unwrap().0.display()),
-                );
-                if let Some(ref mut e) = err {
-                    e.emit();
+                if let Some(candidates) = err_data {
+                    return Err(CrateError::MultipleCandidates(
+                        self.crate_name,
+                        flavor,
+                        candidates,
+                    ));
                 }
-                err = Some(e);
-                error = 1;
+                err_data = Some(vec![ret.as_ref().unwrap().0.clone()]);
                 *slot = None;
             }
-            if error > 0 {
-                error += 1;
-                err.as_mut()
-                    .unwrap()
-                    .span_note(self.span, &format!(r"candidate #{}: {}", error, lib.display()));
+            if let Some(candidates) = &mut err_data {
+                candidates.push(lib);
                 continue;
             }
 
@@ -790,7 +596,7 @@ fn extract_one(
             // As a result, we favor the sysroot crate here. Note that the
             // candidates are all canonicalized, so we canonicalize the sysroot
             // as well.
-            if let Some((ref prev, _)) = ret {
+            if let Some((prev, _)) = &ret {
                 let sysroot = &self.sess.sysroot;
                 let sysroot = sysroot.canonicalize().unwrap_or_else(|_| sysroot.to_path_buf());
                 if prev.starts_with(&sysroot) {
@@ -801,11 +607,10 @@ fn extract_one(
             ret = Some((lib, kind));
         }
 
-        if error > 0 {
-            err.unwrap().emit();
-            None
+        if let Some(candidates) = err_data {
+            Err(CrateError::MultipleCandidates(self.crate_name, flavor, candidates))
         } else {
-            ret
+            Ok(ret)
         }
     }
 
@@ -860,71 +665,29 @@ fn crate_matches(&mut self, metadata: &MetadataBlob, libpath: &Path) -> Option<S
         Some(hash)
     }
 
-    // Returns the corresponding (prefix, suffix) that files need to have for
-    // dynamic libraries
-    fn dylibname(&self) -> (String, String) {
-        let t = &self.target;
-        (t.options.dll_prefix.clone(), t.options.dll_suffix.clone())
-    }
-
-    // Returns the corresponding (prefix, suffix) that files need to have for
-    // static libraries
-    fn staticlibname(&self) -> (String, String) {
-        let t = &self.target;
-        (t.options.staticlib_prefix.clone(), t.options.staticlib_suffix.clone())
-    }
-
-    fn find_commandline_library(&mut self) -> Option<Library> {
+    fn find_commandline_library(&mut self) -> Result<Option<Library>, CrateError> {
         // First, filter out all libraries that look suspicious. We only accept
         // files which actually exist that have the correct naming scheme for
         // rlibs/dylibs.
-        let sess = self.sess;
-        let dylibname = self.dylibname();
         let mut rlibs = FxHashMap::default();
         let mut rmetas = FxHashMap::default();
         let mut dylibs = FxHashMap::default();
-        {
-            let crate_name = self.crate_name;
-            let rejected_via_filename = &mut self.rejected_via_filename;
-            let locs = self.exact_paths.iter().filter(|loc| {
-                if !loc.exists() {
-                    sess.err(&format!(
-                        "extern location for {} does not exist: {}",
-                        crate_name,
-                        loc.display()
-                    ));
-                    return false;
-                }
-                let file = match loc.file_name().and_then(|s| s.to_str()) {
-                    Some(file) => file,
-                    None => {
-                        sess.err(&format!(
-                            "extern location for {} is not a file: {}",
-                            crate_name,
-                            loc.display()
-                        ));
-                        return false;
-                    }
-                };
-                if file.starts_with("lib") && (file.ends_with(".rlib") || file.ends_with(".rmeta"))
-                {
-                    return true;
-                } else {
-                    let (ref prefix, ref suffix) = dylibname;
-                    if file.starts_with(&prefix[..]) && file.ends_with(&suffix[..]) {
-                        return true;
-                    }
+        for loc in &self.exact_paths {
+            if !loc.exists() {
+                return Err(CrateError::ExternLocationNotExist(self.crate_name, loc.clone()));
+            }
+            let file = match loc.file_name().and_then(|s| s.to_str()) {
+                Some(file) => file,
+                None => {
+                    return Err(CrateError::ExternLocationNotFile(self.crate_name, loc.clone()));
                 }
+            };
 
-                rejected_via_filename
-                    .push(CrateMismatch { path: (*loc).clone(), got: String::new() });
-
-                false
-            });
-
-            // Now that we have an iterator of good candidates, make sure
-            // there's at most one rlib and at most one dylib.
-            for loc in locs {
+            if file.starts_with("lib") && (file.ends_with(".rlib") || file.ends_with(".rmeta"))
+                || file.starts_with(&self.target.options.dll_prefix)
+                    && file.ends_with(&self.target.options.dll_suffix)
+            {
+                // Make sure there's at most one rlib and at most one dylib.
                 if loc.file_name().unwrap().to_str().unwrap().ends_with(".rlib") {
                     rlibs.insert(fs::canonicalize(&loc).unwrap(), PathKind::ExternFlag);
                 } else if loc.file_name().unwrap().to_str().unwrap().ends_with(".rmeta") {
@@ -932,25 +695,30 @@ fn find_commandline_library(&mut self) -> Option<Library> {
                 } else {
                     dylibs.insert(fs::canonicalize(&loc).unwrap(), PathKind::ExternFlag);
                 }
+            } else {
+                self.rejected_via_filename
+                    .push(CrateMismatch { path: loc.clone(), got: String::new() });
             }
-        };
+        }
 
         // Extract the dylib/rlib/rmeta triple.
-        self.extract_lib(rlibs, rmetas, dylibs).map(|(_, lib)| lib)
+        Ok(self.extract_lib(rlibs, rmetas, dylibs)?.map(|(_, lib)| lib))
     }
-}
 
-// Just a small wrapper to time how long reading metadata takes.
-fn get_metadata_section(
-    target: &Target,
-    flavor: CrateFlavor,
-    filename: &Path,
-    loader: &dyn MetadataLoader,
-) -> Result<MetadataBlob, String> {
-    let start = Instant::now();
-    let ret = get_metadata_section_imp(target, flavor, filename, loader);
-    info!("reading {:?} => {:?}", filename.file_name().unwrap(), start.elapsed());
-    ret
+    crate fn into_error(self) -> CrateError {
+        CrateError::LocatorCombined(CombinedLocatorError {
+            crate_name: self.crate_name,
+            root: self.root.cloned(),
+            triple: self.triple,
+            dll_prefix: self.target.options.dll_prefix.clone(),
+            dll_suffix: self.target.options.dll_suffix.clone(),
+            rejected_via_hash: self.rejected_via_hash,
+            rejected_via_triple: self.rejected_via_triple,
+            rejected_via_kind: self.rejected_via_kind,
+            rejected_via_version: self.rejected_via_version,
+            rejected_via_filename: self.rejected_via_filename,
+        })
+    }
 }
 
 /// A trivial wrapper for `Mmap` that implements `StableDeref`.
@@ -966,7 +734,7 @@ fn deref(&self) -> &[u8] {
 
 unsafe impl stable_deref_trait::StableDeref for StableDerefMmap {}
 
-fn get_metadata_section_imp(
+fn get_metadata_section(
     target: &Target,
     flavor: CrateFlavor,
     filename: &Path,
@@ -1026,12 +794,19 @@ pub fn find_plugin_registrar(
     metadata_loader: &dyn MetadataLoader,
     span: Span,
     name: Symbol,
-) -> Option<(PathBuf, CrateDisambiguator)> {
+) -> (PathBuf, CrateDisambiguator) {
+    match find_plugin_registrar_impl(sess, metadata_loader, name) {
+        Ok(res) => res,
+        Err(err) => err.report(sess, span),
+    }
+}
+
+fn find_plugin_registrar_impl<'a>(
+    sess: &'a Session,
+    metadata_loader: &dyn MetadataLoader,
+    name: Symbol,
+) -> Result<(PathBuf, CrateDisambiguator), CrateError> {
     info!("find plugin registrar `{}`", name);
-    let target_triple = sess.opts.target_triple.clone();
-    let host_triple = TargetTriple::from_triple(config::host_triple());
-    let is_cross = target_triple != host_triple;
-    let mut target_only = false;
     let mut locator = CrateLocator::new(
         sess,
         metadata_loader,
@@ -1041,57 +816,16 @@ pub fn find_plugin_registrar(
         None, // extra_filename
         true, // is_host
         PathKind::Crate,
-        span,
         None, // root
         None, // is_proc_macro
     );
 
-    let library = locator.maybe_load_library_crate().or_else(|| {
-        if !is_cross {
-            return None;
-        }
-        // Try loading from target crates. This will abort later if we
-        // try to load a plugin registrar function,
-        target_only = true;
-
-        locator.target = &sess.target.target;
-        locator.triple = target_triple;
-        locator.filesearch = sess.target_filesearch(PathKind::Crate);
-
-        locator.maybe_load_library_crate()
-    });
-    let library = match library {
-        Some(l) => l,
-        None => locator.report_errs(),
-    };
-
-    if target_only {
-        let message = format!(
-            "plugin `{}` is not available for triple `{}` (only found {})",
-            name,
-            config::host_triple(),
-            sess.opts.target_triple
-        );
-        struct_span_err!(sess, span, E0456, "{}", &message).emit();
-        return None;
-    }
-
-    match library.source.dylib {
-        Some(dylib) => Some((dylib.0, library.metadata.get_root().disambiguator())),
-        None => {
-            struct_span_err!(
-                sess,
-                span,
-                E0457,
-                "plugin `{}` only found in rlib format, but must be available \
-                        in dylib format",
-                name
-            )
-            .emit();
-            // No need to abort because the loading code will just ignore this
-            // empty dylib.
-            None
-        }
+    match locator.maybe_load_library_crate()? {
+        Some(library) => match library.source.dylib {
+            Some(dylib) => Ok((dylib.0, library.metadata.get_root().disambiguator())),
+            None => Err(CrateError::NonDylibPlugin(name)),
+        },
+        None => Err(locator.into_error()),
     }
 }
 
@@ -1100,8 +834,8 @@ pub fn list_file_metadata(
     target: &Target,
     path: &Path,
     metadata_loader: &dyn MetadataLoader,
-    out: &mut dyn io::Write,
-) -> io::Result<()> {
+    out: &mut dyn Write,
+) -> IoResult<()> {
     let filename = path.file_name().unwrap().to_str().unwrap();
     let flavor = if filename.ends_with(".rlib") {
         CrateFlavor::Rlib
@@ -1115,3 +849,259 @@ pub fn list_file_metadata(
         Err(msg) => write!(out, "{}\n", msg),
     }
 }
+
+// ------------------------------------------ Error reporting -------------------------------------
+
+#[derive(Clone)]
+struct CrateMismatch {
+    path: PathBuf,
+    got: String,
+}
+
+/// Candidate rejection reasons collected during crate search.
+/// If no candidate is accepted, then these reasons are presented to the user,
+/// otherwise they are ignored.
+crate struct CombinedLocatorError {
+    crate_name: Symbol,
+    root: Option<CratePaths>,
+    triple: TargetTriple,
+    dll_prefix: String,
+    dll_suffix: String,
+    rejected_via_hash: Vec<CrateMismatch>,
+    rejected_via_triple: Vec<CrateMismatch>,
+    rejected_via_kind: Vec<CrateMismatch>,
+    rejected_via_version: Vec<CrateMismatch>,
+    rejected_via_filename: Vec<CrateMismatch>,
+}
+
+crate enum CrateError {
+    NonAsciiName(Symbol),
+    ExternLocationNotExist(Symbol, PathBuf),
+    ExternLocationNotFile(Symbol, PathBuf),
+    MultipleCandidates(Symbol, CrateFlavor, Vec<PathBuf>),
+    MultipleMatchingCrates(Symbol, FxHashMap<Svh, Library>),
+    SymbolConflictsCurrent(Symbol),
+    SymbolConflictsOthers(Symbol),
+    DlOpen(String),
+    DlSym(String),
+    LocatorCombined(CombinedLocatorError),
+    NonDylibPlugin(Symbol),
+}
+
+impl CrateError {
+    crate fn report(self, sess: &Session, span: Span) -> ! {
+        let mut err = match self {
+            CrateError::NonAsciiName(crate_name) => sess.struct_span_err(
+                span,
+                &format!("cannot load a crate with a non-ascii name `{}`", crate_name),
+            ),
+            CrateError::ExternLocationNotExist(crate_name, loc) => sess.struct_span_err(
+                span,
+                &format!("extern location for {} does not exist: {}", crate_name, loc.display()),
+            ),
+            CrateError::ExternLocationNotFile(crate_name, loc) => sess.struct_span_err(
+                span,
+                &format!("extern location for {} is not a file: {}", crate_name, loc.display()),
+            ),
+            CrateError::MultipleCandidates(crate_name, flavor, candidates) => {
+                let mut err = struct_span_err!(
+                    sess,
+                    span,
+                    E0465,
+                    "multiple {} candidates for `{}` found",
+                    flavor,
+                    crate_name,
+                );
+                for (i, candidate) in candidates.iter().enumerate() {
+                    err.span_note(span, &format!("candidate #{}: {}", i + 1, candidate.display()));
+                }
+                err
+            }
+            CrateError::MultipleMatchingCrates(crate_name, libraries) => {
+                let mut err = struct_span_err!(
+                    sess,
+                    span,
+                    E0464,
+                    "multiple matching crates for `{}`",
+                    crate_name
+                );
+                let candidates = libraries
+                    .iter()
+                    .filter_map(|(_, lib)| {
+                        let crate_name = &lib.metadata.get_root().name().as_str();
+                        match (&lib.source.dylib, &lib.source.rlib) {
+                            (Some((pd, _)), Some((pr, _))) => Some(format!(
+                                "\ncrate `{}`: {}\n{:>padding$}",
+                                crate_name,
+                                pd.display(),
+                                pr.display(),
+                                padding = 8 + crate_name.len()
+                            )),
+                            (Some((p, _)), None) | (None, Some((p, _))) => {
+                                Some(format!("\ncrate `{}`: {}", crate_name, p.display()))
+                            }
+                            (None, None) => None,
+                        }
+                    })
+                    .collect::<String>();
+                err.note(&format!("candidates:{}", candidates));
+                err
+            }
+            CrateError::SymbolConflictsCurrent(root_name) => struct_span_err!(
+                sess,
+                span,
+                E0519,
+                "the current crate is indistinguishable from one of its dependencies: it has the \
+                 same crate-name `{}` and was compiled with the same `-C metadata` arguments. \
+                 This will result in symbol conflicts between the two.",
+                root_name,
+            ),
+            CrateError::SymbolConflictsOthers(root_name) => struct_span_err!(
+                sess,
+                span,
+                E0523,
+                "found two different crates with name `{}` that are not distinguished by differing \
+                 `-C metadata`. This will result in symbol conflicts between the two.",
+                root_name,
+            ),
+            CrateError::DlOpen(s) | CrateError::DlSym(s) => sess.struct_span_err(span, &s),
+            CrateError::LocatorCombined(locator) => {
+                let crate_name = locator.crate_name;
+                let add = match &locator.root {
+                    None => String::new(),
+                    Some(r) => format!(" which `{}` depends on", r.name),
+                };
+                let mut msg = "the following crate versions were found:".to_string();
+                let mut err = if !locator.rejected_via_hash.is_empty() {
+                    let mut err = struct_span_err!(
+                        sess,
+                        span,
+                        E0460,
+                        "found possibly newer version of crate `{}`{}",
+                        crate_name,
+                        add,
+                    );
+                    err.note("perhaps that crate needs to be recompiled?");
+                    let mismatches = locator.rejected_via_hash.iter();
+                    for CrateMismatch { path, .. } in mismatches {
+                        msg.push_str(&format!("\ncrate `{}`: {}", crate_name, path.display()));
+                    }
+                    if let Some(r) = locator.root {
+                        for path in r.source.paths() {
+                            msg.push_str(&format!("\ncrate `{}`: {}", r.name, path.display()));
+                        }
+                    }
+                    err.note(&msg);
+                    err
+                } else if !locator.rejected_via_triple.is_empty() {
+                    let mut err = struct_span_err!(
+                        sess,
+                        span,
+                        E0461,
+                        "couldn't find crate `{}` with expected target triple {}{}",
+                        crate_name,
+                        locator.triple,
+                        add,
+                    );
+                    let mismatches = locator.rejected_via_triple.iter();
+                    for CrateMismatch { path, got } in mismatches {
+                        msg.push_str(&format!(
+                            "\ncrate `{}`, target triple {}: {}",
+                            crate_name,
+                            got,
+                            path.display(),
+                        ));
+                    }
+                    err.note(&msg);
+                    err
+                } else if !locator.rejected_via_kind.is_empty() {
+                    let mut err = struct_span_err!(
+                        sess,
+                        span,
+                        E0462,
+                        "found staticlib `{}` instead of rlib or dylib{}",
+                        crate_name,
+                        add,
+                    );
+                    err.help("please recompile that crate using --crate-type lib");
+                    let mismatches = locator.rejected_via_kind.iter();
+                    for CrateMismatch { path, .. } in mismatches {
+                        msg.push_str(&format!("\ncrate `{}`: {}", crate_name, path.display()));
+                    }
+                    err.note(&msg);
+                    err
+                } else if !locator.rejected_via_version.is_empty() {
+                    let mut err = struct_span_err!(
+                        sess,
+                        span,
+                        E0514,
+                        "found crate `{}` compiled by an incompatible version of rustc{}",
+                        crate_name,
+                        add,
+                    );
+                    err.help(&format!(
+                        "please recompile that crate using this compiler ({})",
+                        rustc_version(),
+                    ));
+                    let mismatches = locator.rejected_via_version.iter();
+                    for CrateMismatch { path, got } in mismatches {
+                        msg.push_str(&format!(
+                            "\ncrate `{}` compiled by {}: {}",
+                            crate_name,
+                            got,
+                            path.display(),
+                        ));
+                    }
+                    err.note(&msg);
+                    err
+                } else {
+                    let mut err = struct_span_err!(
+                        sess,
+                        span,
+                        E0463,
+                        "can't find crate for `{}`{}",
+                        crate_name,
+                        add,
+                    );
+
+                    if (crate_name == sym::std || crate_name == sym::core)
+                        && locator.triple != TargetTriple::from_triple(config::host_triple())
+                    {
+                        err.note(&format!("the `{}` target may not be installed", locator.triple));
+                    } else if crate_name == sym::profiler_builtins {
+                        err.note(&"the compiler may have been built without the profiler runtime");
+                    }
+                    err.span_label(span, "can't find crate");
+                    err
+                };
+
+                if !locator.rejected_via_filename.is_empty() {
+                    let mismatches = locator.rejected_via_filename.iter();
+                    for CrateMismatch { path, .. } in mismatches {
+                        err.note(&format!(
+                            "extern location for {} is of an unknown type: {}",
+                            crate_name,
+                            path.display(),
+                        ))
+                        .help(&format!(
+                            "file name should be lib*.rlib or {}*.{}",
+                            locator.dll_prefix, locator.dll_suffix
+                        ));
+                    }
+                }
+                err
+            }
+            CrateError::NonDylibPlugin(crate_name) => struct_span_err!(
+                sess,
+                span,
+                E0457,
+                "plugin `{}` only found in rlib format, but must be available in dylib format",
+                crate_name,
+            ),
+        };
+
+        err.emit();
+        sess.abort_if_errors();
+        unreachable!();
+    }
+}
index 4746e53ce59a92d332b6d081423ead4462117675..a6d708ebe9048d0b24779ab8b90d676e0e9c6a00 100644 (file)
@@ -1132,6 +1132,16 @@ fn get_optimized_mir(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> Body<'tcx> {
             .decode((self, tcx))
     }
 
+    fn get_unused_generic_params(&self, id: DefIndex) -> FiniteBitSet<u64> {
+        self.root
+            .tables
+            .unused_generic_params
+            .get(self, id)
+            .filter(|_| !self.is_proc_macro(id))
+            .map(|params| params.decode(self))
+            .unwrap_or_default()
+    }
+
     fn get_promoted_mir(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> IndexVec<Promoted, Body<'tcx>> {
         self.root
             .tables
index be153758a2a0c0d0e76e2a1bb676148ef7388d2d..9160327c1d1b5e3b00b9c737a84736588f41a5db 100644 (file)
@@ -113,6 +113,7 @@ fn into_args(self) -> (DefId, DefId) {
     }
     optimized_mir => { tcx.arena.alloc(cdata.get_optimized_mir(tcx, def_id.index)) }
     promoted_mir => { tcx.arena.alloc(cdata.get_promoted_mir(tcx, def_id.index)) }
+    unused_generic_params => { cdata.get_unused_generic_params(def_id.index) }
     mir_const_qualif => { cdata.mir_const_qualif(def_id.index) }
     fn_sig => { cdata.fn_sig(def_id.index, tcx) }
     inherent_impls => { cdata.get_inherent_implementations_for_type(tcx, def_id.index) }
index a8c46d3e32e6a7fedc2ed9dd11a5bd03b00641f7..186828b6a19f6234fa0a96da047e31108170a5d8 100644 (file)
@@ -1065,6 +1065,8 @@ fn encode_optimized_mir(&mut self, def_id: LocalDefId) {
         debug!("EntryBuilder::encode_mir({:?})", def_id);
         if self.tcx.mir_keys(LOCAL_CRATE).contains(&def_id) {
             record!(self.tables.mir[def_id.to_def_id()] <- self.tcx.optimized_mir(def_id));
+            record!(self.tables.unused_generic_params[def_id.to_def_id()] <-
+                    self.tcx.unused_generic_params(def_id));
         }
     }
 
index 8abc3784d6d2f003a1cab93feffbfb0a38c3d0f7..e616e8cf00a2f5d1127b043fc1f224d5f2cc996b 100644 (file)
@@ -9,7 +9,7 @@
 use rustc_hir::def::CtorKind;
 use rustc_hir::def_id::{DefId, DefIndex};
 use rustc_hir::lang_items;
-use rustc_index::vec::IndexVec;
+use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec};
 use rustc_middle::hir::exports::Export;
 use rustc_middle::middle::cstore::{DepKind, ForeignModule, LinkagePreference, NativeLib};
 use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel};
@@ -277,6 +277,7 @@ fn encode(&self, buf: &mut Encoder) -> LazyTables<'tcx> {
     super_predicates: Table<DefIndex, Lazy!(ty::GenericPredicates<'tcx>)>,
     mir: Table<DefIndex, Lazy!(mir::Body<'tcx>)>,
     promoted_mir: Table<DefIndex, Lazy!(IndexVec<mir::Promoted, mir::Body<'tcx>>)>,
+    unused_generic_params: Table<DefIndex, Lazy<FiniteBitSet<u64>>>,
 }
 
 #[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
diff --git a/src/librustc_middle/build.rs b/src/librustc_middle/build.rs
deleted file mode 100644 (file)
index af7723a..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-use std::env;
-
-fn main() {
-    println!("cargo:rerun-if-changed=build.rs");
-    println!("cargo:rerun-if-env-changed=CFG_LIBDIR_RELATIVE");
-    println!("cargo:rerun-if-env-changed=CFG_COMPILER_HOST_TRIPLE");
-    println!("cargo:rerun-if-env-changed=RUSTC_VERIFY_LLVM_IR");
-
-    if env::var_os("RUSTC_VERIFY_LLVM_IR").is_some() {
-        println!("cargo:rustc-cfg=always_verify_llvm_ir");
-    }
-}
index a68301385b7a5b5a983609f57ce7d4057a438ebf..b7dccb8d8ce6d3ef3aab403891855949f17bae76 100644 (file)
@@ -27,7 +27,6 @@
 #![feature(bool_to_option)]
 #![feature(box_patterns)]
 #![feature(box_syntax)]
-#![feature(cmp_min_max_by)]
 #![feature(const_fn)]
 #![feature(const_panic)]
 #![feature(const_fn_transmute)]
index 54c05bca3bd2bbfac04dbc72c1b0e5422e55ef80..5f7ff54fd31c3ee5a3e329752aa59e6e19e96ad4 100644 (file)
@@ -5,7 +5,7 @@
 
 use crate::ty::{self, TyCtxt};
 use rustc_ast::ast::CRATE_NODE_ID;
-use rustc_attr::{self as attr, ConstStability, Deprecation, RustcDeprecation, Stability};
+use rustc_attr::{self as attr, ConstStability, Deprecation, Stability};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::{Applicability, DiagnosticBuilder};
 use rustc_feature::GateIssue;
@@ -130,14 +130,26 @@ pub fn report_unstable(
 
 /// Checks whether an item marked with `deprecated(since="X")` is currently
 /// deprecated (i.e., whether X is not greater than the current rustc version).
-pub fn deprecation_in_effect(since: &str) -> bool {
+pub fn deprecation_in_effect(is_since_rustc_version: bool, since: Option<&str>) -> bool {
+    let since = if let Some(since) = since {
+        if is_since_rustc_version {
+            since
+        } else {
+            // We assume that the deprecation is in effect if it's not a
+            // rustc version.
+            return true;
+        }
+    } else {
+        // If since attribute is not set, then we're definitely in effect.
+        return true;
+    };
     fn parse_version(ver: &str) -> Vec<u32> {
         // We ignore non-integer components of the version (e.g., "nightly").
         ver.split(|c| c == '.' || c == '-').flat_map(|s| s.parse()).collect()
     }
 
     if let Some(rustc) = option_env!("CFG_RELEASE") {
-        let since: Vec<u32> = parse_version(since);
+        let since: Vec<u32> = parse_version(&since);
         let rustc: Vec<u32> = parse_version(rustc);
         // We simply treat invalid `since` attributes as relating to a previous
         // Rust version, thus always displaying the warning.
@@ -167,31 +179,27 @@ pub fn deprecation_suggestion(
     }
 }
 
-fn deprecation_message_common(message: String, reason: Option<Symbol>) -> String {
-    match reason {
-        Some(reason) => format!("{}: {}", message, reason),
-        None => message,
-    }
-}
-
 pub fn deprecation_message(depr: &Deprecation, path: &str) -> (String, &'static Lint) {
-    let message = format!("use of deprecated item '{}'", path);
-    (deprecation_message_common(message, depr.note), DEPRECATED)
-}
-
-pub fn rustc_deprecation_message(depr: &RustcDeprecation, path: &str) -> (String, &'static Lint) {
-    let (message, lint) = if deprecation_in_effect(&depr.since.as_str()) {
+    let (message, lint) = if deprecation_in_effect(
+        depr.is_since_rustc_version,
+        depr.since.map(Symbol::as_str).as_deref(),
+    ) {
         (format!("use of deprecated item '{}'", path), DEPRECATED)
     } else {
         (
             format!(
                 "use of item '{}' that will be deprecated in future version {}",
-                path, depr.since
+                path,
+                depr.since.unwrap()
             ),
             DEPRECATED_IN_FUTURE,
         )
     };
-    (deprecation_message_common(message, Some(depr.reason)), lint)
+    let message = match depr.note {
+        Some(reason) => format!("{}: {}", message, reason),
+        None => message,
+    };
+    (message, lint)
 }
 
 pub fn early_report_deprecation(
@@ -289,10 +297,23 @@ pub fn eval_stability(self, def_id: DefId, id: Option<HirId>, span: Span) -> Eva
                     .lookup_deprecation_entry(parent_def_id.to_def_id())
                     .map_or(false, |parent_depr| parent_depr.same_origin(&depr_entry));
 
-                if !skip {
+                // #[deprecated] doesn't emit a notice if we're not on the
+                // topmost deprecation. For example, if a struct is deprecated,
+                // the use of a field won't be linted.
+                //
+                // #[rustc_deprecated] however wants to emit down the whole
+                // hierarchy.
+                if !skip || depr_entry.attr.is_since_rustc_version {
                     let (message, lint) =
                         deprecation_message(&depr_entry.attr, &self.def_path_str(def_id));
-                    late_report_deprecation(self, &message, None, lint, span, id);
+                    late_report_deprecation(
+                        self,
+                        &message,
+                        depr_entry.attr.suggestion,
+                        lint,
+                        span,
+                        id,
+                    );
                 }
             };
         }
@@ -310,16 +331,6 @@ pub fn eval_stability(self, def_id: DefId, id: Option<HirId>, span: Span) -> Eva
             def_id, span, stability
         );
 
-        if let Some(id) = id {
-            if let Some(stability) = stability {
-                if let Some(depr) = &stability.rustc_depr {
-                    let (message, lint) =
-                        rustc_deprecation_message(depr, &self.def_path_str(def_id));
-                    late_report_deprecation(self, &message, depr.suggestion, lint, span, id);
-                }
-            }
-        }
-
         // Only the cross-crate scenario matters when checking unstable APIs
         let cross_crate = !def_id.is_local();
         if !cross_crate {
index 327f321bd7534d8eb02ba7890bdac3b30a11cb7c..1e06dadfa24532bbc5f3651679c4c57c3b9d21c6 100644 (file)
@@ -2,9 +2,10 @@
 
 /// Positional arguments to `libcore::count_code_region()`
 pub mod count_code_region_args {
-    pub const COUNTER_INDEX: usize = 0;
-    pub const START_BYTE_POS: usize = 1;
-    pub const END_BYTE_POS: usize = 2;
+    pub const FUNCTION_SOURCE_HASH: usize = 0;
+    pub const COUNTER_INDEX: usize = 1;
+    pub const START_BYTE_POS: usize = 2;
+    pub const END_BYTE_POS: usize = 3;
 }
 
 /// Positional arguments to `libcore::coverage_counter_add()` and
index d22bde2ff8b1ed87029b88eb00f3bed6d0293a45..bb204223b60607ee9079ac6ec8da1e3e02b9d5a1 100644 (file)
@@ -86,7 +86,7 @@ pub fn instantiation_mode(&self, tcx: TyCtxt<'tcx>) -> InstantiationMode {
             .debugging_opts
             .inline_in_all_cgus
             .unwrap_or_else(|| tcx.sess.opts.optimize != OptLevel::No)
-            && !tcx.sess.opts.cg.link_dead_code;
+            && tcx.sess.opts.cg.link_dead_code != Some(true);
 
         match *self {
             MonoItem::Fn(ref instance) => {
@@ -168,7 +168,7 @@ pub fn is_instantiable(&self, tcx: TyCtxt<'tcx>) -> bool {
             MonoItem::GlobalAsm(..) => return true,
         };
 
-        tcx.substitute_normalize_and_test_predicates((def_id, &substs))
+        !tcx.subst_and_check_impossible_predicates((def_id, &substs))
     }
 
     pub fn to_string(&self, tcx: TyCtxt<'tcx>, debug: bool) -> String {
index 402a5c421a7b5ccbf97d28239e91bbf4a81a8f6a..6ce5d61fbed1b82dcd710540511f874d32e38dc0 100644 (file)
@@ -400,13 +400,11 @@ pub struct DestructuredConst<'tcx> {
 /// `InstrumentCoverage` MIR pass and can be retrieved via the `coverageinfo` query.
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
 pub struct CoverageInfo {
-    /// A hash value that can be used by the consumer of the coverage profile data to detect
-    /// changes to the instrumented source of the associated MIR body (typically, for an
-    /// individual function).
-    pub hash: u64,
-
     /// The total number of coverage region counters added to the MIR `Body`.
     pub num_counters: u32,
+
+    /// The total number of coverage region counter expressions added to the MIR `Body`.
+    pub num_expressions: u32,
 }
 
 impl<'tcx> TyCtxt<'tcx> {
index 4dd8723bd72a11d4dc4069e0c8036c41b472db8b..f857af28622d1047cd6dcbd02b60556e568d4c28 100644 (file)
@@ -103,9 +103,13 @@ fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String {
         /// // ^ While calling `opt_const_param_of` for other bodies returns `None`.
         /// }
         /// ```
+        // It looks like caching this query on disk actually slightly
+        // worsened performance in #74376.
+        //
+        // Once const generics are more prevalently used, we might want to
+        // consider only caching calls returning `Some`.
         query opt_const_param_of(key: LocalDefId) -> Option<DefId> {
             desc { |tcx| "computing the optional const parameter of `{}`", tcx.def_path_str(key.to_def_id()) }
-            // FIXME(#74113): consider storing this query on disk.
         }
 
         /// Records the type of every item.
@@ -1309,6 +1313,13 @@ fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String {
         query codegen_unit(_: Symbol) -> &'tcx CodegenUnit<'tcx> {
             desc { "codegen_unit" }
         }
+        query unused_generic_params(key: DefId) -> FiniteBitSet<u64> {
+            cache_on_disk_if { key.is_local() }
+            desc {
+                |tcx| "determining which generic parameters are unused by `{}`",
+                    tcx.def_path_str(key)
+            }
+        }
         query backend_optimization_level(_: CrateNum) -> OptLevel {
             desc { "optimization level used by backend" }
         }
@@ -1461,9 +1472,9 @@ fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String {
             desc { "normalizing `{:?}`", goal }
         }
 
-        query substitute_normalize_and_test_predicates(key: (DefId, SubstsRef<'tcx>)) -> bool {
+        query subst_and_check_impossible_predicates(key: (DefId, SubstsRef<'tcx>)) -> bool {
             desc { |tcx|
-                "testing substituted normalized predicates:`{}`",
+                "impossible substituted predicates:`{}`",
                 tcx.def_path_str(key.0)
             }
         }
index c15c31a53f0c9fefafb2f06bdf6d086e95c08488..d2747e5fc659b9efcef4b621e1d6fea8eb33f347 100644 (file)
@@ -169,6 +169,13 @@ pub fn span(&self, tcx: TyCtxt<'tcx>) -> Span {
     }
 }
 
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub struct UnifyReceiverContext<'tcx> {
+    pub assoc_item: ty::AssocItem,
+    pub param_env: ty::ParamEnv<'tcx>,
+    pub substs: SubstsRef<'tcx>,
+}
+
 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
 pub enum ObligationCauseCode<'tcx> {
     /// Not well classified or should be obvious from the span.
@@ -300,6 +307,8 @@ pub enum ObligationCauseCode<'tcx> {
     /// Method receiver
     MethodReceiver,
 
+    UnifyReceiver(Box<UnifyReceiverContext<'tcx>>),
+
     /// `return` with no expression
     ReturnNoExpression,
 
index f4961617b81c6e8365a4ee6ec6be635b19c5ba7b..c9aae8980076f1a81c3446a03b2d88b0c04fbb91 100644 (file)
@@ -1,5 +1,6 @@
 use crate::ich::{self, StableHashingContext};
 use crate::ty::fast_reject::SimplifiedType;
+use crate::ty::fold::TypeFoldable;
 use crate::ty::{self, TyCtxt};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
@@ -226,7 +227,8 @@ pub fn ancestors(
     start_from_impl: DefId,
 ) -> Result<Ancestors<'tcx>, ErrorReported> {
     let specialization_graph = tcx.specialization_graph_of(trait_def_id);
-    if specialization_graph.has_errored {
+
+    if specialization_graph.has_errored || tcx.type_of(start_from_impl).references_error() {
         Err(ErrorReported)
     } else {
         Ok(Ancestors {
index 334462790edbcc5a2f03c2de543fcdf9148d0065..18b4371053a89c77b3340161b2eaab7cefaa92c2 100644 (file)
@@ -213,12 +213,26 @@ fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
             super::StartFunctionType => Some(super::StartFunctionType),
             super::IntrinsicType => Some(super::IntrinsicType),
             super::MethodReceiver => Some(super::MethodReceiver),
+            super::UnifyReceiver(ref ctxt) => tcx.lift(ctxt).map(|ctxt| super::UnifyReceiver(ctxt)),
             super::BlockTailExpression(id) => Some(super::BlockTailExpression(id)),
             super::TrivialBound => Some(super::TrivialBound),
         }
     }
 }
 
+impl<'a, 'tcx> Lift<'tcx> for traits::UnifyReceiverContext<'a> {
+    type Lifted = traits::UnifyReceiverContext<'tcx>;
+    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+        tcx.lift(&self.param_env).and_then(|param_env| {
+            tcx.lift(&self.substs).map(|substs| traits::UnifyReceiverContext {
+                assoc_item: self.assoc_item,
+                param_env,
+                substs,
+            })
+        })
+    }
+}
+
 impl<'a, 'tcx> Lift<'tcx> for traits::DerivedObligationCause<'a> {
     type Lifted = traits::DerivedObligationCause<'tcx>;
     fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
index 0e86fcf53b247e0d460ab171e3ab18d45e5f73d5..11a8bedb6605bf6caa3de7fd23e818806f244f72 100644 (file)
@@ -85,7 +85,19 @@ fn add_kind(&mut self, kind: &ty::TyKind<'_>) {
             }
 
             &ty::Generator(_, ref substs, _) => {
-                self.add_substs(substs);
+                let substs = substs.as_generator();
+                let should_remove_further_specializable =
+                    !self.flags.contains(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
+                self.add_substs(substs.parent_substs());
+                if should_remove_further_specializable {
+                    self.flags -= TypeFlags::STILL_FURTHER_SPECIALIZABLE;
+                }
+
+                self.add_ty(substs.resume_ty());
+                self.add_ty(substs.return_ty());
+                self.add_ty(substs.witness());
+                self.add_ty(substs.yield_ty());
+                self.add_ty(substs.tupled_upvars_ty());
             }
 
             &ty::GeneratorWitness(ts) => {
@@ -95,7 +107,17 @@ fn add_kind(&mut self, kind: &ty::TyKind<'_>) {
             }
 
             &ty::Closure(_, substs) => {
-                self.add_substs(substs);
+                let substs = substs.as_closure();
+                let should_remove_further_specializable =
+                    !self.flags.contains(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
+                self.add_substs(substs.parent_substs());
+                if should_remove_further_specializable {
+                    self.flags -= TypeFlags::STILL_FURTHER_SPECIALIZABLE;
+                }
+
+                self.add_ty(substs.sig_as_fn_ptr_ty());
+                self.add_ty(substs.kind_ty());
+                self.add_ty(substs.tupled_upvars_ty());
             }
 
             &ty::Bound(debruijn, _) => {
index f627d05d3e9d28686f2265301a82f55d87120797..cdb883da32bb0314eb85fc314e47e3dbb2d24399 100644 (file)
@@ -1,5 +1,6 @@
 use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use crate::ty::print::{FmtPrinter, Printer};
+use crate::ty::subst::InternalSubsts;
 use crate::ty::{self, SubstsRef, Ty, TyCtxt, TypeFoldable};
 use rustc_errors::ErrorReported;
 use rustc_hir::def::Namespace;
@@ -106,32 +107,9 @@ pub enum InstanceDef<'tcx> {
 }
 
 impl<'tcx> Instance<'tcx> {
-    /// Returns the `Ty` corresponding to this `Instance`,
-    /// with generic substitutions applied and lifetimes erased.
-    ///
-    /// This method can only be called when the 'substs' for this Instance
-    /// are fully monomorphic (no `ty::Param`'s are present).
-    /// This is usually the case (e.g. during codegen).
-    /// However, during constant evaluation, we may want
-    /// to try to resolve a `Instance` using generic parameters
-    /// (e.g. when we are attempting to to do const-propagation).
-    /// In this case, `Instance.ty_env` should be used to provide
-    /// the `ParamEnv` for our generic context.
-    pub fn monomorphic_ty(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
-        let ty = tcx.type_of(self.def.def_id());
-        // There shouldn't be any params - if there are, then
-        // Instance.ty_env should have been used to provide the proper
-        // ParamEnv
-        if self.substs.has_param_types_or_consts() {
-            bug!("Instance.ty called for type {:?} with params in substs: {:?}", ty, self.substs);
-        }
-        tcx.subst_and_normalize_erasing_regions(self.substs, ty::ParamEnv::reveal_all(), &ty)
-    }
-
-    /// Like `Instance.ty`, but allows a `ParamEnv` to be specified for use during
-    /// normalization. This method is only really useful during constant evaluation,
-    /// where we are dealing with potentially generic types.
-    pub fn ty_env(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Ty<'tcx> {
+    /// Returns the `Ty` corresponding to this `Instance`, with generic substitutions applied and
+    /// lifetimes erased, allowing a `ParamEnv` to be specified for use during normalization.
+    pub fn ty(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Ty<'tcx> {
         let ty = tcx.type_of(self.def.def_id());
         tcx.subst_and_normalize_erasing_regions(self.substs, param_env, &ty)
     }
@@ -486,6 +464,42 @@ pub fn substs_for_mir_body(&self) -> Option<SubstsRef<'tcx>> {
             | InstanceDef::VtableShim(..) => Some(self.substs),
         }
     }
+
+    /// Returns a new `Instance` where generic parameters in `instance.substs` are replaced by
+    /// identify parameters if they are determined to be unused in `instance.def`.
+    pub fn polymorphize(self, tcx: TyCtxt<'tcx>) -> Self {
+        debug!("polymorphize: running polymorphization analysis");
+        if !tcx.sess.opts.debugging_opts.polymorphize {
+            return self;
+        }
+
+        if let InstanceDef::Item(def) = self.def {
+            let unused = tcx.unused_generic_params(def.did);
+
+            if unused.is_empty() {
+                // Exit early if every parameter was used.
+                return self;
+            }
+
+            debug!("polymorphize: unused={:?}", unused);
+            let polymorphized_substs =
+                InternalSubsts::for_item(tcx, def.did, |param, _| match param.kind {
+                // If parameter is a const or type parameter..
+                ty::GenericParamDefKind::Const | ty::GenericParamDefKind::Type { .. } if
+                    // ..and is within range and unused..
+                    unused.contains(param.index).unwrap_or(false) =>
+                        // ..then use the identity for this parameter.
+                        tcx.mk_param_from_def(param),
+                // Otherwise, use the parameter as before.
+                _ => self.substs[param.index as usize],
+            });
+
+            debug!("polymorphize: self={:?} polymorphized_substs={:?}", self, polymorphized_substs);
+            Self { def: self.def, substs: polymorphized_substs }
+        } else {
+            self
+        }
+    }
 }
 
 fn needs_fn_once_adapter_shim(
index 8ae9269a6bf684e566ee2fa0ef27c98f4758ac4a..215f44819b5d144996f2d8e20c289fffca4fb009 100644 (file)
@@ -876,8 +876,6 @@ fn layout_raw_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<
                     .iter_enumerated()
                     .all(|(i, v)| v.discr == ty::VariantDiscr::Relative(i.as_u32()));
 
-                let mut niche_filling_layout = None;
-
                 // Niche-filling enum optimization.
                 if !def.repr.inhibit_enum_layout_opt() && no_explicit_discriminants {
                     let mut dataful_variant = None;
@@ -974,7 +972,7 @@ fn layout_raw_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<
                             let largest_niche =
                                 Niche::from_scalar(dl, offset, niche_scalar.clone());
 
-                            niche_filling_layout = Some(Layout {
+                            return Ok(tcx.intern_layout(Layout {
                                 variants: Variants::Multiple {
                                     tag: niche_scalar,
                                     tag_encoding: TagEncoding::Niche {
@@ -993,7 +991,7 @@ fn layout_raw_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<
                                 largest_niche,
                                 size,
                                 align,
-                            });
+                            }));
                         }
                     }
                 }
@@ -1216,7 +1214,7 @@ fn layout_raw_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<
 
                 let largest_niche = Niche::from_scalar(dl, Size::ZERO, tag.clone());
 
-                let tagged_layout = Layout {
+                tcx.intern_layout(Layout {
                     variants: Variants::Multiple {
                         tag,
                         tag_encoding: TagEncoding::Direct,
@@ -1231,23 +1229,7 @@ fn layout_raw_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<
                     abi,
                     align,
                     size,
-                };
-
-                let best_layout = match (tagged_layout, niche_filling_layout) {
-                    (tagged_layout, Some(niche_filling_layout)) => {
-                        // Pick the smaller layout; otherwise,
-                        // pick the layout with the larger niche; otherwise,
-                        // pick tagged as it has simpler codegen.
-                        cmp::min_by_key(tagged_layout, niche_filling_layout, |layout| {
-                            let niche_size =
-                                layout.largest_niche.as_ref().map_or(0, |n| n.available(dl));
-                            (layout.size, cmp::Reverse(niche_size))
-                        })
-                    }
-                    (tagged_layout, None) => tagged_layout,
-                };
-
-                tcx.intern_layout(best_layout)
+                })
             }
 
             // Types with no meaningful known layout.
@@ -2166,16 +2148,31 @@ fn field(this: TyAndLayout<'tcx>, cx: &C, i: usize) -> C::TyAndLayout {
     }
 
     fn pointee_info_at(this: TyAndLayout<'tcx>, cx: &C, offset: Size) -> Option<PointeeInfo> {
-        match this.ty.kind {
+        let addr_space_of_ty = |ty: Ty<'tcx>| {
+            if ty.is_fn() { cx.data_layout().instruction_address_space } else { AddressSpace::DATA }
+        };
+
+        let pointee_info = match this.ty.kind {
             ty::RawPtr(mt) if offset.bytes() == 0 => {
                 cx.layout_of(mt.ty).to_result().ok().map(|layout| PointeeInfo {
                     size: layout.size,
                     align: layout.align.abi,
                     safe: None,
+                    address_space: addr_space_of_ty(mt.ty),
+                })
+            }
+            ty::FnPtr(fn_sig) if offset.bytes() == 0 => {
+                cx.layout_of(cx.tcx().mk_fn_ptr(fn_sig)).to_result().ok().map(|layout| {
+                    PointeeInfo {
+                        size: layout.size,
+                        align: layout.align.abi,
+                        safe: None,
+                        address_space: cx.data_layout().instruction_address_space,
+                    }
                 })
             }
-
             ty::Ref(_, ty, mt) if offset.bytes() == 0 => {
+                let address_space = addr_space_of_ty(ty);
                 let tcx = cx.tcx();
                 let is_freeze = ty.is_freeze(tcx.at(DUMMY_SP), cx.param_env());
                 let kind = match mt {
@@ -2210,6 +2207,7 @@ fn pointee_info_at(this: TyAndLayout<'tcx>, cx: &C, offset: Size) -> Option<Poin
                     size: layout.size,
                     align: layout.align.abi,
                     safe: Some(kind),
+                    address_space,
                 })
             }
 
@@ -2254,7 +2252,9 @@ fn pointee_info_at(this: TyAndLayout<'tcx>, cx: &C, offset: Size) -> Option<Poin
                             result = field.to_result().ok().and_then(|field| {
                                 if ptr_end <= field_start + field.size {
                                     // We found the right field, look inside it.
-                                    field.pointee_info_at(cx, offset - field_start)
+                                    let field_info =
+                                        field.pointee_info_at(cx, offset - field_start);
+                                    field_info
                                 } else {
                                     None
                                 }
@@ -2277,7 +2277,14 @@ fn pointee_info_at(this: TyAndLayout<'tcx>, cx: &C, offset: Size) -> Option<Poin
 
                 result
             }
-        }
+        };
+
+        debug!(
+            "pointee_info_at (offset={:?}, type kind: {:?}) => {:?}",
+            offset, this.ty.kind, pointee_info
+        );
+
+        pointee_info
     }
 }
 
@@ -2299,12 +2306,22 @@ impl<'tcx> ty::Instance<'tcx> {
     // or should go through `FnAbi` instead, to avoid losing any
     // adjustments `FnAbi::of_instance` might be performing.
     fn fn_sig_for_fn_abi(&self, tcx: TyCtxt<'tcx>) -> ty::PolyFnSig<'tcx> {
-        let ty = self.monomorphic_ty(tcx);
+        // FIXME(davidtwco,eddyb): A `ParamEnv` should be passed through to this function.
+        let ty = self.ty(tcx, ty::ParamEnv::reveal_all());
         match ty.kind {
-            ty::FnDef(..) |
-            // Shims currently have type FnPtr. Not sure this should remain.
-            ty::FnPtr(_) => {
-                let mut sig = ty.fn_sig(tcx);
+            ty::FnDef(..) => {
+                // HACK(davidtwco,eddyb): This is a workaround for polymorphization considering
+                // parameters unused if they show up in the signature, but not in the `mir::Body`
+                // (i.e. due to being inside a projection that got normalized, see
+                // `src/test/ui/polymorphization/normalized_sig_types.rs`), and codegen not keeping
+                // track of a polymorphization `ParamEnv` to allow normalizing later.
+                let mut sig = match ty.kind {
+                    ty::FnDef(def_id, substs) => tcx
+                        .normalize_erasing_regions(tcx.param_env(def_id), tcx.fn_sig(def_id))
+                        .subst(tcx, substs),
+                    _ => unreachable!(),
+                };
+
                 if let ty::InstanceDef::VtableShim(..) = self.def {
                     // Modify `fn(self, ...)` to `fn(self: *mut Self, ...)`.
                     sig = sig.map_bound(|mut sig| {
@@ -2320,13 +2337,15 @@ fn fn_sig_for_fn_abi(&self, tcx: TyCtxt<'tcx>) -> ty::PolyFnSig<'tcx> {
                 let sig = substs.as_closure().sig();
 
                 let env_ty = tcx.closure_env_ty(def_id, substs).unwrap();
-                sig.map_bound(|sig| tcx.mk_fn_sig(
-                    iter::once(env_ty.skip_binder()).chain(sig.inputs().iter().cloned()),
-                    sig.output(),
-                    sig.c_variadic,
-                    sig.unsafety,
-                    sig.abi
-                ))
+                sig.map_bound(|sig| {
+                    tcx.mk_fn_sig(
+                        iter::once(env_ty.skip_binder()).chain(sig.inputs().iter().cloned()),
+                        sig.output(),
+                        sig.c_variadic,
+                        sig.unsafety,
+                        sig.abi,
+                    )
+                })
             }
             ty::Generator(_, substs, _) => {
                 let sig = substs.as_generator().poly_sig();
@@ -2342,10 +2361,8 @@ fn fn_sig_for_fn_abi(&self, tcx: TyCtxt<'tcx>) -> ty::PolyFnSig<'tcx> {
                 sig.map_bound(|sig| {
                     let state_did = tcx.require_lang_item(GeneratorStateLangItem, None);
                     let state_adt_ref = tcx.adt_def(state_did);
-                    let state_substs = tcx.intern_substs(&[
-                        sig.yield_ty.into(),
-                        sig.return_ty.into(),
-                    ]);
+                    let state_substs =
+                        tcx.intern_substs(&[sig.yield_ty.into(), sig.return_ty.into()]);
                     let ret_ty = tcx.mk_adt(state_adt_ref, state_substs);
 
                     tcx.mk_fn_sig(
@@ -2353,11 +2370,11 @@ fn fn_sig_for_fn_abi(&self, tcx: TyCtxt<'tcx>) -> ty::PolyFnSig<'tcx> {
                         &ret_ty,
                         false,
                         hir::Unsafety::Normal,
-                        rustc_target::spec::abi::Abi::Rust
+                        rustc_target::spec::abi::Abi::Rust,
                     )
                 })
             }
-            _ => bug!("unexpected type {:?} in Instance::fn_sig", ty)
+            _ => bug!("unexpected type {:?} in Instance::fn_sig", ty),
         }
     }
 }
index 21745977b04b1b805b9f84db86653b68ae05c486..a5ddcdfdb0408b8767ef0c75c4534ab44a55b85a 100644 (file)
@@ -136,7 +136,7 @@ pub struct ResolverOutputs {
     pub extern_prelude: FxHashMap<Symbol, bool>,
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable)]
+#[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable, Hash)]
 pub enum AssocItemContainer {
     TraitContainer(DefId),
     ImplContainer(DefId),
@@ -184,7 +184,7 @@ pub enum ImplPolarity {
     Reservation,
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, HashStable)]
+#[derive(Copy, Clone, Debug, PartialEq, HashStable, Eq, Hash)]
 pub struct AssocItem {
     pub def_id: DefId,
     #[stable_hasher(project(name))]
@@ -199,7 +199,7 @@ pub struct AssocItem {
     pub fn_has_self_parameter: bool,
 }
 
-#[derive(Copy, Clone, PartialEq, Debug, HashStable)]
+#[derive(Copy, Clone, PartialEq, Debug, HashStable, Eq, Hash)]
 pub enum AssocKind {
     Const,
     Fn,
@@ -316,7 +316,7 @@ pub fn find_by_name_and_namespace(
     }
 }
 
-#[derive(Clone, Debug, PartialEq, Eq, Copy, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Clone, Debug, PartialEq, Eq, Copy, RustcEncodable, RustcDecodable, HashStable, Hash)]
 pub enum Visibility {
     /// Visible everywhere (including in other crates).
     Public,
@@ -890,6 +890,7 @@ pub fn own_requires_monomorphization(&self) -> bool {
         false
     }
 
+    /// Returns the `GenericParamDef` with the given index.
     pub fn param_at(&'tcx self, param_index: usize, tcx: TyCtxt<'tcx>) -> &'tcx GenericParamDef {
         if let Some(index) = param_index.checked_sub(self.parent_count) {
             &self.params[index]
@@ -899,6 +900,7 @@ pub fn param_at(&'tcx self, param_index: usize, tcx: TyCtxt<'tcx>) -> &'tcx Gene
         }
     }
 
+    /// Returns the `GenericParamDef` associated with this `EarlyBoundRegion`.
     pub fn region_param(
         &'tcx self,
         param: &EarlyBoundRegion,
@@ -920,7 +922,7 @@ pub fn type_param(&'tcx self, param: &ParamTy, tcx: TyCtxt<'tcx>) -> &'tcx Gener
         }
     }
 
-    /// Returns the `ConstParameterDef` associated with this `ParamConst`.
+    /// Returns the `GenericParamDef` associated with this `ParamConst`.
     pub fn const_param(&'tcx self, param: &ParamConst, tcx: TyCtxt<'tcx>) -> &GenericParamDef {
         let param = self.param_at(param.index as usize, tcx);
         match param.kind {
@@ -1615,12 +1617,33 @@ pub struct WithOptConstParam<T> {
 
 impl<T> WithOptConstParam<T> {
     /// Creates a new `WithOptConstParam` setting `const_param_did` to `None`.
+    #[inline(always)]
     pub fn unknown(did: T) -> WithOptConstParam<T> {
         WithOptConstParam { did, const_param_did: None }
     }
 }
 
 impl WithOptConstParam<LocalDefId> {
+    /// Returns `Some((did, param_did))` if `def_id` is a const argument,
+    /// `None` otherwise.
+    #[inline(always)]
+    pub fn try_lookup(did: LocalDefId, tcx: TyCtxt<'_>) -> Option<(LocalDefId, DefId)> {
+        tcx.opt_const_param_of(did).map(|param_did| (did, param_did))
+    }
+
+    /// In case `self` is unknown but `self.did` is a const argument, this returns
+    /// a `WithOptConstParam` with the correct `const_param_did`.
+    #[inline(always)]
+    pub fn try_upgrade(self, tcx: TyCtxt<'_>) -> Option<WithOptConstParam<LocalDefId>> {
+        if self.const_param_did.is_none() {
+            if let const_param_did @ Some(_) = tcx.opt_const_param_of(self.did) {
+                return Some(WithOptConstParam { did: self.did, const_param_did });
+            }
+        }
+
+        None
+    }
+
     pub fn to_global(self) -> WithOptConstParam<DefId> {
         WithOptConstParam { did: self.did.to_def_id(), const_param_did: self.const_param_did }
     }
index 2f0a57c59eb14abc0d8672ca7b9ee5f19be510ce..48a62b64604672f59770171ef7b0db34ae17aef5 100644 (file)
@@ -54,7 +54,6 @@ pub fn normalize_erasing_late_bound_regions<T>(
     where
         T: TypeFoldable<'tcx>,
     {
-        assert!(!value.needs_subst());
         let value = self.erase_late_bound_regions(value);
         self.normalize_erasing_regions(param_env, value)
     }
index 67b6433b6114327e31737dd164bc38d72d1253a5..2ea7cd2a6dc7acb118d8d104ed771bd83515132a 100644 (file)
@@ -144,12 +144,14 @@ pub fn push_type_name(&self, t: Ty<'tcx>, output: &mut String, debug: bool) {
                 let substs = substs.truncate_to(self.tcx, generics);
                 self.push_generic_params(substs, iter::empty(), output, debug);
             }
+            ty::Param(_) => {
+                output.push_str(&t.to_string());
+            }
             ty::Error(_)
             | ty::Bound(..)
             | ty::Infer(_)
             | ty::Placeholder(..)
             | ty::Projection(..)
-            | ty::Param(_)
             | ty::GeneratorWitness(_)
             | ty::Opaque(..) => {
                 if debug {
index 2ad49b1acce435c9ad1cac9f11bda2cdf60e0730..2f7a9aee536d84593461e77df6956f118f276b1a 100644 (file)
@@ -44,7 +44,7 @@
 use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId};
 use rustc_hir::lang_items::{LangItem, LanguageItems};
 use rustc_hir::{Crate, HirIdSet, ItemLocalId, TraitCandidate};
-use rustc_index::vec::IndexVec;
+use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec};
 use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion};
 use rustc_session::utils::NativeLibKind;
 use rustc_session::CrateDisambiguator;
index 2f17db6223362229db7180ba80a4e98efd8787ca..03bf51c95c5a3d7d2a0ecb3beec2f190de0ebab0 100644 (file)
@@ -318,6 +318,7 @@ pub struct ClosureSubsts<'tcx> {
 /// Struct returned by `split()`. Note that these are subslices of the
 /// parent slice and not canonical substs themselves.
 struct SplitClosureSubsts<'tcx> {
+    parent: &'tcx [GenericArg<'tcx>],
     closure_kind_ty: GenericArg<'tcx>,
     closure_sig_as_fn_ptr_ty: GenericArg<'tcx>,
     tupled_upvars_ty: GenericArg<'tcx>,
@@ -329,8 +330,13 @@ impl<'tcx> ClosureSubsts<'tcx> {
     /// ordering.
     fn split(self) -> SplitClosureSubsts<'tcx> {
         match self.substs[..] {
-            [.., closure_kind_ty, closure_sig_as_fn_ptr_ty, tupled_upvars_ty] => {
-                SplitClosureSubsts { closure_kind_ty, closure_sig_as_fn_ptr_ty, tupled_upvars_ty }
+            [ref parent @ .., closure_kind_ty, closure_sig_as_fn_ptr_ty, tupled_upvars_ty] => {
+                SplitClosureSubsts {
+                    parent,
+                    closure_kind_ty,
+                    closure_sig_as_fn_ptr_ty,
+                    tupled_upvars_ty,
+                }
             }
             _ => bug!("closure substs missing synthetics"),
         }
@@ -345,9 +351,20 @@ pub fn is_valid(self) -> bool {
         self.substs.len() >= 3 && matches!(self.split().tupled_upvars_ty.expect_ty().kind, Tuple(_))
     }
 
+    /// Returns the substitutions of the closure's parent.
+    pub fn parent_substs(self) -> &'tcx [GenericArg<'tcx>] {
+        self.split().parent
+    }
+
     #[inline]
     pub fn upvar_tys(self) -> impl Iterator<Item = Ty<'tcx>> + 'tcx {
-        self.split().tupled_upvars_ty.expect_ty().tuple_fields()
+        self.tupled_upvars_ty().tuple_fields()
+    }
+
+    /// Returns the tuple type representing the upvars for this closure.
+    #[inline]
+    pub fn tupled_upvars_ty(self) -> Ty<'tcx> {
+        self.split().tupled_upvars_ty.expect_ty()
     }
 
     /// Returns the closure kind for this closure; may return a type
@@ -392,6 +409,7 @@ pub struct GeneratorSubsts<'tcx> {
 }
 
 struct SplitGeneratorSubsts<'tcx> {
+    parent: &'tcx [GenericArg<'tcx>],
     resume_ty: GenericArg<'tcx>,
     yield_ty: GenericArg<'tcx>,
     return_ty: GenericArg<'tcx>,
@@ -402,8 +420,15 @@ struct SplitGeneratorSubsts<'tcx> {
 impl<'tcx> GeneratorSubsts<'tcx> {
     fn split(self) -> SplitGeneratorSubsts<'tcx> {
         match self.substs[..] {
-            [.., resume_ty, yield_ty, return_ty, witness, tupled_upvars_ty] => {
-                SplitGeneratorSubsts { resume_ty, yield_ty, return_ty, witness, tupled_upvars_ty }
+            [ref parent @ .., resume_ty, yield_ty, return_ty, witness, tupled_upvars_ty] => {
+                SplitGeneratorSubsts {
+                    parent,
+                    resume_ty,
+                    yield_ty,
+                    return_ty,
+                    witness,
+                    tupled_upvars_ty,
+                }
             }
             _ => bug!("generator substs missing synthetics"),
         }
@@ -418,6 +443,11 @@ pub fn is_valid(self) -> bool {
         self.substs.len() >= 5 && matches!(self.split().tupled_upvars_ty.expect_ty().kind, Tuple(_))
     }
 
+    /// Returns the substitutions of the generator's parent.
+    pub fn parent_substs(self) -> &'tcx [GenericArg<'tcx>] {
+        self.split().parent
+    }
+
     /// This describes the types that can be contained in a generator.
     /// It will be a type variable initially and unified in the last stages of typeck of a body.
     /// It contains a tuple of all the types that could end up on a generator frame.
@@ -429,7 +459,13 @@ pub fn witness(self) -> Ty<'tcx> {
 
     #[inline]
     pub fn upvar_tys(self) -> impl Iterator<Item = Ty<'tcx>> + 'tcx {
-        self.split().tupled_upvars_ty.expect_ty().tuple_fields()
+        self.tupled_upvars_ty().tuple_fields()
+    }
+
+    /// Returns the tuple type representing the upvars for this generator.
+    #[inline]
+    pub fn tupled_upvars_ty(self) -> Ty<'tcx> {
+        self.split().tupled_upvars_ty.expect_ty()
     }
 
     /// Returns the type representing the resume type of the generator.
index 1972b7149d569fb42a1066dd06eefe71129099a8..76cc03fa60909ba58b605fa105b6928bac3a6ea0 100644 (file)
 
 pub fn provide(providers: &mut Providers) {
     *providers = Providers {
-        mir_borrowck: |tcx, did| mir_borrowck(tcx, ty::WithOptConstParam::unknown(did)),
+        mir_borrowck: |tcx, did| {
+            if let Some(def) = ty::WithOptConstParam::try_lookup(did, tcx) {
+                tcx.mir_borrowck_const_arg(def)
+            } else {
+                mir_borrowck(tcx, ty::WithOptConstParam::unknown(did))
+            }
+        },
         mir_borrowck_const_arg: |tcx, (did, param_did)| {
             mir_borrowck(tcx, ty::WithOptConstParam { did, const_param_did: Some(param_did) })
         },
@@ -100,12 +106,6 @@ fn mir_borrowck<'tcx>(
     tcx: TyCtxt<'tcx>,
     def: ty::WithOptConstParam<LocalDefId>,
 ) -> &'tcx BorrowCheckResult<'tcx> {
-    if def.const_param_did.is_none() {
-        if let Some(param_did) = tcx.opt_const_param_of(def.did) {
-            return tcx.mir_borrowck_const_arg((def.did, param_did));
-        }
-    }
-
     let (input_body, promoted) = tcx.mir_validated(def);
     debug!("run query mir_borrowck: {}", tcx.def_path_str(def.did.to_def_id()));
 
index dc3e01f3d156128793a69a789b1b25c187fb4bac..705a1b2ae79e52cda180e97db0cd547a5f245729 100644 (file)
@@ -240,7 +240,7 @@ pub fn const_eval_validated_provider<'tcx>(
     // We call `const_eval` for zero arg intrinsics, too, in order to cache their value.
     // Catch such calls and evaluate them instead of trying to load a constant's MIR.
     if let ty::InstanceDef::Intrinsic(def_id) = key.value.instance.def {
-        let ty = key.value.instance.ty_env(tcx, key.param_env);
+        let ty = key.value.instance.ty(tcx, key.param_env);
         let substs = match ty.kind {
             ty::FnDef(_, substs) => substs,
             _ => bug!("intrinsic with type {:?}", ty),
index 851862640226f5a2b303c135b83ba000a93c144c..29549041d258cc285d8db7e636da3e5638a22f31 100644 (file)
@@ -12,7 +12,7 @@
 };
 use rustc_middle::ty;
 use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{Ty, TyCtxt};
+use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable};
 use rustc_span::symbol::{sym, Symbol};
 use rustc_target::abi::{Abi, LayoutOf as _, Primitive, Size};
 
@@ -54,6 +54,9 @@ fn numeric_intrinsic<'tcx, Tag>(
     let name = tcx.item_name(def_id);
     Ok(match name {
         sym::type_name => {
+            if tp_ty.needs_subst() {
+                throw_inval!(TooGeneric);
+            }
             let alloc = type_name::alloc_type_name(tcx, tp_ty);
             ConstValue::Slice { data: alloc, start: 0, end: alloc.len() }
         }
@@ -68,7 +71,12 @@ fn numeric_intrinsic<'tcx, Tag>(
             };
             ConstValue::from_machine_usize(n, &tcx)
         }
-        sym::type_id => ConstValue::from_u64(tcx.type_id_hash(tp_ty)),
+        sym::type_id => {
+            if tp_ty.needs_subst() {
+                throw_inval!(TooGeneric);
+            }
+            ConstValue::from_u64(tcx.type_id_hash(tp_ty))
+        }
         sym::variant_count => {
             if let ty::Adt(ref adt, _) = tp_ty.kind {
                 ConstValue::from_machine_usize(adt.variants.len() as u64, &tcx)
@@ -95,6 +103,7 @@ pub fn emulate_intrinsic(
         let (dest, ret) = match ret {
             None => match intrinsic_name {
                 sym::transmute => throw_ub_format!("transmuting to uninhabited type"),
+                sym::unreachable => throw_ub!(Unreachable),
                 sym::abort => M::abort(self)?,
                 // Unsupported diverging intrinsic.
                 _ => return Ok(false),
index 4681079a22ddf4f3ef7abca68251054098c2ed30..663f61b11554c4c384bff82cdb64275c59ec55db 100644 (file)
@@ -221,7 +221,7 @@ fn eval_fn_call(
         // ABI check
         {
             let callee_abi = {
-                let instance_ty = instance.ty_env(*self.tcx, self.param_env);
+                let instance_ty = instance.ty(*self.tcx, self.param_env);
                 match instance_ty.kind {
                     ty::FnDef(..) => instance_ty.fn_sig(*self.tcx).abi(),
                     ty::Closure(..) => Abi::RustCall,
index a1d124bb7602ebb1408107d5840e90e073e56fbb..49a80ca13457ddb24c042744ca6702bfa50f73ce 100644 (file)
@@ -142,7 +142,7 @@ pub fn read_drop_type_from_vtable(
         // to determine the type.
         let drop_instance = self.memory.get_fn(drop_fn)?.as_instance()?;
         trace!("Found drop fn: {:?}", drop_instance);
-        let fn_sig = drop_instance.ty_env(*self.tcx, self.param_env).fn_sig(*self.tcx);
+        let fn_sig = drop_instance.ty(*self.tcx, self.param_env).fn_sig(*self.tcx);
         let fn_sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, &fn_sig);
         // The drop function takes `*mut T` where `T` is the type being dropped, so get that.
         let args = fn_sig.inputs();
index cd6c38997f18f6a7d843214aad8d2e2c00af0a81..4e7142a93aedc7c20afbe97eca387192d3764f88 100644 (file)
@@ -51,6 +51,7 @@ pub fn provide(providers: &mut Providers) {
     shim::provide(providers);
     transform::provide(providers);
     monomorphize::partitioning::provide(providers);
+    monomorphize::polymorphize::provide(providers);
     providers.const_eval_validated = const_eval::const_eval_validated_provider;
     providers.const_eval_raw = const_eval::const_eval_raw_provider;
     providers.const_caller_location = const_eval::const_caller_location;
index 35fb950ce66b9397eeb632da6c2dd240f9d07184..e724180f4d833d588c199cc4bdf46bab1c681410 100644 (file)
@@ -358,9 +358,9 @@ fn collect_items_rec<'tcx>(
             let instance = Instance::mono(tcx, def_id);
 
             // Sanity check whether this ended up being collected accidentally
-            debug_assert!(should_monomorphize_locally(tcx, &instance));
+            debug_assert!(should_codegen_locally(tcx, &instance));
 
-            let ty = instance.monomorphic_ty(tcx);
+            let ty = instance.ty(tcx, ty::ParamEnv::reveal_all());
             visit_drop_use(tcx, ty, true, starting_point.span, &mut neighbors);
 
             recursion_depth_reset = None;
@@ -371,7 +371,7 @@ fn collect_items_rec<'tcx>(
         }
         MonoItem::Fn(instance) => {
             // Sanity check whether this ended up being collected accidentally
-            debug_assert!(should_monomorphize_locally(tcx, &instance));
+            debug_assert!(should_codegen_locally(tcx, &instance));
 
             // Keep track of the monomorphization recursion depth
             recursion_depth_reset =
@@ -584,8 +584,8 @@ fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
                             substs,
                             ty::ClosureKind::FnOnce,
                         );
-                        if should_monomorphize_locally(self.tcx, &instance) {
-                            self.output.push(create_fn_mono_item(instance, span));
+                        if should_codegen_locally(self.tcx, &instance) {
+                            self.output.push(create_fn_mono_item(self.tcx, instance, span));
                         }
                     }
                     _ => bug!(),
@@ -596,14 +596,14 @@ fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
                 let exchange_malloc_fn_def_id =
                     tcx.require_lang_item(ExchangeMallocFnLangItem, None);
                 let instance = Instance::mono(tcx, exchange_malloc_fn_def_id);
-                if should_monomorphize_locally(tcx, &instance) {
-                    self.output.push(create_fn_mono_item(instance, span));
+                if should_codegen_locally(tcx, &instance) {
+                    self.output.push(create_fn_mono_item(self.tcx, instance, span));
                 }
             }
             mir::Rvalue::ThreadLocalRef(def_id) => {
                 assert!(self.tcx.is_thread_local_static(def_id));
                 let instance = Instance::mono(self.tcx, def_id);
-                if should_monomorphize_locally(self.tcx, &instance) {
+                if should_codegen_locally(self.tcx, &instance) {
                     trace!("collecting thread-local static {:?}", def_id);
                     self.output.push(respan(span, MonoItem::Static(def_id)));
                 }
@@ -627,8 +627,9 @@ fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, location: Location)
                     Ok(val) => collect_const_value(self.tcx, val, self.output),
                     Err(ErrorHandled::Reported(ErrorReported) | ErrorHandled::Linted) => {}
                     Err(ErrorHandled::TooGeneric) => span_bug!(
-                        self.tcx.def_span(def.did),
-                        "collection encountered polymorphic constant",
+                        self.body.source_info(location).span,
+                        "collection encountered polymorphic constant: {}",
+                        substituted_constant
                     ),
                 }
             }
@@ -664,7 +665,7 @@ fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Loc
                         }
                         mir::InlineAsmOperand::SymStatic { def_id } => {
                             let instance = Instance::mono(self.tcx, def_id);
-                            if should_monomorphize_locally(self.tcx, &instance) {
+                            if should_codegen_locally(self.tcx, &instance) {
                                 trace!("collecting asm sym static {:?}", def_id);
                                 self.output.push(respan(source, MonoItem::Static(def_id)));
                             }
@@ -735,7 +736,7 @@ fn visit_instance_use<'tcx>(
     output: &mut Vec<Spanned<MonoItem<'tcx>>>,
 ) {
     debug!("visit_item_use({:?}, is_direct_call={:?})", instance, is_direct_call);
-    if !should_monomorphize_locally(tcx, &instance) {
+    if !should_codegen_locally(tcx, &instance) {
         return;
     }
 
@@ -748,7 +749,7 @@ fn visit_instance_use<'tcx>(
         ty::InstanceDef::DropGlue(_, None) => {
             // Don't need to emit noop drop glue if we are calling directly.
             if !is_direct_call {
-                output.push(create_fn_mono_item(instance, source));
+                output.push(create_fn_mono_item(tcx, instance, source));
             }
         }
         ty::InstanceDef::DropGlue(_, Some(_))
@@ -758,7 +759,7 @@ fn visit_instance_use<'tcx>(
         | ty::InstanceDef::Item(..)
         | ty::InstanceDef::FnPtrShim(..)
         | ty::InstanceDef::CloneShim(..) => {
-            output.push(create_fn_mono_item(instance, source));
+            output.push(create_fn_mono_item(tcx, instance, source));
         }
     }
 }
@@ -766,7 +767,7 @@ fn visit_instance_use<'tcx>(
 // Returns `true` if we should codegen an instance in the local crate.
 // Returns `false` if we can just link to the upstream crate and therefore don't
 // need a mono item.
-fn should_monomorphize_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx>) -> bool {
+fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx>) -> bool {
     let def_id = match instance.def {
         ty::InstanceDef::Item(def) => def.did,
         ty::InstanceDef::DropGlue(def_id, Some(_)) => def_id,
@@ -781,20 +782,19 @@ fn should_monomorphize_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx
     };
 
     if tcx.is_foreign_item(def_id) {
-        // Foreign items are always linked against, there's no way of
-        // instantiating them.
+        // Foreign items are always linked against, there's no way of instantiating them.
         return false;
     }
 
     if def_id.is_local() {
-        // Local items cannot be referred to locally without
-        // monomorphizing them locally.
+        // Local items cannot be referred to locally without monomorphizing them locally.
         return true;
     }
 
-    if tcx.is_reachable_non_generic(def_id) || instance.upstream_monomorphization(tcx).is_some() {
-        // We can link to the item in question, no instance needed
-        // in this crate.
+    if tcx.is_reachable_non_generic(def_id)
+        || instance.polymorphize(tcx).upstream_monomorphization(tcx).is_some()
+    {
+        // We can link to the item in question, no instance needed in this crate.
         return false;
     }
 
@@ -903,9 +903,13 @@ fn find_vtable_types_for_unsizing<'tcx>(
     }
 }
 
-fn create_fn_mono_item(instance: Instance<'_>, source: Span) -> Spanned<MonoItem<'_>> {
+fn create_fn_mono_item<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    instance: Instance<'tcx>,
+    source: Span,
+) -> Spanned<MonoItem<'tcx>> {
     debug!("create_fn_mono_item(instance={})", instance);
-    respan(source, MonoItem::Fn(instance))
+    respan(source, MonoItem::Fn(instance.polymorphize(tcx)))
 }
 
 /// Creates a `MonoItem` for each method that is referenced by the vtable for
@@ -917,12 +921,7 @@ fn create_mono_items_for_vtable_methods<'tcx>(
     source: Span,
     output: &mut Vec<Spanned<MonoItem<'tcx>>>,
 ) {
-    assert!(
-        !trait_ty.needs_subst()
-            && !trait_ty.has_escaping_bound_vars()
-            && !impl_ty.needs_subst()
-            && !impl_ty.has_escaping_bound_vars()
-    );
+    assert!(!trait_ty.has_escaping_bound_vars() && !impl_ty.has_escaping_bound_vars());
 
     if let ty::Dynamic(ref trait_ty, ..) = trait_ty.kind {
         if let Some(principal) = trait_ty.principal() {
@@ -944,8 +943,8 @@ fn create_mono_items_for_vtable_methods<'tcx>(
                     )
                     .unwrap()
                 })
-                .filter(|&instance| should_monomorphize_locally(tcx, &instance))
-                .map(|item| create_fn_mono_item(item, source));
+                .filter(|&instance| should_codegen_locally(tcx, &instance))
+                .map(|item| create_fn_mono_item(tcx, item, source));
             output.extend(methods);
         }
 
@@ -997,7 +996,7 @@ fn visit_item(&mut self, item: &'v hir::Item<'v>) {
                         );
 
                         let ty = Instance::new(def_id.to_def_id(), InternalSubsts::empty())
-                            .monomorphic_ty(self.tcx);
+                            .ty(self.tcx, ty::ParamEnv::reveal_all());
                         visit_drop_use(self.tcx, ty, true, DUMMY_SP, self.output);
                     }
                 }
@@ -1069,7 +1068,7 @@ fn push_if_root(&mut self, def_id: LocalDefId) {
             debug!("RootCollector::push_if_root: found root def_id={:?}", def_id);
 
             let instance = Instance::mono(self.tcx, def_id.to_def_id());
-            self.output.push(create_fn_mono_item(instance, DUMMY_SP));
+            self.output.push(create_fn_mono_item(self.tcx, instance, DUMMY_SP));
         }
     }
 
@@ -1106,7 +1105,7 @@ fn push_extra_entry_roots(&mut self) {
         .unwrap()
         .unwrap();
 
-        self.output.push(create_fn_mono_item(start_instance, DUMMY_SP));
+        self.output.push(create_fn_mono_item(self.tcx, start_instance, DUMMY_SP));
     }
 }
 
@@ -1163,9 +1162,8 @@ fn create_mono_items_for_default_impls<'tcx>(
                         .unwrap()
                         .unwrap();
 
-                    let mono_item = create_fn_mono_item(instance, DUMMY_SP);
-                    if mono_item.node.is_instantiable(tcx)
-                        && should_monomorphize_locally(tcx, &instance)
+                    let mono_item = create_fn_mono_item(tcx, instance, DUMMY_SP);
+                    if mono_item.node.is_instantiable(tcx) && should_codegen_locally(tcx, &instance)
                     {
                         output.push(mono_item);
                     }
@@ -1186,7 +1184,7 @@ fn collect_miri<'tcx>(
         GlobalAlloc::Static(def_id) => {
             assert!(!tcx.is_thread_local_static(def_id));
             let instance = Instance::mono(tcx, def_id);
-            if should_monomorphize_locally(tcx, &instance) {
+            if should_codegen_locally(tcx, &instance) {
                 trace!("collecting static {:?}", def_id);
                 output.push(dummy_spanned(MonoItem::Static(def_id)));
             }
@@ -1200,9 +1198,9 @@ fn collect_miri<'tcx>(
             }
         }
         GlobalAlloc::Function(fn_instance) => {
-            if should_monomorphize_locally(tcx, &fn_instance) {
+            if should_codegen_locally(tcx, &fn_instance) {
                 trace!("collecting {:?} with {:#?}", alloc_id, fn_instance);
-                output.push(create_fn_mono_item(fn_instance, DUMMY_SP));
+                output.push(create_fn_mono_item(tcx, fn_instance, DUMMY_SP));
             }
         }
     }
index 76c1c465a8be0ac9a951dffeee14fcccd6965933..15d7b11124071a59b9e0f01eb2abf1791f8ba50f 100644 (file)
@@ -6,6 +6,7 @@
 
 pub mod collector;
 pub mod partitioning;
+pub mod polymorphize;
 
 pub fn custom_coerce_unsize_info<'tcx>(
     tcx: TyCtxt<'tcx>,
index 410ed66e008dc365d4e3b936900ae92f83a8cb55..6162651db14a0b8d8780a5fadd6e32351eaa5f74 100644 (file)
@@ -161,7 +161,7 @@ pub fn partition<'tcx, I>(
 
     // Next we try to make as many symbols "internal" as possible, so LLVM has
     // more freedom to optimize.
-    if !tcx.sess.opts.cg.link_dead_code {
+    if tcx.sess.opts.cg.link_dead_code != Some(true) {
         let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_internalize_symbols");
         internalize_symbols(tcx, &mut post_inlining, inlining_map);
     }
@@ -906,7 +906,7 @@ fn collect_and_partition_mono_items(
             }
         }
         None => {
-            if tcx.sess.opts.cg.link_dead_code {
+            if tcx.sess.opts.cg.link_dead_code == Some(true) {
                 MonoItemCollectionMode::Eager
             } else {
                 MonoItemCollectionMode::Lazy
diff --git a/src/librustc_mir/monomorphize/polymorphize.rs b/src/librustc_mir/monomorphize/polymorphize.rs
new file mode 100644 (file)
index 0000000..071b9bb
--- /dev/null
@@ -0,0 +1,285 @@
+//! Polymorphization Analysis
+//! =========================
+//!
+//! This module implements an analysis of functions, methods and closures to determine which
+//! generic parameters are unused (and eventually, in what ways generic parameters are used - only
+//! for their size, offset of a field, etc.).
+
+use rustc_hir::{def::DefKind, def_id::DefId};
+use rustc_index::bit_set::FiniteBitSet;
+use rustc_middle::mir::{
+    visit::{TyContext, Visitor},
+    Local, LocalDecl, Location,
+};
+use rustc_middle::ty::{
+    self,
+    fold::{TypeFoldable, TypeVisitor},
+    query::Providers,
+    Const, Ty, TyCtxt,
+};
+use rustc_span::symbol::sym;
+use std::convert::TryInto;
+
+/// Provide implementations of queries relating to polymorphization analysis.
+pub fn provide(providers: &mut Providers) {
+    providers.unused_generic_params = unused_generic_params;
+}
+
+/// Determine which generic parameters are used by the function/method/closure represented by
+/// `def_id`. Returns a bitset where bits representing unused parameters are set (`is_empty`
+/// indicates all parameters are used).
+fn unused_generic_params(tcx: TyCtxt<'_>, def_id: DefId) -> FiniteBitSet<u64> {
+    debug!("unused_generic_params({:?})", def_id);
+
+    if !tcx.sess.opts.debugging_opts.polymorphize {
+        // If polymorphization disabled, then all parameters are used.
+        return FiniteBitSet::new_empty();
+    }
+
+    let generics = tcx.generics_of(def_id);
+    debug!("unused_generic_params: generics={:?}", generics);
+
+    // Exit early when there are no parameters to be unused.
+    if generics.count() == 0 {
+        return FiniteBitSet::new_empty();
+    }
+
+    // Exit early when there is no MIR available.
+    if !tcx.is_mir_available(def_id) {
+        debug!("unused_generic_params: (no mir available) def_id={:?}", def_id);
+        return FiniteBitSet::new_empty();
+    }
+
+    // Create a bitset with N rightmost ones for each parameter.
+    let generics_count: u32 =
+        generics.count().try_into().expect("more generic parameters than can fit into a `u32`");
+    let mut unused_parameters = FiniteBitSet::<u64>::new_empty();
+    unused_parameters.set_range(0..generics_count);
+    debug!("unused_generic_params: (start) unused_parameters={:?}", unused_parameters);
+    mark_used_by_default_parameters(tcx, def_id, generics, &mut unused_parameters);
+    debug!("unused_generic_params: (after default) unused_parameters={:?}", unused_parameters);
+
+    // Visit MIR and accumululate used generic parameters.
+    let body = tcx.optimized_mir(def_id);
+    let mut vis =
+        UsedGenericParametersVisitor { tcx, def_id, unused_parameters: &mut unused_parameters };
+    vis.visit_body(body);
+    debug!("unused_generic_params: (after visitor) unused_parameters={:?}", unused_parameters);
+
+    mark_used_by_predicates(tcx, def_id, &mut unused_parameters);
+    debug!("unused_generic_params: (end) unused_parameters={:?}", unused_parameters);
+
+    // Emit errors for debugging and testing if enabled.
+    if !unused_parameters.is_empty() {
+        emit_unused_generic_params_error(tcx, def_id, generics, &unused_parameters);
+    }
+
+    unused_parameters
+}
+
+/// Some parameters are considered used-by-default, such as non-generic parameters and the dummy
+/// generic parameters from closures, this function marks them as used. `leaf_is_closure` should
+/// be `true` if the item that `unused_generic_params` was invoked on is a closure.
+fn mark_used_by_default_parameters<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def_id: DefId,
+    generics: &'tcx ty::Generics,
+    unused_parameters: &mut FiniteBitSet<u64>,
+) {
+    if !tcx.is_trait(def_id) && (tcx.is_closure(def_id) || tcx.type_of(def_id).is_generator()) {
+        for param in &generics.params {
+            debug!("mark_used_by_default_parameters: (closure/gen) param={:?}", param);
+            unused_parameters.clear(param.index);
+        }
+    } else {
+        for param in &generics.params {
+            debug!("mark_used_by_default_parameters: (other) param={:?}", param);
+            if let ty::GenericParamDefKind::Lifetime = param.kind {
+                unused_parameters.clear(param.index);
+            }
+        }
+    }
+
+    if let Some(parent) = generics.parent {
+        mark_used_by_default_parameters(tcx, parent, tcx.generics_of(parent), unused_parameters);
+    }
+}
+
+/// Search the predicates on used generic parameters for any unused generic parameters, and mark
+/// those as used.
+fn mark_used_by_predicates<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def_id: DefId,
+    unused_parameters: &mut FiniteBitSet<u64>,
+) {
+    let def_id = tcx.closure_base_def_id(def_id);
+
+    let is_self_ty_used = |unused_parameters: &mut FiniteBitSet<u64>, self_ty: Ty<'tcx>| {
+        debug!("unused_generic_params: self_ty={:?}", self_ty);
+        if let ty::Param(param) = self_ty.kind {
+            !unused_parameters.contains(param.index).unwrap_or(false)
+        } else {
+            false
+        }
+    };
+
+    let mark_ty = |unused_parameters: &mut FiniteBitSet<u64>, ty: Ty<'tcx>| {
+        let mut vis = UsedGenericParametersVisitor { tcx, def_id, unused_parameters };
+        ty.visit_with(&mut vis);
+    };
+
+    let predicates = tcx.explicit_predicates_of(def_id);
+    debug!("mark_parameters_used_in_predicates: predicates_of={:?}", predicates);
+    for (predicate, _) in predicates.predicates {
+        match predicate.kind() {
+            ty::PredicateKind::Trait(predicate, ..) => {
+                let trait_ref = predicate.skip_binder().trait_ref;
+                if is_self_ty_used(unused_parameters, trait_ref.self_ty()) {
+                    for ty in trait_ref.substs.types() {
+                        debug!("unused_generic_params: (trait) ty={:?}", ty);
+                        mark_ty(unused_parameters, ty);
+                    }
+                }
+            }
+            ty::PredicateKind::Projection(predicate, ..) => {
+                let self_ty = predicate.skip_binder().projection_ty.self_ty();
+                if is_self_ty_used(unused_parameters, self_ty) {
+                    let ty = predicate.ty();
+                    debug!("unused_generic_params: (projection) ty={:?}", ty);
+                    mark_ty(unused_parameters, ty.skip_binder());
+                }
+            }
+            _ => (),
+        }
+    }
+}
+
+/// Emit errors for the function annotated by `#[rustc_polymorphize_error]`, labelling each generic
+/// parameter which was unused.
+fn emit_unused_generic_params_error<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def_id: DefId,
+    generics: &'tcx ty::Generics,
+    unused_parameters: &FiniteBitSet<u64>,
+) {
+    debug!("emit_unused_generic_params_error: def_id={:?}", def_id);
+    let base_def_id = tcx.closure_base_def_id(def_id);
+    if !tcx.get_attrs(base_def_id).iter().any(|a| a.check_name(sym::rustc_polymorphize_error)) {
+        return;
+    }
+
+    debug!("emit_unused_generic_params_error: unused_parameters={:?}", unused_parameters);
+    let fn_span = match tcx.opt_item_name(def_id) {
+        Some(ident) => ident.span,
+        _ => tcx.def_span(def_id),
+    };
+
+    let mut err = tcx.sess.struct_span_err(fn_span, "item has unused generic parameters");
+
+    let mut next_generics = Some(generics);
+    while let Some(generics) = next_generics {
+        for param in &generics.params {
+            if unused_parameters.contains(param.index).unwrap_or(false) {
+                debug!("emit_unused_generic_params_error: param={:?}", param);
+                let def_span = tcx.def_span(param.def_id);
+                err.span_label(def_span, &format!("generic parameter `{}` is unused", param.name));
+            }
+        }
+
+        next_generics = generics.parent.map(|did| tcx.generics_of(did));
+    }
+
+    err.emit();
+}
+
+/// Visitor used to aggregate generic parameter uses.
+struct UsedGenericParametersVisitor<'a, 'tcx> {
+    tcx: TyCtxt<'tcx>,
+    def_id: DefId,
+    unused_parameters: &'a mut FiniteBitSet<u64>,
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for UsedGenericParametersVisitor<'a, 'tcx> {
+    fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) {
+        debug!("visit_local_decl: local_decl={:?}", local_decl);
+        if local == Local::from_usize(1) {
+            let def_kind = self.tcx.def_kind(self.def_id);
+            if matches!(def_kind, DefKind::Closure | DefKind::Generator) {
+                // Skip visiting the closure/generator that is currently being processed. This only
+                // happens because the first argument to the closure is a reference to itself and
+                // that will call `visit_substs`, resulting in each generic parameter captured being
+                // considered used by default.
+                debug!("visit_local_decl: skipping closure substs");
+                return;
+            }
+        }
+
+        self.super_local_decl(local, local_decl);
+    }
+
+    fn visit_const(&mut self, c: &&'tcx Const<'tcx>, _: Location) {
+        c.visit_with(self);
+    }
+
+    fn visit_ty(&mut self, ty: Ty<'tcx>, _: TyContext) {
+        ty.visit_with(self);
+    }
+}
+
+impl<'a, 'tcx> TypeVisitor<'tcx> for UsedGenericParametersVisitor<'a, 'tcx> {
+    fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> bool {
+        debug!("visit_const: c={:?}", c);
+        if !c.has_param_types_or_consts() {
+            return false;
+        }
+
+        match c.val {
+            ty::ConstKind::Param(param) => {
+                debug!("visit_const: param={:?}", param);
+                self.unused_parameters.clear(param.index);
+                false
+            }
+            _ => c.super_visit_with(self),
+        }
+    }
+
+    fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
+        debug!("visit_ty: ty={:?}", ty);
+        if !ty.has_param_types_or_consts() {
+            return false;
+        }
+
+        match ty.kind {
+            ty::Closure(def_id, substs) | ty::Generator(def_id, substs, ..) => {
+                debug!("visit_ty: def_id={:?}", def_id);
+                // Avoid cycle errors with generators.
+                if def_id == self.def_id {
+                    return false;
+                }
+
+                // Consider any generic parameters used by any closures/generators as used in the
+                // parent.
+                let unused = self.tcx.unused_generic_params(def_id);
+                debug!(
+                    "visit_ty: unused_parameters={:?} unused={:?}",
+                    self.unused_parameters, unused
+                );
+                for (i, arg) in substs.iter().enumerate() {
+                    let i = i.try_into().unwrap();
+                    if !unused.contains(i).unwrap_or(false) {
+                        arg.visit_with(self);
+                    }
+                }
+                debug!("visit_ty: unused_parameters={:?}", self.unused_parameters);
+
+                false
+            }
+            ty::Param(param) => {
+                debug!("visit_ty: param={:?}", param);
+                self.unused_parameters.clear(param.index);
+                false
+            }
+            _ => ty.super_visit_with(self),
+        }
+    }
+}
index 98286cddea68b8d03085f7772b080adac3a37ca4..bfa9bb9e0f0e1a6657ac8dce2b864fa3342838dc 100644 (file)
@@ -4,7 +4,7 @@
 use rustc_middle::mir::*;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::subst::{InternalSubsts, Subst};
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_target::abi::VariantIdx;
 
 use rustc_index::vec::{Idx, IndexVec};
@@ -36,11 +36,6 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
             build_call_shim(tcx, instance, Some(Adjustment::Deref), CallKind::Direct(def_id), None)
         }
         ty::InstanceDef::FnPtrShim(def_id, ty) => {
-            // FIXME(eddyb) support generating shims for a "shallow type",
-            // e.g. `Foo<_>` or `[_]` instead of requiring a fully monomorphic
-            // `Foo<Bar>` or `[String]` etc.
-            assert!(!ty.needs_subst());
-
             let trait_ = tcx.trait_of_item(def_id).unwrap();
             let adjustment = match tcx.fn_trait_kind_from_lang_item(trait_) {
                 Some(ty::ClosureKind::FnOnce) => Adjustment::Identity,
@@ -83,22 +78,8 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
                 None,
             )
         }
-        ty::InstanceDef::DropGlue(def_id, ty) => {
-            // FIXME(eddyb) support generating shims for a "shallow type",
-            // e.g. `Foo<_>` or `[_]` instead of requiring a fully monomorphic
-            // `Foo<Bar>` or `[String]` etc.
-            assert!(!ty.needs_subst());
-
-            build_drop_shim(tcx, def_id, ty)
-        }
-        ty::InstanceDef::CloneShim(def_id, ty) => {
-            // FIXME(eddyb) support generating shims for a "shallow type",
-            // e.g. `Foo<_>` or `[_]` instead of requiring a fully monomorphic
-            // `Foo<Bar>` or `[String]` etc.
-            assert!(!ty.needs_subst());
-
-            build_clone_shim(tcx, def_id, ty)
-        }
+        ty::InstanceDef::DropGlue(def_id, ty) => build_drop_shim(tcx, def_id, ty),
+        ty::InstanceDef::CloneShim(def_id, ty) => build_clone_shim(tcx, def_id, ty),
         ty::InstanceDef::Virtual(..) => {
             bug!("InstanceDef::Virtual ({:?}) is for direct calls only", instance)
         }
index 81d7ac089262206aa24957a226f5c50ea627701e..9c06e173bcd5713b2b946af7faa85dd4a341614b 100644 (file)
@@ -439,7 +439,11 @@ fn check_target_features(&mut self, func_did: DefId) {
 pub(crate) fn provide(providers: &mut Providers) {
     *providers = Providers {
         unsafety_check_result: |tcx, def_id| {
-            unsafety_check_result(tcx, ty::WithOptConstParam::unknown(def_id))
+            if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) {
+                tcx.unsafety_check_result_for_const_arg(def)
+            } else {
+                unsafety_check_result(tcx, ty::WithOptConstParam::unknown(def_id))
+            }
         },
         unsafety_check_result_for_const_arg: |tcx, (did, param_did)| {
             unsafety_check_result(
@@ -499,12 +503,6 @@ fn unsafety_check_result<'tcx>(
     tcx: TyCtxt<'tcx>,
     def: ty::WithOptConstParam<LocalDefId>,
 ) -> &'tcx UnsafetyCheckResult {
-    if def.const_param_did.is_none() {
-        if let Some(param_did) = tcx.opt_const_param_of(def.did) {
-            return tcx.unsafety_check_result_for_const_arg((def.did, param_did));
-        }
-    }
-
     debug!("unsafety_violations({:?})", def);
 
     // N.B., this borrow is valid because all the consumers of
index 237a5a64f8bf851cc600a24ff2f782d48c3dd6b8..3073bf53afd7869486a54daa9f7d13a8f1a86e4c 100644 (file)
@@ -116,7 +116,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'
             .predicates
             .iter()
             .filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None });
-        if !traits::normalize_and_test_predicates(
+        if traits::impossible_predicates(
             tcx,
             traits::elaborate_predicates(tcx, predicates).map(|o| o.predicate).collect(),
         ) {
index 76904b7edd533525da8d826d0c9c0bbe6fb8fd1a..9933a975e4dac194f98fe19a806e203280a6bdc9 100644 (file)
@@ -35,46 +35,64 @@ fn coverageinfo_from_mir<'tcx>(tcx: TyCtxt<'tcx>, mir_def_id: DefId) -> Coverage
     // represents a single function. Validate and/or correct if inlining (which should be disabled
     // if -Zinstrument-coverage is enabled) and/or monomorphization invalidates these assumptions.
     let count_code_region_fn = tcx.require_lang_item(lang_items::CountCodeRegionFnLangItem, None);
+    let coverage_counter_add_fn =
+        tcx.require_lang_item(lang_items::CoverageCounterAddFnLangItem, None);
+    let coverage_counter_subtract_fn =
+        tcx.require_lang_item(lang_items::CoverageCounterSubtractFnLangItem, None);
 
     // The `num_counters` argument to `llvm.instrprof.increment` is the number of injected
     // counters, with each counter having an index from `0..num_counters-1`. MIR optimization
     // may split and duplicate some BasicBlock sequences. Simply counting the calls may not
     // not work; but computing the num_counters by adding `1` to the highest index (for a given
     // instrumented function) is valid.
+    //
+    // `num_expressions` is the number of counter expressions added to the MIR body. Both
+    // `num_counters` and `num_expressions` are used to initialize new vectors, during backend
+    // code generate, to lookup counters and expressions by their simple u32 indexes.
     let mut num_counters: u32 = 0;
-    for terminator in traversal::preorder(mir_body)
-        .map(|(_, data)| (data, count_code_region_fn))
-        .filter_map(terminators_that_call_given_fn)
+    let mut num_expressions: u32 = 0;
+    for terminator in
+        traversal::preorder(mir_body).map(|(_, data)| data).filter_map(call_terminators)
     {
-        if let TerminatorKind::Call { args, .. } = &terminator.kind {
-            let index_arg = args.get(count_code_region_args::COUNTER_INDEX).expect("arg found");
-            let index =
-                mir::Operand::scalar_from_const(index_arg).to_u32().expect("index arg is u32");
-            num_counters = std::cmp::max(num_counters, index + 1);
-        }
-    }
-    let hash = if num_counters > 0 { hash_mir_source(tcx, mir_def_id) } else { 0 };
-    CoverageInfo { num_counters, hash }
-}
-
-fn terminators_that_call_given_fn(
-    (data, fn_def_id): (&'tcx BasicBlockData<'tcx>, DefId),
-) -> Option<&'tcx Terminator<'tcx>> {
-    if let Some(terminator) = &data.terminator {
-        if let TerminatorKind::Call { func: Operand::Constant(func), .. } = &terminator.kind {
-            if let FnDef(called_fn_def_id, _) = func.literal.ty.kind {
-                if called_fn_def_id == fn_def_id {
-                    return Some(&terminator);
+        if let TerminatorKind::Call { func: Operand::Constant(func), args, .. } = &terminator.kind {
+            match func.literal.ty.kind {
+                FnDef(id, _) if id == count_code_region_fn => {
+                    let index_arg =
+                        args.get(count_code_region_args::COUNTER_INDEX).expect("arg found");
+                    let counter_index = mir::Operand::scalar_from_const(index_arg)
+                        .to_u32()
+                        .expect("index arg is u32");
+                    num_counters = std::cmp::max(num_counters, counter_index + 1);
+                }
+                FnDef(id, _)
+                    if id == coverage_counter_add_fn || id == coverage_counter_subtract_fn =>
+                {
+                    let index_arg = args
+                        .get(coverage_counter_expression_args::COUNTER_EXPRESSION_INDEX)
+                        .expect("arg found");
+                    let translated_index = mir::Operand::scalar_from_const(index_arg)
+                        .to_u32()
+                        .expect("index arg is u32");
+                    // Counter expressions start with "translated indexes", descending from
+                    // `u32::MAX`, so the range of expression indexes is disjoint from the range of
+                    // counter indexes. This way, both counters and expressions can be operands in
+                    // other expressions.
+                    let expression_index = u32::MAX - translated_index;
+                    num_expressions = std::cmp::max(num_expressions, expression_index + 1);
                 }
+                _ => {}
             }
         }
     }
-    None
+    CoverageInfo { num_counters, num_expressions }
 }
 
-struct Instrumentor<'tcx> {
-    tcx: TyCtxt<'tcx>,
-    num_counters: u32,
+fn call_terminators(data: &'tcx BasicBlockData<'tcx>) -> Option<&'tcx Terminator<'tcx>> {
+    let terminator = data.terminator();
+    match terminator.kind {
+        TerminatorKind::Call { .. } => Some(terminator),
+        _ => None,
+    }
 }
 
 impl<'tcx> MirPass<'tcx> for InstrumentCoverage {
@@ -83,42 +101,106 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, mir_body: &mut mir::
             // If the InstrumentCoverage pass is called on promoted MIRs, skip them.
             // See: https://github.com/rust-lang/rust/pull/73011#discussion_r438317601
             if src.promoted.is_none() {
-                debug!(
-                    "instrumenting {:?}, span: {}",
-                    src.def_id(),
-                    tcx.sess.source_map().span_to_string(mir_body.span)
-                );
-                Instrumentor::new(tcx).inject_counters(mir_body);
+                Instrumentor::new(tcx, src, mir_body).inject_counters();
             }
         }
     }
 }
 
-impl<'tcx> Instrumentor<'tcx> {
-    fn new(tcx: TyCtxt<'tcx>) -> Self {
-        Self { tcx, num_counters: 0 }
+/// Distinguishes the expression operators.
+enum Op {
+    Add,
+    Subtract,
+}
+
+struct Instrumentor<'a, 'tcx> {
+    tcx: TyCtxt<'tcx>,
+    mir_def_id: DefId,
+    mir_body: &'a mut mir::Body<'tcx>,
+    hir_body: &'tcx rustc_hir::Body<'tcx>,
+    function_source_hash: Option<u64>,
+    num_counters: u32,
+    num_expressions: u32,
+}
+
+impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
+    fn new(tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, mir_body: &'a mut mir::Body<'tcx>) -> Self {
+        let mir_def_id = src.def_id();
+        let hir_body = hir_body(tcx, mir_def_id);
+        Self {
+            tcx,
+            mir_def_id,
+            mir_body,
+            hir_body,
+            function_source_hash: None,
+            num_counters: 0,
+            num_expressions: 0,
+        }
     }
 
+    /// Counter IDs start from zero and go up.
     fn next_counter(&mut self) -> u32 {
+        assert!(self.num_counters < u32::MAX - self.num_expressions);
         let next = self.num_counters;
         self.num_counters += 1;
         next
     }
 
-    fn inject_counters(&mut self, mir_body: &mut mir::Body<'tcx>) {
+    /// Expression IDs start from u32::MAX and go down because a CounterExpression can reference
+    /// (add or subtract counts) of both Counter regions and CounterExpression regions. The indexes
+    /// of each type of region must be contiguous, but also must be unique across both sets.
+    /// The expression IDs are eventually translated into region indexes (starting after the last
+    /// counter index, for the given function), during backend code generation, by the helper method
+    /// `rustc_codegen_ssa::coverageinfo::map::FunctionCoverage::translate_expressions()`.
+    fn next_expression(&mut self) -> u32 {
+        assert!(self.num_counters < u32::MAX - self.num_expressions);
+        let next = u32::MAX - self.num_expressions;
+        self.num_expressions += 1;
+        next
+    }
+
+    fn function_source_hash(&mut self) -> u64 {
+        match self.function_source_hash {
+            Some(hash) => hash,
+            None => {
+                let hash = hash_mir_source(self.tcx, self.hir_body);
+                self.function_source_hash.replace(hash);
+                hash
+            }
+        }
+    }
+
+    fn inject_counters(&mut self) {
+        let body_span = self.hir_body.value.span;
+        debug!(
+            "instrumenting {:?}, span: {}",
+            self.mir_def_id,
+            self.tcx.sess.source_map().span_to_string(body_span)
+        );
+
         // FIXME(richkadel): As a first step, counters are only injected at the top of each
         // function. The complete solution will inject counters at each conditional code branch.
-        let code_region = mir_body.span;
         let next_block = START_BLOCK;
-        self.inject_counter(mir_body, code_region, next_block);
+        self.inject_counter(body_span, next_block);
+
+        // FIXME(richkadel): The next step to implement source based coverage analysis will be
+        // instrumenting branches within functions, and some regions will be counted by "counter
+        // expression". The function to inject counter expression is implemented. Replace this
+        // "fake use" with real use.
+        let fake_use = false;
+        if fake_use {
+            let add = false;
+            if add {
+                self.inject_counter_expression(body_span, next_block, 1, Op::Add, 2);
+            } else {
+                self.inject_counter_expression(body_span, next_block, 1, Op::Subtract, 2);
+            }
+        }
     }
 
-    fn inject_counter(
-        &mut self,
-        mir_body: &mut mir::Body<'tcx>,
-        code_region: Span,
-        next_block: BasicBlock,
-    ) {
+    fn inject_counter(&mut self, code_region: Span, next_block: BasicBlock) -> u32 {
+        let counter_id = self.next_counter();
+        let function_source_hash = self.function_source_hash();
         let injection_point = code_region.shrink_to_lo();
 
         let count_code_region_fn = function_handle(
@@ -127,13 +209,14 @@ fn inject_counter(
             injection_point,
         );
 
-        let index = self.next_counter();
-
         let mut args = Vec::new();
 
         use count_code_region_args::*;
+        debug_assert_eq!(FUNCTION_SOURCE_HASH, args.len());
+        args.push(self.const_u64(function_source_hash, injection_point));
+
         debug_assert_eq!(COUNTER_INDEX, args.len());
-        args.push(self.const_u32(index, injection_point));
+        args.push(self.const_u32(counter_id, injection_point));
 
         debug_assert_eq!(START_BYTE_POS, args.len());
         args.push(self.const_u32(code_region.lo().to_u32(), injection_point));
@@ -141,36 +224,98 @@ fn inject_counter(
         debug_assert_eq!(END_BYTE_POS, args.len());
         args.push(self.const_u32(code_region.hi().to_u32(), injection_point));
 
-        let mut patch = MirPatch::new(mir_body);
+        self.inject_call(count_code_region_fn, args, injection_point, next_block);
 
-        let temp = patch.new_temp(self.tcx.mk_unit(), code_region);
-        let new_block = patch.new_block(placeholder_block(code_region));
+        counter_id
+    }
+
+    fn inject_counter_expression(
+        &mut self,
+        code_region: Span,
+        next_block: BasicBlock,
+        lhs: u32,
+        op: Op,
+        rhs: u32,
+    ) -> u32 {
+        let expression_id = self.next_expression();
+        let injection_point = code_region.shrink_to_lo();
+
+        let count_code_region_fn = function_handle(
+            self.tcx,
+            self.tcx.require_lang_item(
+                match op {
+                    Op::Add => lang_items::CoverageCounterAddFnLangItem,
+                    Op::Subtract => lang_items::CoverageCounterSubtractFnLangItem,
+                },
+                None,
+            ),
+            injection_point,
+        );
+
+        let mut args = Vec::new();
+
+        use coverage_counter_expression_args::*;
+        debug_assert_eq!(COUNTER_EXPRESSION_INDEX, args.len());
+        args.push(self.const_u32(expression_id, injection_point));
+
+        debug_assert_eq!(LEFT_INDEX, args.len());
+        args.push(self.const_u32(lhs, injection_point));
+
+        debug_assert_eq!(RIGHT_INDEX, args.len());
+        args.push(self.const_u32(rhs, injection_point));
+
+        debug_assert_eq!(START_BYTE_POS, args.len());
+        args.push(self.const_u32(code_region.lo().to_u32(), injection_point));
+
+        debug_assert_eq!(END_BYTE_POS, args.len());
+        args.push(self.const_u32(code_region.hi().to_u32(), injection_point));
+
+        self.inject_call(count_code_region_fn, args, injection_point, next_block);
+
+        expression_id
+    }
+
+    fn inject_call(
+        &mut self,
+        func: Operand<'tcx>,
+        args: Vec<Operand<'tcx>>,
+        fn_span: Span,
+        next_block: BasicBlock,
+    ) {
+        let mut patch = MirPatch::new(self.mir_body);
+
+        let temp = patch.new_temp(self.tcx.mk_unit(), fn_span);
+        let new_block = patch.new_block(placeholder_block(fn_span));
         patch.patch_terminator(
             new_block,
             TerminatorKind::Call {
-                func: count_code_region_fn,
+                func,
                 args,
                 // new_block will swapped with the next_block, after applying patch
                 destination: Some((Place::from(temp), new_block)),
                 cleanup: None,
                 from_hir_call: false,
-                fn_span: injection_point,
+                fn_span,
             },
         );
 
         patch.add_statement(new_block.start_location(), StatementKind::StorageLive(temp));
         patch.add_statement(next_block.start_location(), StatementKind::StorageDead(temp));
 
-        patch.apply(mir_body);
+        patch.apply(self.mir_body);
 
         // To insert the `new_block` in front of the first block in the counted branch (the
         // `next_block`), just swap the indexes, leaving the rest of the graph unchanged.
-        mir_body.basic_blocks_mut().swap(next_block, new_block);
+        self.mir_body.basic_blocks_mut().swap(next_block, new_block);
     }
 
     fn const_u32(&self, value: u32, span: Span) -> Operand<'tcx> {
         Operand::const_from_scalar(self.tcx, self.tcx.types.u32, Scalar::from_u32(value), span)
     }
+
+    fn const_u64(&self, value: u64, span: Span) -> Operand<'tcx> {
+        Operand::const_from_scalar(self.tcx, self.tcx.types.u64, Scalar::from_u64(value), span)
+    }
 }
 
 fn function_handle<'tcx>(tcx: TyCtxt<'tcx>, fn_def_id: DefId, span: Span) -> Operand<'tcx> {
@@ -192,10 +337,13 @@ fn placeholder_block(span: Span) -> BasicBlockData<'tcx> {
     }
 }
 
-fn hash_mir_source<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> u64 {
+fn hir_body<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx rustc_hir::Body<'tcx> {
     let hir_node = tcx.hir().get_if_local(def_id).expect("DefId is local");
     let fn_body_id = hir::map::associated_body(hir_node).expect("HIR node is a function with body");
-    let hir_body = tcx.hir().body(fn_body_id);
+    tcx.hir().body(fn_body_id)
+}
+
+fn hash_mir_source<'tcx>(tcx: TyCtxt<'tcx>, hir_body: &'tcx rustc_hir::Body<'tcx>) -> u64 {
     let mut hcx = tcx.create_no_span_stable_hashing_context();
     hash(&mut hcx, &hir_body.value).to_smaller_hash()
 }
index 51a9e76e762ebe50a66548dd4db53e0214da7417..283e4b289f286925979d94c6733fe9c7867cb058 100644 (file)
@@ -48,8 +48,13 @@ pub(crate) fn provide(providers: &mut Providers) {
     *providers = Providers {
         mir_keys,
         mir_const,
-        mir_const_qualif: |tcx, did| {
-            mir_const_qualif(tcx, ty::WithOptConstParam::unknown(did.expect_local()))
+        mir_const_qualif: |tcx, def_id| {
+            let def_id = def_id.expect_local();
+            if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) {
+                tcx.mir_const_qualif_const_arg(def)
+            } else {
+                mir_const_qualif(tcx, ty::WithOptConstParam::unknown(def_id))
+            }
         },
         mir_const_qualif_const_arg: |tcx, (did, param_did)| {
             mir_const_qualif(tcx, ty::WithOptConstParam { did, const_param_did: Some(param_did) })
@@ -60,7 +65,12 @@ pub(crate) fn provide(providers: &mut Providers) {
         optimized_mir_of_const_arg,
         is_mir_available,
         promoted_mir: |tcx, def_id| {
-            promoted_mir(tcx, ty::WithOptConstParam::unknown(def_id.expect_local()))
+            let def_id = def_id.expect_local();
+            if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) {
+                tcx.promoted_mir_of_const_arg(def)
+            } else {
+                promoted_mir(tcx, ty::WithOptConstParam::unknown(def_id))
+            }
         },
         promoted_mir_of_const_arg: |tcx, (did, param_did)| {
             promoted_mir(tcx, ty::WithOptConstParam { did, const_param_did: Some(param_did) })
@@ -221,12 +231,6 @@ pub fn run_passes(
 }
 
 fn mir_const_qualif(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> ConstQualifs {
-    if def.const_param_did.is_none() {
-        if let Some(param_did) = tcx.opt_const_param_of(def.did) {
-            return tcx.mir_const_qualif_const_arg((def.did, param_did));
-        }
-    }
-
     let const_kind = tcx.hir().body_const_context(def.did);
 
     // No need to const-check a non-const `fn`.
@@ -266,10 +270,8 @@ fn mir_const<'tcx>(
     tcx: TyCtxt<'tcx>,
     def: ty::WithOptConstParam<LocalDefId>,
 ) -> &'tcx Steal<Body<'tcx>> {
-    if def.const_param_did.is_none() {
-        if let const_param_did @ Some(_) = tcx.opt_const_param_of(def.did) {
-            return tcx.mir_const(ty::WithOptConstParam { const_param_did, ..def });
-        }
+    if let Some(def) = def.try_upgrade(tcx) {
+        return tcx.mir_const(def);
     }
 
     // Unsafety check uses the raw mir, so make sure it is run.
@@ -312,10 +314,8 @@ fn mir_validated(
     tcx: TyCtxt<'tcx>,
     def: ty::WithOptConstParam<LocalDefId>,
 ) -> (&'tcx Steal<Body<'tcx>>, &'tcx Steal<IndexVec<Promoted, Body<'tcx>>>) {
-    if def.const_param_did.is_none() {
-        if let const_param_did @ Some(_) = tcx.opt_const_param_of(def.did) {
-            return tcx.mir_validated(ty::WithOptConstParam { const_param_did, ..def });
-        }
+    if let Some(def) = def.try_upgrade(tcx) {
+        return tcx.mir_validated(def);
     }
 
     // Ensure that we compute the `mir_const_qualif` for constants at
@@ -357,13 +357,8 @@ fn mir_drops_elaborated_and_const_checked<'tcx>(
     tcx: TyCtxt<'tcx>,
     def: ty::WithOptConstParam<LocalDefId>,
 ) -> &'tcx Steal<Body<'tcx>> {
-    if def.const_param_did.is_none() {
-        if let const_param_did @ Some(_) = tcx.opt_const_param_of(def.did) {
-            return tcx.mir_drops_elaborated_and_const_checked(ty::WithOptConstParam {
-                const_param_did,
-                ..def
-            });
-        }
+    if let Some(def) = def.try_upgrade(tcx) {
+        return tcx.mir_drops_elaborated_and_const_checked(def);
     }
 
     // (Mir-)Borrowck uses `mir_validated`, so we have to force it to
@@ -490,8 +485,8 @@ fn run_optimization_passes<'tcx>(
 
 fn optimized_mir<'tcx>(tcx: TyCtxt<'tcx>, did: DefId) -> &'tcx Body<'tcx> {
     let did = did.expect_local();
-    if let Some(param_did) = tcx.opt_const_param_of(did) {
-        tcx.optimized_mir_of_const_arg((did, param_did))
+    if let Some(def) = ty::WithOptConstParam::try_lookup(did, tcx) {
+        tcx.optimized_mir_of_const_arg(def)
     } else {
         tcx.arena.alloc(inner_optimized_mir(tcx, ty::WithOptConstParam::unknown(did)))
     }
@@ -528,12 +523,6 @@ fn promoted_mir<'tcx>(
     tcx: TyCtxt<'tcx>,
     def: ty::WithOptConstParam<LocalDefId>,
 ) -> &'tcx IndexVec<Promoted, Body<'tcx>> {
-    if def.const_param_did.is_none() {
-        if let Some(param_did) = tcx.opt_const_param_of(def.did) {
-            return tcx.promoted_mir_of_const_arg((def.did, param_did));
-        }
-    }
-
     if tcx.is_constructor(def.did.to_def_id()) {
         return tcx.arena.alloc(IndexVec::new());
     }
index eb47195c06278d189fff0ac7c9c8204af936e97e..1e677f3d2aba82693e775972cefab82ce3a1dc38 100644 (file)
     tcx: TyCtxt<'tcx>,
     def: ty::WithOptConstParam<LocalDefId>,
 ) -> &'tcx ty::steal::Steal<Body<'tcx>> {
-    if def.const_param_did.is_none() {
-        if let const_param_did @ Some(_) = tcx.opt_const_param_of(def.did) {
-            return tcx.mir_built(ty::WithOptConstParam { const_param_did, ..def });
-        }
+    if let Some(def) = def.try_upgrade(tcx) {
+        return tcx.mir_built(def);
     }
 
     tcx.alloc_steal_mir(mir_build(tcx, def))
index 5d972c70d139255f27b137c08895167d1c9f572d..830af8d31e7a6a3b48baa76f6f72ffb05624c9a6 100644 (file)
@@ -59,20 +59,50 @@ fn annotate<F>(
     ) where
         F: FnOnce(&mut Self),
     {
+        debug!("annotate(id = {:?}, attrs = {:?})", hir_id, attrs);
+        let mut did_error = false;
         if !self.tcx.features().staged_api {
-            self.forbid_staged_api_attrs(hir_id, attrs, item_sp, kind, visit_children);
-            return;
+            did_error = self.forbid_staged_api_attrs(hir_id, attrs);
         }
 
-        // This crate explicitly wants staged API.
+        let depr = if did_error {
+            None
+        } else {
+            attr::find_deprecation(&self.tcx.sess.parse_sess, attrs, item_sp)
+        };
+        let mut is_deprecated = false;
+        if let Some(depr) = &depr {
+            is_deprecated = true;
 
-        debug!("annotate(id = {:?}, attrs = {:?})", hir_id, attrs);
-        if let Some(..) = attr::find_deprecation(&self.tcx.sess.parse_sess, attrs, item_sp) {
-            self.tcx.sess.span_err(
-                item_sp,
-                "`#[deprecated]` cannot be used in staged API; \
-                                             use `#[rustc_deprecated]` instead",
+            if kind == AnnotationKind::Prohibited {
+                self.tcx.sess.span_err(item_sp, "This deprecation annotation is useless");
+            }
+
+            // `Deprecation` is just two pointers, no need to intern it
+            let depr_entry = DeprecationEntry::local(depr.clone(), hir_id);
+            self.index.depr_map.insert(hir_id, depr_entry);
+        } else if let Some(parent_depr) = self.parent_depr.clone() {
+            is_deprecated = true;
+            info!("tagging child {:?} as deprecated from parent", hir_id);
+            self.index.depr_map.insert(hir_id, parent_depr);
+        }
+
+        if self.tcx.features().staged_api {
+            if let Some(..) = attrs.iter().find(|a| a.check_name(sym::deprecated)) {
+                self.tcx.sess.span_err(
+                    item_sp,
+                    "`#[deprecated]` cannot be used in staged API; \
+                                                use `#[rustc_deprecated]` instead",
+                );
+            }
+        } else {
+            self.recurse_with_stability_attrs(
+                depr.map(|d| DeprecationEntry::local(d, hir_id)),
+                None,
+                None,
+                visit_children,
             );
+            return;
         }
 
         let (stab, const_stab) = attr::find_stability(&self.tcx.sess.parse_sess, attrs, item_sp);
@@ -92,33 +122,34 @@ fn annotate<F>(
             }
         }
 
-        let stab = stab.map(|mut stab| {
+        if depr.as_ref().map_or(false, |d| d.is_since_rustc_version) {
+            if stab.is_none() {
+                struct_span_err!(
+                    self.tcx.sess,
+                    item_sp,
+                    E0549,
+                    "rustc_deprecated attribute must be paired with \
+                    either stable or unstable attribute"
+                )
+                .emit();
+            }
+        }
+
+        let stab = stab.map(|stab| {
             // Error if prohibited, or can't inherit anything from a container.
             if kind == AnnotationKind::Prohibited
-                || (kind == AnnotationKind::Container
-                    && stab.level.is_stable()
-                    && stab.rustc_depr.is_none())
+                || (kind == AnnotationKind::Container && stab.level.is_stable() && is_deprecated)
             {
                 self.tcx.sess.span_err(item_sp, "This stability annotation is useless");
             }
 
             debug!("annotate: found {:?}", stab);
-            // If parent is deprecated and we're not, inherit this by merging
-            // deprecated_since and its reason.
-            if let Some(parent_stab) = self.parent_stab {
-                if parent_stab.rustc_depr.is_some() && stab.rustc_depr.is_none() {
-                    stab.rustc_depr = parent_stab.rustc_depr
-                }
-            }
-
             let stab = self.tcx.intern_stability(stab);
 
             // Check if deprecated_since < stable_since. If it is,
             // this is *almost surely* an accident.
-            if let (
-                &Some(attr::RustcDeprecation { since: dep_since, .. }),
-                &attr::Stable { since: stab_since },
-            ) = (&stab.rustc_depr, &stab.level)
+            if let (&Some(dep_since), &attr::Stable { since: stab_since }) =
+                (&depr.as_ref().and_then(|d| d.since), &stab.level)
             {
                 // Explicit version of iter::order::lt to handle parse errors properly
                 for (dep_v, stab_v) in
@@ -163,19 +194,29 @@ fn annotate<F>(
             }
         }
 
-        self.recurse_with_stability_attrs(stab, const_stab, visit_children);
+        self.recurse_with_stability_attrs(
+            depr.map(|d| DeprecationEntry::local(d, hir_id)),
+            stab,
+            const_stab,
+            visit_children,
+        );
     }
 
     fn recurse_with_stability_attrs(
         &mut self,
+        depr: Option<DeprecationEntry>,
         stab: Option<&'tcx Stability>,
         const_stab: Option<&'tcx ConstStability>,
         f: impl FnOnce(&mut Self),
     ) {
         // These will be `Some` if this item changes the corresponding stability attribute.
+        let mut replaced_parent_depr = None;
         let mut replaced_parent_stab = None;
         let mut replaced_parent_const_stab = None;
 
+        if let Some(depr) = depr {
+            replaced_parent_depr = Some(replace(&mut self.parent_depr, Some(depr)));
+        }
         if let Some(stab) = stab {
             replaced_parent_stab = Some(replace(&mut self.parent_stab, Some(stab)));
         }
@@ -186,6 +227,9 @@ fn recurse_with_stability_attrs(
 
         f(self);
 
+        if let Some(orig_parent_depr) = replaced_parent_depr {
+            self.parent_depr = orig_parent_depr;
+        }
         if let Some(orig_parent_stab) = replaced_parent_stab {
             self.parent_stab = orig_parent_stab;
         }
@@ -194,14 +238,8 @@ fn recurse_with_stability_attrs(
         }
     }
 
-    fn forbid_staged_api_attrs(
-        &mut self,
-        hir_id: HirId,
-        attrs: &[Attribute],
-        item_sp: Span,
-        kind: AnnotationKind,
-        visit_children: impl FnOnce(&mut Self),
-    ) {
+    // returns true if an error occurred, used to suppress some spurious errors
+    fn forbid_staged_api_attrs(&mut self, hir_id: HirId, attrs: &[Attribute]) -> bool {
         // Emit errors for non-staged-api crates.
         let unstable_attrs = [
             sym::unstable,
@@ -210,6 +248,7 @@ fn forbid_staged_api_attrs(
             sym::rustc_const_unstable,
             sym::rustc_const_stable,
         ];
+        let mut has_error = false;
         for attr in attrs {
             let name = attr.name_or_empty();
             if unstable_attrs.contains(&name) {
@@ -221,6 +260,7 @@ fn forbid_staged_api_attrs(
                     "stability attributes may not be used outside of the standard library",
                 )
                 .emit();
+                has_error = true;
             }
         }
 
@@ -232,24 +272,7 @@ fn forbid_staged_api_attrs(
             }
         }
 
-        if let Some(depr) = attr::find_deprecation(&self.tcx.sess.parse_sess, attrs, item_sp) {
-            if kind == AnnotationKind::Prohibited {
-                self.tcx.sess.span_err(item_sp, "This deprecation annotation is useless");
-            }
-
-            // `Deprecation` is just two pointers, no need to intern it
-            let depr_entry = DeprecationEntry::local(depr, hir_id);
-            self.index.depr_map.insert(hir_id, depr_entry.clone());
-
-            let orig_parent_depr = replace(&mut self.parent_depr, Some(depr_entry));
-            visit_children(self);
-            self.parent_depr = orig_parent_depr;
-        } else if let Some(parent_depr) = self.parent_depr.clone() {
-            self.index.depr_map.insert(hir_id, parent_depr);
-            visit_children(self);
-        } else {
-            visit_children(self);
-        }
+        has_error
     }
 }
 
@@ -454,7 +477,6 @@ fn new_index(tcx: TyCtxt<'tcx>) -> Index<'tcx> {
                     is_soft: false,
                 },
                 feature: sym::rustc_private,
-                rustc_depr: None,
             });
             annotator.parent_stab = Some(stability);
         }
index d85d8401db676bf44dad3db6708fc06fe550c998..3b11fb379625f717b78521c34de778f7d69d04c0 100644 (file)
@@ -3,14 +3,13 @@
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
+use rustc_hir::fake_lang_items::FAKE_ITEMS_REFS;
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::lang_items;
-use rustc_hir::lang_items::ITEM_REFS;
 use rustc_hir::weak_lang_items::WEAK_ITEMS_REFS;
 use rustc_middle::middle::lang_items::required;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::CrateType;
-use rustc_span::symbol::sym;
 use rustc_span::symbol::Symbol;
 use rustc_span::Span;
 
@@ -77,15 +76,14 @@ fn register(&mut self, name: Symbol, span: Span, hir_id: hir::HirId) {
             if self.items.require(item).is_err() {
                 self.items.missing.push(item);
             }
-        } else if name == sym::count_code_region {
-            // `core::intrinsics::code_count_region()` is (currently) the only `extern` lang item
-            // that is never actually linked. It is not a `weak_lang_item` that can be registered
-            // when used, and should be registered here instead.
-            if let Some((item_index, _)) = ITEM_REFS.get(&name).cloned() {
-                if self.items.items[item_index].is_none() {
-                    let item_def_id = self.tcx.hir().local_def_id(hir_id).to_def_id();
-                    self.items.items[item_index] = Some(item_def_id);
-                }
+        } else if let Some(&item) = FAKE_ITEMS_REFS.get(&name) {
+            // Ensure "fake lang items" are registered. These are `extern` lang items that are
+            // injected into the MIR automatically (such as source code coverage counters), but are
+            // never actually linked; therefore, unlike "weak lang items", they cannot by registered
+            // when used, because they never appear to be used.
+            if self.items.items[item as usize].is_none() {
+                let item_def_id = self.tcx.hir().local_def_id(hir_id).to_def_id();
+                self.items.items[item as usize] = Some(item_def_id);
             }
         } else {
             struct_span_err!(self.tcx.sess, span, E0264, "unknown external lang item: `{}`", name)
index c3a60166968888c41799308ce85c4b98d9529b39..62a87b47a2f74e7215a85d1310841273289f7a16 100644 (file)
@@ -55,13 +55,11 @@ fn load_plugin(
     metadata_loader: &dyn MetadataLoader,
     ident: Ident,
 ) {
-    let registrar = locator::find_plugin_registrar(sess, metadata_loader, ident.span, ident.name);
-
-    if let Some((lib, disambiguator)) = registrar {
-        let symbol = sess.generate_plugin_registrar_symbol(disambiguator);
-        let fun = dylink_registrar(sess, ident.span, lib, symbol);
-        plugins.push(fun);
-    }
+    let (lib, disambiguator) =
+        locator::find_plugin_registrar(sess, metadata_loader, ident.span, ident.name);
+    let symbol = sess.generate_plugin_registrar_symbol(disambiguator);
+    let fun = dylink_registrar(sess, ident.span, lib, symbol);
+    plugins.push(fun);
 }
 
 // Dynamically link a registrar function into the compiler process.
index 575049c6bac2fa52ba7f1aba2abb7e78420568f0..a7a005bdeb9f2e3b59b2d0796c2947bc6ae6dddd 100644 (file)
@@ -859,9 +859,7 @@ fn lookup_import_candidates_from_module<FilterFn>(
                     // otherwise cause duplicate suggestions.
                     continue;
                 }
-                if let Some(crate_id) =
-                    self.crate_loader.maybe_process_path_extern(ident.name, ident.span)
-                {
+                if let Some(crate_id) = self.crate_loader.maybe_process_path_extern(ident.name) {
                     let crate_root =
                         self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
                     suggestions.extend(self.lookup_import_candidates_from_module(
index ed88e5496921596a15f783c79c84a648f7a617f8..261c2031364f66d409a012139a21231a4e11dc06 100644 (file)
@@ -1500,11 +1500,17 @@ fn resolve_pattern_inner(
         pat_src: PatternSource,
         bindings: &mut SmallVec<[(PatBoundCtx, FxHashSet<Ident>); 1]>,
     ) {
+        let is_tuple_struct_pat = matches!(pat.kind, PatKind::TupleStruct(_, _));
+
         // Visit all direct subpatterns of this pattern.
         pat.walk(&mut |pat| {
             debug!("resolve_pattern pat={:?} node={:?}", pat, pat.kind);
             match pat.kind {
-                PatKind::Ident(bmode, ident, ref sub) => {
+                // In tuple struct patterns ignore the invalid `ident @ ...`.
+                // It will be handled as an error by the AST lowering.
+                PatKind::Ident(bmode, ident, ref sub)
+                    if !(is_tuple_struct_pat && sub.as_ref().filter(|p| p.is_rest()).is_some()) =>
+                {
                     // First try to resolve the identifier as some existing entity,
                     // then fall back to a fresh binding.
                     let has_sub = sub.is_some();
index 95888c38ba5e1f043710ce0e02b31b709f499026..c86b414184759114559e253ac9c4ed78d7b357e3 100644 (file)
@@ -760,10 +760,8 @@ fn lookup_typo_candidate(
                         if !module.no_implicit_prelude {
                             let extern_prelude = self.r.extern_prelude.clone();
                             names.extend(extern_prelude.iter().flat_map(|(ident, _)| {
-                                self.r
-                                    .crate_loader
-                                    .maybe_process_path_extern(ident.name, ident.span)
-                                    .and_then(|crate_id| {
+                                self.r.crate_loader.maybe_process_path_extern(ident.name).and_then(
+                                    |crate_id| {
                                         let crate_mod = Res::Def(
                                             DefKind::Mod,
                                             DefId { krate: crate_id, index: CRATE_DEF_INDEX },
@@ -774,7 +772,8 @@ fn lookup_typo_candidate(
                                         } else {
                                             None
                                         }
-                                    })
+                                    },
+                                )
                             }));
 
                             if let Some(prelude) = self.r.prelude {
@@ -1142,6 +1141,24 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
         err.emit();
     }
 
+    // FIXME(const_generics): This patches over a ICE caused by non-'static lifetimes in const
+    // generics. We are disallowing this until we can decide on how we want to handle non-'static
+    // lifetimes in const generics. See issue #74052 for discussion.
+    crate fn emit_non_static_lt_in_const_generic_error(&self, lifetime_ref: &hir::Lifetime) {
+        let mut err = struct_span_err!(
+            self.tcx.sess,
+            lifetime_ref.span,
+            E0771,
+            "use of non-static lifetime `{}` in const generic",
+            lifetime_ref
+        );
+        err.note(
+            "for more information, see issue #74052 \
+            <https://github.com/rust-lang/rust/issues/74052>",
+        );
+        err.emit();
+    }
+
     crate fn is_trait_ref_fn_scope(&mut self, trait_ref: &'tcx hir::PolyTraitRef<'tcx>) -> bool {
         if let def::Res::Def(_, did) = trait_ref.trait_ref.path.res {
             if [
index 567db8edec9afe25b550f83e8be1e2df685c28b1..6009e48a54f5ef028f9e4530a93af01e05c362e5 100644 (file)
@@ -173,6 +173,8 @@ struct NamedRegionMap {
     /// Used to disallow the use of in-band lifetimes in `fn` or `Fn` syntax.
     is_in_fn_syntax: bool,
 
+    is_in_const_generic: bool,
+
     /// List of labels in the function/method currently under analysis.
     labels_in_fn: Vec<Ident>,
 
@@ -333,6 +335,7 @@ fn krate(tcx: TyCtxt<'_>) -> NamedRegionMap {
             scope: ROOT_SCOPE,
             trait_ref_hack: false,
             is_in_fn_syntax: false,
+            is_in_const_generic: false,
             labels_in_fn: vec![],
             xcrate_object_lifetime_defaults: Default::default(),
             lifetime_uses: &mut Default::default(),
@@ -828,6 +831,10 @@ fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
             self.insert_lifetime(lifetime_ref, Region::Static);
             return;
         }
+        if self.is_in_const_generic && lifetime_ref.name != LifetimeName::Error {
+            self.emit_non_static_lt_in_const_generic_error(lifetime_ref);
+            return;
+        }
         self.resolve_lifetime_ref(lifetime_ref);
     }
 
@@ -860,8 +867,11 @@ fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) {
                     }
                 }
                 GenericParamKind::Const { ref ty, .. } => {
+                    let was_in_const_generic = self.is_in_const_generic;
+                    self.is_in_const_generic = true;
                     walk_list!(self, visit_param_bound, param.bounds);
                     self.visit_ty(&ty);
+                    self.is_in_const_generic = was_in_const_generic;
                 }
             }
         }
@@ -1317,6 +1327,7 @@ fn with<F>(&mut self, wrap_scope: Scope<'_>, f: F)
             scope: &wrap_scope,
             trait_ref_hack: self.trait_ref_hack,
             is_in_fn_syntax: self.is_in_fn_syntax,
+            is_in_const_generic: self.is_in_const_generic,
             labels_in_fn,
             xcrate_object_lifetime_defaults,
             lifetime_uses,
index 686385e24ece8052b6d86ddb6713c302450dfd3c..da39f79efcd3bc487d8889a90a4d4bab146e8b29 100644 (file)
@@ -2957,7 +2957,7 @@ fn extern_prelude_get(
                 let crate_id = if !speculative {
                     self.crate_loader.process_path_extern(ident.name, ident.span)
                 } else {
-                    self.crate_loader.maybe_process_path_extern(ident.name, ident.span)?
+                    self.crate_loader.maybe_process_path_extern(ident.name)?
                 };
                 let crate_root = self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
                 Some(
index 3976e501c169feb0f46574bf1b19c53f70d5f1df..fee7cb4836e3d6a61e11901540979b02f4e33b23 100644 (file)
@@ -1017,22 +1017,17 @@ fn check_stability_and_deprecation(
                     );
                 }
             }
-            if let Some(depr) = &stability.rustc_depr {
-                let path = pprust::path_to_string(path);
-                let (message, lint) = stability::rustc_deprecation_message(depr, &path);
-                stability::early_report_deprecation(
-                    &mut self.lint_buffer,
-                    &message,
-                    depr.suggestion,
-                    lint,
-                    span,
-                );
-            }
         }
         if let Some(depr) = &ext.deprecation {
             let path = pprust::path_to_string(&path);
             let (message, lint) = stability::deprecation_message(depr, &path);
-            stability::early_report_deprecation(&mut self.lint_buffer, &message, None, lint, span);
+            stability::early_report_deprecation(
+                &mut self.lint_buffer,
+                &message,
+                depr.suggestion,
+                lint,
+                span,
+            );
         }
     }
 
index 348fe105a4315abf15bfc1420df7304734c74359..620a04b45b0e4c457823af78a21d1bc9abf2b38b 100644 (file)
@@ -103,7 +103,7 @@ pub enum Strip {
     Symbols,
 }
 
-/// The different settings that the `-Z control-flow-guard` flag can have.
+/// The different settings that the `-C control-flow-guard` flag can have.
 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
 pub enum CFGuard {
     /// Do not emit Control Flow Guard metadata or checks.
@@ -1707,6 +1707,31 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
         );
     }
 
+    if debugging_opts.instrument_coverage {
+        if cg.profile_generate.enabled() || cg.profile_use.is_some() {
+            early_error(
+                error_format,
+                "option `-Z instrument-coverage` is not compatible with either `-C profile-use` \
+                or `-C profile-generate`",
+            );
+        }
+
+        // `-Z instrument-coverage` implies:
+        //   * `-Z symbol-mangling-version=v0` - to ensure consistent and reversable name mangling.
+        //     Note, LLVM coverage tools can analyze coverage over multiple runs, including some
+        //     changes to source code; so mangled names must be consistent across compilations.
+        //   * `-C link-dead-code` - so unexecuted code is still counted as zero, rather than be
+        //     optimized out. Note that instrumenting dead code can be explicitly disabled with:
+        //         `-Z instrument-coverage -C link-dead-code=no`.
+        debugging_opts.symbol_mangling_version = SymbolManglingVersion::V0;
+        if cg.link_dead_code == None {
+            // FIXME(richkadel): Investigate if the `instrument-coverage` implementation can
+            // inject ["zero counters"](https://llvm.org/docs/CoverageMappingFormat.html#counter)
+            // in the coverage map when "dead code" is removed, rather than forcing `link-dead-code`.
+            cg.link_dead_code = Some(true);
+        }
+    }
+
     if !cg.embed_bitcode {
         match cg.lto {
             LtoCli::No | LtoCli::Unspecified => {}
index 2ad7d09cbf415ff4ebb3bc5c0a77f73bbe5b4388..502102fa1787647139a57ffa11dc4b14868bc736 100644 (file)
@@ -692,6 +692,8 @@ fn parse_target_feature(slot: &mut String, v: Option<&str>) -> bool {
         "choose the code model to use (`rustc --print code-models` for details)"),
     codegen_units: Option<usize> = (None, parse_opt_uint, [UNTRACKED],
         "divide crate into N units to optimize in parallel"),
+    control_flow_guard: CFGuard = (CFGuard::Disabled, parse_cfguard, [TRACKED],
+        "use Windows Control Flow Guard (default: no)"),
     debug_assertions: Option<bool> = (None, parse_opt_bool, [TRACKED],
         "explicitly enable the `cfg(debug_assertions)` directive"),
     debuginfo: usize = (0, parse_uint, [TRACKED],
@@ -715,7 +717,7 @@ fn parse_target_feature(slot: &mut String, v: Option<&str>) -> bool {
         "a single extra argument to append to the linker invocation (can be used several times)"),
     link_args: Vec<String> = (Vec::new(), parse_list, [UNTRACKED],
         "extra arguments to append to the linker invocation (space separated)"),
-    link_dead_code: bool = (false, parse_bool, [UNTRACKED],
+    link_dead_code: Option<bool> = (None, parse_opt_bool, [UNTRACKED],
         "keep dead code at link time (useful for code coverage) (default: no)"),
     linker: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
         "system linker to link outputs with"),
@@ -809,8 +811,6 @@ fn parse_target_feature(slot: &mut String, v: Option<&str>) -> bool {
         "enable the experimental Chalk-based trait solving engine"),
     codegen_backend: Option<String> = (None, parse_opt_string, [TRACKED],
         "the backend to use"),
-    control_flow_guard: CFGuard = (CFGuard::Disabled, parse_cfguard, [TRACKED],
-        "use Windows Control Flow Guard (default: no)"),
     crate_attr: Vec<String> = (Vec::new(), parse_string_push, [TRACKED],
         "inject the given attribute in the crate"),
     debug_macros: bool = (false, parse_bool, [TRACKED],
@@ -880,10 +880,12 @@ fn parse_target_feature(slot: &mut String, v: Option<&str>) -> bool {
         (such as entering an empty infinite loop) by inserting llvm.sideeffect \
         (default: no)"),
     instrument_coverage: bool = (false, parse_bool, [TRACKED],
-        "instrument the generated code with LLVM code region counters to (in the \
-        future) generate coverage reports; disables/overrides some optimization \
-        options (note, the compiler build config must include `profiler = true`) \
-        (default: no)"),
+        "instrument the generated code to support LLVM source-based code coverage \
+        reports (note, the compiler build config must include `profiler = true`, \
+        and is mutually exclusive with `-C profile-generate`/`-C profile-use`); \
+        implies `-C link-dead-code` (unless explicitly disabled)` and
+        `-Z symbol-mangling-version=v0`; and disables/overrides some optimization \
+        options (default: no)"),
     instrument_mcount: bool = (false, parse_bool, [TRACKED],
         "insert function instrument code for mcount-based tracing (default: no)"),
     keep_hygiene_data: bool = (false, parse_bool, [UNTRACKED],
@@ -947,6 +949,8 @@ fn parse_target_feature(slot: &mut String, v: Option<&str>) -> bool {
         (default: PLT is disabled if full relro is enabled)"),
     polonius: bool = (false, parse_bool, [UNTRACKED],
         "enable polonius-based borrow-checker (default: no)"),
+    polymorphize: bool = (false, parse_bool, [TRACKED],
+          "perform polymorphization analysis"),
     pre_link_arg: (/* redirected to pre_link_args */) = ((), parse_string_push, [UNTRACKED],
         "a single extra argument to prepend the linker invocation (can be used several times)"),
     pre_link_args: Vec<String> = (Vec::new(), parse_list, [UNTRACKED],
index fcd5dab94a6c25efe39d6c0f0a2ea23dabe3665a..1b8f6cdd8bebcc7a2d8bd328a4dd14d25a7c27be 100644 (file)
@@ -548,7 +548,7 @@ pub fn asm_comments(&self) -> bool {
         self.opts.debugging_opts.asm_comments
     }
     pub fn verify_llvm_ir(&self) -> bool {
-        self.opts.debugging_opts.verify_llvm_ir || cfg!(always_verify_llvm_ir)
+        self.opts.debugging_opts.verify_llvm_ir || option_env!("RUSTC_VERIFY_LLVM_IR").is_some()
     }
     pub fn borrowck_stats(&self) -> bool {
         self.opts.debugging_opts.borrowck_stats
@@ -1357,6 +1357,20 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
         );
     }
 
+    // FIXME(richkadel): See `src/test/run-make-fulldeps/instrument-coverage/Makefile`. After
+    // compiling with `-Zinstrument-coverage`, the resulting binary generates a segfault during
+    // the program's exit process (likely while attempting to generate the coverage stats in
+    // the "*.profraw" file). An investigation to resolve the problem on Windows is ongoing,
+    // but until this is resolved, the option is disabled on Windows, and the test is skipped
+    // when targeting `MSVC`.
+    if sess.opts.debugging_opts.instrument_coverage && sess.target.target.options.is_like_msvc {
+        sess.warn(
+            "Rust source-based code coverage instrumentation (with `-Z instrument-coverage`) \
+            is not yet supported on Windows when targeting MSVC. The resulting binaries will \
+            still be instrumented for experimentation purposes, but may not execute correctly.",
+        );
+    }
+
     const ASAN_SUPPORTED_TARGETS: &[&str] = &[
         "aarch64-fuchsia",
         "aarch64-unknown-linux-gnu",
index 5d332ddf5f3df1ccecf1165219bd67d875fdd1b9..22a5115c7f556f12c508a678c299cd59048ec6b4 100644 (file)
         rustc_peek_liveness,
         rustc_peek_maybe_init,
         rustc_peek_maybe_uninit,
+        rustc_polymorphize_error,
         rustc_private,
         rustc_proc_macro_decls,
         rustc_promotable,
index 3038b0c6bd7eb26062d824e718fc07b16381f881..90c89ea6b0a86243b8be7e564c50abb1a5c139a8 100644 (file)
@@ -116,7 +116,6 @@ fn get_symbol_hash<'tcx>(
 
         // also include any type parameters (for generic items)
         assert!(!substs.has_erasable_regions());
-        assert!(!substs.needs_subst());
         substs.hash_stable(&mut hcx, &mut hasher);
 
         if let Some(instantiating_crate) = instantiating_crate {
index c79e9bb28900882ed0a41860f628a477d56b16a8..b3e5f5c0c74b163e90d55d521ac17a93e1050059 100644 (file)
@@ -32,7 +32,7 @@ pub struct TargetDataLayout {
     /// Alignments for vector types.
     pub vector_align: Vec<(Size, AbiAndPrefAlign)>,
 
-    pub instruction_address_space: u32,
+    pub instruction_address_space: AddressSpace,
 }
 
 impl Default for TargetDataLayout {
@@ -56,7 +56,7 @@ fn default() -> TargetDataLayout {
                 (Size::from_bits(64), AbiAndPrefAlign::new(align(64))),
                 (Size::from_bits(128), AbiAndPrefAlign::new(align(128))),
             ],
-            instruction_address_space: 0,
+            instruction_address_space: AddressSpace::DATA,
         }
     }
 }
@@ -65,7 +65,7 @@ impl TargetDataLayout {
     pub fn parse(target: &Target) -> Result<TargetDataLayout, String> {
         // Parse an address space index from a string.
         let parse_address_space = |s: &str, cause: &str| {
-            s.parse::<u32>().map_err(|err| {
+            s.parse::<u32>().map(AddressSpace).map_err(|err| {
                 format!("invalid address space `{}` for `{}` in \"data-layout\": {}", s, cause, err)
             })
         };
@@ -744,6 +744,17 @@ pub fn index_by_increasing_offset<'a>(&'a self) -> impl Iterator<Item = usize> +
     }
 }
 
+/// An identifier that specifies the address space that some operation
+/// should operate on. Special address spaces have an effect on code generation,
+/// depending on the target and the address spaces it implements.
+#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
+pub struct AddressSpace(pub u32);
+
+impl AddressSpace {
+    /// The default address space, corresponding to data space.
+    pub const DATA: Self = AddressSpace(0);
+}
+
 /// Describes how values of the type are passed by target ABIs,
 /// in terms of categories of C types there are ABI rules for.
 #[derive(Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
@@ -1013,7 +1024,7 @@ fn to_result(self) -> Result<T, Self::Error> {
     }
 }
 
-#[derive(Copy, Clone, PartialEq, Eq)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
 pub enum PointerKind {
     /// Most general case, we know no restrictions to tell LLVM.
     Shared,
@@ -1028,11 +1039,12 @@ pub enum PointerKind {
     UniqueOwned,
 }
 
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Debug)]
 pub struct PointeeInfo {
     pub size: Size,
     pub align: Align,
     pub safe: Option<PointerKind>,
+    pub address_space: AddressSpace,
 }
 
 pub trait TyAndLayoutMethods<'a, C: LayoutOf<Ty = Self>>: Sized {
diff --git a/src/librustc_target/build.rs b/src/librustc_target/build.rs
deleted file mode 100644 (file)
index 368200b..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-fn main() {
-    println!("cargo:rerun-if-changed=build.rs");
-    println!("cargo:rerun-if-env-changed=CFG_DEFAULT_LINKER");
-}
diff --git a/src/librustc_target/spec/aarch64_apple_darwin.rs b/src/librustc_target/spec/aarch64_apple_darwin.rs
new file mode 100644 (file)
index 0000000..60daf10
--- /dev/null
@@ -0,0 +1,30 @@
+use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+
+pub fn target() -> TargetResult {
+    let mut base = super::apple_base::opts();
+    base.cpu = "apple-a12".to_string();
+    base.max_atomic_width = Some(128);
+    base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-arch".to_string(), "arm64".to_string()]);
+
+    base.link_env_remove.extend(super::apple_base::macos_link_env_remove());
+
+    // Clang automatically chooses a more specific target based on
+    // MACOSX_DEPLOYMENT_TARGET.  To enable cross-language LTO to work
+    // correctly, we do too.
+    let arch = "aarch64";
+    let llvm_target = super::apple_base::macos_llvm_target(&arch);
+
+    Ok(Target {
+        llvm_target,
+        target_endian: "little".to_string(),
+        target_pointer_width: "64".to_string(),
+        target_c_int_width: "32".to_string(),
+        data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".to_string(),
+        arch: arch.to_string(),
+        target_os: "macos".to_string(),
+        target_env: String::new(),
+        target_vendor: "apple".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
+        options: TargetOptions { target_mcount: "\u{1}mcount".to_string(), ..base },
+    })
+}
index bdd5a893d34e2c19c1a300b986010ceb32fd2736..e7b565ae9cad979a7741b6509713db4ae8157d9f 100644 (file)
@@ -31,6 +31,7 @@ pub fn opts() -> TargetOptions {
         has_elf_tls: version >= (10, 7),
         abi_return_struct_as_int: true,
         emit_debug_gdb_scripts: false,
+        eh_frame_header: false,
 
         // This environment variable is pretty magical but is intended for
         // producing deterministic builds. This was first discovered to be used
index 5402ea074fae1ee891c64a17560783761408ff6e..c338856228dc66b607304672531fe61243f4b3ce 100644 (file)
@@ -25,6 +25,7 @@ pub fn opts() -> TargetOptions {
         has_rpath: false,
         pre_link_args: args,
         position_independent_executables: false,
+        eh_frame_header: false,
         ..Default::default()
     }
 }
index 35ac346fb3f6f1586d6f32167aa00b04a9c1be41..214142b88fc2c7721f6617ba6e999abdbb6d0c25 100644 (file)
@@ -23,6 +23,7 @@ pub fn opts() -> TargetOptions {
         is_like_solaris: true,
         limit_rdylib_exports: false, // Linker doesn't support this
         eliminate_frame_pointer: false,
+        eh_frame_header: false,
         late_link_args,
 
         // While we support ELF TLS, rust requires a way to register
index 231ab1ea68ded7d538114a32e755a868f4183b18..961a438fd233cc175c5019a5d984ab5a0eb2de58 100644 (file)
@@ -574,6 +574,7 @@ fn $module() {
     ("i686-unknown-haiku", i686_unknown_haiku),
     ("x86_64-unknown-haiku", x86_64_unknown_haiku),
 
+    ("aarch64-apple-darwin", aarch64_apple_darwin),
     ("x86_64-apple-darwin", x86_64_apple_darwin),
     ("i686-apple-darwin", i686_apple_darwin),
 
@@ -676,6 +677,7 @@ fn $module() {
     ("powerpc64-wrs-vxworks", powerpc64_wrs_vxworks),
 
     ("mipsel-sony-psp", mipsel_sony_psp),
+    ("thumbv4t-none-eabi", thumbv4t_none_eabi),
 }
 
 /// Everything `rustc` knows about how to compile for a specific target.
@@ -986,6 +988,11 @@ pub struct TargetOptions {
     /// Whether to use legacy .ctors initialization hooks rather than .init_array. Defaults
     /// to false (uses .init_array).
     pub use_ctors_section: bool,
+
+    /// Whether the linker is instructed to add a `GNU_EH_FRAME` ELF header
+    /// used to locate unwinding information is passed
+    /// (only has effect if the linker is `ld`-like).
+    pub eh_frame_header: bool,
 }
 
 impl Default for TargetOptions {
@@ -1077,6 +1084,7 @@ fn default() -> TargetOptions {
             relax_elf_relocations: false,
             llvm_args: vec![],
             use_ctors_section: false,
+            eh_frame_header: true,
         }
     }
 }
@@ -1469,6 +1477,7 @@ macro_rules! key {
         key!(relax_elf_relocations, bool);
         key!(llvm_args, list);
         key!(use_ctors_section, bool);
+        key!(eh_frame_header, bool);
 
         // NB: The old name is deprecated, but support for it is retained for
         // compatibility.
@@ -1706,6 +1715,7 @@ macro_rules! target_option_val {
         target_option_val!(relax_elf_relocations);
         target_option_val!(llvm_args);
         target_option_val!(use_ctors_section);
+        target_option_val!(eh_frame_header);
 
         if default.unsupported_abis != self.options.unsupported_abis {
             d.insert(
index c6d0308f8f82feec5ef3022e3dab8b44a304cb12..f75697996ac7863870e02b78052bc5a09c613945 100644 (file)
@@ -56,6 +56,8 @@ pub fn target() -> TargetResult {
             // See the thumb_base.rs file for an explanation of this value
             emit_debug_gdb_scripts: false,
 
+            eh_frame_header: false,
+
             ..Default::default()
         },
     })
index 977aa896f2520573df84a8c8b7eea9b708f7d078..5b5e342000b55d70d486a0bc508215ef983e3785 100644 (file)
@@ -25,6 +25,7 @@ pub fn target() -> TargetResult {
             relocation_model: RelocModel::Static,
             emit_debug_gdb_scripts: false,
             unsupported_abis: super::riscv_base::unsupported_abis(),
+            eh_frame_header: false,
             ..Default::default()
         },
     })
index 1a85cdff1315ca0f41a4fc2b1b2a89fd3ad606df..4cef5c42d8ddfc8c54d5036280a3fcd38402c563 100644 (file)
@@ -25,6 +25,7 @@ pub fn target() -> TargetResult {
             relocation_model: RelocModel::Static,
             emit_debug_gdb_scripts: false,
             unsupported_abis: super::riscv_base::unsupported_abis(),
+            eh_frame_header: false,
             ..Default::default()
         },
     })
index e3c1c6908a23af24a13cba44b2bf421fe0bf3a0c..8ad563e441de3183345e829804e9c2befbdf814a 100644 (file)
@@ -25,6 +25,7 @@ pub fn target() -> TargetResult {
             relocation_model: RelocModel::Static,
             emit_debug_gdb_scripts: false,
             unsupported_abis: super::riscv_base::unsupported_abis(),
+            eh_frame_header: false,
             ..Default::default()
         },
     })
index 857af4ceb0d9f1635a8e3cfbd9af18b07720372a..3aeb3f3ca72b2beef3b33f89641cc4a398105bcf 100644 (file)
@@ -26,6 +26,7 @@ pub fn target() -> TargetResult {
             code_model: Some(CodeModel::Medium),
             emit_debug_gdb_scripts: false,
             unsupported_abis: super::riscv_base::unsupported_abis(),
+            eh_frame_header: false,
             ..Default::default()
         },
     })
index 36fe7730f95bfcaea3837c556d2a93683ea804e5..d8144964dc913277ea849a163e7dd68a55c51baf 100644 (file)
@@ -26,6 +26,7 @@ pub fn target() -> TargetResult {
             code_model: Some(CodeModel::Medium),
             emit_debug_gdb_scripts: false,
             unsupported_abis: super::riscv_base::unsupported_abis(),
+            eh_frame_header: false,
             ..Default::default()
         },
     })
index 8d3a3563f4164a87fc6de8803e52be11da28a16f..3d7f0034b8b10dd128f5311102e431d93dcc9f2b 100644 (file)
@@ -8,6 +8,7 @@ pub fn opts() -> TargetOptions {
         target_family: Some("unix".to_string()),
         is_like_solaris: true,
         limit_rdylib_exports: false, // Linker doesn't support this
+        eh_frame_header: false,
 
         ..Default::default()
     }
diff --git a/src/librustc_target/spec/thumbv4t_none_eabi.rs b/src/librustc_target/spec/thumbv4t_none_eabi.rs
new file mode 100644 (file)
index 0000000..31417b0
--- /dev/null
@@ -0,0 +1,62 @@
+//! Targets the ARMv4T, with code as `t32` code by default.
+//!
+//! Primarily of use for the GBA, but usable with other devices too.
+//!
+//! Please ping @Lokathor if changes are needed.
+//!
+//! This target profile assumes that you have the ARM binutils in your path (specifically the linker, `arm-none-eabi-ld`). They can be obtained for free for all major OSes from the ARM developer's website, and they may also be available in your system's package manager. Unfortunately, the standard linker that Rust uses (`lld`) only supports as far back as `ARMv5TE`, so we must use the GNU `ld` linker.
+//!
+//! **Important:** This target profile **does not** specify a linker script. You just get the default link script when you build a binary for this target. The default link script is very likely wrong, so you should use `-Clink-arg=-Tmy_script.ld` to override that with a correct linker script.
+
+use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+
+pub fn target() -> TargetResult {
+    Ok(Target {
+        llvm_target: "thumbv4t-none-eabi".to_string(),
+        target_endian: "little".to_string(),
+        target_pointer_width: "32".to_string(),
+        target_c_int_width: "32".to_string(),
+        target_os: "none".to_string(),
+        target_env: "".to_string(),
+        target_vendor: "".to_string(),
+        arch: "arm".to_string(),
+        /* Data layout args are '-' separated:
+         * little endian
+         * stack is 64-bit aligned (EABI)
+         * pointers are 32-bit
+         * i64 must be 64-bit aligned (EABI)
+         * mangle names with ELF style
+         * native integers are 32-bit
+         * All other elements are default
+         */
+        data_layout: "e-S64-p:32:32-i64:64-m:e-n32".to_string(),
+        linker_flavor: LinkerFlavor::Ld,
+        options: TargetOptions {
+            linker: Some("arm-none-eabi-ld".to_string()),
+            linker_is_gnu: true,
+
+            // extra args passed to the external assembler (assuming `arm-none-eabi-as`):
+            // * activate t32/a32 interworking
+            // * use arch ARMv4T
+            // * use little-endian
+            asm_args: vec![
+                "-mthumb-interwork".to_string(),
+                "-march=armv4t".to_string(),
+                "-mlittle-endian".to_string(),
+            ],
+
+            // minimum extra features, these cannot be disabled via -C
+            features: "+soft-float,+strict-align".to_string(),
+
+            main_needs_argc_argv: false,
+
+            // No thread-local storage (just use a static Cell)
+            has_elf_tls: false,
+
+            // don't have atomic compare-and-swap
+            atomic_cas: false,
+
+            ..super::thumb_base::opts()
+        },
+    })
+}
index 680dbbad4b0a02e91f0bc76ef1570f0f82d7b156..69236e98e58d7890befe267b1076a2cfd6268f23 100644 (file)
@@ -91,6 +91,7 @@ pub fn opts() -> TargetOptions {
         abi_return_struct_as_int: true,
         emit_debug_gdb_scripts: false,
         requires_uwtable: true,
+        eh_frame_header: false,
 
         ..Default::default()
     }
index 31011e847495838d3a1083b6449c88942052b0f9..909aebec70b58766a1f26d55b7f6b2828903049e 100644 (file)
@@ -5,7 +5,10 @@ pub fn target() -> TargetResult {
     base.cpu = "core2".to_string();
     base.max_atomic_width = Some(128); // core2 support cmpxchg16b
     base.eliminate_frame_pointer = false;
-    base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]);
+    base.pre_link_args.insert(
+        LinkerFlavor::Gcc,
+        vec!["-m64".to_string(), "-arch".to_string(), "x86_64".to_string()],
+    );
     base.link_env_remove.extend(super::apple_base::macos_link_env_remove());
     base.stack_probes = true;
 
index cf575d3eca9c226853e7481af7b0b728f180a0ae..dd7ea55cc1043693be0a1e0e96399a602c21c32e 100644 (file)
@@ -6,6 +6,7 @@
 use crate::infer::{InferCtxt, TyCtxtInferExt};
 use crate::traits::{
     FulfillmentContext, ImplSource, Obligation, ObligationCause, SelectionContext, TraitEngine,
+    Unimplemented,
 };
 use rustc_errors::ErrorReported;
 use rustc_middle::ty::fold::TypeFoldable;
@@ -58,6 +59,18 @@ pub fn codegen_fulfill_obligation<'tcx>(
                 );
                 return Err(ErrorReported);
             }
+            Err(Unimplemented) => {
+                // This can trigger when we probe for the source of a `'static` lifetime requirement
+                // on a trait object: `impl Foo for dyn Trait {}` has an implicit `'static` bound.
+                infcx.tcx.sess.delay_span_bug(
+                    rustc_span::DUMMY_SP,
+                    &format!(
+                        "Encountered error `Unimplemented` selecting `{:?}` during codegen",
+                        trait_ref
+                    ),
+                );
+                return Err(ErrorReported);
+            }
             Err(e) => {
                 bug!("Encountered error `{:?}` selecting `{:?}` during codegen", e, trait_ref)
             }
index 3ec7fe2bf25c68f2635fb64f117a8487ee374bde..b06cf4411d053188e80f90188b4ea1c5125a526f 100644 (file)
@@ -289,11 +289,11 @@ pub fn orphan_check(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Result<(), OrphanChe
 ///     - but (knowing that `Vec<T>` is non-fundamental, and assuming it's
 ///       not local), `Vec<LocalType>` is bad, because `Vec<->` is between
 ///       the local type and the type parameter.
-/// 3. Every type parameter before the local key parameter is fully known in C.
-///     - e.g., `impl<T> T: Trait<LocalType>` is bad, because `T` might be
-///       an unknown type.
-///     - but `impl<T> LocalType: Trait<T>` is OK, because `LocalType`
-///       occurs before `T`.
+/// 3. Before this local type, no generic type parameter of the impl must
+///    be reachable through fundamental types.
+///     - e.g. `impl<T> Trait<LocalType> for Vec<T>` is fine, as `Vec` is not fundamental.
+///     - while `impl<T> Trait<LocalType for Box<T>` results in an error, as `T` is
+///       reachable through the fundamental type `Box`.
 /// 4. Every type in the local key parameter not known in C, going
 ///    through the parameter's type tree, must appear only as a subtree of
 ///    a type local to C, with only fundamental types between the type
@@ -387,9 +387,9 @@ fn uncover_fundamental_ty<'tcx>(
         ty: Ty<'tcx>,
         in_crate: InCrate,
     ) -> Vec<Ty<'tcx>> {
-        // FIXME(eddyb) figure out if this is redundant with `ty_is_non_local`,
-        // or maybe if this should be calling `ty_is_non_local_constructor`.
-        if ty_is_non_local(tcx, ty, in_crate).is_some() {
+        // FIXME: this is currently somewhat overly complicated,
+        // but fixing this requires a more complicated refactor.
+        if !contained_non_local_types(tcx, ty, in_crate).is_empty() {
             if let Some(inner_tys) = fundamental_ty_inner_tys(tcx, ty) {
                 return inner_tys
                     .flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate))
@@ -408,8 +408,8 @@ fn uncover_fundamental_ty<'tcx>(
         .enumerate()
     {
         debug!("orphan_check_trait_ref: check ty `{:?}`", input_ty);
-        let non_local_tys = ty_is_non_local(tcx, input_ty, in_crate);
-        if non_local_tys.is_none() {
+        let non_local_tys = contained_non_local_types(tcx, input_ty, in_crate);
+        if non_local_tys.is_empty() {
             debug!("orphan_check_trait_ref: ty_is_local `{:?}`", input_ty);
             return Ok(());
         } else if let ty::Param(_) = input_ty.kind {
@@ -418,16 +418,15 @@ fn uncover_fundamental_ty<'tcx>(
                 .substs
                 .types()
                 .flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate))
-                .find(|ty| ty_is_non_local_constructor(ty, in_crate).is_none());
+                .find(|ty| ty_is_local_constructor(ty, in_crate));
 
             debug!("orphan_check_trait_ref: uncovered ty local_type: `{:?}`", local_type);
 
             return Err(OrphanCheckErr::UncoveredTy(input_ty, local_type));
         }
-        if let Some(non_local_tys) = non_local_tys {
-            for input_ty in non_local_tys {
-                non_local_spans.push((input_ty, i == 0));
-            }
+
+        for input_ty in non_local_tys {
+            non_local_spans.push((input_ty, i == 0));
         }
     }
     // If we exit above loop, never found a local type.
@@ -435,20 +434,29 @@ fn uncover_fundamental_ty<'tcx>(
     Err(OrphanCheckErr::NonLocalInputType(non_local_spans))
 }
 
-fn ty_is_non_local(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, in_crate: InCrate) -> Option<Vec<Ty<'tcx>>> {
-    match ty_is_non_local_constructor(ty, in_crate) {
-        Some(ty) => {
-            if let Some(inner_tys) = fundamental_ty_inner_tys(tcx, ty) {
-                let tys: Vec<_> = inner_tys
-                    .filter_map(|ty| ty_is_non_local(tcx, ty, in_crate))
-                    .flatten()
-                    .collect();
-                if tys.is_empty() { None } else { Some(tys) }
-            } else {
-                Some(vec![ty])
+/// Returns a list of relevant non-local types for `ty`.
+///
+/// This is just `ty` itself unless `ty` is `#[fundamental]`,
+/// in which case we recursively look into this type.
+///
+/// If `ty` is local itself, this method returns an empty `Vec`.
+///
+/// # Examples
+///
+/// - `u32` is not local, so this returns `[u32]`.
+/// - for `Foo<u32>`, where `Foo` is a local type, this returns `[]`.
+/// - `&mut u32` returns `[u32]`, as `&mut` is a fundamental type, similar to `Box`.
+/// - `Box<Foo<u32>>` returns `[]`, as `Box` is a fundamental type and `Foo` is local.
+fn contained_non_local_types(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, in_crate: InCrate) -> Vec<Ty<'tcx>> {
+    if ty_is_local_constructor(ty, in_crate) {
+        Vec::new()
+    } else {
+        match fundamental_ty_inner_tys(tcx, ty) {
+            Some(inner_tys) => {
+                inner_tys.flat_map(|ty| contained_non_local_types(tcx, ty, in_crate)).collect()
             }
+            None => vec![ty],
         }
-        None => None,
     }
 }
 
@@ -493,9 +501,8 @@ fn def_id_is_local(def_id: DefId, in_crate: InCrate) -> bool {
     }
 }
 
-// FIXME(eddyb) this can just return `bool` as it always returns `Some(ty)` or `None`.
-fn ty_is_non_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> Option<Ty<'_>> {
-    debug!("ty_is_non_local_constructor({:?})", ty);
+fn ty_is_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> bool {
+    debug!("ty_is_local_constructor({:?})", ty);
 
     match ty.kind {
         ty::Bool
@@ -513,29 +520,17 @@ fn ty_is_non_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> Option<Ty<'_>>
         | ty::Never
         | ty::Tuple(..)
         | ty::Param(..)
-        | ty::Projection(..) => Some(ty),
+        | ty::Projection(..) => false,
 
         ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) => match in_crate {
-            InCrate::Local => Some(ty),
+            InCrate::Local => false,
             // The inference variable might be unified with a local
             // type in that remote crate.
-            InCrate::Remote => None,
+            InCrate::Remote => true,
         },
 
-        ty::Adt(def, _) => {
-            if def_id_is_local(def.did, in_crate) {
-                None
-            } else {
-                Some(ty)
-            }
-        }
-        ty::Foreign(did) => {
-            if def_id_is_local(did, in_crate) {
-                None
-            } else {
-                Some(ty)
-            }
-        }
+        ty::Adt(def, _) => def_id_is_local(def.did, in_crate),
+        ty::Foreign(did) => def_id_is_local(did, in_crate),
         ty::Opaque(..) => {
             // This merits some explanation.
             // Normally, opaque types are not involed when performing
@@ -553,7 +548,7 @@ fn ty_is_non_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> Option<Ty<'_>>
             // the underlying type *within the same crate*. When an
             // opaque type is used from outside the module
             // where it is declared, it should be impossible to observe
-            // anyything about it other than the traits that it implements.
+            // anything about it other than the traits that it implements.
             //
             // The alternative would be to look at the underlying type
             // to determine whether or not the opaque type itself should
@@ -562,18 +557,18 @@ fn ty_is_non_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> Option<Ty<'_>>
             // to a remote type. This would violate the rule that opaque
             // types should be completely opaque apart from the traits
             // that they implement, so we don't use this behavior.
-            Some(ty)
+            false
         }
 
         ty::Dynamic(ref tt, ..) => {
             if let Some(principal) = tt.principal() {
-                if def_id_is_local(principal.def_id(), in_crate) { None } else { Some(ty) }
+                def_id_is_local(principal.def_id(), in_crate)
             } else {
-                Some(ty)
+                false
             }
         }
 
-        ty::Error(_) => None,
+        ty::Error(_) => true,
 
         ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) => {
             bug!("ty_is_local invoked on unexpected type: {:?}", ty)
index 0a6fb72ca51eae890af70698ac34d8b50d788cf9..0632ce2319aeef1d462898e2537243cbcd7f0d42 100644 (file)
@@ -1706,6 +1706,7 @@ fn note_obligation_cause_code<T>(
             | ObligationCauseCode::IntrinsicType
             | ObligationCauseCode::MethodReceiver
             | ObligationCauseCode::ReturnNoExpression
+            | ObligationCauseCode::UnifyReceiver(..)
             | ObligationCauseCode::MiscObligation => {}
             ObligationCauseCode::SliceOrArrayElem => {
                 err.note("slice and array elements must have `Sized` type");
index e8006129e3ef8666f8148c34c7f185a97cbe282e..1c3755222495e28585dbb4d83efb2d57de7b8ee9 100644 (file)
@@ -418,15 +418,14 @@ pub fn fully_normalize<'a, 'tcx, T>(
     Ok(resolved_value)
 }
 
-/// Normalizes the predicates and checks whether they hold in an empty
-/// environment. If this returns false, then either normalize
-/// encountered an error or one of the predicates did not hold. Used
-/// when creating vtables to check for unsatisfiable methods.
-pub fn normalize_and_test_predicates<'tcx>(
+/// Normalizes the predicates and checks whether they hold in an empty environment. If this
+/// returns true, then either normalize encountered an error or one of the predicates did not
+/// hold. Used when creating vtables to check for unsatisfiable methods.
+pub fn impossible_predicates<'tcx>(
     tcx: TyCtxt<'tcx>,
     predicates: Vec<ty::Predicate<'tcx>>,
 ) -> bool {
-    debug!("normalize_and_test_predicates(predicates={:?})", predicates);
+    debug!("impossible_predicates(predicates={:?})", predicates);
 
     let result = tcx.infer_ctxt().enter(|infcx| {
         let param_env = ty::ParamEnv::reveal_all();
@@ -443,22 +442,23 @@ pub fn normalize_and_test_predicates<'tcx>(
             fulfill_cx.register_predicate_obligation(&infcx, obligation);
         }
 
-        fulfill_cx.select_all_or_error(&infcx).is_ok()
+        fulfill_cx.select_all_or_error(&infcx).is_err()
     });
-    debug!("normalize_and_test_predicates(predicates={:?}) = {:?}", predicates, result);
+    debug!("impossible_predicates(predicates={:?}) = {:?}", predicates, result);
     result
 }
 
-fn substitute_normalize_and_test_predicates<'tcx>(
+fn subst_and_check_impossible_predicates<'tcx>(
     tcx: TyCtxt<'tcx>,
     key: (DefId, SubstsRef<'tcx>),
 ) -> bool {
-    debug!("substitute_normalize_and_test_predicates(key={:?})", key);
+    debug!("subst_and_check_impossible_predicates(key={:?})", key);
 
-    let predicates = tcx.predicates_of(key.0).instantiate(tcx, key.1).predicates;
-    let result = normalize_and_test_predicates(tcx, predicates);
+    let mut predicates = tcx.predicates_of(key.0).instantiate(tcx, key.1).predicates;
+    predicates.retain(|predicate| !predicate.needs_subst());
+    let result = impossible_predicates(tcx, predicates);
 
-    debug!("substitute_normalize_and_test_predicates(key={:?}) = {:?}", key, result);
+    debug!("subst_and_check_impossible_predicates(key={:?}) = {:?}", key, result);
     result
 }
 
@@ -510,7 +510,7 @@ fn vtable_methods<'tcx>(
             // 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 !normalize_and_test_predicates(tcx, predicates.predicates) {
+            if impossible_predicates(tcx, predicates.predicates) {
                 debug!("vtable_methods: predicates do not hold");
                 return None;
             }
@@ -558,8 +558,8 @@ pub fn provide(providers: &mut ty::query::Providers) {
         specializes: specialize::specializes,
         codegen_fulfill_obligation: codegen::codegen_fulfill_obligation,
         vtable_methods,
-        substitute_normalize_and_test_predicates,
         type_implements_trait,
+        subst_and_check_impossible_predicates,
         ..*providers
     };
 }
index 0bc6c4709786833e4b0ac3eeead6554635e9a579..324ae4ec29e9b9cd7eb75a243e0069b15495bb16 100644 (file)
@@ -3,7 +3,7 @@
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::{self, Instance, TyCtxt, TypeFoldable};
-use rustc_span::sym;
+use rustc_span::{sym, DUMMY_SP};
 use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::traits;
 use traits::{translate_substs, Reveal};
@@ -67,12 +67,19 @@ fn inner_resolve_instance<'tcx>(
                 let ty = substs.type_at(0);
 
                 if ty.needs_drop(tcx, param_env) {
-                    // `DropGlue` requires a monomorphic aka concrete type.
-                    if ty.needs_subst() {
-                        return Ok(None);
+                    debug!(" => nontrivial drop glue");
+                    match ty.kind {
+                        ty::Closure(..)
+                        | ty::Generator(..)
+                        | ty::Tuple(..)
+                        | ty::Adt(..)
+                        | ty::Dynamic(..)
+                        | ty::Array(..)
+                        | ty::Slice(..) => {}
+                        // Drop shims can only be built from ADTs.
+                        _ => return Ok(None),
                     }
 
-                    debug!(" => nontrivial drop glue");
                     ty::InstanceDef::DropGlue(def_id, Some(ty))
                 } else {
                     debug!(" => trivial drop glue");
@@ -224,17 +231,13 @@ fn resolve_associated_item<'tcx>(
                 trait_closure_kind,
             ))
         }
-        traits::ImplSourceFnPointer(ref data) => {
-            // `FnPtrShim` requires a monomorphic aka concrete type.
-            if data.fn_ty.needs_subst() {
-                return Ok(None);
-            }
-
-            Some(Instance {
+        traits::ImplSourceFnPointer(ref data) => match data.fn_ty.kind {
+            ty::FnDef(..) | ty::FnPtr(..) => Some(Instance {
                 def: ty::InstanceDef::FnPtrShim(trait_item.def_id, data.fn_ty),
                 substs: rcvr_substs,
-            })
-        }
+            }),
+            _ => None,
+        },
         traits::ImplSourceObject(ref data) => {
             let index = traits::get_vtable_index_of_object_method(tcx, data, def_id);
             Some(Instance { def: ty::InstanceDef::Virtual(def_id, index), substs: rcvr_substs })
@@ -246,10 +249,12 @@ fn resolve_associated_item<'tcx>(
                 if name == sym::clone {
                     let self_ty = trait_ref.self_ty();
 
-                    // `CloneShim` requires a monomorphic aka concrete type.
-                    if self_ty.needs_subst() {
-                        return Ok(None);
-                    }
+                    let is_copy = self_ty.is_copy_modulo_regions(tcx.at(DUMMY_SP), param_env);
+                    match self_ty.kind {
+                        _ if is_copy => (),
+                        ty::Array(..) | ty::Closure(..) | ty::Tuple(..) => {}
+                        _ => return Ok(None),
+                    };
 
                     Some(Instance {
                         def: ty::InstanceDef::CloneShim(def_id, self_ty),
index 37f48f82ea6746176b0745a8f2691720caa34331..e6d59d30e2f585331ba3bff358cf7e50acd16602 100644 (file)
@@ -1485,28 +1485,33 @@ fn add_predicates_for_ast_type_binding(
                 debug!("late_bound_in_ty = {:?}", late_bound_in_ty);
                 for br in late_bound_in_ty.difference(&late_bound_in_trait_ref) {
                     let br_name = match *br {
-                        ty::BrNamed(_, name) => name,
-                        _ => {
-                            span_bug!(
-                                binding.span,
-                                "anonymous bound region {:?} in binding but not trait ref",
-                                br
-                            );
-                        }
+                        ty::BrNamed(_, name) => format!("lifetime `{}`", name),
+                        _ => "an anonymous lifetime".to_string(),
                     };
                     // FIXME: point at the type params that don't have appropriate lifetimes:
                     // struct S1<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F);
                     //                         ----  ----     ^^^^^^^
-                    struct_span_err!(
+                    let mut err = struct_span_err!(
                         tcx.sess,
                         binding.span,
                         E0582,
-                        "binding for associated type `{}` references lifetime `{}`, \
+                        "binding for associated type `{}` references {}, \
                          which does not appear in the trait input types",
                         binding.item_name,
                         br_name
-                    )
-                    .emit();
+                    );
+
+                    if let ty::BrAnon(_) = *br {
+                        // The only way for an anonymous lifetime to wind up
+                        // in the return type but **also** be unconstrained is
+                        // if it only appears in "associated types" in the
+                        // input. See #62200 for an example. In this case,
+                        // though we can easily give a hint that ought to be
+                        // relevant.
+                        err.note("lifetimes appearing in an associated type are not considered constrained");
+                    }
+
+                    err.emit();
                 }
             }
         }
index 944e02acd610a7fc361cfa8e067abb98a8a4aa33..a09edf575c8072b17370bd3461048b8eb58b1e99 100644 (file)
@@ -386,7 +386,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
             }
 
             sym::count_code_region => {
-                (0, vec![tcx.types.u32, tcx.types.u32, tcx.types.u32], tcx.mk_unit())
+                (0, vec![tcx.types.u64, tcx.types.u32, tcx.types.u32, tcx.types.u32], tcx.mk_unit())
             }
 
             sym::coverage_counter_add | sym::coverage_counter_subtract => (
index 96248e18aaf87a44fb6b9be380a14c112dfbd38d..ed84095ae6b0cbc4a5a6d7094edb3eea07cd9509 100644 (file)
@@ -6,6 +6,7 @@
 use crate::hir::GenericArg;
 use rustc_hir as hir;
 use rustc_infer::infer::{self, InferOk};
+use rustc_middle::traits::{ObligationCauseCode, UnifyReceiverContext};
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast};
 use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
 use rustc_middle::ty::fold::TypeFoldable;
@@ -91,7 +92,11 @@ fn confirm(
         // signature (which is also done during probing).
         let method_sig_rcvr =
             self.normalize_associated_types_in(self.span, &method_sig.inputs()[0]);
-        self.unify_receivers(self_ty, method_sig_rcvr);
+        debug!(
+            "confirm: self_ty={:?} method_sig_rcvr={:?} method_sig={:?} method_predicates={:?}",
+            self_ty, method_sig_rcvr, method_sig, method_predicates
+        );
+        self.unify_receivers(self_ty, method_sig_rcvr, &pick, all_substs);
 
         let (method_sig, method_predicates) =
             self.normalize_associated_types_in(self.span, &(method_sig, method_predicates));
@@ -150,7 +155,7 @@ fn adjust_self_ty(
             self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false));
 
         if let Some(mutbl) = pick.autoref {
-            let region = self.next_region_var(infer::Autoref(self.span));
+            let region = self.next_region_var(infer::Autoref(self.span, pick.item));
             target = self.tcx.mk_ref(region, ty::TypeAndMut { mutbl, ty: target });
             let mutbl = match mutbl {
                 hir::Mutability::Not => AutoBorrowMutability::Not,
@@ -334,8 +339,26 @@ fn instantiate_method_substs(
         )
     }
 
-    fn unify_receivers(&mut self, self_ty: Ty<'tcx>, method_self_ty: Ty<'tcx>) {
-        match self.at(&self.misc(self.span), self.param_env).sup(method_self_ty, self_ty) {
+    fn unify_receivers(
+        &mut self,
+        self_ty: Ty<'tcx>,
+        method_self_ty: Ty<'tcx>,
+        pick: &probe::Pick<'tcx>,
+        substs: SubstsRef<'tcx>,
+    ) {
+        debug!(
+            "unify_receivers: self_ty={:?} method_self_ty={:?} span={:?} pick={:?}",
+            self_ty, method_self_ty, self.span, pick
+        );
+        let cause = self.cause(
+            self.span,
+            ObligationCauseCode::UnifyReceiver(Box::new(UnifyReceiverContext {
+                assoc_item: pick.item,
+                param_env: self.param_env,
+                substs,
+            })),
+        );
+        match self.at(&cause, self.param_env).sup(method_self_ty, self_ty) {
             Ok(InferOk { obligations, value: () }) => {
                 self.register_predicates(obligations);
             }
index 04e02704296defd79c3b2a8cbfc98eaee84c2eaf..6e77aba30506a5ba89c946207752d7be27d7745a 100644 (file)
@@ -256,14 +256,6 @@ pub struct Inherited<'a, 'tcx> {
     /// opaque type.
     opaque_types_vars: RefCell<FxHashMap<Ty<'tcx>, Ty<'tcx>>>,
 
-    /// Each type parameter has an implicit region bound that
-    /// indicates it must outlive at least the function body (the user
-    /// may specify stronger requirements). This field indicates the
-    /// region of the callee. If it is `None`, then the parameter
-    /// environment is for an item or something where the "callee" is
-    /// not clear.
-    implicit_region_bound: Option<ty::Region<'tcx>>,
-
     body_id: Option<hir::BodyId>,
 }
 
@@ -684,7 +676,6 @@ fn new(infcx: InferCtxt<'a, 'tcx>, def_id: LocalDefId) -> Self {
             deferred_generator_interiors: RefCell::new(Vec::new()),
             opaque_types: RefCell::new(Default::default()),
             opaque_types_vars: RefCell::new(Default::default()),
-            implicit_region_bound: None,
             body_id,
         }
     }
index b72152d1911f7dc5851f627149f7d5d1205335aa..221e5f72dc977b135d5a263212ecf5094d187285 100644 (file)
@@ -309,7 +309,7 @@ fn visit_region_obligations(&mut self, hir_id: hir::HirId) {
     fn resolve_regions_and_report_errors(&self, mode: RegionckMode) {
         self.infcx.process_registered_region_obligations(
             self.outlives_environment.region_bound_pairs_map(),
-            self.implicit_region_bound,
+            Some(self.tcx.lifetimes.re_root_empty),
             self.param_env,
         );
 
index 845a4fcafc2241e31b0c4ab308eff591be9e1edc..dabae6cbc41377a3fdf75e55101086b8c8da6dd8 100644 (file)
@@ -15,7 +15,7 @@
     self, AdtKind, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
 };
 use rustc_session::parse::feature_err;
-use rustc_span::symbol::{sym, Symbol};
+use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::Span;
 use rustc_trait_selection::opaque_types::may_define_opaque_type;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
@@ -142,8 +142,8 @@ pub fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
                 _ => unreachable!(),
             }
         }
-        hir::ItemKind::Fn(..) => {
-            check_item_fn(tcx, item);
+        hir::ItemKind::Fn(ref sig, ..) => {
+            check_item_fn(tcx, item.hir_id, item.ident, item.span, sig.decl);
         }
         hir::ItemKind::Static(ref ty, ..) => {
             check_item_type(tcx, item.hir_id, ty.span, false);
@@ -153,8 +153,14 @@ pub fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
         }
         hir::ItemKind::ForeignMod(ref module) => {
             for it in module.items.iter() {
-                if let hir::ForeignItemKind::Static(ref ty, ..) = it.kind {
-                    check_item_type(tcx, it.hir_id, ty.span, true);
+                match it.kind {
+                    hir::ForeignItemKind::Fn(ref decl, ..) => {
+                        check_item_fn(tcx, it.hir_id, it.ident, it.span, decl)
+                    }
+                    hir::ForeignItemKind::Static(ref ty, ..) => {
+                        check_item_type(tcx, it.hir_id, ty.span, true)
+                    }
+                    hir::ForeignItemKind::Type => (),
                 }
             }
         }
@@ -303,7 +309,7 @@ fn check_associated_item(
                     fcx,
                     item.ident.span,
                     sig,
-                    hir_sig,
+                    hir_sig.decl,
                     item.def_id,
                     &mut implied_bounds,
                 );
@@ -564,22 +570,24 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
     }
 }
 
-fn check_item_fn(tcx: TyCtxt<'_>, item: &hir::Item<'_>) {
-    for_item(tcx, item).with_fcx(|fcx, tcx| {
-        let def_id = fcx.tcx.hir().local_def_id(item.hir_id);
+fn check_item_fn(
+    tcx: TyCtxt<'_>,
+    item_id: hir::HirId,
+    ident: Ident,
+    span: Span,
+    decl: &hir::FnDecl<'_>,
+) {
+    for_id(tcx, item_id, span).with_fcx(|fcx, tcx| {
+        let def_id = fcx.tcx.hir().local_def_id(item_id);
         let sig = fcx.tcx.fn_sig(def_id);
-        let sig = fcx.normalize_associated_types_in(item.span, &sig);
+        let sig = fcx.normalize_associated_types_in(span, &sig);
         let mut implied_bounds = vec![];
-        let hir_sig = match &item.kind {
-            ItemKind::Fn(sig, ..) => sig,
-            _ => bug!("expected `ItemKind::Fn`, found `{:?}`", item.kind),
-        };
         check_fn_or_method(
             tcx,
             fcx,
-            item.ident.span,
+            ident.span,
             sig,
-            hir_sig,
+            decl,
             def_id.to_def_id(),
             &mut implied_bounds,
         );
@@ -835,28 +843,28 @@ fn check_fn_or_method<'fcx, 'tcx>(
     fcx: &FnCtxt<'fcx, 'tcx>,
     span: Span,
     sig: ty::PolyFnSig<'tcx>,
-    hir_sig: &hir::FnSig<'_>,
+    hir_decl: &hir::FnDecl<'_>,
     def_id: DefId,
     implied_bounds: &mut Vec<Ty<'tcx>>,
 ) {
     let sig = fcx.normalize_associated_types_in(span, &sig);
     let sig = fcx.tcx.liberate_late_bound_regions(def_id, &sig);
 
-    for (&input_ty, span) in sig.inputs().iter().zip(hir_sig.decl.inputs.iter().map(|t| t.span)) {
+    for (&input_ty, span) in sig.inputs().iter().zip(hir_decl.inputs.iter().map(|t| t.span)) {
         fcx.register_wf_obligation(input_ty.into(), span, ObligationCauseCode::MiscObligation);
     }
     implied_bounds.extend(sig.inputs());
 
     fcx.register_wf_obligation(
         sig.output().into(),
-        hir_sig.decl.output.span(),
+        hir_decl.output.span(),
         ObligationCauseCode::ReturnType,
     );
 
     // FIXME(#25759) return types should not be implied bounds
     implied_bounds.push(sig.output());
 
-    check_where_clauses(tcx, fcx, span, def_id, Some((sig.output(), hir_sig.decl.output.span())));
+    check_where_clauses(tcx, fcx, span, def_id, Some((sig.output(), hir_decl.output.span())));
 }
 
 /// Checks "defining uses" of opaque `impl Trait` types to ensure that they meet the restrictions
index ec534aa925d4f2b58fd12463e33022440bff6de4..cb9348a9521bcd6e05f4061080d41ac76752cdd7 100644 (file)
@@ -730,7 +730,13 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::HirId) {
             placeholder_type_error(tcx, None, &[], visitor.0, false);
         }
 
-        hir::TraitItemKind::Type(_, None) => {}
+        hir::TraitItemKind::Type(_, None) => {
+            // #74612: Visit and try to find bad placeholders
+            // even if there is no concrete type.
+            let mut visitor = PlaceholderHirTyCollector::default();
+            visitor.visit_trait_item(trait_item);
+            placeholder_type_error(tcx, None, &[], visitor.0, false);
+        }
     };
 
     tcx.ensure().predicates_of(def_id);
@@ -1927,7 +1933,7 @@ fn extend<I: IntoIterator<Item = (ty::Predicate<'tcx>, Span)>>(&mut self, iter:
                         let re_root_empty = tcx.lifetimes.re_root_empty;
                         let predicate = ty::OutlivesPredicate(ty, re_root_empty);
                         predicates.push((
-                            ty::PredicateKind::TypeOutlives(ty::Binder::dummy(predicate))
+                            ty::PredicateKind::TypeOutlives(ty::Binder::bind(predicate))
                                 .to_predicate(tcx),
                             span,
                         ));
index 491daa80e5c859ddd0f8692fe4cf0e99c85f9a11..1f576a17dd9d665cfe1d147e1ec0b7108b41773c 100644 (file)
@@ -346,9 +346,11 @@ pub fn build_impl(
         // such. This helps prevent dependencies of the standard library, for
         // example, from getting documented as "traits `u32` implements" which
         // isn't really too helpful.
-        if let Some(stab) = cx.tcx.lookup_stability(did) {
-            if stab.level.is_unstable() {
-                return;
+        if let Some(trait_did) = associated_trait {
+            if let Some(stab) = cx.tcx.lookup_stability(trait_did.def_id) {
+                if stab.level.is_unstable() {
+                    return;
+                }
             }
         }
     }
index 8a4ee91df405fcb8b033ec6911e8916b71154aaf..94d95115dcdbcaed7bfd447b6cc22331da063d87 100644 (file)
@@ -2353,10 +2353,6 @@ fn clean(&self, _: &DocContext<'_>) -> Stability {
                 attr::Stable { ref since } => since.to_string(),
                 _ => String::new(),
             },
-            deprecation: self.rustc_depr.as_ref().map(|d| Deprecation {
-                note: Some(d.reason.to_string()).filter(|r| !r.is_empty()),
-                since: Some(d.since.to_string()).filter(|d| !d.is_empty()),
-            }),
             unstable_reason: match self.level {
                 attr::Unstable { reason: Some(ref reason), .. } => Some(reason.to_string()),
                 _ => None,
@@ -2374,6 +2370,7 @@ fn clean(&self, _: &DocContext<'_>) -> Deprecation {
         Deprecation {
             since: self.since.map(|s| s.to_string()).filter(|s| !s.is_empty()),
             note: self.note.map(|n| n.to_string()).filter(|n| !n.is_empty()),
+            is_since_rustc_version: self.is_since_rustc_version,
         }
     }
 }
index 6a03722cd0802786f31710bb146e981c3fecf13e..071834c59d65ec749aafa5f8b4a72113638b74d7 100644 (file)
@@ -195,7 +195,8 @@ pub fn stability_class(&self) -> Option<String> {
                 classes.push("unstable");
             }
 
-            if s.deprecation.is_some() {
+            // FIXME: what about non-staged API items that are deprecated?
+            if self.deprecation.is_some() {
                 classes.push("deprecated");
             }
 
@@ -216,14 +217,6 @@ pub fn type_(&self) -> ItemType {
         ItemType::from(self)
     }
 
-    /// Returns the info in the item's `#[deprecated]` or `#[rustc_deprecated]` attributes.
-    ///
-    /// If the item is not deprecated, returns `None`.
-    pub fn deprecation(&self) -> Option<&Deprecation> {
-        self.deprecation
-            .as_ref()
-            .or_else(|| self.stability.as_ref().and_then(|s| s.deprecation.as_ref()))
-    }
     pub fn is_default(&self) -> bool {
         match self.inner {
             ItemEnum::MethodItem(ref meth) => {
@@ -1528,7 +1521,6 @@ pub struct Stability {
     pub level: stability::StabilityLevel,
     pub feature: Option<String>,
     pub since: String,
-    pub deprecation: Option<Deprecation>,
     pub unstable_reason: Option<String>,
     pub issue: Option<NonZeroU32>,
 }
@@ -1537,6 +1529,7 @@ pub struct Stability {
 pub struct Deprecation {
     pub since: Option<String>,
     pub note: Option<String>,
+    pub is_since_rustc_version: bool,
 }
 
 /// An type binding on an associated type (e.g., `A = Bar` in `Foo<A = Bar>` or
index f872ed7010c7537ad3aae0cdec855f2e6a771213..f7050cf377722622eee91859903f82a04b0cf5d0 100644 (file)
@@ -2216,16 +2216,10 @@ fn tag_html(class: &str, contents: &str) -> String {
     }
 
     // The trailing space after each tag is to space it properly against the rest of the docs.
-    if item.deprecation().is_some() {
+    if let Some(depr) = &item.deprecation {
         let mut message = "Deprecated";
-        if let Some(ref stab) = item.stability {
-            if let Some(ref depr) = stab.deprecation {
-                if let Some(ref since) = depr.since {
-                    if !stability::deprecation_in_effect(&since) {
-                        message = "Deprecation planned";
-                    }
-                }
-            }
+        if !stability::deprecation_in_effect(depr.is_since_rustc_version, depr.since.as_deref()) {
+            message = "Deprecation planned";
         }
         tags += &tag_html("deprecated", message);
     }
@@ -2254,23 +2248,18 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec<String> {
     let mut stability = vec![];
     let error_codes = cx.shared.codes;
 
-    if let Some(Deprecation { note, since }) = &item.deprecation() {
+    if let Some(Deprecation { ref note, ref since, is_since_rustc_version }) = item.deprecation {
         // We display deprecation messages for #[deprecated] and #[rustc_deprecated]
         // but only display the future-deprecation messages for #[rustc_deprecated].
         let mut message = if let Some(since) = since {
-            format!("Deprecated since {}", Escape(since))
+            if !stability::deprecation_in_effect(is_since_rustc_version, Some(since)) {
+                format!("Deprecating in {}", Escape(&since))
+            } else {
+                format!("Deprecated since {}", Escape(&since))
+            }
         } else {
             String::from("Deprecated")
         };
-        if let Some(ref stab) = item.stability {
-            if let Some(ref depr) = stab.deprecation {
-                if let Some(ref since) = depr.since {
-                    if !stability::deprecation_in_effect(&since) {
-                        message = format!("Deprecating in {}", Escape(&since));
-                    }
-                }
-            }
-        }
 
         if let Some(note) = note {
             let mut ids = cx.id_map.borrow_mut();
index 38709b445efae9aa89649872aa167af0053942dd..d0312d77a7c5d5867e5c027b76ae27957b910454 100644 (file)
@@ -1291,6 +1291,16 @@ h4 > .important-traits {
 
 /* Media Queries */
 
+@media (min-width: 701px) {
+       /* In case there is no documentation before a code block, we need to add some margin at the top
+       to prevent an overlay between the "collapse toggle" and the information tooltip.
+       However, it's needed needed with smaller screen width because the doc/code block is always put
+       "one line" below. */
+       .information:first-child > .tooltip {
+               margin-top: 16px;
+       }
+}
+
 @media (max-width: 700px) {
        body {
                padding-top: 0px;
@@ -1511,6 +1521,11 @@ h4 > .important-traits {
        #main > .line-numbers {
                margin-top: 0;
        }
+
+       .important-traits .important-traits-tooltiptext {
+               left: 0;
+               top: 100%;
+       }
 }
 
 @media print {
index e0ab7170ea8772d0bc5816d6d557f03d6f3b551f..41fe8e0fafb413185b7fa4e0043758435b2539d4 100644 (file)
@@ -62,6 +62,10 @@ pre {
        background-color: #14191f;
 }
 
+.logo-container > img {
+       filter: drop-shadow(0 0 5px #fff);
+}
+
 /* Improve the scrollbar display on firefox */
 * {
        scrollbar-color: #5c6773 transparent;
@@ -237,16 +241,6 @@ a {
 
 #crate-search+.search-input:focus {
        box-shadow: 0 0 0 1px #148099,0 0 0 2px transparent;
-       color: #ffffff;
-       background-color: #141920;
-       box-shadow: none;
-       transition: box-shadow 150ms ease-in-out;
-       border-radius: 4px;
-       margin-left: 8px;
-}
-
-#crate-search+.search-input:focus {
-       box-shadow: 0px 6px 20px 0px black;
 }
 
 .search-focus:disabled {
@@ -318,12 +312,12 @@ a.test-arrow {
        font-size: 100%;
        color: #788797;
        border-radius: 4px;
-       background-color: rgba(255, 255, 255, 0);
+       background-color: rgba(57, 175, 215, 0.09);
 }
 
 a.test-arrow:hover {
-       background-color: rgba(242, 151, 24, 0.05);
-       color: #ffb44c;
+       background-color: rgba(57, 175, 215, 0.368);
+       color: #c5c5c5;
 }
 
 .toggle-label {
@@ -332,7 +326,7 @@ a.test-arrow:hover {
 
 :target > code, :target > .in-band {
        background: rgba(255, 236, 164, 0.06);
-       border-right: 3px solid #ffb44c;
+       border-right: 3px solid rgba(255, 180, 76, 0.85);
 }
 
 pre.compile_fail {
index 33c0f885fa95b4afe9f136c299f4db23e9c59b1b..b3b586ba362fa475b9f7c5c392bcf126305527c8 100644 (file)
@@ -34,6 +34,10 @@ pre {
        background-color: #505050;
 }
 
+.logo-container > img {
+       filter: drop-shadow(0 0 5px #fff);
+}
+
 /* Improve the scrollbar display on firefox */
 * {
        scrollbar-color: rgb(64, 65, 67) #717171;
@@ -270,6 +274,7 @@ a.test-arrow:hover{
 
 :target > code, :target > .in-band {
        background-color: #494a3d;
+       border-right: 3px solid #bb7410;
 }
 
 pre.compile_fail {
index 569ce7da2091f07d79c2499d6f7fe4335de6bdd6..b0c5715604baab86ea5d29eab697f5b3b6a0701f 100644 (file)
@@ -45,6 +45,10 @@ pre {
        scrollbar-color: rgba(36, 37, 39, 0.6) #d9d9d9;
 }
 
+.logo-container > img {
+       filter: drop-shadow(0 0 5px #aaa);
+}
+
 /* Improve the scrollbar display on webkit-based browsers */
 ::-webkit-scrollbar-track {
        background-color: #ecebeb;
@@ -265,6 +269,7 @@ a.test-arrow:hover{
 
 :target > code, :target > .in-band {
        background: #FDFFD3;
+       border-right: 3px solid #ffb44c;
 }
 
 pre.compile_fail {
index e187b9251f71e5194d002060dbca21f94b2211e7..5187839423d6b1d8e00f981b6ee2d54f07e5a310 100644 (file)
@@ -1,5 +1,5 @@
 use rustc_ast::ast;
-use rustc_errors::Applicability;
+use rustc_errors::{Applicability, DiagnosticBuilder};
 use rustc_expand::base::SyntaxExtensionKind;
 use rustc_feature::UnstableFeatures;
 use rustc_hir as hir;
@@ -45,7 +45,17 @@ pub fn collect_intra_doc_links(krate: Crate, cx: &DocContext<'_>) -> Crate {
 
 enum ErrorKind {
     ResolutionFailure,
-    AnchorFailure(&'static str),
+    AnchorFailure(AnchorFailure),
+}
+
+enum AnchorFailure {
+    MultipleAnchors,
+    Primitive,
+    Variant,
+    AssocConstant,
+    AssocType,
+    Field,
+    Method,
 }
 
 struct LinkCollector<'a, 'tcx> {
@@ -197,9 +207,7 @@ fn resolve(
                     // Not a trait item; just return what we found.
                     Res::PrimTy(..) => {
                         if extra_fragment.is_some() {
-                            return Err(ErrorKind::AnchorFailure(
-                                "primitive types cannot be followed by anchors",
-                            ));
+                            return Err(ErrorKind::AnchorFailure(AnchorFailure::Primitive));
                         }
                         return Ok((res, Some(path_str.to_owned())));
                     }
@@ -209,9 +217,7 @@ fn resolve(
                         if disambiguator == Some("type") {
                             if let Some(prim) = is_primitive(path_str, ns) {
                                 if extra_fragment.is_some() {
-                                    return Err(ErrorKind::AnchorFailure(
-                                        "primitive types cannot be followed by anchors",
-                                    ));
+                                    return Err(ErrorKind::AnchorFailure(AnchorFailure::Primitive));
                                 }
                                 return Ok((prim, Some(path_str.to_owned())));
                             }
@@ -228,9 +234,7 @@ fn resolve(
                 }
             } else if let Some(prim) = is_primitive(path_str, ns) {
                 if extra_fragment.is_some() {
-                    return Err(ErrorKind::AnchorFailure(
-                        "primitive types cannot be followed by anchors",
-                    ));
+                    return Err(ErrorKind::AnchorFailure(AnchorFailure::Primitive));
                 }
                 return Ok((prim, Some(path_str.to_owned())));
             } else {
@@ -338,9 +342,9 @@ fn resolve(
                         };
                         if extra_fragment.is_some() {
                             Err(ErrorKind::AnchorFailure(if item.kind == ty::AssocKind::Fn {
-                                "methods cannot be followed by anchors"
+                                AnchorFailure::Method
                             } else {
-                                "associated constants cannot be followed by anchors"
+                                AnchorFailure::AssocConstant
                             }))
                         } else {
                             Ok((ty_res, Some(format!("{}.{}", out, item_name))))
@@ -358,9 +362,9 @@ fn resolve(
                                 } {
                                     if extra_fragment.is_some() {
                                         Err(ErrorKind::AnchorFailure(if def.is_enum() {
-                                            "enum variants cannot be followed by anchors"
+                                            AnchorFailure::Variant
                                         } else {
-                                            "struct fields cannot be followed by anchors"
+                                            AnchorFailure::Field
                                         }))
                                     } else {
                                         Ok((
@@ -404,11 +408,11 @@ fn resolve(
 
                         if extra_fragment.is_some() {
                             Err(ErrorKind::AnchorFailure(if item.kind == ty::AssocKind::Const {
-                                "associated constants cannot be followed by anchors"
+                                AnchorFailure::AssocConstant
                             } else if item.kind == ty::AssocKind::Type {
-                                "associated types cannot be followed by anchors"
+                                AnchorFailure::AssocType
                             } else {
-                                "methods cannot be followed by anchors"
+                                AnchorFailure::Method
                             }))
                         } else {
                             Ok((ty_res, Some(format!("{}.{}", kind, item_name))))
@@ -559,16 +563,7 @@ fn fold_item(&mut self, mut item: Item) -> Option<Item> {
             let link = ori_link.replace("`", "");
             let parts = link.split('#').collect::<Vec<_>>();
             let (link, extra_fragment) = if parts.len() > 2 {
-                build_diagnostic(
-                    cx,
-                    &item,
-                    &link,
-                    &dox,
-                    link_range,
-                    "has an issue with the link anchor.",
-                    "only one `#` is allowed in a link",
-                    None,
-                );
+                anchor_failure(cx, &item, &link, &dox, link_range, AnchorFailure::MultipleAnchors);
                 continue;
             } else if parts.len() == 2 {
                 if parts[0].trim().is_empty() {
@@ -795,29 +790,22 @@ fn fold_item(&mut self, mut item: Item) -> Option<Item> {
                 item.attrs.links.push((ori_link, None, fragment));
             } else {
                 debug!("intra-doc link to {} resolved to {:?}", path_str, res);
-                if let Some(local) = res.opt_def_id().and_then(|def_id| def_id.as_local()) {
+
+                // item can be non-local e.g. when using #[doc(primitive = "pointer")]
+                if let Some((src_id, dst_id)) = res
+                    .opt_def_id()
+                    .and_then(|def_id| def_id.as_local())
+                    .and_then(|dst_id| item.def_id.as_local().map(|src_id| (src_id, dst_id)))
+                {
                     use rustc_hir::def_id::LOCAL_CRATE;
 
-                    let hir_id = self.cx.tcx.hir().as_local_hir_id(local);
-                    if !self.cx.tcx.privacy_access_levels(LOCAL_CRATE).is_exported(hir_id)
-                        && (item.visibility == Visibility::Public)
-                        && !self.cx.render_options.document_private
+                    let hir_src = self.cx.tcx.hir().as_local_hir_id(src_id);
+                    let hir_dst = self.cx.tcx.hir().as_local_hir_id(dst_id);
+
+                    if self.cx.tcx.privacy_access_levels(LOCAL_CRATE).is_exported(hir_src)
+                        && !self.cx.tcx.privacy_access_levels(LOCAL_CRATE).is_exported(hir_dst)
                     {
-                        let item_name = item.name.as_deref().unwrap_or("<unknown>");
-                        let err_msg = format!(
-                            "public documentation for `{}` links to a private item",
-                            item_name
-                        );
-                        build_diagnostic(
-                            cx,
-                            &item,
-                            path_str,
-                            &dox,
-                            link_range,
-                            &err_msg,
-                            "this item is private",
-                            None,
-                        );
+                        privacy_error(cx, &item, &path_str, &dox, link_range);
                         continue;
                     }
                 }
@@ -851,24 +839,33 @@ fn fold_crate(&mut self, mut c: Crate) -> Crate {
     }
 }
 
-fn build_diagnostic(
+/// Reports a diagnostic for an intra-doc link.
+///
+/// If no link range is provided, or the source span of the link cannot be determined, the span of
+/// the entire documentation block is used for the lint. If a range is provided but the span
+/// calculation fails, a note is added to the diagnostic pointing to the link in the markdown.
+///
+/// The `decorate` callback is invoked in all cases to allow further customization of the
+/// diagnostic before emission. If the span of the link was able to be determined, the second
+/// parameter of the callback will contain it, and the primary span of the diagnostic will be set
+/// to it.
+fn report_diagnostic(
     cx: &DocContext<'_>,
+    msg: &str,
     item: &Item,
-    path_str: &str,
     dox: &str,
     link_range: Option<Range<usize>>,
-    err_msg: &str,
-    short_err_msg: &str,
-    help_msg: Option<&str>,
+    decorate: impl FnOnce(&mut DiagnosticBuilder<'_>, Option<rustc_span::Span>),
 ) {
     let hir_id = match cx.as_local_hir_id(item.def_id) {
         Some(hir_id) => hir_id,
         None => {
             // If non-local, no need to check anything.
-            info!("ignoring warning from parent crate: {}", err_msg);
+            info!("ignoring warning from parent crate: {}", msg);
             return;
         }
     };
+
     let attrs = &item.attrs;
     let sp = span_of_attrs(attrs).unwrap_or(item.source.span());
 
@@ -877,12 +874,15 @@ fn build_diagnostic(
         hir_id,
         sp,
         |lint| {
-            let mut diag = lint.build(&format!("`[{}]` {}", path_str, err_msg));
+            let mut diag = lint.build(msg);
+
+            let span = link_range
+                .as_ref()
+                .and_then(|range| super::source_span_for_markdown_range(cx, dox, range, attrs));
+
             if let Some(link_range) = link_range {
-                if let Some(sp) = super::source_span_for_markdown_range(cx, dox, &link_range, attrs)
-                {
+                if let Some(sp) = span {
                     diag.set_span(sp);
-                    diag.span_label(sp, short_err_msg);
                 } else {
                     // blah blah blah\nblah\nblah [blah] blah blah\nblah blah
                     //                       ^     ~~~~
@@ -902,20 +902,15 @@ fn build_diagnostic(
                         found = link_range.len(),
                     ));
                 }
-            };
-            if let Some(help_msg) = help_msg {
-                diag.help(help_msg);
             }
+
+            decorate(&mut diag, span);
+
             diag.emit();
         },
     );
 }
 
-/// Reports a resolution failure diagnostic.
-///
-/// If we cannot find the exact source span of the resolution failure, we use the span of the
-/// documentation attributes themselves. This is a little heavy-handed, so we display the markdown
-/// line containing the failure as a note as well.
 fn resolution_failure(
     cx: &DocContext<'_>,
     item: &Item,
@@ -923,15 +918,19 @@ fn resolution_failure(
     dox: &str,
     link_range: Option<Range<usize>>,
 ) {
-    build_diagnostic(
+    report_diagnostic(
         cx,
+        &format!("unresolved link to `{}`", path_str),
         item,
-        path_str,
         dox,
         link_range,
-        "cannot be resolved, ignoring it.",
-        "cannot be resolved, ignoring",
-        Some("to escape `[` and `]` characters, just add '\\' before them like `\\[` or `\\]`"),
+        |diag, sp| {
+            if let Some(sp) = sp {
+                diag.span_label(sp, "unresolved link");
+            }
+
+            diag.help(r#"to escape `[` and `]` characters, add '\' before them like `\[` or `\]`"#);
+        },
     );
 }
 
@@ -941,18 +940,39 @@ fn anchor_failure(
     path_str: &str,
     dox: &str,
     link_range: Option<Range<usize>>,
-    msg: &str,
+    failure: AnchorFailure,
 ) {
-    build_diagnostic(
-        cx,
-        item,
-        path_str,
-        dox,
-        link_range,
-        "has an issue with the link anchor.",
-        msg,
-        None,
-    );
+    let msg = match failure {
+        AnchorFailure::MultipleAnchors => format!("`{}` contains multiple anchors", path_str),
+        AnchorFailure::Primitive
+        | AnchorFailure::Variant
+        | AnchorFailure::AssocConstant
+        | AnchorFailure::AssocType
+        | AnchorFailure::Field
+        | AnchorFailure::Method => {
+            let kind = match failure {
+                AnchorFailure::Primitive => "primitive type",
+                AnchorFailure::Variant => "enum variant",
+                AnchorFailure::AssocConstant => "associated constant",
+                AnchorFailure::AssocType => "associated type",
+                AnchorFailure::Field => "struct field",
+                AnchorFailure::Method => "method",
+                AnchorFailure::MultipleAnchors => unreachable!("should be handled already"),
+            };
+
+            format!(
+                "`{}` contains an anchor, but links to {kind}s are already anchored",
+                path_str,
+                kind = kind
+            )
+        }
+    };
+
+    report_diagnostic(cx, &msg, item, dox, link_range, |diag, sp| {
+        if let Some(sp) = sp {
+            diag.span_label(sp, "contains invalid anchor");
+        }
+    });
 }
 
 fn ambiguity_error(
@@ -963,121 +983,107 @@ fn ambiguity_error(
     link_range: Option<Range<usize>>,
     candidates: PerNS<Option<Res>>,
 ) {
-    let hir_id = match cx.as_local_hir_id(item.def_id) {
-        Some(hir_id) => hir_id,
-        None => {
-            // If non-local, no need to check anything.
-            return;
+    let mut msg = format!("`{}` is ", path_str);
+
+    let candidates = [TypeNS, ValueNS, MacroNS]
+        .iter()
+        .filter_map(|&ns| candidates[ns].map(|res| (res, ns)))
+        .collect::<Vec<_>>();
+    match candidates.as_slice() {
+        [(first_def, _), (second_def, _)] => {
+            msg += &format!(
+                "both {} {} and {} {}",
+                first_def.article(),
+                first_def.descr(),
+                second_def.article(),
+                second_def.descr(),
+            );
         }
-    };
-    let attrs = &item.attrs;
-    let sp = span_of_attrs(attrs).unwrap_or(item.source.span());
-
-    cx.tcx.struct_span_lint_hir(
-        lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE,
-        hir_id,
-        sp,
-        |lint| {
-            let mut msg = format!("`{}` is ", path_str);
-
-            let candidates = [TypeNS, ValueNS, MacroNS]
-                .iter()
-                .filter_map(|&ns| candidates[ns].map(|res| (res, ns)))
-                .collect::<Vec<_>>();
-            match candidates.as_slice() {
-                [(first_def, _), (second_def, _)] => {
-                    msg += &format!(
-                        "both {} {} and {} {}",
-                        first_def.article(),
-                        first_def.descr(),
-                        second_def.article(),
-                        second_def.descr(),
-                    );
-                }
-                _ => {
-                    let mut candidates = candidates.iter().peekable();
-                    while let Some((res, _)) = candidates.next() {
-                        if candidates.peek().is_some() {
-                            msg += &format!("{} {}, ", res.article(), res.descr());
-                        } else {
-                            msg += &format!("and {} {}", res.article(), res.descr());
-                        }
-                    }
+        _ => {
+            let mut candidates = candidates.iter().peekable();
+            while let Some((res, _)) = candidates.next() {
+                if candidates.peek().is_some() {
+                    msg += &format!("{} {}, ", res.article(), res.descr());
+                } else {
+                    msg += &format!("and {} {}", res.article(), res.descr());
                 }
             }
+        }
+    }
 
-            let mut diag = lint.build(&msg);
-
-            if let Some(link_range) = link_range {
-                if let Some(sp) = super::source_span_for_markdown_range(cx, dox, &link_range, attrs)
-                {
-                    diag.set_span(sp);
-                    diag.span_label(sp, "ambiguous link");
+    report_diagnostic(cx, &msg, item, dox, link_range.clone(), |diag, sp| {
+        if let Some(sp) = sp {
+            diag.span_label(sp, "ambiguous link");
 
-                    for (res, ns) in candidates {
-                        let (action, mut suggestion) = match res {
-                            Res::Def(DefKind::AssocFn | DefKind::Fn, _) => {
-                                ("add parentheses", format!("{}()", path_str))
-                            }
-                            Res::Def(DefKind::Macro(MacroKind::Bang), _) => {
-                                ("add an exclamation mark", format!("{}!", path_str))
-                            }
-                            _ => {
-                                let type_ = match (res, ns) {
-                                    (Res::Def(DefKind::Const, _), _) => "const",
-                                    (Res::Def(DefKind::Static, _), _) => "static",
-                                    (Res::Def(DefKind::Struct, _), _) => "struct",
-                                    (Res::Def(DefKind::Enum, _), _) => "enum",
-                                    (Res::Def(DefKind::Union, _), _) => "union",
-                                    (Res::Def(DefKind::Trait, _), _) => "trait",
-                                    (Res::Def(DefKind::Mod, _), _) => "module",
-                                    (_, TypeNS) => "type",
-                                    (_, ValueNS) => "value",
-                                    (Res::Def(DefKind::Macro(MacroKind::Derive), _), MacroNS) => {
-                                        "derive"
-                                    }
-                                    (_, MacroNS) => "macro",
-                                };
+            let link_range = link_range.expect("must have a link range if we have a span");
 
-                                // FIXME: if this is an implied shortcut link, it's bad style to suggest `@`
-                                ("prefix with the item type", format!("{}@{}", type_, path_str))
-                            }
+            for (res, ns) in candidates {
+                let (action, mut suggestion) = match res {
+                    Res::Def(DefKind::AssocFn | DefKind::Fn, _) => {
+                        ("add parentheses", format!("{}()", path_str))
+                    }
+                    Res::Def(DefKind::Macro(MacroKind::Bang), _) => {
+                        ("add an exclamation mark", format!("{}!", path_str))
+                    }
+                    _ => {
+                        let type_ = match (res, ns) {
+                            (Res::Def(DefKind::Const, _), _) => "const",
+                            (Res::Def(DefKind::Static, _), _) => "static",
+                            (Res::Def(DefKind::Struct, _), _) => "struct",
+                            (Res::Def(DefKind::Enum, _), _) => "enum",
+                            (Res::Def(DefKind::Union, _), _) => "union",
+                            (Res::Def(DefKind::Trait, _), _) => "trait",
+                            (Res::Def(DefKind::Mod, _), _) => "module",
+                            (_, TypeNS) => "type",
+                            (_, ValueNS) => "value",
+                            (Res::Def(DefKind::Macro(MacroKind::Derive), _), MacroNS) => "derive",
+                            (_, MacroNS) => "macro",
                         };
 
-                        if dox.bytes().nth(link_range.start) == Some(b'`') {
-                            suggestion = format!("`{}`", suggestion);
-                        }
-
-                        diag.span_suggestion(
-                            sp,
-                            &format!("to link to the {}, {}", res.descr(), action),
-                            suggestion,
-                            Applicability::MaybeIncorrect,
-                        );
+                        // FIXME: if this is an implied shortcut link, it's bad style to suggest `@`
+                        ("prefix with the item type", format!("{}@{}", type_, path_str))
                     }
-                } else {
-                    // blah blah blah\nblah\nblah [blah] blah blah\nblah blah
-                    //                       ^     ~~~~
-                    //                       |     link_range
-                    //                       last_new_line_offset
-                    let last_new_line_offset =
-                        dox[..link_range.start].rfind('\n').map_or(0, |n| n + 1);
-                    let line = dox[last_new_line_offset..].lines().next().unwrap_or("");
+                };
 
-                    // Print the line containing the `link_range` and manually mark it with '^'s.
-                    diag.note(&format!(
-                        "the link appears in this line:\n\n{line}\n\
-                         {indicator: <before$}{indicator:^<found$}",
-                        line = line,
-                        indicator = "",
-                        before = link_range.start - last_new_line_offset,
-                        found = link_range.len(),
-                    ));
+                if dox.bytes().nth(link_range.start) == Some(b'`') {
+                    suggestion = format!("`{}`", suggestion);
                 }
+
+                // FIXME: Create a version of this suggestion for when we don't have the span.
+                diag.span_suggestion(
+                    sp,
+                    &format!("to link to the {}, {}", res.descr(), action),
+                    suggestion,
+                    Applicability::MaybeIncorrect,
+                );
             }
-            diag.emit();
-        },
-    );
+        }
+    });
+}
+
+fn privacy_error(
+    cx: &DocContext<'_>,
+    item: &Item,
+    path_str: &str,
+    dox: &str,
+    link_range: Option<Range<usize>>,
+) {
+    let item_name = item.name.as_deref().unwrap_or("<unknown>");
+    let msg =
+        format!("public documentation for `{}` links to private item `{}`", item_name, path_str);
+
+    report_diagnostic(cx, &msg, item, dox, link_range, |diag, sp| {
+        if let Some(sp) = sp {
+            diag.span_label(sp, "this item is private");
+        }
+
+        let note_msg = if cx.render_options.document_private {
+            "this link resolves only because you passed `--document-private-items`, but will break without"
+        } else {
+            "this link will resolve properly if you pass `--document-private-items`"
+        };
+        diag.note(note_msg);
+    });
 }
 
 /// Given an enum variant's res, return the res of its enum and the associated fragment.
@@ -1089,7 +1095,7 @@ fn handle_variant(
     use rustc_middle::ty::DefIdTree;
 
     if extra_fragment.is_some() {
-        return Err(ErrorKind::AnchorFailure("variants cannot be followed by anchors"));
+        return Err(ErrorKind::AnchorFailure(AnchorFailure::Variant));
     }
     let parent = if let Some(parent) = cx.tcx.parent(res.def_id()) {
         parent
index 29893bd12f1f7ced0cf13e841006473de17e7257..8138dfa580d80c04aa50d356abb2e466c5fad54f 100644 (file)
@@ -2,7 +2,6 @@
 authors = ["The Rust Project Developers"]
 name = "std"
 version = "0.0.0"
-build = "build.rs"
 license = "MIT OR Apache-2.0"
 repository = "https://github.com/rust-lang/rust.git"
 description = "The Rust Standard Library"
index 38d223d84e90fa3e296656123e7dfba4acf0f14d..ecfaaeace513e329873de16187a83875b0c5a4c4 100644 (file)
@@ -59,6 +59,7 @@
 //! The `#[global_allocator]` can only be used once in a crate
 //! or its recursive dependencies.
 
+#![deny(unsafe_op_in_unsafe_fn)]
 #![stable(feature = "alloc_module", since = "1.28.0")]
 
 use core::intrinsics;
@@ -158,7 +159,9 @@ fn alloc(&mut self, layout: Layout, init: AllocInit) -> Result<MemoryBlock, Allo
     #[inline]
     unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
         if layout.size() != 0 {
-            GlobalAlloc::dealloc(self, ptr.as_ptr(), layout)
+            // SAFETY: The safety guarantees are explained in the documentation
+            // for the `GlobalAlloc` trait and its `dealloc` method.
+            unsafe { GlobalAlloc::dealloc(self, ptr.as_ptr(), layout) }
         }
     }
 
@@ -184,16 +187,36 @@ unsafe fn grow(
         match placement {
             ReallocPlacement::InPlace => Err(AllocErr),
             ReallocPlacement::MayMove if layout.size() == 0 => {
-                let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
+                let new_layout =
+                    // SAFETY: The new size and layout alignement guarantees
+                    // are transfered to the caller (they come from parameters).
+                    //
+                    // See the preconditions for `Layout::from_size_align` to
+                    // see what must be checked.
+                    unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) };
                 self.alloc(new_layout, init)
             }
             ReallocPlacement::MayMove => {
-                // `realloc` probably checks for `new_size > size` or something similar.
-                intrinsics::assume(new_size > size);
-                let ptr = GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size);
-                let memory =
-                    MemoryBlock { ptr: NonNull::new(ptr).ok_or(AllocErr)?, size: new_size };
-                init.init_offset(memory, size);
+                // SAFETY:
+                //
+                // The safety guarantees are explained in the documentation
+                // for the `GlobalAlloc` trait and its `dealloc` method.
+                //
+                // `realloc` probably checks for `new_size > size` or something
+                // similar.
+                //
+                // For the guarantees about `init_offset`, see its documentation:
+                // `ptr` is assumed valid (and checked for non-NUL) and
+                // `memory.size` is set to `new_size` so the offset being `size`
+                // is valid.
+                let memory = unsafe {
+                    intrinsics::assume(new_size > size);
+                    let ptr = GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size);
+                    let memory =
+                        MemoryBlock { ptr: NonNull::new(ptr).ok_or(AllocErr)?, size: new_size };
+                    init.init_offset(memory, size);
+                    memory
+                };
                 Ok(memory)
             }
         }
@@ -220,14 +243,28 @@ unsafe fn shrink(
         match placement {
             ReallocPlacement::InPlace => Err(AllocErr),
             ReallocPlacement::MayMove if new_size == 0 => {
-                self.dealloc(ptr, layout);
+                // SAFETY: see `GlobalAlloc::dealloc` for the guarantees that
+                // must be respected. `ptr` and `layout` are parameters and so
+                // those guarantees must be checked by the caller.
+                unsafe { self.dealloc(ptr, layout) };
                 Ok(MemoryBlock { ptr: layout.dangling(), size: 0 })
             }
             ReallocPlacement::MayMove => {
-                // `realloc` probably checks for `new_size < size` or something similar.
-                intrinsics::assume(new_size < size);
-                let ptr = GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size);
-                Ok(MemoryBlock { ptr: NonNull::new(ptr).ok_or(AllocErr)?, size: new_size })
+                // SAFETY:
+                //
+                // See `GlobalAlloc::realloc` for more informations about the
+                // guarantees expected by this method. `ptr`, `layout` and
+                // `new_size` are parameters and the responsability for their
+                // correctness is left to the caller.
+                //
+                // `realloc` probably checks for `new_size < size` or something
+                // similar.
+                let memory = unsafe {
+                    intrinsics::assume(new_size < size);
+                    let ptr = GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size);
+                    MemoryBlock { ptr: NonNull::new(ptr).ok_or(AllocErr)?, size: new_size }
+                };
+                Ok(memory)
             }
         }
     }
@@ -300,13 +337,19 @@ pub mod __default_lib_allocator {
 
     #[rustc_std_internal_symbol]
     pub unsafe extern "C" fn __rdl_alloc(size: usize, align: usize) -> *mut u8 {
-        let layout = Layout::from_size_align_unchecked(size, align);
-        System.alloc(layout)
+        // SAFETY: see the guarantees expected by `Layout::from_size_align` and
+        // `GlobalAlloc::alloc`.
+        unsafe {
+            let layout = Layout::from_size_align_unchecked(size, align);
+            System.alloc(layout)
+        }
     }
 
     #[rustc_std_internal_symbol]
     pub unsafe extern "C" fn __rdl_dealloc(ptr: *mut u8, size: usize, align: usize) {
-        System.dealloc(ptr, Layout::from_size_align_unchecked(size, align))
+        // SAFETY: see the guarantees expected by `Layout::from_size_align` and
+        // `GlobalAlloc::dealloc`.
+        unsafe { System.dealloc(ptr, Layout::from_size_align_unchecked(size, align)) }
     }
 
     #[rustc_std_internal_symbol]
@@ -316,13 +359,21 @@ pub mod __default_lib_allocator {
         align: usize,
         new_size: usize,
     ) -> *mut u8 {
-        let old_layout = Layout::from_size_align_unchecked(old_size, align);
-        System.realloc(ptr, old_layout, new_size)
+        // SAFETY: see the guarantees expected by `Layout::from_size_align` and
+        // `GlobalAlloc::realloc`.
+        unsafe {
+            let old_layout = Layout::from_size_align_unchecked(old_size, align);
+            System.realloc(ptr, old_layout, new_size)
+        }
     }
 
     #[rustc_std_internal_symbol]
     pub unsafe extern "C" fn __rdl_alloc_zeroed(size: usize, align: usize) -> *mut u8 {
-        let layout = Layout::from_size_align_unchecked(size, align);
-        System.alloc_zeroed(layout)
+        // SAFETY: see the guarantees expected by `Layout::from_size_align` and
+        // `GlobalAlloc::alloc_zeroed`.
+        unsafe {
+            let layout = Layout::from_size_align_unchecked(size, align);
+            System.alloc_zeroed(layout)
+        }
     }
 }
index e10d466030f0b1abc135e1418373c8d08fc0ea40..02e6811bc3f4357e33b732e17f138925562a31f7 100644 (file)
@@ -292,6 +292,12 @@ pub fn force_capture() -> Backtrace {
         Backtrace::create(Backtrace::force_capture as usize)
     }
 
+    /// Forcibly captures a disabled backtrace, regardless of environment
+    /// variable configuration.
+    pub const fn disabled() -> Backtrace {
+        Backtrace { inner: Inner::Disabled }
+    }
+
     // Capture a backtrace which start just before the function addressed by
     // `ip`
     fn create(ip: usize) -> Backtrace {
index eb2753d62457a6fab85f31ec5e9337240387fd98..43a3327d84b613905ad8c65daaf9ab52ff181633 100644 (file)
@@ -1,6 +1,7 @@
 use std::env;
 
 fn main() {
+    println!("cargo:rerun-if-changed=build.rs");
     let target = env::var("TARGET").expect("TARGET was not set");
     if target.contains("linux") {
         if target.contains("android") {
index 5ba5eff44076b54318043a3547935cffb8e248f8..7b48deee1abdf73f013f49637742fc7e13424d46 100644 (file)
 /// The easiest way to use `HashMap` with a custom key type is to derive [`Eq`] and [`Hash`].
 /// We must also derive [`PartialEq`].
 ///
-/// [`Eq`]: ../../std/cmp/trait.Eq.html
-/// [`Hash`]: ../../std/hash/trait.Hash.html
-/// [`PartialEq`]: ../../std/cmp/trait.PartialEq.html
-/// [`RefCell`]: ../../std/cell/struct.RefCell.html
-/// [`Cell`]: ../../std/cell/struct.Cell.html
-/// [`default`]: #method.default
-/// [`with_hasher`]: #method.with_hasher
-/// [`with_capacity_and_hasher`]: #method.with_capacity_and_hasher
+/// [`RefCell`]: crate::cell::RefCell
+/// [`Cell`]: crate::cell::Cell
+/// [`default`]: Default::default
+/// [`with_hasher`]: Self::with_hasher
+/// [`with_capacity_and_hasher`]: Self::with_capacity_and_hasher
 /// [`fnv`]: https://crates.io/crates/fnv
 ///
 /// ```
@@ -264,8 +261,6 @@ impl<K, V, S> HashMap<K, V, S> {
     /// let mut map = HashMap::with_hasher(s);
     /// map.insert(1, 2);
     /// ```
-    ///
-    /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html
     #[inline]
     #[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
     pub fn with_hasher(hash_builder: S) -> HashMap<K, V, S> {
@@ -296,8 +291,6 @@ pub fn with_hasher(hash_builder: S) -> HashMap<K, V, S> {
     /// let mut map = HashMap::with_capacity_and_hasher(10, s);
     /// map.insert(1, 2);
     /// ```
-    ///
-    /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html
     #[inline]
     #[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
     pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> HashMap<K, V, S> {
@@ -524,8 +517,6 @@ pub fn clear(&mut self) {
 
     /// Returns a reference to the map's [`BuildHasher`].
     ///
-    /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html
-    ///
     /// # Examples
     ///
     /// ```
@@ -556,8 +547,6 @@ impl<K, V, S> HashMap<K, V, S>
     ///
     /// Panics if the new allocation size overflows [`usize`].
     ///
-    /// [`usize`]: ../../std/primitive.usize.html
-    ///
     /// # Examples
     ///
     /// ```
@@ -676,9 +665,6 @@ pub fn entry(&mut self, key: K) -> Entry<'_, K, V> {
     /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for
     /// the key type.
     ///
-    /// [`Eq`]: ../../std/cmp/trait.Eq.html
-    /// [`Hash`]: ../../std/hash/trait.Hash.html
-    ///
     /// # Examples
     ///
     /// ```
@@ -705,9 +691,6 @@ pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V>
     /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for
     /// the key type.
     ///
-    /// [`Eq`]: ../../std/cmp/trait.Eq.html
-    /// [`Hash`]: ../../std/hash/trait.Hash.html
-    ///
     /// # Examples
     ///
     /// ```
@@ -734,9 +717,6 @@ pub fn get_key_value<Q: ?Sized>(&self, k: &Q) -> Option<(&K, &V)>
     /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for
     /// the key type.
     ///
-    /// [`Eq`]: ../../std/cmp/trait.Eq.html
-    /// [`Hash`]: ../../std/hash/trait.Hash.html
-    ///
     /// # Examples
     ///
     /// ```
@@ -763,9 +743,6 @@ pub fn contains_key<Q: ?Sized>(&self, k: &Q) -> bool
     /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for
     /// the key type.
     ///
-    /// [`Eq`]: ../../std/cmp/trait.Eq.html
-    /// [`Hash`]: ../../std/hash/trait.Hash.html
-    ///
     /// # Examples
     ///
     /// ```
@@ -797,8 +774,7 @@ pub fn get_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V>
     /// types that can be `==` without being identical. See the [module-level
     /// documentation] for more.
     ///
-    /// [`None`]: ../../std/option/enum.Option.html#variant.None
-    /// [module-level documentation]: index.html#insert-and-complex-keys
+    /// [module-level documentation]: crate::collections#insert-and-complex-keys
     ///
     /// # Examples
     ///
@@ -826,9 +802,6 @@ pub fn insert(&mut self, k: K, v: V) -> Option<V> {
     /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for
     /// the key type.
     ///
-    /// [`Eq`]: ../../std/cmp/trait.Eq.html
-    /// [`Hash`]: ../../std/hash/trait.Hash.html
-    ///
     /// # Examples
     ///
     /// ```
@@ -856,9 +829,6 @@ pub fn remove<Q: ?Sized>(&mut self, k: &Q) -> Option<V>
     /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for
     /// the key type.
     ///
-    /// [`Eq`]: ../../std/cmp/trait.Eq.html
-    /// [`Hash`]: ../../std/hash/trait.Hash.html
-    ///
     /// # Examples
     ///
     /// ```
@@ -1040,8 +1010,7 @@ fn index(&self, key: &Q) -> &V {
 /// This `struct` is created by the [`iter`] method on [`HashMap`]. See its
 /// documentation for more.
 ///
-/// [`iter`]: struct.HashMap.html#method.iter
-/// [`HashMap`]: struct.HashMap.html
+/// [`iter`]: HashMap::iter
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Iter<'a, K: 'a, V: 'a> {
     base: base::Iter<'a, K, V>,
@@ -1068,8 +1037,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 /// This `struct` is created by the [`iter_mut`] method on [`HashMap`]. See its
 /// documentation for more.
 ///
-/// [`iter_mut`]: struct.HashMap.html#method.iter_mut
-/// [`HashMap`]: struct.HashMap.html
+/// [`iter_mut`]: HashMap::iter_mut
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct IterMut<'a, K: 'a, V: 'a> {
     base: base::IterMut<'a, K, V>,
@@ -1088,8 +1056,7 @@ pub(super) fn iter(&self) -> Iter<'_, K, V> {
 /// This `struct` is created by the [`into_iter`] method on [`HashMap`]
 /// (provided by the `IntoIterator` trait). See its documentation for more.
 ///
-/// [`into_iter`]: struct.HashMap.html#method.into_iter
-/// [`HashMap`]: struct.HashMap.html
+/// [`into_iter`]: IntoIterator::into_iter
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct IntoIter<K, V> {
     base: base::IntoIter<K, V>,
@@ -1108,8 +1075,7 @@ pub(super) fn iter(&self) -> Iter<'_, K, V> {
 /// This `struct` is created by the [`keys`] method on [`HashMap`]. See its
 /// documentation for more.
 ///
-/// [`keys`]: struct.HashMap.html#method.keys
-/// [`HashMap`]: struct.HashMap.html
+/// [`keys`]: HashMap::keys
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Keys<'a, K: 'a, V: 'a> {
     inner: Iter<'a, K, V>,
@@ -1136,8 +1102,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 /// This `struct` is created by the [`values`] method on [`HashMap`]. See its
 /// documentation for more.
 ///
-/// [`values`]: struct.HashMap.html#method.values
-/// [`HashMap`]: struct.HashMap.html
+/// [`values`]: HashMap::values
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Values<'a, K: 'a, V: 'a> {
     inner: Iter<'a, K, V>,
@@ -1164,8 +1129,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 /// This `struct` is created by the [`drain`] method on [`HashMap`]. See its
 /// documentation for more.
 ///
-/// [`drain`]: struct.HashMap.html#method.drain
-/// [`HashMap`]: struct.HashMap.html
+/// [`drain`]: HashMap::drain
 #[stable(feature = "drain", since = "1.6.0")]
 pub struct Drain<'a, K: 'a, V: 'a> {
     base: base::Drain<'a, K, V>,
@@ -1184,8 +1148,7 @@ pub(super) fn iter(&self) -> Iter<'_, K, V> {
 /// This `struct` is created by the [`values_mut`] method on [`HashMap`]. See its
 /// documentation for more.
 ///
-/// [`values_mut`]: struct.HashMap.html#method.values_mut
-/// [`HashMap`]: struct.HashMap.html
+/// [`values_mut`]: HashMap::values_mut
 #[stable(feature = "map_values_mut", since = "1.10.0")]
 pub struct ValuesMut<'a, K: 'a, V: 'a> {
     inner: IterMut<'a, K, V>,
@@ -1195,7 +1158,7 @@ pub struct ValuesMut<'a, K: 'a, V: 'a> {
 ///
 /// See the [`HashMap::raw_entry_mut`] docs for usage examples.
 ///
-/// [`HashMap::raw_entry_mut`]: struct.HashMap.html#method.raw_entry_mut
+/// [`HashMap::raw_entry_mut`]: HashMap::raw_entry_mut
 
 #[unstable(feature = "hash_raw_entry", issue = "56167")]
 pub struct RawEntryBuilderMut<'a, K: 'a, V: 'a, S: 'a> {
@@ -1209,9 +1172,8 @@ pub struct RawEntryBuilderMut<'a, K: 'a, V: 'a, S: 'a> {
 /// This `enum` is constructed through the [`raw_entry_mut`] method on [`HashMap`],
 /// then calling one of the methods of that [`RawEntryBuilderMut`].
 ///
-/// [`HashMap`]: struct.HashMap.html
 /// [`Entry`]: enum.Entry.html
-/// [`raw_entry_mut`]: struct.HashMap.html#method.raw_entry_mut
+/// [`raw_entry_mut`]: HashMap::raw_entry_mut
 /// [`RawEntryBuilderMut`]: struct.RawEntryBuilderMut.html
 #[unstable(feature = "hash_raw_entry", issue = "56167")]
 pub enum RawEntryMut<'a, K: 'a, V: 'a, S: 'a> {
@@ -1223,8 +1185,6 @@ pub enum RawEntryMut<'a, K: 'a, V: 'a, S: 'a> {
 
 /// A view into an occupied entry in a `HashMap`.
 /// It is part of the [`RawEntryMut`] enum.
-///
-/// [`RawEntryMut`]: enum.RawEntryMut.html
 #[unstable(feature = "hash_raw_entry", issue = "56167")]
 pub struct RawOccupiedEntryMut<'a, K: 'a, V: 'a> {
     base: base::RawOccupiedEntryMut<'a, K, V>,
@@ -1232,8 +1192,6 @@ pub struct RawOccupiedEntryMut<'a, K: 'a, V: 'a> {
 
 /// A view into a vacant entry in a `HashMap`.
 /// It is part of the [`RawEntryMut`] enum.
-///
-/// [`RawEntryMut`]: enum.RawEntryMut.html
 #[unstable(feature = "hash_raw_entry", issue = "56167")]
 pub struct RawVacantEntryMut<'a, K: 'a, V: 'a, S: 'a> {
     base: base::RawVacantEntryMut<'a, K, V, S>,
@@ -1243,7 +1201,7 @@ pub struct RawVacantEntryMut<'a, K: 'a, V: 'a, S: 'a> {
 ///
 /// See the [`HashMap::raw_entry`] docs for usage examples.
 ///
-/// [`HashMap::raw_entry`]: struct.HashMap.html#method.raw_entry
+/// [`HashMap::raw_entry`]: HashMap::raw_entry
 #[unstable(feature = "hash_raw_entry", issue = "56167")]
 pub struct RawEntryBuilder<'a, K: 'a, V: 'a, S: 'a> {
     map: &'a HashMap<K, V, S>,
@@ -1597,8 +1555,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 ///
 /// This `enum` is constructed from the [`entry`] method on [`HashMap`].
 ///
-/// [`HashMap`]: struct.HashMap.html
-/// [`entry`]: struct.HashMap.html#method.entry
+/// [`entry`]: HashMap::entry
 #[stable(feature = "rust1", since = "1.0.0")]
 pub enum Entry<'a, K: 'a, V: 'a> {
     /// An occupied entry.
@@ -2156,7 +2113,7 @@ pub fn get(&self) -> &V {
     /// If you need a reference to the `OccupiedEntry` which may outlive the
     /// destruction of the `Entry` value, see [`into_mut`].
     ///
-    /// [`into_mut`]: #method.into_mut
+    /// [`into_mut`]: Self::into_mut
     ///
     /// # Examples
     ///
@@ -2189,7 +2146,7 @@ pub fn get_mut(&mut self) -> &mut V {
     ///
     /// If you need multiple references to the `OccupiedEntry`, see [`get_mut`].
     ///
-    /// [`get_mut`]: #method.get_mut
+    /// [`get_mut`]: Self::get_mut
     ///
     /// # Examples
     ///
@@ -2475,9 +2432,6 @@ fn extend_reserve(&mut self, additional: usize) {
 /// [`Hasher`], but the hashers created by two different `RandomState`
 /// instances are unlikely to produce the same result for the same values.
 ///
-/// [`HashMap`]: struct.HashMap.html
-/// [`Hasher`]: ../../hash/trait.Hasher.html
-///
 /// # Examples
 ///
 /// ```
@@ -2547,9 +2501,6 @@ fn build_hasher(&self) -> DefaultHasher {
 ///
 /// The internal algorithm is not specified, and so it and its hashes should
 /// not be relied upon over releases.
-///
-/// [`RandomState`]: struct.RandomState.html
-/// [`Hasher`]: ../../hash/trait.Hasher.html
 #[stable(feature = "hashmap_default_hasher", since = "1.13.0")]
 #[allow(deprecated)]
 #[derive(Clone, Debug)]
index cb2f829803b85e8b1d748a308300d3f72339cde3..10bf917daea4680534d685b4ba7678b98974d6f3 100644 (file)
 /// // use the values stored in the set
 /// ```
 ///
-/// [`Cell`]: ../../std/cell/struct.Cell.html
-/// [`Eq`]: ../../std/cmp/trait.Eq.html
-/// [`Hash`]: ../../std/hash/trait.Hash.html
-/// [`HashMap`]: struct.HashMap.html
-/// [`PartialEq`]: ../../std/cmp/trait.PartialEq.html
-/// [`RefCell`]: ../../std/cell/struct.RefCell.html
+/// [`RefCell`]: crate::cell::RefCell
+/// [`Cell`]: crate::cell::Cell
 #[derive(Clone)]
 #[cfg_attr(not(test), rustc_diagnostic_item = "hashset_type")]
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -286,8 +282,6 @@ pub fn clear(&mut self) {
     /// let mut set = HashSet::with_hasher(s);
     /// set.insert(2);
     /// ```
-    ///
-    /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html
     #[inline]
     #[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
     pub fn with_hasher(hasher: S) -> HashSet<T, S> {
@@ -318,8 +312,6 @@ pub fn with_hasher(hasher: S) -> HashSet<T, S> {
     /// let mut set = HashSet::with_capacity_and_hasher(10, s);
     /// set.insert(1);
     /// ```
-    ///
-    /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html
     #[inline]
     #[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
     pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> HashSet<T, S> {
@@ -328,8 +320,6 @@ pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> HashSet<T, S> {
 
     /// Returns a reference to the set's [`BuildHasher`].
     ///
-    /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html
-    ///
     /// # Examples
     ///
     /// ```
@@ -577,9 +567,6 @@ pub fn union<'a>(&'a self, other: &'a HashSet<T, S>) -> Union<'a, T, S> {
     /// assert_eq!(set.contains(&1), true);
     /// assert_eq!(set.contains(&4), false);
     /// ```
-    ///
-    /// [`Eq`]: ../../std/cmp/trait.Eq.html
-    /// [`Hash`]: ../../std/hash/trait.Hash.html
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn contains<Q: ?Sized>(&self, value: &Q) -> bool
@@ -605,9 +592,6 @@ pub fn contains<Q: ?Sized>(&self, value: &Q) -> bool
     /// assert_eq!(set.get(&2), Some(&2));
     /// assert_eq!(set.get(&4), None);
     /// ```
-    ///
-    /// [`Eq`]: ../../std/cmp/trait.Eq.html
-    /// [`Hash`]: ../../std/hash/trait.Hash.html
     #[inline]
     #[stable(feature = "set_recovery", since = "1.9.0")]
     pub fn get<Q: ?Sized>(&self, value: &Q) -> Option<&T>
@@ -849,9 +833,6 @@ pub fn replace(&mut self, value: T) -> Option<T> {
     /// assert_eq!(set.remove(&2), true);
     /// assert_eq!(set.remove(&2), false);
     /// ```
-    ///
-    /// [`Eq`]: ../../std/cmp/trait.Eq.html
-    /// [`Hash`]: ../../std/hash/trait.Hash.html
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn remove<Q: ?Sized>(&mut self, value: &Q) -> bool
@@ -877,9 +858,6 @@ pub fn remove<Q: ?Sized>(&mut self, value: &Q) -> bool
     /// assert_eq!(set.take(&2), Some(2));
     /// assert_eq!(set.take(&2), None);
     /// ```
-    ///
-    /// [`Eq`]: ../../std/cmp/trait.Eq.html
-    /// [`Hash`]: ../../std/hash/trait.Hash.html
     #[inline]
     #[stable(feature = "set_recovery", since = "1.9.0")]
     pub fn take<Q: ?Sized>(&mut self, value: &Q) -> Option<T>
@@ -1153,8 +1131,7 @@ fn sub(self, rhs: &HashSet<T, S>) -> HashSet<T, S> {
 /// This `struct` is created by the [`iter`] method on [`HashSet`].
 /// See its documentation for more.
 ///
-/// [`HashSet`]: struct.HashSet.html
-/// [`iter`]: struct.HashSet.html#method.iter
+/// [`iter`]: HashSet::iter
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Iter<'a, K: 'a> {
     iter: Keys<'a, K, ()>,
@@ -1165,8 +1142,7 @@ pub struct Iter<'a, K: 'a> {
 /// This `struct` is created by the [`into_iter`] method on [`HashSet`]
 /// (provided by the `IntoIterator` trait). See its documentation for more.
 ///
-/// [`HashSet`]: struct.HashSet.html
-/// [`into_iter`]: struct.HashSet.html#method.into_iter
+/// [`into_iter`]: IntoIterator::into_iter
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct IntoIter<K> {
     iter: map::IntoIter<K, ()>,
@@ -1177,8 +1153,7 @@ pub struct IntoIter<K> {
 /// This `struct` is created by the [`drain`] method on [`HashSet`].
 /// See its documentation for more.
 ///
-/// [`HashSet`]: struct.HashSet.html
-/// [`drain`]: struct.HashSet.html#method.drain
+/// [`drain`]: HashSet::drain
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Drain<'a, K: 'a> {
     iter: map::Drain<'a, K, ()>,
@@ -1189,8 +1164,7 @@ pub struct Drain<'a, K: 'a> {
 /// This `struct` is created by the [`intersection`] method on [`HashSet`].
 /// See its documentation for more.
 ///
-/// [`HashSet`]: struct.HashSet.html
-/// [`intersection`]: struct.HashSet.html#method.intersection
+/// [`intersection`]: HashSet::intersection
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Intersection<'a, T: 'a, S: 'a> {
     // iterator of the first set
@@ -1204,8 +1178,7 @@ pub struct Intersection<'a, T: 'a, S: 'a> {
 /// This `struct` is created by the [`difference`] method on [`HashSet`].
 /// See its documentation for more.
 ///
-/// [`HashSet`]: struct.HashSet.html
-/// [`difference`]: struct.HashSet.html#method.difference
+/// [`difference`]: HashSet::difference
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Difference<'a, T: 'a, S: 'a> {
     // iterator of the first set
@@ -1219,8 +1192,7 @@ pub struct Difference<'a, T: 'a, S: 'a> {
 /// This `struct` is created by the [`symmetric_difference`] method on
 /// [`HashSet`]. See its documentation for more.
 ///
-/// [`HashSet`]: struct.HashSet.html
-/// [`symmetric_difference`]: struct.HashSet.html#method.symmetric_difference
+/// [`symmetric_difference`]: HashSet::symmetric_difference
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct SymmetricDifference<'a, T: 'a, S: 'a> {
     iter: Chain<Difference<'a, T, S>, Difference<'a, T, S>>,
@@ -1231,8 +1203,7 @@ pub struct SymmetricDifference<'a, T: 'a, S: 'a> {
 /// This `struct` is created by the [`union`] method on [`HashSet`].
 /// See its documentation for more.
 ///
-/// [`HashSet`]: struct.HashSet.html
-/// [`union`]: struct.HashSet.html#method.union
+/// [`union`]: HashSet::union
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Union<'a, T: 'a, S: 'a> {
     iter: Chain<Iter<'a, T>, Difference<'a, T, S>>,
index cc6663bebd3d4cf99aa8ce21f798d0f43010d3dc..b6488ae61b153ee2c1cb6ffeb0184f7d70dbace5 100644 (file)
@@ -86,7 +86,7 @@
 //! cost are suffixed with a `~`.
 //!
 //! All amortized costs are for the potential need to resize when capacity is
-//! exhausted. If a resize occurs it will take O(n) time. Our collections never
+//! exhausted. If a resize occurs it will take *O*(*n*) time. Our collections never
 //! automatically shrink, so removal operations aren't amortized. Over a
 //! sufficiently large series of operations, the average cost per operation will
 //! deterministically equal the given cost.
index b392d6e7226d2d7bba2080ebefae53cd89626c45..c905bcf5e3db4255819b3c952eb5277012042add 100644 (file)
@@ -1500,7 +1500,7 @@ fn test_float_bits_conv() {
         assert_approx_eq!(f32::from_bits(0x44a72000), 1337.0);
         assert_approx_eq!(f32::from_bits(0xc1640000), -14.25);
 
-        // Check that NaNs roundtrip their bits regardless of signalingness
+        // Check that NaNs roundtrip their bits regardless of signaling-ness
         // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits
         let masked_nan1 = f32::NAN.to_bits() ^ 0x002A_AAAA;
         let masked_nan2 = f32::NAN.to_bits() ^ 0x0055_5555;
index 72268d2cc2f984be863501d2e4df84197d3fbb61..f09fc8d790b28faade6c3d0a2193263d32b07a42 100644 (file)
@@ -1523,7 +1523,7 @@ fn test_float_bits_conv() {
         assert_approx_eq!(f64::from_bits(0x4094e40000000000), 1337.0);
         assert_approx_eq!(f64::from_bits(0xc02c800000000000), -14.25);
 
-        // Check that NaNs roundtrip their bits regardless of signalingness
+        // Check that NaNs roundtrip their bits regardless of signaling-ness
         // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits
         let masked_nan1 = f64::NAN.to_bits() ^ 0x000A_AAAA_AAAA_AAAA;
         let masked_nan2 = f64::NAN.to_bits() ^ 0x0005_5555_5555_5555;
index dca1fdde4824295f72cd1539d5fa124ca96b3d9e..da25a0ede729d1fd3c66b1819fda6e91d17aa3bb 100644 (file)
@@ -1551,6 +1551,27 @@ fn index(&self, _index: ops::RangeFull) -> &CStr {
     }
 }
 
+#[stable(feature = "cstr_range_from", since = "1.47.0")]
+impl ops::Index<ops::RangeFrom<usize>> for CStr {
+    type Output = CStr;
+
+    fn index(&self, index: ops::RangeFrom<usize>) -> &CStr {
+        let bytes = self.to_bytes_with_nul();
+        // we need to manually check the starting index to account for the null
+        // byte, since otherwise we could get an empty string that doesn't end
+        // in a null.
+        if index.start < bytes.len() {
+            unsafe { CStr::from_bytes_with_nul_unchecked(&bytes[index.start..]) }
+        } else {
+            panic!(
+                "index out of bounds: the len is {} but the index is {}",
+                bytes.len(),
+                index.start
+            );
+        }
+    }
+}
+
 #[stable(feature = "cstring_asref", since = "1.7.0")]
 impl AsRef<CStr> for CStr {
     #[inline]
@@ -1747,4 +1768,21 @@ fn cstr_const_constructor() {
 
         assert_eq!(CSTR.to_str().unwrap(), "Hello, world!");
     }
+
+    #[test]
+    fn cstr_index_from() {
+        let original = b"Hello, world!\0";
+        let cstr = CStr::from_bytes_with_nul(original).unwrap();
+        let result = CStr::from_bytes_with_nul(&original[7..]).unwrap();
+
+        assert_eq!(&cstr[7..], result);
+    }
+
+    #[test]
+    #[should_panic]
+    fn cstr_index_from_empty() {
+        let original = b"Hello, world!\0";
+        let cstr = CStr::from_bytes_with_nul(original).unwrap();
+        let _ = &cstr[original.len()..];
+    }
 }
index d5af4f25102d1de3c31bb63f3105a49278d36dc9..797318d95b7775f3d5e13011acc9401da7cfb1ee 100644 (file)
 //! contract. The implementation of many of these functions are subject to change over
 //! time and may call fewer or more syscalls/library functions.
 //!
-//! [`Read`]: trait.Read.html
-//! [`Write`]: trait.Write.html
-//! [`Seek`]: trait.Seek.html
-//! [`BufRead`]: trait.BufRead.html
-//! [`File`]: ../fs/struct.File.html
-//! [`TcpStream`]: ../net/struct.TcpStream.html
-//! [`Vec<T>`]: ../vec/struct.Vec.html
-//! [`BufReader`]: struct.BufReader.html
-//! [`BufWriter`]: struct.BufWriter.html
-//! [`Write::write`]: trait.Write.html#tymethod.write
-//! [`io::stdout`]: fn.stdout.html
-//! [`println!`]: ../macro.println.html
-//! [`Lines`]: struct.Lines.html
-//! [`io::Result`]: type.Result.html
+//! [`File`]: crate::fs::File
+//! [`TcpStream`]: crate::net::TcpStream
+//! [`Vec<T>`]: crate::vec::Vec
+//! [`io::stdout`]: stdout
+//! [`io::Result`]: crate::io::Result
 //! [`?` operator]: ../../book/appendix-02-operators.html
-//! [`Read::read`]: trait.Read.html#tymethod.read
-//! [`Result`]: ../result/enum.Result.html
-//! [`.unwrap()`]: ../result/enum.Result.html#method.unwrap
-// ignore-tidy-filelength
+//! [`Result`]: crate::result::Result
+//! [`.unwrap()`]: crate::result::Result::unwrap
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
@@ -491,12 +480,10 @@ pub(crate) fn default_write_vectored<F>(write: F, bufs: &[IoSlice<'_>]) -> Resul
 /// }
 /// ```
 ///
-/// [`read()`]: trait.Read.html#tymethod.read
-/// [`std::io`]: ../../std/io/index.html
-/// [`File`]: ../fs/struct.File.html
-/// [`BufRead`]: trait.BufRead.html
-/// [`BufReader`]: struct.BufReader.html
-/// [`&str`]: ../../std/primitive.str.html
+/// [`read()`]: Read::read
+/// [`&str`]: str
+/// [`std::io`]: self
+/// [`File`]: crate::fs::File
 /// [slice]: ../../std/primitive.slice.html
 #[stable(feature = "rust1", since = "1.0.0")]
 #[doc(spotlight)]
@@ -535,7 +522,7 @@ pub trait Read {
     /// before calling `read`. Calling `read` with an uninitialized `buf` (of the kind one
     /// obtains via [`MaybeUninit<T>`]) is not safe, and can lead to undefined behavior.
     ///
-    /// [`MaybeUninit<T>`]: ../mem/union.MaybeUninit.html
+    /// [`MaybeUninit<T>`]: crate::mem::MaybeUninit
     ///
     /// # Errors
     ///
@@ -550,10 +537,8 @@ pub trait Read {
     ///
     /// [`File`]s implement `Read`:
     ///
-    /// [`Err`]: ../../std/result/enum.Result.html#variant.Err
-    /// [`Ok(n)`]: ../../std/result/enum.Result.html#variant.Ok
-    /// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted
-    /// [`File`]: ../fs/struct.File.html
+    /// [`Ok(n)`]: Ok
+    /// [`File`]: crate::fs::File
     ///
     /// ```no_run
     /// use std::io;
@@ -620,9 +605,6 @@ fn is_read_vectored(&self) -> bool {
     /// This method is unsafe because a `Read`er could otherwise return a
     /// non-zeroing `Initializer` from another `Read` type without an `unsafe`
     /// block.
-    ///
-    /// [`Initializer::nop()`]: ../../std/io/struct.Initializer.html#method.nop
-    /// [`Initializer`]: ../../std/io/struct.Initializer.html
     #[unstable(feature = "read_initializer", issue = "42788")]
     #[inline]
     unsafe fn initializer(&self) -> Initializer {
@@ -652,10 +634,9 @@ unsafe fn initializer(&self) -> Initializer {
     ///
     /// [`File`]s implement `Read`:
     ///
-    /// [`read()`]: trait.Read.html#tymethod.read
-    /// [`Ok(0)`]: ../../std/result/enum.Result.html#variant.Ok
-    /// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted
-    /// [`File`]: ../fs/struct.File.html
+    /// [`read()`]: Read::read
+    /// [`Ok(0)`]: Ok
+    /// [`File`]: crate::fs::File
     ///
     /// ```no_run
     /// use std::io;
@@ -675,7 +656,7 @@ unsafe fn initializer(&self) -> Initializer {
     /// (See also the [`std::fs::read`] convenience function for reading from a
     /// file.)
     ///
-    /// [`std::fs::read`]: ../fs/fn.read.html
+    /// [`std::fs::read`]: crate::fs::read
     #[stable(feature = "rust1", since = "1.0.0")]
     fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize> {
         read_to_end(self, buf)
@@ -693,13 +674,13 @@ fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize> {
     ///
     /// See [`read_to_end`][readtoend] for other error semantics.
     ///
-    /// [readtoend]: #method.read_to_end
+    /// [readtoend]: Self::read_to_end
     ///
     /// # Examples
     ///
     /// [`File`][file]s implement `Read`:
     ///
-    /// [file]: ../fs/struct.File.html
+    /// [file]: crate::fs::File
     ///
     /// ```no_run
     /// use std::io;
@@ -718,7 +699,7 @@ fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize> {
     /// (See also the [`std::fs::read_to_string`] convenience function for
     /// reading from a file.)
     ///
-    /// [`std::fs::read_to_string`]: ../fs/fn.read_to_string.html
+    /// [`std::fs::read_to_string`]: crate::fs::read_to_string
     #[stable(feature = "rust1", since = "1.0.0")]
     fn read_to_string(&mut self, buf: &mut String) -> Result<usize> {
         // Note that we do *not* call `.read_to_end()` here. We are passing
@@ -741,7 +722,9 @@ fn read_to_string(&mut self, buf: &mut String) -> Result<usize> {
     /// No guarantees are provided about the contents of `buf` when this
     /// function is called, implementations cannot rely on any property of the
     /// contents of `buf` being true. It is recommended that implementations
-    /// only write data to `buf` instead of reading its contents.
+    /// only write data to `buf` instead of reading its contents. The
+    /// documentation on [`read`] has a more detailed explanation on this
+    /// subject.
     ///
     /// # Errors
     ///
@@ -764,9 +747,8 @@ fn read_to_string(&mut self, buf: &mut String) -> Result<usize> {
     ///
     /// [`File`]s implement `Read`:
     ///
-    /// [`File`]: ../fs/struct.File.html
-    /// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted
-    /// [`ErrorKind::UnexpectedEof`]: ../../std/io/enum.ErrorKind.html#variant.UnexpectedEof
+    /// [`read`]: Read::read
+    /// [`File`]: crate::fs::File
     ///
     /// ```no_run
     /// use std::io;
@@ -811,7 +793,7 @@ fn read_exact(&mut self, mut buf: &mut [u8]) -> Result<()> {
     ///
     /// [`File`][file]s implement `Read`:
     ///
-    /// [file]: ../fs/struct.File.html
+    /// [file]: crate::fs::File
     ///
     /// ```no_run
     /// use std::io;
@@ -855,14 +837,10 @@ fn by_ref(&mut self) -> &mut Self
     ///
     /// [`File`][file]s implement `Read`:
     ///
-    /// [file]: ../fs/struct.File.html
-    /// [`Iterator`]: ../../std/iter/trait.Iterator.html
-    /// [`Result`]: ../../std/result/enum.Result.html
-    /// [`io::Error`]: ../../std/io/struct.Error.html
-    /// [`u8`]: ../../std/primitive.u8.html
-    /// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok
-    /// [`Err`]: ../../std/result/enum.Result.html#variant.Err
-    /// [`None`]: ../../std/option/enum.Option.html#variant.None
+    /// [file]: crate::fs::File
+    /// [`Iterator`]: crate::iter::Iterator
+    /// [`Result`]: crate::result::Result
+    /// [`io::Error`]: self::Error
     ///
     /// ```no_run
     /// use std::io;
@@ -896,7 +874,7 @@ fn bytes(self) -> Bytes<Self>
     ///
     /// [`File`][file]s implement `Read`:
     ///
-    /// [file]: ../fs/struct.File.html
+    /// [file]: crate::fs::File
     ///
     /// ```no_run
     /// use std::io;
@@ -935,9 +913,9 @@ fn chain<R: Read>(self, next: R) -> Chain<Self, R>
     ///
     /// [`File`]s implement `Read`:
     ///
-    /// [`File`]: ../fs/struct.File.html
-    /// [`Ok(0)`]: ../../std/result/enum.Result.html#variant.Ok
-    /// [`read()`]: trait.Read.html#tymethod.read
+    /// [`File`]: crate::fs::File
+    /// [`Ok(0)`]: Ok
+    /// [`read()`]: Read::read
     ///
     /// ```no_run
     /// use std::io;
@@ -1233,8 +1211,8 @@ pub fn initialize(&self, buf: &mut [u8]) {
 /// throughout [`std::io`] take and provide types which implement the `Write`
 /// trait.
 ///
-/// [`write`]: #tymethod.write
-/// [`flush`]: #tymethod.flush
+/// [`write`]: Self::write
+/// [`flush`]: Self::flush
 /// [`std::io`]: index.html
 ///
 /// # Examples
@@ -1260,7 +1238,7 @@ pub fn initialize(&self, buf: &mut [u8]) {
 /// The trait also provides convenience methods like [`write_all`], which calls
 /// `write` in a loop until its entire input has been written.
 ///
-/// [`write_all`]: #method.write_all
+/// [`write_all`]: Self::write_all
 #[stable(feature = "rust1", since = "1.0.0")]
 #[doc(spotlight)]
 pub trait Write {
@@ -1292,10 +1270,6 @@ pub trait Write {
     /// An error of the [`ErrorKind::Interrupted`] kind is non-fatal and the
     /// write operation should be retried if there is nothing else to do.
     ///
-    /// [`Err`]: ../../std/result/enum.Result.html#variant.Err
-    /// [`Ok(n)`]:  ../../std/result/enum.Result.html#variant.Ok
-    /// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted
-    ///
     /// # Examples
     ///
     /// ```no_run
@@ -1381,8 +1355,7 @@ fn is_write_vectored(&self) -> bool {
     /// This function will return the first error of
     /// non-[`ErrorKind::Interrupted`] kind that [`write`] returns.
     ///
-    /// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted
-    /// [`write`]: #tymethod.write
+    /// [`write`]: Self::write
     ///
     /// # Examples
     ///
@@ -1423,8 +1396,7 @@ fn write_all(&mut self, mut buf: &[u8]) -> Result<()> {
     ///
     /// If the buffer contains no data, this will never call [`write_vectored`].
     ///
-    /// [`write_vectored`]: #method.write_vectored
-    /// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted
+    /// [`write_vectored`]: Self::write_vectored
     ///
     /// # Notes
     ///
@@ -1480,19 +1452,16 @@ fn write_all_vectored(&mut self, mut bufs: &mut [IoSlice<'_>]) -> Result<()> {
     /// encountered.
     ///
     /// This method is primarily used to interface with the
-    /// [`format_args!`][formatargs] macro, but it is rare that this should
-    /// explicitly be called. The [`write!`][write] macro should be favored to
+    /// [`format_args!()`] macro, but it is rare that this should
+    /// explicitly be called. The [`write!()`] macro should be favored to
     /// invoke this method instead.
     ///
-    /// [formatargs]: ../macro.format_args.html
-    /// [write]: ../macro.write.html
-    ///
     /// This function internally uses the [`write_all`][writeall] method on
     /// this trait and hence will continuously write data so long as no errors
     /// are received. This also means that partial writes are not indicated in
     /// this signature.
     ///
-    /// [writeall]: #method.write_all
+    /// [writeall]: Self::write_all
     ///
     /// # Errors
     ///
@@ -1589,7 +1558,7 @@ fn by_ref(&mut self) -> &mut Self
 ///
 /// [`File`][file]s implement `Seek`:
 ///
-/// [file]: ../fs/struct.File.html
+/// [file]: crate::fs::File
 ///
 /// ```no_run
 /// use std::io;
@@ -1789,9 +1758,9 @@ fn read_until<R: BufRead + ?Sized>(r: &mut R, delim: u8, buf: &mut Vec<u8>) -> R
 /// [`BufReader`] to the rescue!
 ///
 /// [`BufReader`]: struct.BufReader.html
-/// [`File`]: ../fs/struct.File.html
-/// [`read_line`]: #method.read_line
-/// [`lines`]: #method.lines
+/// [`File`]: crate::fs::File
+/// [`read_line`]: Self::read_line
+/// [`lines`]: Self::lines
 /// [`Read`]: trait.Read.html
 ///
 /// ```no_run
@@ -1823,7 +1792,7 @@ pub trait BufRead: Read {
     /// be called with the number of bytes that are consumed from this buffer to
     /// ensure that the bytes are never returned twice.
     ///
-    /// [`consume`]: #tymethod.consume
+    /// [`consume`]: Self::consume
     ///
     /// An empty buffer returned indicates that the stream has reached EOF.
     ///
@@ -1873,7 +1842,7 @@ pub trait BufRead: Read {
     /// Since `consume()` is meant to be used with [`fill_buf`],
     /// that method's example includes an example of `consume()`.
     ///
-    /// [`fill_buf`]: #tymethod.fill_buf
+    /// [`fill_buf`]: Self::fill_buf
     #[stable(feature = "rust1", since = "1.0.0")]
     fn consume(&mut self, amt: usize);
 
@@ -1897,7 +1866,7 @@ pub trait BufRead: Read {
     /// If an I/O error is encountered then all bytes read so far will be
     /// present in `buf` and its length will have been adjusted appropriately.
     ///
-    /// [`fill_buf`]: #tymethod.fill_buf
+    /// [`fill_buf`]: Self::fill_buf
     /// [`ErrorKind::Interrupted`]: enum.ErrorKind.html#variant.Interrupted
     ///
     /// # Examples
@@ -1962,7 +1931,7 @@ fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> Result<usize> {
     /// error is encountered then `buf` may contain some bytes already read in
     /// the event that all data read so far was valid UTF-8.
     ///
-    /// [`read_until`]: #method.read_until
+    /// [`read_until`]: Self::read_until
     ///
     /// # Examples
     ///
@@ -2015,9 +1984,9 @@ fn read_line(&mut self, buf: &mut String) -> Result<usize> {
     /// This function will yield errors whenever [`read_until`] would have
     /// also yielded an error.
     ///
-    /// [`io::Result`]: type.Result.html
-    /// [`Vec<u8>`]: ../vec/struct.Vec.html
-    /// [`read_until`]: #method.read_until
+    /// [`io::Result`]: self::Result
+    /// [`Vec<u8>`]: crate::vec::Vec
+    /// [`read_until`]: Self::read_until
     ///
     /// # Examples
     ///
@@ -2052,8 +2021,7 @@ fn split(self, byte: u8) -> Split<Self>
     /// [`io::Result`]`<`[`String`]`>`. Each string returned will *not* have a newline
     /// byte (the 0xA byte) or CRLF (0xD, 0xA bytes) at the end.
     ///
-    /// [`io::Result`]: type.Result.html
-    /// [`String`]: ../string/struct.String.html
+    /// [`io::Result`]: self::Result
     ///
     /// # Examples
     ///
@@ -2061,8 +2029,6 @@ fn split(self, byte: u8) -> Split<Self>
     /// this example, we use [`Cursor`] to iterate over all the lines in a byte
     /// slice.
     ///
-    /// [`Cursor`]: struct.Cursor.html
-    ///
     /// ```
     /// use std::io::{self, BufRead};
     ///
@@ -2253,8 +2219,6 @@ impl<T> Take<T> {
     /// This instance may reach `EOF` after reading fewer bytes than indicated by
     /// this method if the underlying [`Read`] instance reaches EOF.
     ///
-    /// [`Read`]: ../../std/io/trait.Read.html
-    ///
     /// # Examples
     ///
     /// ```no_run
index a53e7f5cf57aa15c2af6912db92921b7ceb91a5c..a62987891b99b24f5b4c153dd5f4a7827a30b98e 100644 (file)
@@ -387,10 +387,11 @@ mod extern_keyword {}
 //
 /// A value of type [`bool`] representing logical **false**.
 ///
-/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+/// `false` is the logical opposite of [`true`].
 ///
-/// [`bool`]: primitive.bool.html
-/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+/// See the documentation for [`true`] for more information.
+///
+/// [`true`]: keyword.true.html
 mod false_keyword {}
 
 #[doc(keyword = "fn")]
@@ -473,8 +474,8 @@ mod fn_keyword {}
 /// * `for` is also used for [higher-ranked trait bounds] as in `for<'a> &'a T: PartialEq<i32>`.
 ///
 /// for-in-loops, or to be more precise, iterator loops, are a simple syntactic sugar over a common
-/// practice within Rust, which is to loop over an iterator until that iterator returns `None` (or
-/// `break` is called).
+/// practice within Rust, which is to loop over anything that implements [`IntoIterator`] until the
+/// iterator returned by `.into_iter()` returns `None` (or the loop body uses `break`).
 ///
 /// ```rust
 /// for i in 0..5 {
@@ -680,7 +681,7 @@ mod impl_keyword {}
 //
 /// Iterate over a series of values with [`for`].
 ///
-/// The expression immediately following `in` must implement the [`Iterator`] trait.
+/// The expression immediately following `in` must implement the [`IntoIterator`] trait.
 ///
 /// ## Literal Examples:
 ///
@@ -689,7 +690,7 @@ mod impl_keyword {}
 ///
 /// (Read more about [range patterns])
 ///
-/// [`Iterator`]: ../book/ch13-04-performance.html
+/// [`IntoIterator`]: ../book/ch13-04-performance.html
 /// [range patterns]: ../reference/patterns.html?highlight=range#range-patterns
 /// [`for`]: keyword.for.html
 mod in_keyword {}
@@ -1497,11 +1498,188 @@ mod super_keyword {}
 
 #[doc(keyword = "trait")]
 //
-/// A common interface for a class of types.
+/// A common interface for a group of types.
 ///
-/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+/// A `trait` is like an interface that data types can implement. When a type
+/// implements a trait it can be treated abstractly as that trait using generics
+/// or trait objects.
 ///
-/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+/// Traits can be made up of three varieties of associated items:
+///
+/// - functions and methods
+/// - types
+/// - constants
+///
+/// Traits may also contain additional type parameters. Those type parameters
+/// or the trait itself can be constrained by other traits.
+///
+/// Traits can serve as markers or carry other logical semantics that
+/// aren't expressed through their items. When a type implements that
+/// trait it is promising to uphold its contract. [`Send`] and [`Sync`] are two
+/// such marker traits present in the standard library.
+///
+/// See the [Reference][Ref-Traits] for a lot more information on traits.
+///
+/// # Examples
+///
+/// Traits are declared using the `trait` keyword. Types can implement them
+/// using [`impl`] `Trait` [`for`] `Type`:
+///
+/// ```rust
+/// trait Zero {
+///     const ZERO: Self;
+///     fn is_zero(&self) -> bool;
+/// }
+///
+/// impl Zero for i32 {
+///     const ZERO: Self = 0;
+///
+///     fn is_zero(&self) -> bool {
+///         *self == Self::ZERO
+///     }
+/// }
+///
+/// assert_eq!(i32::ZERO, 0);
+/// assert!(i32::ZERO.is_zero());
+/// assert!(!4.is_zero());
+/// ```
+///
+/// With an associated type:
+///
+/// ```rust
+/// trait Builder {
+///     type Built;
+///
+///     fn build(&self) -> Self::Built;
+/// }
+/// ```
+///
+/// Traits can be generic, with constraints or without:
+///
+/// ```rust
+/// trait MaybeFrom<T> {
+///     fn maybe_from(value: T) -> Option<Self>
+///     where
+///         Self: Sized;
+/// }
+/// ```
+///
+/// Traits can build upon the requirements of other traits. In the example
+/// below `Iterator` is a **supertrait** and `ThreeIterator` is a **subtrait**:
+///
+/// ```rust
+/// trait ThreeIterator: std::iter::Iterator {
+///     fn next_three(&mut self) -> Option<[Self::Item; 3]>;
+/// }
+/// ```
+///
+/// Traits can be used in functions, as parameters:
+///
+/// ```rust
+/// # #![allow(dead_code)]
+/// fn debug_iter<I: Iterator>(it: I) where I::Item: std::fmt::Debug {
+///     for elem in it {
+///         println!("{:#?}", elem);
+///     }
+/// }
+///
+/// // u8_len_1, u8_len_2 and u8_len_3 are equivalent
+///
+/// fn u8_len_1(val: impl Into<Vec<u8>>) -> usize {
+///     val.into().len()
+/// }
+///
+/// fn u8_len_2<T: Into<Vec<u8>>>(val: T) -> usize {
+///     val.into().len()
+/// }
+///
+/// fn u8_len_3<T>(val: T) -> usize
+/// where
+///     T: Into<Vec<u8>>,
+/// {
+///     val.into().len()
+/// }
+/// ```
+///
+/// Or as return types:
+///
+/// ```rust
+/// # #![allow(dead_code)]
+/// fn from_zero_to(v: u8) -> impl Iterator<Item = u8> {
+///     (0..v).into_iter()
+/// }
+/// ```
+///
+/// The use of the [`impl`] keyword in this position allows the function writer
+/// to hide the concrete type as an implementation detail which can change
+/// without breaking user's code.
+///
+/// # Trait objects
+///
+/// A *trait object* is an opaque value of another type that implements a set of
+/// traits. A trait object implements all specified traits as well as their
+/// supertraits (if any).
+///
+/// The syntax is the following: `dyn BaseTrait + AutoTrait1 + ... AutoTraitN`.
+/// Only one `BaseTrait` can be used so this will not compile:
+///
+/// ```rust,compile_fail,E0225
+/// trait A {}
+/// trait B {}
+///
+/// let _: Box<dyn A + B>;
+/// ```
+///
+/// Neither will this, which is a syntax error:
+///
+/// ```rust,compile_fail
+/// trait A {}
+/// trait B {}
+///
+/// let _: Box<dyn A + dyn B>;
+/// ```
+///
+/// On the other hand, this is correct:
+///
+/// ```rust
+/// trait A {}
+///
+/// let _: Box<dyn A + Send + Sync>;
+/// ```
+///
+/// The [Reference][Ref-Trait-Objects] has more information about trait objects,
+/// their limitations and the differences between editions.
+///
+/// # Unsafe traits
+///
+/// Some traits may be unsafe to implement. Using the [`unsafe`] keyword in
+/// front of the trait's declaration is used to mark this:
+///
+/// ```rust
+/// unsafe trait UnsafeTrait {}
+///
+/// unsafe impl UnsafeTrait for i32 {}
+/// ```
+///
+/// # Differences between the 2015 and 2018 editions
+///
+/// In the 2015 edition parameters pattern where not needed for traits:
+///
+/// ```rust,edition2015
+/// trait Tr {
+///     fn f(i32);
+/// }
+/// ```
+///
+/// This behavior is no longer valid in edition 2018.
+///
+/// [`for`]: keyword.for.html
+/// [`impl`]: keyword.impl.html
+/// [`unsafe`]: keyword.unsafe.html
+/// [`Send`]: marker/trait.Send.html
+/// [`Sync`]: marker/trait.Sync.html
+/// [Ref-Traits]: ../reference/items/traits.html
+/// [Ref-Trait-Objects]: ../reference/types/trait-object.html
 mod trait_keyword {}
 
 #[doc(keyword = "true")]
index be8d9f7a7c9cd2d914c444bc33c62f184b5b4a21..00f2fff94c9a16928b34e188bad85b7cf27bfcb7 100644 (file)
     all(target_vendor = "fortanix", target_env = "sgx"),
     feature(slice_index_methods, coerce_unsized, sgx_platform, ptr_wrapping_offset_from)
 )]
-#![cfg_attr(
-    all(test, target_vendor = "fortanix", target_env = "sgx"),
-    feature(fixed_size_array, maybe_uninit_extra)
-)]
+#![cfg_attr(all(test, target_vendor = "fortanix", target_env = "sgx"), feature(fixed_size_array))]
 // std is implemented with unstable features, many of which are internal
 // compiler details that will never be stable
 // NB: the following list is sorted to minimize merge conflicts.
 #![feature(ptr_internals)]
 #![feature(raw)]
 #![feature(raw_ref_macros)]
+#![feature(ready_macro)]
 #![feature(renamed_spin_loop)]
 #![feature(rustc_attrs)]
 #![feature(rustc_private)]
index d22b44a06666295787ed0a614c5418b35ad51ecb..657737394ab82fe5feb1f29a57f2402cf1a2495c 100644 (file)
@@ -285,7 +285,7 @@ pub trait MetadataExt {
     /// ```
     #[stable(feature = "metadata_ext2", since = "1.8.0")]
     fn st_ctime_nsec(&self) -> i64;
-    /// Returns the "preferred" blocksize for efficient filesystem I/O.
+    /// Returns the "preferred" block size for efficient filesystem I/O.
     ///
     /// # Examples
     ///
index 6c87df534bdc683c929cbddc584a361bb7b95717..61b5bff380518674c4341fc74f121ea7a5381142 100644 (file)
@@ -289,7 +289,7 @@ pub trait MetadataExt {
     /// ```
     #[stable(feature = "metadata_ext2", since = "1.8.0")]
     fn st_ctime_nsec(&self) -> i64;
-    /// Returns the "preferred" blocksize for efficient filesystem I/O.
+    /// Returns the "preferred" block size for efficient filesystem I/O.
     ///
     /// # Examples
     ///
index f14a9ff72f62f473ef8437ed5c63650cbab30785..392c815ef2803a5002d03564d49e5f330c55e884 100644 (file)
@@ -2244,6 +2244,9 @@ fn _with_file_name(&self, file_name: &OsStr) -> PathBuf {
     ///
     /// let path = Path::new("foo.rs");
     /// assert_eq!(path.with_extension("txt"), PathBuf::from("foo.txt"));
+    ///
+    /// let path = Path::new("foo.tar.gz");
+    /// assert_eq!(path.with_extension(""), PathBuf::from("foo.tar"));
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn with_extension<S: AsRef<OsStr>>(&self, extension: S) -> PathBuf {
index 90158030c7fbe19c8a6c00f8d2e367fb8bc6fa45..e5dc5b5adaa934a0ed34de571c425e2e231275da 100644 (file)
@@ -19,7 +19,7 @@ pub fn raw(&self) -> Fd {
         self.fd
     }
 
-    /// Extracts the actual filedescriptor without closing it.
+    /// Extracts the actual file descriptor without closing it.
     pub fn into_raw(self) -> Fd {
         let fd = self.fd;
         mem::forget(self);
index 2b2bbc6e9d6ae473a24ca68f6b2676fa0428fffa..f174a59b49a6ba51b01a1bc50f720ee2a6e4dd37 100644 (file)
@@ -624,7 +624,7 @@ pub trait MetadataExt {
     /// ```
     #[stable(feature = "metadata_ext", since = "1.1.0")]
     fn ctime_nsec(&self) -> i64;
-    /// Returns the blocksize for filesystem I/O.
+    /// Returns the block size for filesystem I/O.
     ///
     /// # Examples
     ///
@@ -635,7 +635,7 @@ pub trait MetadataExt {
     ///
     /// fn main() -> io::Result<()> {
     ///     let meta = fs::metadata("some_file")?;
-    ///     let blocksize = meta.blksize();
+    ///     let block_size = meta.blksize();
     ///     Ok(())
     /// }
     /// ```
index c481ca8961f86192a3629e4660690bff33b141e9..84c4d662161bca7fac8a938c71e5799618787e10 100644 (file)
@@ -3,28 +3,28 @@
 use crate::cmp;
 use crate::io::{self, Initializer, IoSlice, IoSliceMut, Read};
 use crate::mem;
-use crate::sync::atomic::{AtomicBool, Ordering};
 use crate::sys::cvt;
 use crate::sys_common::AsInner;
 
-use libc::{c_int, c_void, ssize_t};
+use libc::{c_int, c_void};
 
 #[derive(Debug)]
 pub struct FileDesc {
     fd: c_int,
 }
 
-fn max_len() -> usize {
-    // The maximum read limit on most posix-like systems is `SSIZE_MAX`,
-    // with the man page quoting that if the count of bytes to read is
-    // greater than `SSIZE_MAX` the result is "unspecified".
-    //
-    // On macOS, however, apparently the 64-bit libc is either buggy or
-    // intentionally showing odd behavior by rejecting any read with a size
-    // larger than or equal to INT_MAX. To handle both of these the read
-    // size is capped on both platforms.
-    if cfg!(target_os = "macos") { <c_int>::MAX as usize - 1 } else { <ssize_t>::MAX as usize }
-}
+// The maximum read limit on most POSIX-like systems is `SSIZE_MAX`,
+// with the man page quoting that if the count of bytes to read is
+// greater than `SSIZE_MAX` the result is "unspecified".
+//
+// On macOS, however, apparently the 64-bit libc is either buggy or
+// intentionally showing odd behavior by rejecting any read with a size
+// larger than or equal to INT_MAX. To handle both of these the read
+// size is capped on both platforms.
+#[cfg(target_os = "macos")]
+const READ_LIMIT: usize = c_int::MAX as usize - 1;
+#[cfg(not(target_os = "macos"))]
+const READ_LIMIT: usize = libc::ssize_t::MAX as usize;
 
 impl FileDesc {
     pub fn new(fd: c_int) -> FileDesc {
@@ -44,7 +44,7 @@ pub fn into_raw(self) -> c_int {
 
     pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
         let ret = cvt(unsafe {
-            libc::read(self.fd, buf.as_mut_ptr() as *mut c_void, cmp::min(buf.len(), max_len()))
+            libc::read(self.fd, buf.as_mut_ptr() as *mut c_void, cmp::min(buf.len(), READ_LIMIT))
         })?;
         Ok(ret as usize)
     }
@@ -92,7 +92,7 @@ unsafe fn cvt_pread64(
             cvt_pread64(
                 self.fd,
                 buf.as_mut_ptr() as *mut c_void,
-                cmp::min(buf.len(), max_len()),
+                cmp::min(buf.len(), READ_LIMIT),
                 offset as i64,
             )
             .map(|n| n as usize)
@@ -101,7 +101,7 @@ unsafe fn cvt_pread64(
 
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
         let ret = cvt(unsafe {
-            libc::write(self.fd, buf.as_ptr() as *const c_void, cmp::min(buf.len(), max_len()))
+            libc::write(self.fd, buf.as_ptr() as *const c_void, cmp::min(buf.len(), READ_LIMIT))
         })?;
         Ok(ret as usize)
     }
@@ -144,7 +144,7 @@ unsafe fn cvt_pwrite64(
             cvt_pwrite64(
                 self.fd,
                 buf.as_ptr() as *const c_void,
-                cmp::min(buf.len(), max_len()),
+                cmp::min(buf.len(), READ_LIMIT),
                 offset as i64,
             )
             .map(|n| n as usize)
@@ -223,50 +223,9 @@ pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
     pub fn duplicate(&self) -> io::Result<FileDesc> {
         // We want to atomically duplicate this file descriptor and set the
         // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This
-        // flag, however, isn't supported on older Linux kernels (earlier than
-        // 2.6.24).
-        //
-        // To detect this and ensure that CLOEXEC is still set, we
-        // follow a strategy similar to musl [1] where if passing
-        // F_DUPFD_CLOEXEC causes `fcntl` to return EINVAL it means it's not
-        // supported (the third parameter, 0, is always valid), so we stop
-        // trying that.
-        //
-        // Also note that Android doesn't have F_DUPFD_CLOEXEC, but get it to
-        // resolve so we at least compile this.
-        //
-        // [1]: http://comments.gmane.org/gmane.linux.lib.musl.general/2963
-        #[cfg(any(target_os = "android", target_os = "haiku"))]
-        use libc::F_DUPFD as F_DUPFD_CLOEXEC;
-        #[cfg(not(any(target_os = "android", target_os = "haiku")))]
-        use libc::F_DUPFD_CLOEXEC;
-
-        let make_filedesc = |fd| {
-            let fd = FileDesc::new(fd);
-            fd.set_cloexec()?;
-            Ok(fd)
-        };
-        static TRY_CLOEXEC: AtomicBool = AtomicBool::new(!cfg!(target_os = "android"));
-        let fd = self.raw();
-        if TRY_CLOEXEC.load(Ordering::Relaxed) {
-            match cvt(unsafe { libc::fcntl(fd, F_DUPFD_CLOEXEC, 0) }) {
-                // We *still* call the `set_cloexec` method as apparently some
-                // linux kernel at some point stopped setting CLOEXEC even
-                // though it reported doing so on F_DUPFD_CLOEXEC.
-                Ok(fd) => {
-                    return Ok(if cfg!(target_os = "linux") {
-                        make_filedesc(fd)?
-                    } else {
-                        FileDesc::new(fd)
-                    });
-                }
-                Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {
-                    TRY_CLOEXEC.store(false, Ordering::Relaxed);
-                }
-                Err(e) => return Err(e),
-            }
-        }
-        cvt(unsafe { libc::fcntl(fd, libc::F_DUPFD, 0) }).and_then(make_filedesc)
+        // is a POSIX flag that was added to Linux in 2.6.24.
+        let fd = cvt(unsafe { libc::fcntl(self.raw(), libc::F_DUPFD_CLOEXEC, 0) })?;
+        Ok(FileDesc::new(fd))
     }
 }
 
index 29cdbf05354fbe353ba382332c54d8f927bb20a1..acb18e6d064e6e826d0e3910035e12fd516f1e98 100644 (file)
@@ -708,56 +708,7 @@ pub fn open_c(path: &CStr, opts: &OpenOptions) -> io::Result<File> {
         // However, since this is a variadic function, C integer promotion rules mean that on
         // the ABI level, this still gets passed as `c_int` (aka `u32` on Unix platforms).
         let fd = cvt_r(|| unsafe { open64(path.as_ptr(), flags, opts.mode as c_int) })?;
-        let fd = FileDesc::new(fd);
-
-        // Currently the standard library supports Linux 2.6.18 which did not
-        // have the O_CLOEXEC flag (passed above). If we're running on an older
-        // Linux kernel then the flag is just ignored by the OS. After we open
-        // the first file, we check whether it has CLOEXEC set. If it doesn't,
-        // we will explicitly ask for a CLOEXEC fd for every further file we
-        // open, if it does, we will skip that step.
-        //
-        // The CLOEXEC flag, however, is supported on versions of macOS/BSD/etc
-        // that we support, so we only do this on Linux currently.
-        #[cfg(target_os = "linux")]
-        fn ensure_cloexec(fd: &FileDesc) -> io::Result<()> {
-            use crate::sync::atomic::{AtomicUsize, Ordering};
-
-            const OPEN_CLOEXEC_UNKNOWN: usize = 0;
-            const OPEN_CLOEXEC_SUPPORTED: usize = 1;
-            const OPEN_CLOEXEC_NOTSUPPORTED: usize = 2;
-            static OPEN_CLOEXEC: AtomicUsize = AtomicUsize::new(OPEN_CLOEXEC_UNKNOWN);
-
-            let need_to_set;
-            match OPEN_CLOEXEC.load(Ordering::Relaxed) {
-                OPEN_CLOEXEC_UNKNOWN => {
-                    need_to_set = !fd.get_cloexec()?;
-                    OPEN_CLOEXEC.store(
-                        if need_to_set {
-                            OPEN_CLOEXEC_NOTSUPPORTED
-                        } else {
-                            OPEN_CLOEXEC_SUPPORTED
-                        },
-                        Ordering::Relaxed,
-                    );
-                }
-                OPEN_CLOEXEC_SUPPORTED => need_to_set = false,
-                OPEN_CLOEXEC_NOTSUPPORTED => need_to_set = true,
-                _ => unreachable!(),
-            }
-            if need_to_set {
-                fd.set_cloexec()?;
-            }
-            Ok(())
-        }
-
-        #[cfg(not(target_os = "linux"))]
-        fn ensure_cloexec(_: &FileDesc) -> io::Result<()> {
-            Ok(())
-        }
-
-        ensure_cloexec(&fd)?;
-        Ok(File(fd))
+        Ok(File(FileDesc::new(fd)))
     }
 
     pub fn file_attr(&self) -> io::Result<FileAttr> {
index 3717c660b575d6f1c9e2d353be65fdfa6be3212f..011325fddc5b93b08304406256bcc748d7e8e3eb 100644 (file)
@@ -54,31 +54,26 @@ pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result<Socket> {
 
     pub fn new_raw(fam: c_int, ty: c_int) -> io::Result<Socket> {
         unsafe {
-            // On linux we first attempt to pass the SOCK_CLOEXEC flag to
-            // atomically create the socket and set it as CLOEXEC. Support for
-            // this option, however, was added in 2.6.27, and we still support
-            // 2.6.18 as a kernel, so if the returned error is EINVAL we
-            // fallthrough to the fallback.
-            #[cfg(target_os = "linux")]
-            {
-                match cvt(libc::socket(fam, ty | libc::SOCK_CLOEXEC, 0)) {
-                    Ok(fd) => return Ok(Socket(FileDesc::new(fd))),
-                    Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {}
-                    Err(e) => return Err(e),
-                }
-            }
-
-            let fd = cvt(libc::socket(fam, ty, 0))?;
-            let fd = FileDesc::new(fd);
-            fd.set_cloexec()?;
-            let socket = Socket(fd);
+            cfg_if::cfg_if! {
+                if #[cfg(target_os = "linux")] {
+                    // On Linux we pass the SOCK_CLOEXEC flag to atomically create
+                    // the socket and set it as CLOEXEC, added in 2.6.27.
+                    let fd = cvt(libc::socket(fam, ty | libc::SOCK_CLOEXEC, 0))?;
+                    Ok(Socket(FileDesc::new(fd)))
+                } else {
+                    let fd = cvt(libc::socket(fam, ty, 0))?;
+                    let fd = FileDesc::new(fd);
+                    fd.set_cloexec()?;
+                    let socket = Socket(fd);
 
-            // macOS and iOS use `SO_NOSIGPIPE` as a `setsockopt`
-            // flag to disable `SIGPIPE` emission on socket.
-            #[cfg(target_vendor = "apple")]
-            setsockopt(&socket, libc::SOL_SOCKET, libc::SO_NOSIGPIPE, 1)?;
+                    // macOS and iOS use `SO_NOSIGPIPE` as a `setsockopt`
+                    // flag to disable `SIGPIPE` emission on socket.
+                    #[cfg(target_vendor = "apple")]
+                    setsockopt(&socket, libc::SOL_SOCKET, libc::SO_NOSIGPIPE, 1)?;
 
-            Ok(socket)
+                    Ok(socket)
+                }
+            }
         }
     }
 
@@ -86,24 +81,20 @@ pub fn new_pair(fam: c_int, ty: c_int) -> io::Result<(Socket, Socket)> {
         unsafe {
             let mut fds = [0, 0];
 
-            // Like above, see if we can set cloexec atomically
-            #[cfg(target_os = "linux")]
-            {
-                match cvt(libc::socketpair(fam, ty | libc::SOCK_CLOEXEC, 0, fds.as_mut_ptr())) {
-                    Ok(_) => {
-                        return Ok((Socket(FileDesc::new(fds[0])), Socket(FileDesc::new(fds[1]))));
-                    }
-                    Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {}
-                    Err(e) => return Err(e),
+            cfg_if::cfg_if! {
+                if #[cfg(target_os = "linux")] {
+                    // Like above, set cloexec atomically
+                    cvt(libc::socketpair(fam, ty | libc::SOCK_CLOEXEC, 0, fds.as_mut_ptr()))?;
+                    Ok((Socket(FileDesc::new(fds[0])), Socket(FileDesc::new(fds[1]))))
+                } else {
+                    cvt(libc::socketpair(fam, ty, 0, fds.as_mut_ptr()))?;
+                    let a = FileDesc::new(fds[0]);
+                    let b = FileDesc::new(fds[1]);
+                    a.set_cloexec()?;
+                    b.set_cloexec()?;
+                    Ok((Socket(a), Socket(b)))
                 }
             }
-
-            cvt(libc::socketpair(fam, ty, 0, fds.as_mut_ptr()))?;
-            let a = FileDesc::new(fds[0]);
-            let b = FileDesc::new(fds[1]);
-            a.set_cloexec()?;
-            b.set_cloexec()?;
-            Ok((Socket(a), Socket(b)))
         }
     }
 
@@ -177,30 +168,20 @@ pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Resul
     pub fn accept(&self, storage: *mut sockaddr, len: *mut socklen_t) -> io::Result<Socket> {
         // Unfortunately the only known way right now to accept a socket and
         // atomically set the CLOEXEC flag is to use the `accept4` syscall on
-        // Linux. This was added in 2.6.28, however, and because we support
-        // 2.6.18 we must detect this support dynamically.
-        #[cfg(target_os = "linux")]
-        {
-            syscall! {
-                fn accept4(
-                    fd: c_int,
-                    addr: *mut sockaddr,
-                    addr_len: *mut socklen_t,
-                    flags: c_int
-                ) -> c_int
-            }
-            let res = cvt_r(|| unsafe { accept4(self.0.raw(), storage, len, libc::SOCK_CLOEXEC) });
-            match res {
-                Ok(fd) => return Ok(Socket(FileDesc::new(fd))),
-                Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => {}
-                Err(e) => return Err(e),
+        // Linux. This was added in 2.6.28, glibc 2.10 and musl 0.9.5.
+        cfg_if::cfg_if! {
+            if #[cfg(target_os = "linux")] {
+                let fd = cvt_r(|| unsafe {
+                    libc::accept4(self.0.raw(), storage, len, libc::SOCK_CLOEXEC)
+                })?;
+                Ok(Socket(FileDesc::new(fd)))
+            } else {
+                let fd = cvt_r(|| unsafe { libc::accept(self.0.raw(), storage, len) })?;
+                let fd = FileDesc::new(fd);
+                fd.set_cloexec()?;
+                Ok(Socket(fd))
             }
         }
-
-        let fd = cvt_r(|| unsafe { libc::accept(self.0.raw(), storage, len) })?;
-        let fd = FileDesc::new(fd);
-        fd.set_cloexec()?;
-        Ok(Socket(fd))
     }
 
     pub fn duplicate(&self) -> io::Result<Socket> {
index a9cd5094997bd68b9e2ae6e675f0bcb61862777d..2fcb5b9c4e66e722098efde38810b1ab60389582 100644 (file)
@@ -71,6 +71,7 @@ pub fn errno() -> i32 {
 
 /// Sets the platform-specific value of errno
 #[cfg(all(not(target_os = "linux"), not(target_os = "dragonfly")))] // needed for readdir and syscall!
+#[allow(dead_code)] // but not all target cfgs actually end up using it
 pub fn set_errno(e: i32) {
     unsafe { *errno_location() = e as c_int }
 }
index f2a2eabef9132509db4c864a40ba769b0974fb0f..7ae37bdda70bded963b72d304b7abbbbfed904a9 100644 (file)
@@ -1,11 +1,8 @@
 use crate::io::{self, IoSlice, IoSliceMut};
 use crate::mem;
-use crate::sync::atomic::{AtomicBool, Ordering};
 use crate::sys::fd::FileDesc;
 use crate::sys::{cvt, cvt_r};
 
-use libc::c_int;
-
 ////////////////////////////////////////////////////////////////////////////////
 // Anonymous pipes
 ////////////////////////////////////////////////////////////////////////////////
 pub struct AnonPipe(FileDesc);
 
 pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
-    syscall! { fn pipe2(fds: *mut c_int, flags: c_int) -> c_int }
-    static INVALID: AtomicBool = AtomicBool::new(false);
-
     let mut fds = [0; 2];
 
-    // Unfortunately the only known way right now to create atomically set the
-    // CLOEXEC flag is to use the `pipe2` syscall on Linux. This was added in
-    // 2.6.27, however, and because we support 2.6.18 we must detect this
-    // support dynamically.
-    if cfg!(any(
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "linux",
-        target_os = "netbsd",
-        target_os = "openbsd",
-        target_os = "redox"
-    )) && !INVALID.load(Ordering::SeqCst)
-    {
-        // Note that despite calling a glibc function here we may still
-        // get ENOSYS. Glibc has `pipe2` since 2.9 and doesn't try to
-        // emulate on older kernels, so if you happen to be running on
-        // an older kernel you may see `pipe2` as a symbol but still not
-        // see the syscall.
-        match cvt(unsafe { pipe2(fds.as_mut_ptr(), libc::O_CLOEXEC) }) {
-            Ok(_) => {
-                return Ok((AnonPipe(FileDesc::new(fds[0])), AnonPipe(FileDesc::new(fds[1]))));
-            }
-            Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => {
-                INVALID.store(true, Ordering::SeqCst);
-            }
-            Err(e) => return Err(e),
+    // The only known way right now to create atomically set the CLOEXEC flag is
+    // to use the `pipe2` syscall. This was added to Linux in 2.6.27, glibc 2.9
+    // and musl 0.9.3, and some other targets also have it.
+    cfg_if::cfg_if! {
+        if #[cfg(any(
+            target_os = "dragonfly",
+            target_os = "freebsd",
+            target_os = "linux",
+            target_os = "netbsd",
+            target_os = "openbsd",
+            target_os = "redox"
+        ))] {
+            cvt(unsafe { libc::pipe2(fds.as_mut_ptr(), libc::O_CLOEXEC) })?;
+            Ok((AnonPipe(FileDesc::new(fds[0])), AnonPipe(FileDesc::new(fds[1]))))
+        } else {
+            cvt(unsafe { libc::pipe(fds.as_mut_ptr()) })?;
+
+            let fd0 = FileDesc::new(fds[0]);
+            let fd1 = FileDesc::new(fds[1]);
+            fd0.set_cloexec()?;
+            fd1.set_cloexec()?;
+            Ok((AnonPipe(fd0), AnonPipe(fd1)))
         }
     }
-    cvt(unsafe { libc::pipe(fds.as_mut_ptr()) })?;
-
-    let fd0 = FileDesc::new(fds[0]);
-    let fd1 = FileDesc::new(fds[1]);
-    fd0.set_cloexec()?;
-    fd1.set_cloexec()?;
-    Ok((AnonPipe(fd0), AnonPipe(fd1)))
 }
 
 impl AnonPipe {
index 371291b9f76ab0a529bbaaab35646ed66f2febe3..0f349dfa3021611fdb3513aa9b87b2fd9f912bd1 100644 (file)
@@ -84,12 +84,12 @@ pub fn spawn(
                 Ok(0) => return Ok((p, ours)),
                 Ok(8) => {
                     let (errno, footer) = bytes.split_at(4);
-                    assert!(
-                        combine(CLOEXEC_MSG_FOOTER) == combine(footer.try_into().unwrap()),
+                    assert_eq!(
+                        CLOEXEC_MSG_FOOTER, footer,
                         "Validation on the CLOEXEC pipe failed: {:?}",
                         bytes
                     );
-                    let errno = combine(errno.try_into().unwrap());
+                    let errno = i32::from_be_bytes(errno.try_into().unwrap());
                     assert!(p.wait().is_ok(), "wait() should either return Ok or panic");
                     return Err(Error::from_raw_os_error(errno));
                 }
@@ -105,10 +105,6 @@ pub fn spawn(
                 }
             }
         }
-
-        fn combine(arr: [u8; 4]) -> i32 {
-            i32::from_be_bytes(arr)
-        }
     }
 
     pub fn exec(&mut self, default: Stdio) -> io::Error {
index 08cbe59617465731a22fdc228c84b9d5ce7e9733..f4b33a00f7c85d79d8b682be0884024283a529f0 100644 (file)
 //! symbol, but that caused Debian to detect an unnecessarily strict versioned
 //! dependency on libc6 (#23628).
 
+// There are a variety of `#[cfg]`s controlling which targets are involved in
+// each instance of `weak!` and `syscall!`. Rather than trying to unify all of
+// that, we'll just allow that some unix targets don't use this module at all.
+#![allow(dead_code, unused_macros)]
+
 use crate::ffi::CStr;
 use crate::marker;
 use crate::mem;
index 7fa86f0db043f21bc2be1efa9a6c719aba73327d..ea186846929be135479736277e31ece1035b4960 100644 (file)
@@ -13,12 +13,10 @@ pub struct FileDesc {
     fd: c_int,
 }
 
-fn max_len() -> usize {
-    // The maximum read limit on most posix-like systems is `SSIZE_MAX`,
-    // with the man page quoting that if the count of bytes to read is
-    // greater than `SSIZE_MAX` the result is "unspecified".
-    <ssize_t>::MAX as usize
-}
+// The maximum read limit on most POSIX-like systems is `SSIZE_MAX`,
+// with the man page quoting that if the count of bytes to read is
+// greater than `SSIZE_MAX` the result is "unspecified".
+const READ_LIMIT: usize = ssize_t::MAX as usize;
 
 impl FileDesc {
     pub fn new(fd: c_int) -> FileDesc {
@@ -29,7 +27,7 @@ pub fn raw(&self) -> c_int {
         self.fd
     }
 
-    /// Extracts the actual filedescriptor without closing it.
+    /// Extracts the actual file descriptor without closing it.
     pub fn into_raw(self) -> c_int {
         let fd = self.fd;
         mem::forget(self);
@@ -38,7 +36,7 @@ pub fn into_raw(self) -> c_int {
 
     pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
         let ret = cvt(unsafe {
-            libc::read(self.fd, buf.as_mut_ptr() as *mut c_void, cmp::min(buf.len(), max_len()))
+            libc::read(self.fd, buf.as_mut_ptr() as *mut c_void, cmp::min(buf.len(), READ_LIMIT))
         })?;
         Ok(ret as usize)
     }
@@ -79,7 +77,7 @@ unsafe fn cvt_pread(
             cvt_pread(
                 self.fd,
                 buf.as_mut_ptr() as *mut c_void,
-                cmp::min(buf.len(), max_len()),
+                cmp::min(buf.len(), READ_LIMIT),
                 offset as i64,
             )
             .map(|n| n as usize)
@@ -88,7 +86,7 @@ unsafe fn cvt_pread(
 
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
         let ret = cvt(unsafe {
-            libc::write(self.fd, buf.as_ptr() as *const c_void, cmp::min(buf.len(), max_len()))
+            libc::write(self.fd, buf.as_ptr() as *const c_void, cmp::min(buf.len(), READ_LIMIT))
         })?;
         Ok(ret as usize)
     }
@@ -124,7 +122,7 @@ unsafe fn cvt_pwrite(
             cvt_pwrite(
                 self.fd,
                 buf.as_ptr() as *const c_void,
-                cmp::min(buf.len(), max_len()),
+                cmp::min(buf.len(), READ_LIMIT),
                 offset as i64,
             )
             .map(|n| n as usize)
index 8365c9ee9c995dbdd70c045e30fb573dac424eeb..8f46f4d284f0bf71ad499c3457da75c9faac5a55 100644 (file)
@@ -1,6 +1,6 @@
 use crate::cmp::Ordering;
 use crate::time::Duration;
-use ::core::hash::{Hash, Hasher};
+use core::hash::{Hash, Hasher};
 
 pub use self::inner::{Instant, SystemTime, UNIX_EPOCH};
 use crate::convert::TryInto;
index 5f8b1cbfa0b5314a37a4355318a52996a84ad344..58c8c46c969c180cf38f46107908de10445f577f 100644 (file)
@@ -18,5 +18,5 @@ pub mod prelude {
     pub use crate::sys::ext::fs::{DirEntryExt, FileExt, MetadataExt, OpenOptionsExt};
     #[doc(no_inline)]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub use crate::sys::ext::io::{AsRawFd, FromRawFd, IntoRawFd};
+    pub use crate::sys::ext::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
 }
index 793daea43c215baf07149e2157d73781a7102634..2eed9e436a956003a200a6af668024da9b786f0c 100644 (file)
@@ -597,14 +597,14 @@ fn open_at(fd: &WasiFd, path: &Path, opts: &OpenOptions) -> io::Result<File> {
 ///
 /// WASI has no fundamental capability to do this. All syscalls and operations
 /// are relative to already-open file descriptors. The C library, however,
-/// manages a map of preopened file descriptors to their path, and then the C
+/// manages a map of pre-opened file descriptors to their path, and then the C
 /// library provides an API to look at this. In other words, when you want to
 /// open a path `p`, you have to find a previously opened file descriptor in a
 /// global table and then see if `p` is relative to that file descriptor.
 ///
 /// This function, if successful, will return two items:
 ///
-/// * The first is a `ManuallyDrop<WasiFd>`. This represents a preopened file
+/// * The first is a `ManuallyDrop<WasiFd>`. This represents a pre-opened file
 ///   descriptor which we don't have ownership of, but we can use. You shouldn't
 ///   actually drop the `fd`.
 ///
@@ -619,7 +619,7 @@ fn open_at(fd: &WasiFd, path: &Path, opts: &OpenOptions) -> io::Result<File> {
 /// appropriate rights for performing `rights` actions.
 ///
 /// Note that this can fail if `p` doesn't look like it can be opened relative
-/// to any preopened file descriptor.
+/// to any pre-opened file descriptor.
 fn open_parent(p: &Path) -> io::Result<(ManuallyDrop<WasiFd>, PathBuf)> {
     let p = CString::new(p.as_os_str().as_bytes())?;
     unsafe {
@@ -627,7 +627,7 @@ fn open_parent(p: &Path) -> io::Result<(ManuallyDrop<WasiFd>, PathBuf)> {
         let fd = __wasilibc_find_relpath(p.as_ptr(), &mut ret);
         if fd == -1 {
             let msg = format!(
-                "failed to find a preopened file descriptor \
+                "failed to find a pre-opened file descriptor \
                  through which {:?} could be opened",
                 p
             );
index 77bcfffd506c93a6913f1f0fea7390a435793814..b6baa9a8c6bcc71b77d42e3ffe1cf2fef45ab7bd 100644 (file)
@@ -2,7 +2,6 @@
 authors = ["The Rust Project Developers"]
 name = "unwind"
 version = "0.0.0"
-build = "build.rs"
 edition = "2018"
 include = [
   '/libunwind/*',
diff --git a/src/rustllvm/CoverageMappingWrapper.cpp b/src/rustllvm/CoverageMappingWrapper.cpp
new file mode 100644 (file)
index 0000000..c6c4cdb
--- /dev/null
@@ -0,0 +1,115 @@
+#include "rustllvm.h"
+#include "llvm/ProfileData/Coverage/CoverageMapping.h"
+#include "llvm/ProfileData/Coverage/CoverageMappingWriter.h"
+#include "llvm/ProfileData/InstrProf.h"
+#include "llvm/ADT/ArrayRef.h"
+
+#include <iostream>
+
+using namespace llvm;
+
+extern "C" SmallVectorTemplateBase<coverage::CounterExpression>
+    *LLVMRustCoverageSmallVectorCounterExpressionCreate() {
+  return new SmallVector<coverage::CounterExpression, 32>();
+}
+
+extern "C" void LLVMRustCoverageSmallVectorCounterExpressionDispose(
+    SmallVectorTemplateBase<coverage::CounterExpression> *Vector) {
+  delete Vector;
+}
+
+extern "C" void LLVMRustCoverageSmallVectorCounterExpressionAdd(
+    SmallVectorTemplateBase<coverage::CounterExpression> *Expressions,
+    coverage::CounterExpression::ExprKind Kind,
+    unsigned LeftIndex,
+    unsigned RightIndex) {
+  auto LHS = coverage::Counter::getCounter(LeftIndex);
+  auto RHS = coverage::Counter::getCounter(RightIndex);
+  Expressions->push_back(coverage::CounterExpression { Kind, LHS, RHS });
+}
+
+extern "C" SmallVectorTemplateBase<coverage::CounterMappingRegion>
+    *LLVMRustCoverageSmallVectorCounterMappingRegionCreate() {
+  return new SmallVector<coverage::CounterMappingRegion, 32>();
+}
+
+extern "C" void LLVMRustCoverageSmallVectorCounterMappingRegionDispose(
+    SmallVectorTemplateBase<coverage::CounterMappingRegion> *Vector) {
+  delete Vector;
+}
+
+extern "C" void LLVMRustCoverageSmallVectorCounterMappingRegionAdd(
+    SmallVectorTemplateBase<coverage::CounterMappingRegion> *MappingRegions,
+    unsigned Index,
+    unsigned FileID,
+    unsigned LineStart,
+    unsigned ColumnStart,
+    unsigned LineEnd,
+    unsigned ColumnEnd) {
+  auto Counter = coverage::Counter::getCounter(Index);
+  MappingRegions->push_back(coverage::CounterMappingRegion::makeRegion(
+           Counter, FileID, LineStart,
+           ColumnStart, LineEnd, ColumnEnd));
+
+  // FIXME(richkadel): As applicable, implement additional CounterMappingRegion types using the
+  // static method alternatives to `coverage::CounterMappingRegion::makeRegion`:
+  //
+  //   makeExpansion(unsigned FileID, unsigned ExpandedFileID, unsigned LineStart,
+  //                 unsigned ColumnStart, unsigned LineEnd, unsigned ColumnEnd) {
+  //   makeSkipped(unsigned FileID, unsigned LineStart, unsigned ColumnStart,
+  //               unsigned LineEnd, unsigned ColumnEnd) {
+  //   makeGapRegion(Counter Count, unsigned FileID, unsigned LineStart,
+  //                 unsigned ColumnStart, unsigned LineEnd, unsigned ColumnEnd) {
+}
+
+extern "C" void LLVMRustCoverageWriteFilenamesSectionToBuffer(
+    const char* const Filenames[],
+    size_t FilenamesLen,
+    RustStringRef BufferOut) {
+  SmallVector<StringRef,32> FilenameRefs;
+  for (size_t i = 0; i < FilenamesLen; i++) {
+    FilenameRefs.push_back(StringRef(Filenames[i]));
+  }
+  auto FilenamesWriter = coverage::CoverageFilenamesSectionWriter(
+    makeArrayRef(FilenameRefs));
+  RawRustStringOstream OS(BufferOut);
+  FilenamesWriter.write(OS);
+}
+
+extern "C" void LLVMRustCoverageWriteMappingToBuffer(
+    const unsigned *VirtualFileMappingIDs,
+    unsigned NumVirtualFileMappingIDs,
+    const SmallVectorImpl<coverage::CounterExpression> *Expressions,
+    SmallVectorImpl<coverage::CounterMappingRegion> *MappingRegions,
+    RustStringRef BufferOut) {
+  auto CoverageMappingWriter = coverage::CoverageMappingWriter(
+    makeArrayRef(VirtualFileMappingIDs, NumVirtualFileMappingIDs),
+    makeArrayRef(*Expressions),
+    MutableArrayRef<coverage::CounterMappingRegion> { *MappingRegions });
+  RawRustStringOstream OS(BufferOut);
+  CoverageMappingWriter.write(OS);
+}
+
+extern "C" uint64_t LLVMRustCoverageComputeHash(const char *Name) {
+  StringRef NameRef(Name);
+  return IndexedInstrProf::ComputeHash(NameRef);
+}
+
+extern "C" void LLVMRustCoverageWriteSectionNameToString(LLVMModuleRef M,
+                                                         RustStringRef Str) {
+  Triple TargetTriple(unwrap(M)->getTargetTriple());
+  auto name = getInstrProfSectionName(IPSK_covmap,
+                                      TargetTriple.getObjectFormat());
+  RawRustStringOstream OS(Str);
+  OS << name;
+}
+
+extern "C" void LLVMRustCoverageWriteMappingVarNameToString(RustStringRef Str) {
+  auto name = getCoverageMappingVarName();
+  RawRustStringOstream OS(Str);
+  OS << name;
+}
+
+extern "C" uint32_t LLVMRustCoverageMappingVersion() {
+  return coverage::CovMapVersion::CurrentVersion;
+}
index c92cf65f98af7fc1909f483a118c23c920791a95..667bf4a2ded37e7931df99735435f05eef8cbda0 100644 (file)
@@ -1395,7 +1395,7 @@ extern "C" LLVMValueRef LLVMRustBuildCall(LLVMBuilderRef B, LLVMValueRef Fn,
       FTy, Callee, makeArrayRef(unwrap(Args), NumArgs), Bundles));
 }
 
-extern "C" LLVMValueRef LLVMRustGetInstrprofIncrementIntrinsic(LLVMModuleRef M) {
+extern "C" LLVMValueRef LLVMRustGetInstrProfIncrementIntrinsic(LLVMModuleRef M) {
   return wrap(llvm::Intrinsic::getDeclaration(unwrap(M),
               (llvm::Intrinsic::ID)llvm::Intrinsic::instrprof_increment));
 }
index da48048113bc218f6fb7464e9bd190be589aa1fc..57b8664d3b6058d1050790354cb0a5fc89cc16ca 100644 (file)
@@ -3,6 +3,7 @@
 #include "llvm-c/Object.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/Triple.h"
 #include "llvm/Analysis/Lint.h"
 #include "llvm/Analysis/Passes.h"
index f6005eed43c7d85afba6c4ddef2516fe70206a4b..9d79171c4cb98e120f46390d19bdb128cf48bf88 100644 (file)
@@ -1,4 +1,4 @@
-// compile-flags:-Zprint-mono-items=eager
+// compile-flags:-Zprint-mono-items=eager -Zpolymorphize=on
 
 #![feature(start)]
 
@@ -6,7 +6,7 @@
 
 pub fn foo<T>() { }
 
-//~ MONO_ITEM fn static_init::foo[0]<i32>
+//~ MONO_ITEM fn static_init::foo[0]<T>
 //~ MONO_ITEM static static_init::FN[0]
 
 //~ MONO_ITEM fn static_init::start[0]
index 11f6cc62d49e3c9ee72f3b8c2befb8db8a5297f1..6cf59fdc39694b3488eed5848cc83c90511c5e08 100644 (file)
@@ -1,4 +1,4 @@
-// compile-flags:-Zprint-mono-items=eager
+// compile-flags:-Zprint-mono-items=eager -Zpolymorphize=on
 
 #![deny(dead_code)]
 #![feature(start)]
@@ -27,7 +27,7 @@ impl SomeGenericTrait<u64> for i32 {
 
     // For the non-generic foo(), we should generate a codegen-item even if it
     // is not called anywhere
-    //~ MONO_ITEM fn trait_method_default_impl::SomeGenericTrait[0]::foo[0]<i32, u64>
+    //~ MONO_ITEM fn trait_method_default_impl::SomeGenericTrait[0]::foo[0]<i32, T1>
 }
 
 // Non-generic impl of generic trait
diff --git a/src/test/codegen-units/polymorphization/unused_type_parameters.rs b/src/test/codegen-units/polymorphization/unused_type_parameters.rs
new file mode 100644 (file)
index 0000000..403f68b
--- /dev/null
@@ -0,0 +1,323 @@
+// compile-flags:-Zpolymorphize=on -Zprint-mono-items=lazy -Copt-level=1
+// ignore-tidy-linelength
+
+#![crate_type = "rlib"]
+
+// This test checks that the polymorphization analysis correctly reduces the
+// generated mono items.
+
+mod functions {
+    // Function doesn't have any type parameters to be unused.
+    pub fn no_parameters() {}
+
+//~ MONO_ITEM fn unused_type_parameters::functions[0]::no_parameters[0]
+
+    // Function has an unused type parameter.
+    pub fn unused<T>() {
+    }
+
+//~ MONO_ITEM fn unused_type_parameters::functions[0]::unused[0]<T>
+
+    // Function uses type parameter in value of a binding.
+    pub fn used_binding_value<T: Default>() {
+        let _: T = Default::default();
+    }
+
+//~ MONO_ITEM fn unused_type_parameters::functions[0]::used_binding_value[0]<u32>
+//~ MONO_ITEM fn unused_type_parameters::functions[0]::used_binding_value[0]<u64>
+
+    // Function uses type parameter in type of a binding.
+    pub fn used_binding_type<T>() {
+        let _: Option<T> = None;
+    }
+
+//~ MONO_ITEM fn unused_type_parameters::functions[0]::used_binding_type[0]<u32>
+//~ MONO_ITEM fn unused_type_parameters::functions[0]::used_binding_type[0]<u64>
+
+    // Function uses type parameter in argument.
+    pub fn used_argument<T>(_: T) {
+    }
+
+//~ MONO_ITEM fn unused_type_parameters::functions[0]::used_argument[0]<u32>
+//~ MONO_ITEM fn unused_type_parameters::functions[0]::used_argument[0]<u64>
+//
+    // Function uses type parameter in substitutions to another function.
+    pub fn used_substs<T>() {
+        unused::<T>()
+    }
+
+//~ MONO_ITEM fn unused_type_parameters::functions[0]::used_substs[0]<u32>
+//~ MONO_ITEM fn unused_type_parameters::functions[0]::used_substs[0]<u64>
+}
+
+
+mod closures {
+    // Function doesn't have any type parameters to be unused.
+    pub fn no_parameters() {
+        let _ = || {};
+    }
+
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::no_parameters[0]
+
+    // Function has an unused type parameter in parent and closure.
+    pub fn unused<T>() -> u32 {
+        let add_one = |x: u32| x + 1;
+        add_one(3)
+    }
+
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::unused[0]::{{closure}}[0]<T, i8, extern "rust-call" fn((u32)) -> u32, ()>
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::unused[0]<T>
+
+    // Function has an unused type parameter in closure, but not in parent.
+    pub fn used_parent<T: Default>() -> u32 {
+        let _: T = Default::default();
+        let add_one = |x: u32| x + 1;
+        add_one(3)
+    }
+
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_parent[0]::{{closure}}[0]<T, i8, extern "rust-call" fn((u32)) -> u32, ()>
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_parent[0]<u32>
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_parent[0]<u64>
+
+    // Function uses type parameter in value of a binding in closure.
+    pub fn used_binding_value<T: Default>() -> T {
+        let x = || {
+            let y: T = Default::default();
+            y
+        };
+
+        x()
+    }
+
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_binding_value[0]::{{closure}}[0]<u32, i8, extern "rust-call" fn(()) -> u32, ()>
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_binding_value[0]::{{closure}}[0]<u64, i8, extern "rust-call" fn(()) -> u64, ()>
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_binding_value[0]<u32>
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_binding_value[0]<u64>
+
+    // Function uses type parameter in type of a binding in closure.
+    pub fn used_binding_type<T>() -> Option<T> {
+        let x = || {
+            let y: Option<T> = None;
+            y
+        };
+
+        x()
+    }
+
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_binding_type[0]::{{closure}}[0]<u32, i8, extern "rust-call" fn(()) -> core::option[0]::Option[0]<u32>, ()>
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_binding_type[0]::{{closure}}[0]<u64, i8, extern "rust-call" fn(()) -> core::option[0]::Option[0]<u64>, ()>
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_binding_type[0]<u32>
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_binding_type[0]<u64>
+
+    // Function and closure uses type parameter in argument.
+    pub fn used_argument<T>(t: T) -> u32 {
+        let x = |_: T| 3;
+        x(t)
+    }
+
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_argument[0]::{{closure}}[0]<u32, i8, extern "rust-call" fn((u32)) -> u32, ()>
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_argument[0]::{{closure}}[0]<u64, i8, extern "rust-call" fn((u64)) -> u32, ()>
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_argument[0]<u32>
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_argument[0]<u64>
+
+    // Closure uses type parameter in argument.
+    pub fn used_argument_closure<T: Default>() -> u32 {
+        let t: T = Default::default();
+        let x = |_: T| 3;
+        x(t)
+    }
+
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_argument_closure[0]::{{closure}}[0]<u32, i8, extern "rust-call" fn((u32)) -> u32, ()>
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_argument_closure[0]::{{closure}}[0]<u64, i8, extern "rust-call" fn((u64)) -> u32, ()>
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_argument_closure[0]<u32>
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_argument_closure[0]<u64>
+
+    // Closure uses type parameter as upvar.
+    pub fn used_upvar<T: Default>() -> T {
+        let x: T = Default::default();
+        let y = || x;
+        y()
+    }
+
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_upvar[0]::{{closure}}[0]<u32, i32, extern "rust-call" fn(()) -> u32, (u32)>
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_upvar[0]::{{closure}}[0]<u64, i32, extern "rust-call" fn(()) -> u64, (u64)>
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_upvar[0]<u32>
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_upvar[0]<u64>
+
+    // Closure uses type parameter in substitutions to another function.
+    pub fn used_substs<T>() {
+        let x = || super::functions::unused::<T>();
+        x()
+    }
+
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_substs[0]::{{closure}}[0]<u32, i8, extern "rust-call" fn(()), ()>
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_substs[0]::{{closure}}[0]<u64, i8, extern "rust-call" fn(()), ()>
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_substs[0]<u32>
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_substs[0]<u64>
+}
+
+mod methods {
+    pub struct Foo<F>(F);
+
+    impl<F: Default> Foo<F> {
+        // Function has an unused type parameter from impl.
+        pub fn unused_impl() {
+        }
+
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::unused_impl[0]<F>
+
+        // Function has an unused type parameter from impl and fn.
+        pub fn unused_both<G: Default>() {
+        }
+
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::unused_both[0]<F, G>
+
+        // Function uses type parameter from impl.
+        pub fn used_impl() {
+            let _: F = Default::default();
+        }
+
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::used_impl[0]<u32>
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::used_impl[0]<u64>
+
+        // Function uses type parameter from impl.
+        pub fn used_fn<G: Default>() {
+            let _: G = Default::default();
+        }
+
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::used_fn[0]<F, u32>
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::used_fn[0]<F, u64>
+
+        // Function uses type parameter from impl.
+        pub fn used_both<G: Default>() {
+            let _: F = Default::default();
+            let _: G = Default::default();
+        }
+
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::used_both[0]<u32, u32>
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::used_both[0]<u64, u64>
+
+        // Function uses type parameter in substitutions to another function.
+        pub fn used_substs() {
+            super::functions::unused::<F>()
+        }
+
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::used_substs[0]<u32>
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::used_substs[0]<u64>
+
+        // Function has an unused type parameter from impl and fn.
+        pub fn closure_unused_all<G: Default>() -> u32 {
+            let add_one = |x: u32| x + 1;
+            add_one(3)
+        }
+
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_unused_all[0]::{{closure}}[0]<F, G, i8, extern "rust-call" fn((u32)) -> u32, ()>
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_unused_all[0]<F, G>
+
+        // Function uses type parameter from impl and fn in closure.
+        pub fn closure_used_both<G: Default>() -> u32 {
+            let add_one = |x: u32| {
+                let _: F = Default::default();
+                let _: G = Default::default();
+                x + 1
+            };
+
+            add_one(3)
+        }
+
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_both[0]::{{closure}}[0]<u32, u32, i8, extern "rust-call" fn((u32)) -> u32, ()>
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_both[0]::{{closure}}[0]<u64, u64, i8, extern "rust-call" fn((u32)) -> u32, ()>
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_both[0]<u32, u32>
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_both[0]<u64, u64>
+
+        // Function uses type parameter from fn in closure.
+        pub fn closure_used_fn<G: Default>() -> u32 {
+            let add_one = |x: u32| {
+                let _: G = Default::default();
+                x + 1
+            };
+
+            add_one(3)
+        }
+
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_fn[0]::{{closure}}[0]<F, u32, i8, extern "rust-call" fn((u32)) -> u32, ()>
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_fn[0]::{{closure}}[0]<F, u64, i8, extern "rust-call" fn((u32)) -> u32, ()>
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_fn[0]<F, u32>
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_fn[0]<F, u64>
+
+        // Function uses type parameter from impl in closure.
+        pub fn closure_used_impl<G: Default>() -> u32 {
+            let add_one = |x: u32| {
+                let _: F = Default::default();
+                x + 1
+            };
+
+            add_one(3)
+        }
+
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_impl[0]::{{closure}}[0]<u32, G, i8, extern "rust-call" fn((u32)) -> u32, ()>
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_impl[0]::{{closure}}[0]<u64, G, i8, extern "rust-call" fn((u32)) -> u32, ()>
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_impl[0]<u32, G>
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_impl[0]<u64, G>
+
+        // Closure uses type parameter in substitutions to another function.
+        pub fn closure_used_substs() {
+            let x = || super::functions::unused::<F>();
+            x()
+        }
+
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_substs[0]::{{closure}}[0]<u32, i8, extern "rust-call" fn(()), ()>
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_substs[0]::{{closure}}[0]<u64, i8, extern "rust-call" fn(()), ()>
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_substs[0]<u32>
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_substs[0]<u64>
+    }
+}
+
+
+
+fn dispatch<T: Default>() {
+    functions::no_parameters();
+    functions::unused::<T>();
+    functions::used_binding_value::<T>();
+    functions::used_binding_type::<T>();
+    functions::used_argument::<T>(Default::default());
+    functions::used_substs::<T>();
+
+    closures::no_parameters();
+    let _ = closures::unused::<T>();
+    let _ = closures::used_parent::<T>();
+    let _ = closures::used_binding_value::<T>();
+    let _ = closures::used_binding_type::<T>();
+    let _ = closures::used_argument::<T>(Default::default());
+    let _ = closures::used_argument_closure::<T>();
+    let _ = closures::used_upvar::<T>();
+    let _ = closures::used_substs::<T>();
+
+    methods::Foo::<T>::unused_impl();
+    methods::Foo::<T>::unused_both::<T>();
+    methods::Foo::<T>::used_impl();
+    methods::Foo::<T>::used_fn::<T>();
+    methods::Foo::<T>::used_both::<T>();
+    methods::Foo::<T>::used_substs();
+    let _ = methods::Foo::<T>::closure_unused_all::<T>();
+    let _ = methods::Foo::<T>::closure_used_both::<T>();
+    let _ = methods::Foo::<T>::closure_used_impl::<T>();
+    let _ = methods::Foo::<T>::closure_used_fn::<T>();
+    let _ = methods::Foo::<T>::closure_used_substs();
+}
+
+//~ MONO_ITEM fn unused_type_parameters::dispatch[0]<u32>
+//~ MONO_ITEM fn unused_type_parameters::dispatch[0]<u64>
+
+pub fn foo() {
+    // Generate two copies of each function to check that where the type parameter is unused,
+    // there is only a single copy.
+    dispatch::<u32>();
+    dispatch::<u64>();
+}
+
+//~ MONO_ITEM fn unused_type_parameters::foo[0] @@ unused_type_parameters-cgu.0[External]
+
+// These are all the items that aren't relevant to the test.
+//~ MONO_ITEM fn core::default[0]::{{impl}}[6]::default[0]
+//~ MONO_ITEM fn core::default[0]::{{impl}}[7]::default[0]
index 8aeee5859d0adedcf8be1436101ebe03aa35e840..7c61b7809901f81c7f67d1d7c0b45ee5489fffe4 100644 (file)
@@ -2,7 +2,7 @@
 
 // revisions:x86_64 i686 arm
 
-// min-llvm-version 9.0
+// min-llvm-version: 9.0
 
 //[x86_64] compile-flags: --target x86_64-unknown-uefi
 //[i686] compile-flags: --target i686-unknown-linux-musl
diff --git a/src/test/codegen/avr/avr-func-addrspace.rs b/src/test/codegen/avr/avr-func-addrspace.rs
new file mode 100644 (file)
index 0000000..7759d96
--- /dev/null
@@ -0,0 +1,93 @@
+// compile-flags: -O --target=avr-unknown-unknown --crate-type=rlib
+
+// This test validates that function pointers can be stored in global variables
+// and called upon. It ensures that Rust emits function pointers in the correct
+// address space to LLVM so that an assertion error relating to casting is
+// not triggered.
+//
+// It also validates that functions can be called through function pointers
+// through traits.
+
+#![feature(no_core, lang_items, unboxed_closures, arbitrary_self_types)]
+#![crate_type = "lib"]
+#![no_core]
+
+#[lang = "sized"]
+pub trait Sized { }
+#[lang = "copy"]
+pub trait Copy { }
+#[lang = "receiver"]
+pub trait Receiver { }
+
+pub struct Result<T, E> { _a: T, _b: E }
+
+impl Copy for usize {}
+
+#[lang = "drop_in_place"]
+pub unsafe fn drop_in_place<T: ?Sized>(_: *mut T) {}
+
+#[lang = "fn_once"]
+pub trait FnOnce<Args> {
+    #[lang = "fn_once_output"]
+    type Output;
+
+    extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
+}
+
+#[lang = "fn_mut"]
+pub trait FnMut<Args> : FnOnce<Args> {
+    extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
+}
+
+#[lang = "fn"]
+pub trait Fn<Args>: FnOnce<Args> {
+    /// Performs the call operation.
+    extern "rust-call" fn call(&self, args: Args) -> Self::Output;
+}
+
+impl<'a, A, R> FnOnce<A> for &'a fn(A) -> R {
+    type Output = R;
+
+    extern "rust-call" fn call_once(self, args: A) -> R {
+        (*self)(args)
+    }
+}
+
+pub static mut STORAGE_FOO: fn(&usize, &mut u32) -> Result<(), ()> = arbitrary_black_box;
+pub static mut STORAGE_BAR: u32 = 12;
+
+fn arbitrary_black_box(ptr: &usize, _: &mut u32) -> Result<(), ()> {
+    let raw_ptr = ptr as *const usize;
+    let _v: usize = unsafe { *raw_ptr };
+    loop {}
+}
+
+#[inline(never)]
+#[no_mangle]
+fn call_through_fn_trait(a: &mut impl Fn<(), Output=()>) {
+    (*a)()
+}
+
+#[inline(never)]
+fn update_bar_value() {
+    unsafe {
+        STORAGE_BAR = 88;
+    }
+}
+
+// CHECK: define void @test(){{.+}}addrspace(1)
+#[no_mangle]
+pub extern "C" fn test() {
+    let mut buf = 7;
+
+    // A call through the Fn trait must use address space 1.
+    //
+    // CHECK: call{{.+}}addrspace(1) void @call_through_fn_trait()
+    call_through_fn_trait(&mut update_bar_value);
+
+    // A call through a global variable must use address space 1.
+    // CHECK: load {{.*}}addrspace(1){{.+}}FOO
+    unsafe {
+        STORAGE_FOO(&1, &mut buf);
+    }
+}
index 96a0a321199a37dc6e03eeb8f973cda45862ba64..571a2654bcbfd2f6d7f6543479d009f6abe3cad7 100644 (file)
@@ -1,4 +1,4 @@
-// compile-flags: -Z control-flow-guard=checks
+// compile-flags: -C control-flow-guard=checks
 // only-msvc
 
 #![crate_type = "lib"]
index 925e4e8e2d15557bc4dd9fdb9d43fcddba7cc6c1..c3f8f4116819ce2bf420dce85a50b7c7926dc24c 100644 (file)
@@ -1,4 +1,4 @@
-// compile-flags: -Z control-flow-guard=no
+// compile-flags: -C control-flow-guard=no
 // only-msvc
 
 #![crate_type = "lib"]
index d7dc3d7e89eea007fdeb644d237efab8dd6c181d..3847c3e81ed7a6d78f2e3e6b50741fb549c68431 100644 (file)
@@ -1,4 +1,4 @@
-// compile-flags: -Z control-flow-guard=nochecks
+// compile-flags: -C control-flow-guard=nochecks
 // only-msvc
 
 #![crate_type = "lib"]
index 4008f0187a0b05bc318262744e5d8bb17d4ff63e..6278a951e35f1565151946520f4919088e9b20eb 100644 (file)
@@ -1,4 +1,4 @@
-// compile-flags: -Z control-flow-guard
+// compile-flags: -C control-flow-guard
 // ignore-msvc
 
 #![crate_type = "lib"]
index fbaf38d69df7fc2608e92060fe69bdc50b3bcefd..eba4a7469f9308d2ade0946fdaa1d916cc82e6e0 100644 (file)
@@ -1,4 +1,4 @@
-// min-llvm-version 8.0
+// min-llvm-version: 8.0
 // compile-flags: -C no-prepopulate-passes -C force-unwind-tables=y
 
 #![crate_type="lib"]
index 789feea12d6d7e8a67ecfd84b406b5fb99571c37..4e3bfcd439744cb77b60cdbcc8575cb9a4e3441f 100644 (file)
@@ -2,6 +2,7 @@
 // unchecked intrinsics.
 
 // compile-flags: -C opt-level=3
+// ignore-wasm32 the wasm target is tested in `wasm_casts_*`
 
 #![crate_type = "lib"]
 
index 45b905190493a12151704411e8b8955842f16d1b..b7f8522fdfb033664327e8e7a65d84e1730af16c 100644 (file)
@@ -38,7 +38,6 @@ pub fn cast_f32_i32(a: f32) -> i32 {
     a as _
 }
 
-
 // CHECK-LABEL: @cast_f64_u64
 #[no_mangle]
 pub fn cast_f64_u64(a: f64) -> u64 {
@@ -84,13 +83,10 @@ pub fn cast_f32_u8(a: f32) -> u8 {
     a as _
 }
 
-
-
 // CHECK-LABEL: @cast_unchecked_f64_i64
 #[no_mangle]
 pub unsafe fn cast_unchecked_f64_i64(a: f64) -> i64 {
-    // CHECK-NOT: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}}
-    // CHECK: fptosi double {{.*}} to i64
+    // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.signed.{{.*}}
     // CHECK-NEXT: ret i64 {{.*}}
     a.to_int_unchecked()
 }
@@ -98,8 +94,7 @@ pub unsafe fn cast_unchecked_f64_i64(a: f64) -> i64 {
 // CHECK-LABEL: @cast_unchecked_f64_i32
 #[no_mangle]
 pub unsafe fn cast_unchecked_f64_i32(a: f64) -> i32 {
-    // CHECK-NOT: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}}
-    // CHECK: fptosi double {{.*}} to i32
+    // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.signed.{{.*}}
     // CHECK-NEXT: ret i32 {{.*}}
     a.to_int_unchecked()
 }
@@ -107,8 +102,7 @@ pub unsafe fn cast_unchecked_f64_i32(a: f64) -> i32 {
 // CHECK-LABEL: @cast_unchecked_f32_i64
 #[no_mangle]
 pub unsafe fn cast_unchecked_f32_i64(a: f32) -> i64 {
-    // CHECK-NOT: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}}
-    // CHECK: fptosi float {{.*}} to i64
+    // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.signed.{{.*}}
     // CHECK-NEXT: ret i64 {{.*}}
     a.to_int_unchecked()
 }
@@ -116,18 +110,15 @@ pub unsafe fn cast_unchecked_f32_i64(a: f32) -> i64 {
 // CHECK-LABEL: @cast_unchecked_f32_i32
 #[no_mangle]
 pub unsafe fn cast_unchecked_f32_i32(a: f32) -> i32 {
-    // CHECK-NOT: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}}
-    // CHECK: fptosi float {{.*}} to i32
+    // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.signed.{{.*}}
     // CHECK-NEXT: ret i32 {{.*}}
     a.to_int_unchecked()
 }
 
-
 // CHECK-LABEL: @cast_unchecked_f64_u64
 #[no_mangle]
 pub unsafe fn cast_unchecked_f64_u64(a: f64) -> u64 {
-    // CHECK-NOT: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}}
-    // CHECK: fptoui double {{.*}} to i64
+    // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.unsigned.{{.*}}
     // CHECK-NEXT: ret i64 {{.*}}
     a.to_int_unchecked()
 }
@@ -135,8 +126,7 @@ pub unsafe fn cast_unchecked_f64_u64(a: f64) -> u64 {
 // CHECK-LABEL: @cast_unchecked_f64_u32
 #[no_mangle]
 pub unsafe fn cast_unchecked_f64_u32(a: f64) -> u32 {
-    // CHECK-NOT: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}}
-    // CHECK: fptoui double {{.*}} to i32
+    // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.unsigned.{{.*}}
     // CHECK-NEXT: ret i32 {{.*}}
     a.to_int_unchecked()
 }
@@ -144,8 +134,7 @@ pub unsafe fn cast_unchecked_f64_u32(a: f64) -> u32 {
 // CHECK-LABEL: @cast_unchecked_f32_u64
 #[no_mangle]
 pub unsafe fn cast_unchecked_f32_u64(a: f32) -> u64 {
-    // CHECK-NOT: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}}
-    // CHECK: fptoui float {{.*}} to i64
+    // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.unsigned.{{.*}}
     // CHECK-NEXT: ret i64 {{.*}}
     a.to_int_unchecked()
 }
@@ -153,8 +142,7 @@ pub unsafe fn cast_unchecked_f32_u64(a: f32) -> u64 {
 // CHECK-LABEL: @cast_unchecked_f32_u32
 #[no_mangle]
 pub unsafe fn cast_unchecked_f32_u32(a: f32) -> u32 {
-    // CHECK-NOT: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}}
-    // CHECK: fptoui float {{.*}} to i32
+    // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.unsigned.{{.*}}
     // CHECK-NEXT: ret i32 {{.*}}
     a.to_int_unchecked()
 }
index ae28fcad903be648871df818a2c1b370e3e57461..d3cb5aaaeba89095fed6fbae4ac5cdfc7427d8ac 100644 (file)
@@ -1,4 +1,4 @@
 // compile-flags: --extern std=
-// error-pattern: can't find crate for `std`
+// error-pattern: extern location for std does not exist
 
 fn main() {}
index 98ad8983a60a0bd470360bddc2ac9c196c168ea1..a5d5942b539539861978d420ba2bd61630c7a591 100644 (file)
@@ -1,5 +1,5 @@
 // This test does not passed with gdb < 8.0. See #53497.
-// min-gdb-version 8.0
+// min-gdb-version: 8.0
 
 // compile-flags:-g
 
index 2616c9465246ee5ef96497735086cf26e2961da9..cbd2278f7e27c863f3dd5211e5022f82afc5f0a3 100644 (file)
@@ -2,7 +2,7 @@
 // ignore-freebsd: gdb package too new
 // ignore-android: FIXME(#10381)
 // compile-flags:-g
-// min-gdb-version 8.1
+// min-gdb-version: 8.1
 // min-lldb-version: 310
 
 // === GDB TESTS ===================================================================================
index 4e95a028e074948baadc3a085a515d54dc8a9edd..a4fbff5725c97aa20bbf0694a219199d597384c4 100644 (file)
@@ -6,7 +6,7 @@
 
 // The pretty printers being tested here require the patch from
 // https://sourceware.org/bugzilla/show_bug.cgi?id=21763
-// min-gdb-version 8.1
+// min-gdb-version: 8.1
 
 // min-lldb-version: 310
 
index 57721ce103c3921706a6fe24a33d99aa0c35e463..7ae82d522b09dc37dfe588b52b7da46a4d428501 100644 (file)
@@ -2,7 +2,7 @@
 // only-cdb // "Temporarily" ignored on GDB/LLDB due to debuginfo tests being disabled, see PR 47155
 // ignore-android: FIXME(#10381)
 // compile-flags:-g
-// min-gdb-version 7.7
+// min-gdb-version: 7.7
 // min-lldb-version: 310
 
 // === GDB TESTS ===================================================================================
index 7ce004681e100ab6954382c1567ade4cf2a8a90b..61791f48f4db76683adde4dcbacbed0038a72015 100644 (file)
@@ -2,7 +2,7 @@
 // ignore-freebsd: gdb package too new
 // ignore-android: FIXME(#10381)
 // compile-flags:-g
-// min-gdb-version 8.1
+// min-gdb-version: 8.1
 // min-lldb-version: 310
 
 // === GDB TESTS ===================================================================================
index af2899c887a949cc17ce55d119002c4d9904902a..e7fef4622b1c6cb09e791cd3586dea2049d5978c 100644 (file)
@@ -3,34 +3,40 @@
   
   fn bar() -> bool {
       let mut _0: bool;                    // return place in scope 0 at $DIR/instrument_coverage.rs:18:13: 18:17
-+     let mut _1: ();                      // in scope 0 at $DIR/instrument_coverage.rs:18:1: 20:2
++     let mut _1: ();                      // in scope 0 at $DIR/instrument_coverage.rs:18:18: 18:18
   
       bb0: {
-+         StorageLive(_1);                 // scope 0 at $DIR/instrument_coverage.rs:18:1: 20:2
-+         _1 = const std::intrinsics::count_code_region(const 0_u32, const 484_u32, const 513_u32) -> bb2; // scope 0 at $DIR/instrument_coverage.rs:18:1: 20:2
++         StorageLive(_1);                 // scope 0 at $DIR/instrument_coverage.rs:18:18: 18:18
++         _1 = const std::intrinsics::count_code_region(const 10208505205182607101_u64, const 0_u32, const 501_u32, const 513_u32) -> bb2; // scope 0 at $DIR/instrument_coverage.rs:18:18: 18:18
 +                                          // ty::Const
-+                                          // + ty: unsafe extern "rust-intrinsic" fn(u32, u32, u32) {std::intrinsics::count_code_region}
++                                          // + ty: unsafe extern "rust-intrinsic" fn(u64, u32, u32, u32) {std::intrinsics::count_code_region}
 +                                          // + val: Value(Scalar(<ZST>))
 +                                          // mir::Constant
-+                                          // + span: $DIR/instrument_coverage.rs:18:1: 18:1
-+                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u32, u32, u32) {std::intrinsics::count_code_region}, val: Value(Scalar(<ZST>)) }
++                                          // + span: $DIR/instrument_coverage.rs:18:18: 18:18
++                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u64, u32, u32, u32) {std::intrinsics::count_code_region}, val: Value(Scalar(<ZST>)) }
++                                          // ty::Const
++                                          // + ty: u64
++                                          // + val: Value(Scalar(0x8dabe565aaa2aefd))
++                                          // mir::Constant
++                                          // + span: $DIR/instrument_coverage.rs:18:18: 18:18
++                                          // + literal: Const { ty: u64, val: Value(Scalar(0x8dabe565aaa2aefd)) }
 +                                          // ty::Const
 +                                          // + ty: u32
 +                                          // + val: Value(Scalar(0x00000000))
 +                                          // mir::Constant
-+                                          // + span: $DIR/instrument_coverage.rs:18:1: 18:1
++                                          // + span: $DIR/instrument_coverage.rs:18:18: 18:18
 +                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000000)) }
 +                                          // ty::Const
 +                                          // + ty: u32
-+                                          // + val: Value(Scalar(0x000001e4))
++                                          // + val: Value(Scalar(0x000001f5))
 +                                          // mir::Constant
-+                                          // + span: $DIR/instrument_coverage.rs:18:1: 18:1
-+                                          // + literal: Const { ty: u32, val: Value(Scalar(0x000001e4)) }
++                                          // + span: $DIR/instrument_coverage.rs:18:18: 18:18
++                                          // + literal: Const { ty: u32, val: Value(Scalar(0x000001f5)) }
 +                                          // ty::Const
 +                                          // + ty: u32
 +                                          // + val: Value(Scalar(0x00000201))
 +                                          // mir::Constant
-+                                          // + span: $DIR/instrument_coverage.rs:18:1: 18:1
++                                          // + span: $DIR/instrument_coverage.rs:18:18: 18:18
 +                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000201)) }
 +     }
 + 
index 4a300230f8a9728334eb680876ec48676a067696..51378c216da641b9d2958a6def88f14c62a971ed 100644 (file)
@@ -6,35 +6,41 @@
       let mut _1: ();                      // in scope 0 at $DIR/instrument_coverage.rs:9:1: 15:2
       let mut _2: bool;                    // in scope 0 at $DIR/instrument_coverage.rs:11:12: 11:17
       let mut _3: !;                       // in scope 0 at $DIR/instrument_coverage.rs:11:18: 13:10
-+     let mut _4: ();                      // in scope 0 at $DIR/instrument_coverage.rs:9:1: 15:2
++     let mut _4: ();                      // in scope 0 at $DIR/instrument_coverage.rs:9:11: 9:11
   
       bb0: {
 -         falseUnwind -> [real: bb1, cleanup: bb2]; // scope 0 at $DIR/instrument_coverage.rs:10:5: 14:6
-+         StorageLive(_4);                 // scope 0 at $DIR/instrument_coverage.rs:9:1: 15:2
-+         _4 = const std::intrinsics::count_code_region(const 0_u32, const 387_u32, const 465_u32) -> bb7; // scope 0 at $DIR/instrument_coverage.rs:9:1: 15:2
++         StorageLive(_4);                 // scope 0 at $DIR/instrument_coverage.rs:9:11: 9:11
++         _4 = const std::intrinsics::count_code_region(const 16004455475339839479_u64, const 0_u32, const 397_u32, const 465_u32) -> bb7; // scope 0 at $DIR/instrument_coverage.rs:9:11: 9:11
 +                                          // ty::Const
-+                                          // + ty: unsafe extern "rust-intrinsic" fn(u32, u32, u32) {std::intrinsics::count_code_region}
++                                          // + ty: unsafe extern "rust-intrinsic" fn(u64, u32, u32, u32) {std::intrinsics::count_code_region}
 +                                          // + val: Value(Scalar(<ZST>))
 +                                          // mir::Constant
-+                                          // + span: $DIR/instrument_coverage.rs:9:1: 9:1
-+                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u32, u32, u32) {std::intrinsics::count_code_region}, val: Value(Scalar(<ZST>)) }
++                                          // + span: $DIR/instrument_coverage.rs:9:11: 9:11
++                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u64, u32, u32, u32) {std::intrinsics::count_code_region}, val: Value(Scalar(<ZST>)) }
++                                          // ty::Const
++                                          // + ty: u64
++                                          // + val: Value(Scalar(0xde1b3f75a72fc7f7))
++                                          // mir::Constant
++                                          // + span: $DIR/instrument_coverage.rs:9:11: 9:11
++                                          // + literal: Const { ty: u64, val: Value(Scalar(0xde1b3f75a72fc7f7)) }
 +                                          // ty::Const
 +                                          // + ty: u32
 +                                          // + val: Value(Scalar(0x00000000))
 +                                          // mir::Constant
-+                                          // + span: $DIR/instrument_coverage.rs:9:1: 9:1
++                                          // + span: $DIR/instrument_coverage.rs:9:11: 9:11
 +                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000000)) }
 +                                          // ty::Const
 +                                          // + ty: u32
-+                                          // + val: Value(Scalar(0x00000183))
++                                          // + val: Value(Scalar(0x0000018d))
 +                                          // mir::Constant
-+                                          // + span: $DIR/instrument_coverage.rs:9:1: 9:1
-+                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000183)) }
++                                          // + span: $DIR/instrument_coverage.rs:9:11: 9:11
++                                          // + literal: Const { ty: u32, val: Value(Scalar(0x0000018d)) }
 +                                          // ty::Const
 +                                          // + ty: u32
 +                                          // + val: Value(Scalar(0x000001d1))
 +                                          // mir::Constant
-+                                          // + span: $DIR/instrument_coverage.rs:9:1: 9:1
++                                          // + span: $DIR/instrument_coverage.rs:9:11: 9:11
 +                                          // + literal: Const { ty: u32, val: Value(Scalar(0x000001d1)) }
       }
   
index a0a5b141ec0e19df5eb6b2db83b757a070643b88..5830ef033d38990198300d15843d721b42b41d29 100644 (file)
@@ -91,3 +91,58 @@ unsafe fn compare_c_str(ptr: *const c_char, val: &str) -> bool {
 pub unsafe extern "C" fn check_varargs_2(_: c_int, _ap: ...) -> usize {
     0
 }
+
+#[no_mangle]
+pub unsafe extern "C" fn check_varargs_3(_: c_int, mut ap: ...) -> usize {
+    continue_if!(ap.arg::<c_int>() == 1);
+    continue_if!(ap.arg::<c_int>() == 2);
+    continue_if!(ap.arg::<c_int>() == 3);
+    continue_if!(ap.arg::<c_int>() == 4);
+    continue_if!(ap.arg::<c_int>() == 5);
+    continue_if!(ap.arg::<c_int>() == 6);
+    continue_if!(ap.arg::<c_int>() == 7);
+    continue_if!(ap.arg::<c_int>() == 8);
+    continue_if!(ap.arg::<c_int>() == 9);
+    continue_if!(ap.arg::<c_int>() == 10);
+    0
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn check_varargs_4(_: c_double, mut ap: ...) -> usize {
+    continue_if!(ap.arg::<c_double>() == 1.0);
+    continue_if!(ap.arg::<c_double>() == 2.0);
+    continue_if!(ap.arg::<c_double>() == 3.0);
+    continue_if!(ap.arg::<c_double>() == 4.0);
+    continue_if!(ap.arg::<c_double>() == 5.0);
+    continue_if!(ap.arg::<c_double>() == 6.0);
+    continue_if!(ap.arg::<c_double>() == 7.0);
+    continue_if!(ap.arg::<c_double>() == 8.0);
+    continue_if!(ap.arg::<c_double>() == 9.0);
+    continue_if!(ap.arg::<c_double>() == 10.0);
+    0
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn check_varargs_5(_: c_int, mut ap: ...) -> usize {
+    continue_if!(ap.arg::<c_double>() == 1.0);
+    continue_if!(ap.arg::<c_int>() == 1);
+    continue_if!(ap.arg::<c_double>() == 2.0);
+    continue_if!(ap.arg::<c_int>() == 2);
+    continue_if!(ap.arg::<c_double>() == 3.0);
+    continue_if!(ap.arg::<c_int>() == 3);
+    continue_if!(ap.arg::<c_double>() == 4.0);
+    continue_if!(ap.arg::<c_int>() == 4);
+    continue_if!(ap.arg::<c_int>() == 5);
+    continue_if!(ap.arg::<c_double>() == 5.0);
+    continue_if!(ap.arg::<c_int>() == 6);
+    continue_if!(ap.arg::<c_double>() == 6.0);
+    continue_if!(ap.arg::<c_int>() == 7);
+    continue_if!(ap.arg::<c_double>() == 7.0);
+    continue_if!(ap.arg::<c_int>() == 8);
+    continue_if!(ap.arg::<c_double>() == 8.0);
+    continue_if!(ap.arg::<c_int>() == 9);
+    continue_if!(ap.arg::<c_double>() == 9.0);
+    continue_if!(ap.arg::<c_int>() == 10);
+    continue_if!(ap.arg::<c_double>() == 10.0);
+    0
+}
index 91b060dce26f436f6f9f5d21b7d038784dba115d..5bdb51680a6562ec25d03597146de4bdf4cbb417 100644 (file)
@@ -11,6 +11,9 @@ extern size_t check_list_copy_0(va_list ap);
 extern size_t check_varargs_0(int fixed, ...);
 extern size_t check_varargs_1(int fixed, ...);
 extern size_t check_varargs_2(int fixed, ...);
+extern size_t check_varargs_3(int fixed, ...);
+extern size_t check_varargs_4(double fixed, ...);
+extern size_t check_varargs_5(int fixed, ...);
 
 int test_rust(size_t (*fn)(va_list), ...) {
     size_t ret = 0;
@@ -36,5 +39,12 @@ int main(int argc, char* argv[]) {
 
     assert(check_varargs_2(0, "All", "of", "these", "are", "ignored", ".") == 0);
 
+    assert(check_varargs_3(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10) == 0);
+
+    assert(check_varargs_4(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0) == 0);
+
+    assert(check_varargs_5(0, 1.0, 1, 2.0, 2, 3.0, 3, 4.0, 4, 5, 5.0, 6, 6.0, 7, 7.0, 8, 8.0,
+                           9, 9.0, 10, 10.0) == 0);
+
     return 0;
 }
diff --git a/src/test/run-make-fulldeps/instrument-coverage/Makefile b/src/test/run-make-fulldeps/instrument-coverage/Makefile
new file mode 100644 (file)
index 0000000..df47305
--- /dev/null
@@ -0,0 +1,57 @@
+# needs-profiler-support
+# ignore-msvc
+
+# FIXME(richkadel): Debug the following problem, and reenable on Windows (by
+# removing the `# ignore-msvc` directive above). The current implementation
+# generates a segfault when running the instrumented `main` executable,
+# after the `main` program code executes, but before the process terminates.
+# This most likely points to a problem generating the LLVM "main.profraw"
+# file.
+
+-include ../tools.mk
+
+# This test makes sure that LLVM coverage maps are genereated in LLVM IR.
+
+COMMON_FLAGS=-Zinstrument-coverage
+
+all:
+       # Compile the test program with instrumentation, and also generate LLVM IR
+       $(RUSTC) $(COMMON_FLAGS) main.rs
+
+       # 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)"/main.profraw \
+         $(call RUN,main)
+
+       # Postprocess the profiling data so it can be used by the llvm-cov tool
+       "$(LLVM_BIN_DIR)"/llvm-profdata merge --sparse \
+         "$(TMPDIR)"/main.profraw \
+               -o "$(TMPDIR)"/main.profdata
+
+       # Generate a coverage report using `llvm-cov show`. The output ordering
+       # can be non-deterministic, so ignore the return status. If the test fails
+       # when comparing the JSON `export`, the `show` output may be useful when
+       # debugging.
+       "$(LLVM_BIN_DIR)"/llvm-cov show \
+         --Xdemangler="$(RUST_DEMANGLER)" \
+         --show-line-counts-or-regions \
+         --instr-profile="$(TMPDIR)"/main.profdata \
+               $(call BIN,"$(TMPDIR)"/main) \
+               > "$(TMPDIR)"/actual_show_coverage.txt
+
+       # Compare the show coverage output
+       $(DIFF) typical_show_coverage.txt "$(TMPDIR)"/actual_show_coverage.txt || \
+         >&2 echo 'diff failed for `llvm-cov show` (might not be an error)'
+
+       # Generate a coverage report in JSON, using `llvm-cov export`, and fail if
+       # there are differences from the expected output.
+       "$(LLVM_BIN_DIR)"/llvm-cov export \
+         --summary-only \
+         --instr-profile="$(TMPDIR)"/main.profdata \
+               $(call BIN,"$(TMPDIR)"/main) \
+               | "$(PYTHON)" prettify_json.py \
+               > "$(TMPDIR)"/actual_export_coverage.json
+
+       # Check that the exported JSON coverage data matches what we expect
+       $(DIFF) expected_export_coverage.json "$(TMPDIR)"/actual_export_coverage.json
diff --git a/src/test/run-make-fulldeps/instrument-coverage/expected_export_coverage.json b/src/test/run-make-fulldeps/instrument-coverage/expected_export_coverage.json
new file mode 100644 (file)
index 0000000..9d739a8
--- /dev/null
@@ -0,0 +1,59 @@
+{
+  "data": [
+    {
+      "files": [
+        {
+          "filename": "main.rs",
+          "summary": {
+            "functions": {
+              "count": 7,
+              "covered": 5,
+              "percent": 71.42857142857143
+            },
+            "instantiations": {
+              "count": 8,
+              "covered": 6,
+              "percent": 75
+            },
+            "lines": {
+              "count": 30,
+              "covered": 25,
+              "percent": 83.33333333333334
+            },
+            "regions": {
+              "count": 7,
+              "covered": 5,
+              "notcovered": 2,
+              "percent": 71.42857142857143
+            }
+          }
+        }
+      ],
+      "totals": {
+        "functions": {
+          "count": 7,
+          "covered": 5,
+          "percent": 71.42857142857143
+        },
+        "instantiations": {
+          "count": 8,
+          "covered": 6,
+          "percent": 75
+        },
+        "lines": {
+          "count": 30,
+          "covered": 25,
+          "percent": 83.33333333333334
+        },
+        "regions": {
+          "count": 7,
+          "covered": 5,
+          "notcovered": 2,
+          "percent": 71.42857142857143
+        }
+      }
+    }
+  ],
+  "type": "llvm.coverage.json.export",
+  "version": "2.0.0"
+}
diff --git a/src/test/run-make-fulldeps/instrument-coverage/main.rs b/src/test/run-make-fulldeps/instrument-coverage/main.rs
new file mode 100644 (file)
index 0000000..358c256
--- /dev/null
@@ -0,0 +1,38 @@
+pub fn will_be_called() -> &'static str {
+    let val = "called";
+    println!("{}", val);
+    val
+}
+
+pub fn will_not_be_called() -> bool {
+    println!("should not have been called");
+    false
+}
+
+pub fn print<T>(left: &str, value: T, right: &str)
+where
+    T: std::fmt::Display,
+{
+    println!("{}{}{}", left, value, right);
+}
+
+pub fn wrap_with<F, T>(inner: T, should_wrap: bool, wrapper: F)
+where
+    F: FnOnce(&T)
+{
+    if should_wrap {
+        wrapper(&inner)
+    }
+}
+
+fn main() {
+    let less = 1;
+    let more = 100;
+
+    if less < more {
+        wrap_with(will_be_called(), less < more, |inner| print(" ***", inner, "*** "));
+        wrap_with(will_be_called(), more < less, |inner| print(" ***", inner, "*** "));
+    } else {
+        wrap_with(will_not_be_called(), true, |inner| print("wrapped result is: ", inner, ""));
+    }
+}
diff --git a/src/test/run-make-fulldeps/instrument-coverage/prettify_json.py b/src/test/run-make-fulldeps/instrument-coverage/prettify_json.py
new file mode 100644 (file)
index 0000000..ed92798
--- /dev/null
@@ -0,0 +1,9 @@
+#!/usr/bin/env python
+
+import sys
+import json
+
+# Try to decode line in order to ensure it is a valid JSON document
+for line in sys.stdin:
+    parsed = json.loads(line)
+    print (json.dumps(parsed, indent=2, separators=(',', ': '), sort_keys=True))
diff --git a/src/test/run-make-fulldeps/instrument-coverage/typical_show_coverage.txt b/src/test/run-make-fulldeps/instrument-coverage/typical_show_coverage.txt
new file mode 100644 (file)
index 0000000..9c593d0
--- /dev/null
@@ -0,0 +1,55 @@
+    1|      2|pub fn will_be_called() -> &'static str {
+    2|      2|    let val = "called";
+    3|      2|    println!("{}", val);
+    4|      2|    val
+    5|      2|}
+    6|       |
+    7|      0|pub fn will_not_be_called() -> bool {
+    8|      0|    println!("should not have been called");
+    9|      0|    false
+   10|      0|}
+   11|       |
+   12|       |pub fn print<T>(left: &str, value: T, right: &str)
+   13|       |where
+   14|       |    T: std::fmt::Display,
+   15|      1|{
+   16|      1|    println!("{}{}{}", left, value, right);
+   17|      1|}
+   18|       |
+   19|       |pub fn wrap_with<F, T>(inner: T, should_wrap: bool, wrapper: F)
+   20|       |where
+   21|       |    F: FnOnce(&T)
+   22|      2|{
+   23|      2|    if should_wrap {
+   24|      2|        wrapper(&inner)
+   25|      2|    }
+   26|      2|}
+  ------------------
+  | main[317d481089b8c8fe]::wrap_with::<main[317d481089b8c8fe]::main::{closure#0}, &str>:
+  |   22|      1|{
+  |   23|      1|    if should_wrap {
+  |   24|      1|        wrapper(&inner)
+  |   25|      1|    }
+  |   26|      1|}
+  ------------------
+  | main[317d481089b8c8fe]::wrap_with::<main[317d481089b8c8fe]::main::{closure#1}, &str>:
+  |   22|      1|{
+  |   23|      1|    if should_wrap {
+  |   24|      1|        wrapper(&inner)
+  |   25|      1|    }
+  |   26|      1|}
+  ------------------
+   27|       |
+   28|      1|fn main() {
+   29|      1|    let less = 1;
+   30|      1|    let more = 100;
+   31|      1|
+   32|      1|    if less < more {
+   33|      1|        wrap_with(will_be_called(), less < more, |inner| print(" ***", inner, "*** "));
+   34|      1|        wrap_with(will_be_called(), more < less, |inner| print(" ***", inner, "*** "));
+                                                                       ^0
+   35|      1|    } else {
+   36|      1|        wrap_with(will_not_be_called(), true, |inner| print("wrapped result is: ", inner, ""));
+   37|      1|    }
+   38|      1|}
+
index 1effa46e101eba906e392f2dd535ce3a1cf8353d..8b885f1dc6d58e387669c4eb83a83bd6e3eeecbc 100644 (file)
@@ -18,6 +18,9 @@ endif
 HTMLDOCCK := '$(PYTHON)' '$(S)/src/etc/htmldocck.py'
 CGREP := "$(S)/src/etc/cat-and-grep.sh"
 
+# diff with common flags for multi-platform diffs against text output
+DIFF := diff -u --strip-trailing-cr
+
 # This is the name of the binary we will generate and run; use this
 # e.g. for `$(CC) -o $(RUN_BINFILE)`.
 RUN_BINFILE = $(TMPDIR)/$(1)
index bc21cfd47c5d1000e535e5db74ebf8e21d634039..894518faa31686f810052fad43a2f3790da9c8e0 100644 (file)
@@ -1,15 +1,15 @@
-error: `[v2]` cannot be resolved, ignoring it.
+error: unresolved link to `v2`
   --> $DIR/deny-intra-link-resolution-failure.rs:3:6
    |
 LL | /// [v2]
-   |      ^^ cannot be resolved, ignoring
+   |      ^^ unresolved link
    |
 note: the lint level is defined here
   --> $DIR/deny-intra-link-resolution-failure.rs:1:9
    |
 LL | #![deny(intra_doc_link_resolution_failure)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
 error: aborting due to previous error
 
index cf26675163054067e30c40a75bed45e2a9990e86..d2b2b90a4e50d69a7222f0e377c840ad8c302762 100644 (file)
@@ -1,15 +1,15 @@
-error: `[TypeAlias::hoge]` cannot be resolved, ignoring it.
+error: unresolved link to `TypeAlias::hoge`
   --> $DIR/intra-doc-alias-ice.rs:5:30
    |
 LL | /// [broken cross-reference](TypeAlias::hoge)
-   |                              ^^^^^^^^^^^^^^^ cannot be resolved, ignoring
+   |                              ^^^^^^^^^^^^^^^ unresolved link
    |
 note: the lint level is defined here
   --> $DIR/intra-doc-alias-ice.rs:1:9
    |
 LL | #![deny(intra_doc_link_resolution_failure)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
 error: aborting due to previous error
 
index 44997c90f59320465bbc7a6b063886aca329afe1..95388003f84704a79b8f01637e386c0430987eb4 100644 (file)
@@ -7,7 +7,7 @@
 /// ## For example:
 ///
 /// (arr[i])
-//~^ ERROR `[i]` cannot be resolved, ignoring it.
+//~^ ERROR `i`
 pub fn test_ice() {
     unimplemented!();
 }
index ce31eb3a8a3786cd2bf9712ac1c4c45d3f7dd6f6..156e214a79ff05258fb811d0bbb3d7f1d6bc2555 100644 (file)
@@ -1,15 +1,15 @@
-error: `[i]` cannot be resolved, ignoring it.
+error: unresolved link to `i`
   --> $DIR/intra-link-span-ice-55723.rs:9:10
    |
 LL | /// (arr[i])
-   |           ^ cannot be resolved, ignoring
+   |           ^ unresolved link
    |
 note: the lint level is defined here
   --> $DIR/intra-link-span-ice-55723.rs:1:9
    |
 LL | #![deny(intra_doc_link_resolution_failure)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
 error: aborting due to previous error
 
index 7f8a8dd3c45e03e7a396cfbaad84e0dd060b4e9e..7e61bd725359a4c57422264bce630bc1244096d7 100644 (file)
@@ -23,23 +23,23 @@ pub enum Enum {
 /// Like [Foo#hola].
 ///
 /// Or maybe [Foo::f#hola].
-//~^ ERROR `[Foo::f#hola]` has an issue with the link anchor.
+//~^ ERROR `Foo::f#hola` contains an anchor
 pub fn foo() {}
 
 /// Empty.
 ///
 /// Another anchor error: [hello#people#!].
-//~^ ERROR `[hello#people#!]` has an issue with the link anchor.
+//~^ ERROR `hello#people#!` contains multiple anchors
 pub fn bar() {}
 
 /// Empty?
 ///
 /// Damn enum's variants: [Enum::A#whatever].
-//~^ ERROR `[Enum::A#whatever]` has an issue with the link anchor.
+//~^ ERROR `Enum::A#whatever` contains an anchor
 pub fn enum_link() {}
 
 /// Primitives?
 ///
 /// [u32#hello]
-//~^ ERROR `[u32#hello]` has an issue with the link anchor.
+//~^ ERROR `u32#hello` contains an anchor
 pub fn x() {}
index 11dee5547db4f541c8ecaea0637609ad985b8757..ef33d8f3e06fefbee4a4c1c0c3987ac6de8345e5 100644 (file)
@@ -1,8 +1,8 @@
-error: `[Foo::f#hola]` has an issue with the link anchor.
+error: `Foo::f#hola` contains an anchor, but links to struct fields are already anchored
   --> $DIR/intra-links-anchors.rs:25:15
    |
 LL | /// Or maybe [Foo::f#hola].
-   |               ^^^^^^^^^^^ struct fields cannot be followed by anchors
+   |               ^^^^^^^^^^^ contains invalid anchor
    |
 note: the lint level is defined here
   --> $DIR/intra-links-anchors.rs:1:9
@@ -10,23 +10,23 @@ note: the lint level is defined here
 LL | #![deny(intra_doc_link_resolution_failure)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: `[hello#people#!]` has an issue with the link anchor.
+error: `hello#people#!` contains multiple anchors
   --> $DIR/intra-links-anchors.rs:31:28
    |
 LL | /// Another anchor error: [hello#people#!].
-   |                            ^^^^^^^^^^^^^^ only one `#` is allowed in a link
+   |                            ^^^^^^^^^^^^^^ contains invalid anchor
 
-error: `[Enum::A#whatever]` has an issue with the link anchor.
+error: `Enum::A#whatever` contains an anchor, but links to enum variants are already anchored
   --> $DIR/intra-links-anchors.rs:37:28
    |
 LL | /// Damn enum's variants: [Enum::A#whatever].
-   |                            ^^^^^^^^^^^^^^^^ variants cannot be followed by anchors
+   |                            ^^^^^^^^^^^^^^^^ contains invalid anchor
 
-error: `[u32#hello]` has an issue with the link anchor.
+error: `u32#hello` contains an anchor, but links to primitive types are already anchored
   --> $DIR/intra-links-anchors.rs:43:6
    |
 LL | /// [u32#hello]
-   |      ^^^^^^^^^ primitive types cannot be followed by anchors
+   |      ^^^^^^^^^ contains invalid anchor
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/rustdoc-ui/intra-links-private.private.stderr b/src/test/rustdoc-ui/intra-links-private.private.stderr
new file mode 100644 (file)
index 0000000..a2148b8
--- /dev/null
@@ -0,0 +1,11 @@
+warning: public documentation for `DocMe` links to private item `DontDocMe`
+  --> $DIR/intra-links-private.rs:5:11
+   |
+LL | /// docs [DontDocMe]
+   |           ^^^^^^^^^ this item is private
+   |
+   = note: `#[warn(intra_doc_link_resolution_failure)]` on by default
+   = note: this link resolves only because you passed `--document-private-items`, but will break without
+
+warning: 1 warning emitted
+
index 0a8dafdaf94667ef591fcc5f9ad5f8fd00c28cb3..56742406992fcc63138c147074c0d176f207b8b8 100644 (file)
@@ -1,10 +1,11 @@
-warning: `[DontDocMe]` public documentation for `DocMe` links to a private item
-  --> $DIR/intra-links-private.rs:6:11
+warning: public documentation for `DocMe` links to private item `DontDocMe`
+  --> $DIR/intra-links-private.rs:5:11
    |
 LL | /// docs [DontDocMe]
    |           ^^^^^^^^^ this item is private
    |
    = note: `#[warn(intra_doc_link_resolution_failure)]` on by default
+   = note: this link will resolve properly if you pass `--document-private-items`
 
 warning: 1 warning emitted
 
index 86cf9fed3dab48cb176a2009969632bc26c7a647..613236d75d2ee952e847f7ac23590a95509bfccd 100644 (file)
@@ -1,10 +1,9 @@
 // check-pass
 // revisions: public private
 // [private]compile-flags: --document-private-items
-#![cfg_attr(private, deny(intra_doc_link_resolution_failure))]
 
 /// docs [DontDocMe]
-//[public]~^ WARNING `[DontDocMe]` public documentation for `DocMe` links to a private item
+//~^ WARNING public documentation for `DocMe` links to private item `DontDocMe`
 // FIXME: for [private] we should also make sure the link was actually generated
 pub struct DocMe;
 struct DontDocMe;
index 18c9837b0bb457e449312e21e811e12cec6b5b97..a19c33b53be09673b8f24197a2ab001812800f13 100644 (file)
@@ -6,16 +6,16 @@
 
 /// [error]
 pub struct A;
-//~^^ WARNING `[error]` cannot be resolved
+//~^^ WARNING `error`
 
 ///
 /// docs [error1]
-//~^ WARNING `[error1]` cannot be resolved
+//~^ WARNING `error1`
 
 /// docs [error2]
 ///
 pub struct B;
-//~^^^ WARNING `[error2]` cannot be resolved
+//~^^^ WARNING `error2`
 
 /**
  * This is a multi-line comment.
@@ -23,4 +23,4 @@
  * It also has an [error].
  */
 pub struct C;
-//~^^^ WARNING `[error]` cannot be resolved
+//~^^^ WARNING `error`
index ac8691a8743ba7dbffe9e984e029f1b07c183f41..bc31264c170eaf3bed48c3bd07eda0fdd4d891f5 100644 (file)
@@ -1,35 +1,35 @@
-warning: `[error]` cannot be resolved, ignoring it.
+warning: unresolved link to `error`
   --> $DIR/intra-links-warning-crlf.rs:7:6
    |
 LL | /// [error]
-   |      ^^^^^ cannot be resolved, ignoring
+   |      ^^^^^ unresolved link
    |
    = note: `#[warn(intra_doc_link_resolution_failure)]` on by default
-   = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
-warning: `[error1]` cannot be resolved, ignoring it.
+warning: unresolved link to `error1`
   --> $DIR/intra-links-warning-crlf.rs:12:11
    |
 LL | /// docs [error1]
-   |           ^^^^^^ cannot be resolved, ignoring
+   |           ^^^^^^ unresolved link
    |
-   = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
-warning: `[error2]` cannot be resolved, ignoring it.
+warning: unresolved link to `error2`
   --> $DIR/intra-links-warning-crlf.rs:15:11
    |
 LL | /// docs [error2]
-   |           ^^^^^^ cannot be resolved, ignoring
+   |           ^^^^^^ unresolved link
    |
-   = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
-warning: `[error]` cannot be resolved, ignoring it.
+warning: unresolved link to `error`
   --> $DIR/intra-links-warning-crlf.rs:23:20
    |
 LL |  * It also has an [error].
-   |                    ^^^^^ cannot be resolved, ignoring
+   |                    ^^^^^ unresolved link
    |
-   = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
 warning: 4 warnings emitted
 
index 623dcc320bb8dcd83a06b860640f4fb3dbba7733..eab1f03480460b2d05d9c722a44aaa41085805bc 100644 (file)
@@ -1,37 +1,37 @@
 // check-pass
 
        //! Test with [Foo::baz], [Bar::foo], ...
-//~^ WARNING `[Foo::baz]` cannot be resolved
-//~| WARNING `[Bar::foo]` cannot be resolved
+//~^ WARNING `Foo::baz`
+//~| WARNING `Bar::foo`
      //! , [Uniooon::X] and [Qux::Z].
-//~^ WARNING `[Uniooon::X]` cannot be resolved
-//~| WARNING `[Qux::Z]` cannot be resolved
+//~^ WARNING `Uniooon::X`
+//~| WARNING `Qux::Z`
        //!
       //! , [Uniooon::X] and [Qux::Z].
-//~^ WARNING `[Uniooon::X]` cannot be resolved
-//~| WARNING `[Qux::Z]` cannot be resolved
+//~^ WARNING `Uniooon::X`
+//~| WARNING `Qux::Z`
 
        /// [Qux:Y]
-//~^ WARNING `[Qux:Y]` cannot be resolved
+//~^ WARNING `Qux:Y`
 pub struct Foo {
     pub bar: usize,
 }
 
 /// Foo
-/// bar [BarA] bar //~ WARNING `[BarA]` cannot be resolved
+/// bar [BarA] bar //~ WARNING `BarA`
 /// baz
 pub fn a() {}
 
 /**
  * Foo
- * bar [BarB] bar //~ WARNING `[BarB]` cannot be resolved
+ * bar [BarB] bar //~ WARNING `BarB`
  * baz
  */
 pub fn b() {}
 
 /** Foo
 
-bar [BarC] bar //~ WARNING `[BarC]` cannot be resolved
+bar [BarC] bar //~ WARNING `BarC`
 baz
 
     let bar_c_1 = 0;
@@ -42,12 +42,12 @@ pub fn b() {}
 */
 pub fn c() {}
 
-#[doc = "Foo\nbar [BarD] bar\nbaz"] //~ WARNING `[BarD]` cannot be resolved
+#[doc = "Foo\nbar [BarD] bar\nbaz"] //~ WARNING `BarD`
 pub fn d() {}
 
 macro_rules! f {
     ($f:expr) => {
-        #[doc = $f] //~ WARNING `[BarF]` cannot be resolved
+        #[doc = $f] //~ WARNING `BarF`
         pub fn f() {}
     }
 }
@@ -55,30 +55,30 @@ pub fn f() {}
 
 /** # for example,
  *
- * time to introduce a link [error]*/ //~ WARNING `[error]` cannot be resolved
+ * time to introduce a link [error]*/ //~ WARNING `error`
 pub struct A;
 
 /**
  * # for example,
  *
- * time to introduce a link [error] //~ WARNING `[error]` cannot be resolved
+ * time to introduce a link [error] //~ WARNING `error`
  */
 pub struct B;
 
-#[doc = "single line [error]"] //~ WARNING `[error]` cannot be resolved
+#[doc = "single line [error]"] //~ WARNING `error`
 pub struct C;
 
-#[doc = "single line with \"escaping\" [error]"] //~ WARNING `[error]` cannot be resolved
+#[doc = "single line with \"escaping\" [error]"] //~ WARNING `error`
 pub struct D;
 
-/// Item docs. //~ WARNING `[error]` cannot be resolved
+/// Item docs. //~ WARNING `error`
 #[doc="Hello there!"]
 /// [error]
 pub struct E;
 
 ///
-/// docs [error1] //~ WARNING `[error1]` cannot be resolved
+/// docs [error1] //~ WARNING `error1`
 
-/// docs [error2] //~ WARNING `[error2]` cannot be resolved
+/// docs [error2] //~ WARNING `error2`
 ///
 pub struct F;
index 914a19fc536c7f185e6f9126f4b09fe11e1b4ef8..81931399c240a87f29cfa8a5b7aaf658be4c95f9 100644 (file)
@@ -1,77 +1,77 @@
-warning: `[Foo::baz]` cannot be resolved, ignoring it.
+warning: unresolved link to `Foo::baz`
   --> $DIR/intra-links-warning.rs:3:23
    |
 LL |        //! Test with [Foo::baz], [Bar::foo], ...
-   |                       ^^^^^^^^ cannot be resolved, ignoring
+   |                       ^^^^^^^^ unresolved link
    |
    = note: `#[warn(intra_doc_link_resolution_failure)]` on by default
-   = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
-warning: `[Bar::foo]` cannot be resolved, ignoring it.
+warning: unresolved link to `Bar::foo`
   --> $DIR/intra-links-warning.rs:3:35
    |
 LL |        //! Test with [Foo::baz], [Bar::foo], ...
-   |                                   ^^^^^^^^ cannot be resolved, ignoring
+   |                                   ^^^^^^^^ unresolved link
    |
-   = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
-warning: `[Uniooon::X]` cannot be resolved, ignoring it.
+warning: unresolved link to `Uniooon::X`
   --> $DIR/intra-links-warning.rs:6:13
    |
 LL |      //! , [Uniooon::X] and [Qux::Z].
-   |             ^^^^^^^^^^ cannot be resolved, ignoring
+   |             ^^^^^^^^^^ unresolved link
    |
-   = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
-warning: `[Qux::Z]` cannot be resolved, ignoring it.
+warning: unresolved link to `Qux::Z`
   --> $DIR/intra-links-warning.rs:6:30
    |
 LL |      //! , [Uniooon::X] and [Qux::Z].
-   |                              ^^^^^^ cannot be resolved, ignoring
+   |                              ^^^^^^ unresolved link
    |
-   = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
-warning: `[Uniooon::X]` cannot be resolved, ignoring it.
+warning: unresolved link to `Uniooon::X`
   --> $DIR/intra-links-warning.rs:10:14
    |
 LL |       //! , [Uniooon::X] and [Qux::Z].
-   |              ^^^^^^^^^^ cannot be resolved, ignoring
+   |              ^^^^^^^^^^ unresolved link
    |
-   = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
-warning: `[Qux::Z]` cannot be resolved, ignoring it.
+warning: unresolved link to `Qux::Z`
   --> $DIR/intra-links-warning.rs:10:31
    |
 LL |       //! , [Uniooon::X] and [Qux::Z].
-   |                               ^^^^^^ cannot be resolved, ignoring
+   |                               ^^^^^^ unresolved link
    |
-   = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
-warning: `[Qux:Y]` cannot be resolved, ignoring it.
+warning: unresolved link to `Qux:Y`
   --> $DIR/intra-links-warning.rs:14:13
    |
 LL |        /// [Qux:Y]
-   |             ^^^^^ cannot be resolved, ignoring
+   |             ^^^^^ unresolved link
    |
-   = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
-warning: `[error]` cannot be resolved, ignoring it.
+warning: unresolved link to `error`
   --> $DIR/intra-links-warning.rs:58:30
    |
 LL |  * time to introduce a link [error]*/
-   |                              ^^^^^ cannot be resolved, ignoring
+   |                              ^^^^^ unresolved link
    |
-   = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
-warning: `[error]` cannot be resolved, ignoring it.
+warning: unresolved link to `error`
   --> $DIR/intra-links-warning.rs:64:30
    |
 LL |  * time to introduce a link [error]
-   |                              ^^^^^ cannot be resolved, ignoring
+   |                              ^^^^^ unresolved link
    |
-   = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
-warning: `[error]` cannot be resolved, ignoring it.
+warning: unresolved link to `error`
   --> $DIR/intra-links-warning.rs:68:1
    |
 LL | #[doc = "single line [error]"]
@@ -81,9 +81,9 @@ LL | #[doc = "single line [error]"]
            
            single line [error]
                         ^^^^^
-   = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
-warning: `[error]` cannot be resolved, ignoring it.
+warning: unresolved link to `error`
   --> $DIR/intra-links-warning.rs:71:1
    |
 LL | #[doc = "single line with \"escaping\" [error]"]
@@ -93,9 +93,9 @@ LL | #[doc = "single line with \"escaping\" [error]"]
            
            single line with "escaping" [error]
                                         ^^^^^
-   = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
-warning: `[error]` cannot be resolved, ignoring it.
+warning: unresolved link to `error`
   --> $DIR/intra-links-warning.rs:74:1
    |
 LL | / /// Item docs.
@@ -107,49 +107,49 @@ LL | | /// [error]
            
            [error]
             ^^^^^
-   = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
-warning: `[error1]` cannot be resolved, ignoring it.
+warning: unresolved link to `error1`
   --> $DIR/intra-links-warning.rs:80:11
    |
 LL | /// docs [error1]
-   |           ^^^^^^ cannot be resolved, ignoring
+   |           ^^^^^^ unresolved link
    |
-   = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
-warning: `[error2]` cannot be resolved, ignoring it.
+warning: unresolved link to `error2`
   --> $DIR/intra-links-warning.rs:82:11
    |
 LL | /// docs [error2]
-   |           ^^^^^^ cannot be resolved, ignoring
+   |           ^^^^^^ unresolved link
    |
-   = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
-warning: `[BarA]` cannot be resolved, ignoring it.
+warning: unresolved link to `BarA`
   --> $DIR/intra-links-warning.rs:21:10
    |
 LL | /// bar [BarA] bar
-   |          ^^^^ cannot be resolved, ignoring
+   |          ^^^^ unresolved link
    |
-   = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
-warning: `[BarB]` cannot be resolved, ignoring it.
+warning: unresolved link to `BarB`
   --> $DIR/intra-links-warning.rs:27:9
    |
 LL |  * bar [BarB] bar
-   |         ^^^^ cannot be resolved, ignoring
+   |         ^^^^ unresolved link
    |
-   = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
-warning: `[BarC]` cannot be resolved, ignoring it.
+warning: unresolved link to `BarC`
   --> $DIR/intra-links-warning.rs:34:6
    |
 LL | bar [BarC] bar
-   |      ^^^^ cannot be resolved, ignoring
+   |      ^^^^ unresolved link
    |
-   = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
-warning: `[BarD]` cannot be resolved, ignoring it.
+warning: unresolved link to `BarD`
   --> $DIR/intra-links-warning.rs:45:1
    |
 LL | #[doc = "Foo\nbar [BarD] bar\nbaz"]
@@ -159,9 +159,9 @@ LL | #[doc = "Foo\nbar [BarD] bar\nbaz"]
            
            bar [BarD] bar
                 ^^^^
-   = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
-warning: `[BarF]` cannot be resolved, ignoring it.
+warning: unresolved link to `BarF`
   --> $DIR/intra-links-warning.rs:50:9
    |
 LL |         #[doc = $f]
@@ -174,7 +174,7 @@ LL | f!("Foo\nbar [BarF] bar\nbaz");
            
            bar [BarF] bar
                 ^^^^
-   = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
    = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 warning: 19 warnings emitted
diff --git a/src/test/rustdoc-ui/issue-74134.private.stderr b/src/test/rustdoc-ui/issue-74134.private.stderr
new file mode 100644 (file)
index 0000000..9c5cdf0
--- /dev/null
@@ -0,0 +1,11 @@
+warning: public documentation for `public_item` links to private item `PrivateType`
+  --> $DIR/issue-74134.rs:19:10
+   |
+LL |     /// [`PrivateType`]
+   |          ^^^^^^^^^^^^^ this item is private
+   |
+   = note: `#[warn(intra_doc_link_resolution_failure)]` on by default
+   = note: this link resolves only because you passed `--document-private-items`, but will break without
+
+warning: 1 warning emitted
+
index 03f95f19d326e7b531896f9e2fa56e59de9f6343..ff2951d864e642e6dd57f13068f1bfec40f50e67 100644 (file)
@@ -1,10 +1,11 @@
-warning: `[PrivateType]` public documentation for `public_item` links to a private item
+warning: public documentation for `public_item` links to private item `PrivateType`
   --> $DIR/issue-74134.rs:19:10
    |
 LL |     /// [`PrivateType`]
    |          ^^^^^^^^^^^^^ this item is private
    |
    = note: `#[warn(intra_doc_link_resolution_failure)]` on by default
+   = note: this link will resolve properly if you pass `--document-private-items`
 
 warning: 1 warning emitted
 
index d561c2dd8901502736ab1001b06b3f671b65724f..b1be9123aaf838cf4750c84dc06fb23d1f01b5cd 100644 (file)
@@ -4,7 +4,7 @@
 
 // There are 4 cases here:
 // 1. public item  -> public type:  no warning
-// 2. public item  -> private type: warning, if --document-private-items is not passed
+// 2. public item  -> private type: warning
 // 3. private item -> public type:  no warning
 // 4. private item -> private type: no warning
 // All 4 cases are tested with and without --document-private-items.
@@ -17,7 +17,7 @@
 pub struct Public {
     /// [`PublicType`]
     /// [`PrivateType`]
-    //[public]~^ WARNING public documentation for `public_item` links to a private
+    //~^ WARNING public documentation for `public_item` links to private item `PrivateType`
     pub public_item: u32,
 
     /// [`PublicType`]
index 06766db5335a1eeb4d3c2ec7da0f1db03cac6e7f..e58c8b12f68cb8550ef9bd0c43bbe40f54554175 100644 (file)
@@ -11,7 +11,7 @@
 /// ```
 /// println!("sup");
 /// ```
-pub fn link_error() {} //~^^^^^ ERROR cannot be resolved, ignoring it
+pub fn link_error() {} //~^^^^^ ERROR unresolved link to `error`
 
 /// wait, this doesn't have a doctest?
 pub fn no_doctest() {} //~^ ERROR missing code example in this documentation
index 852c9120e0bf9ca141b9e7cbdca9369a74020965..14d72e9aad3ba8cfaa9a21db2ab5dd41fccc9569 100644 (file)
@@ -15,11 +15,11 @@ LL | #![deny(rustdoc)]
    |         ^^^^^^^
    = note: `#[deny(private_doc_tests)]` implied by `#[deny(rustdoc)]`
 
-error: `[error]` cannot be resolved, ignoring it.
+error: unresolved link to `error`
   --> $DIR/lint-group.rs:9:29
    |
 LL | /// what up, let's make an [error]
-   |                             ^^^^^ cannot be resolved, ignoring
+   |                             ^^^^^ unresolved link
    |
 note: the lint level is defined here
   --> $DIR/lint-group.rs:7:9
@@ -27,7 +27,7 @@ note: the lint level is defined here
 LL | #![deny(rustdoc)]
    |         ^^^^^^^
    = note: `#[deny(intra_doc_link_resolution_failure)]` implied by `#[deny(rustdoc)]`
-   = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
 error: missing code example in this documentation
   --> $DIR/lint-group.rs:16:1
diff --git a/src/test/rustdoc/auxiliary/unstable-trait.rs b/src/test/rustdoc/auxiliary/unstable-trait.rs
new file mode 100644 (file)
index 0000000..6f06a6e
--- /dev/null
@@ -0,0 +1,26 @@
+#![feature(staged_api)]
+#![stable(feature = "private_general", since = "1.0.0")]
+
+#[unstable(feature = "private_trait", issue = "none")]
+pub trait Bar {}
+
+#[stable(feature = "private_general", since = "1.0.0")]
+pub struct Foo {
+    // nothing
+}
+
+impl Foo {
+    #[stable(feature = "private_general", since = "1.0.0")]
+    pub fn stable_impl() {}
+}
+
+impl Foo {
+    #[unstable(feature = "private_trait", issue = "none")]
+    pub fn bar() {}
+
+    #[stable(feature = "private_general", since = "1.0.0")]
+    pub fn bar2() {}
+}
+
+#[stable(feature = "private_general", since = "1.0.0")]
+impl Bar for Foo {}
diff --git a/src/test/rustdoc/hide-unstable-trait.rs b/src/test/rustdoc/hide-unstable-trait.rs
new file mode 100644 (file)
index 0000000..c30d6ed
--- /dev/null
@@ -0,0 +1,11 @@
+// aux-build:unstable-trait.rs
+
+#![crate_name = "foo"]
+#![feature(private_trait)]
+
+extern crate unstable_trait;
+
+// @has foo/struct.Foo.html 'bar'
+// @has foo/struct.Foo.html 'bar2'
+#[doc(inline)]
+pub use unstable_trait::Foo;
index b5038a58249d2b7c5b20fc07765386988428ae53..1fd514c6173290945a775d5873b56f72124593a8 100644 (file)
@@ -1,10 +1,8 @@
 // aux-build:rlib-crate-test.rs
-// ignore-tidy-linelength
 // ignore-cross-compile gives a different error message
 
 #![feature(plugin)]
 #![plugin(rlib_crate_test)]
-//~^ ERROR: plugin `rlib_crate_test` only found in rlib format, but must be available in dylib format
-//~| WARN use of deprecated attribute `plugin`: compiler plugins are deprecated
+//~^ ERROR: plugin `rlib_crate_test` only found in rlib format, but must be available in dylib
 
 fn main() {}
index 342663312a8539708136fcf6b84ff25d70a45f00..7b31f28a26e7d3555411b265c23af8d0fd6fb50c 100644 (file)
@@ -1,16 +1,8 @@
 error[E0457]: plugin `rlib_crate_test` only found in rlib format, but must be available in dylib format
-  --> $DIR/macro-crate-rlib.rs:6:11
+  --> $DIR/macro-crate-rlib.rs:5:11
    |
 LL | #![plugin(rlib_crate_test)]
    |           ^^^^^^^^^^^^^^^
 
-warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
-  --> $DIR/macro-crate-rlib.rs:6:1
-   |
-LL | #![plugin(rlib_crate_test)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
-   |
-   = note: `#[warn(deprecated)]` on by default
-
-error: aborting due to previous error; 1 warning emitted
+error: aborting due to previous error
 
index 8c6073e2f7a4918bd468ebad139420b4a70487f3..1eeb01ccc846e9d82691725254e58eac7f0830e4 100644 (file)
@@ -35,7 +35,7 @@ fn baz<'a,'b>(x: &'a u32, y: &'b u32) -> (&'a u32, &'b u32) {
 
 #[cfg(transmute)] // one instantiations: BAD
 fn baz<'a,'b>(x: &'a u32) -> &'static u32 {
-   bar(foo, x) //[transmute]~ ERROR E0495
+   bar(foo, x) //[transmute]~ ERROR E0759
 }
 
 #[cfg(krisskross)] // two instantiations, mixing and matching: BAD
index 5ea98dcd4a972a194e603ec6067d98dfb659b873..0be9b37263a48bbea3847ef93b55c4fa4b636950 100644 (file)
@@ -1,26 +1,11 @@
-error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
+error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
   --> $DIR/project-fn-ret-contravariant.rs:38:8
    |
-LL |    bar(foo, x)
-   |        ^^^
-   |
-note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 37:8...
-  --> $DIR/project-fn-ret-contravariant.rs:37:8
-   |
 LL | fn baz<'a,'b>(x: &'a u32) -> &'static u32 {
-   |        ^^
-note: ...so that reference does not outlive borrowed content
-  --> $DIR/project-fn-ret-contravariant.rs:38:13
-   |
-LL |    bar(foo, x)
-   |             ^
-   = note: but, the lifetime must be valid for the static lifetime...
-note: ...so that reference does not outlive borrowed content
-  --> $DIR/project-fn-ret-contravariant.rs:38:4
-   |
+   |                  ------- this data with lifetime `'a`...
 LL |    bar(foo, x)
-   |    ^^^^^^^^^^^
+   |    ----^^^---- ...is captured and required to live as long as `'static` here
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0495`.
+For more information about this error, try `rustc --explain E0759`.
index 0034d796826de662b16e8aec226e8e3bfcaf8ada..08d864f7836d20467ad4292d937f2809f154b089 100644 (file)
@@ -46,7 +46,7 @@ fn baz<'a, 'b>(x: Type<'a>) -> Type<'static> {
     // Cannot instantiate `foo` with any lifetime other than `'a`,
     // since it is provided as input.
 
-    bar(foo, x) //[transmute]~ ERROR E0495
+    bar(foo, x) //[transmute]~ ERROR E0759
 }
 
 #[cfg(krisskross)] // two instantiations, mixing and matching: BAD
index ef57f9e0bc480049ba6ed9bfab821693693f1e1f..0a44864b249551b3a03d6f5f792e7f49c00c13ab 100644 (file)
@@ -1,30 +1,12 @@
-error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
+error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
   --> $DIR/project-fn-ret-invariant.rs:49:9
    |
-LL |     bar(foo, x)
-   |         ^^^
-   |
-note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 45:8...
-  --> $DIR/project-fn-ret-invariant.rs:45:8
-   |
 LL | fn baz<'a, 'b>(x: Type<'a>) -> Type<'static> {
-   |        ^^
-note: ...so that the expression is assignable
-  --> $DIR/project-fn-ret-invariant.rs:49:14
-   |
-LL |     bar(foo, x)
-   |              ^
-   = note: expected `Type<'_>`
-              found `Type<'a>`
-   = note: but, the lifetime must be valid for the static lifetime...
-note: ...so that the expression is assignable
-  --> $DIR/project-fn-ret-invariant.rs:49:5
-   |
+   |                   -------- this data with lifetime `'a`...
+...
 LL |     bar(foo, x)
-   |     ^^^^^^^^^^^
-   = note: expected `Type<'static>`
-              found `Type<'_>`
+   |     ----^^^---- ...is captured and required to live as long as `'static` here
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0495`.
+For more information about this error, try `rustc --explain E0759`.
diff --git a/src/test/ui/associated-types/issue-62200.rs b/src/test/ui/associated-types/issue-62200.rs
new file mode 100644 (file)
index 0000000..9d18690
--- /dev/null
@@ -0,0 +1,15 @@
+struct S {}
+
+trait T<'a> {
+    type A;
+}
+
+impl T<'_> for S {
+    type A = u32;
+}
+
+fn foo(x: impl Fn(<S as T<'_>>::A) -> <S as T<'_>>::A) {}
+//~^ ERROR binding for associated type `Output` references an anonymous lifetime
+//~^^ NOTE lifetimes appearing in an associated type are not considered constrained
+
+fn main() {}
diff --git a/src/test/ui/associated-types/issue-62200.stderr b/src/test/ui/associated-types/issue-62200.stderr
new file mode 100644 (file)
index 0000000..f14cd81
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0582]: binding for associated type `Output` references an anonymous lifetime, which does not appear in the trait input types
+  --> $DIR/issue-62200.rs:11:39
+   |
+LL | fn foo(x: impl Fn(<S as T<'_>>::A) -> <S as T<'_>>::A) {}
+   |                                       ^^^^^^^^^^^^^^^
+   |
+   = note: lifetimes appearing in an associated type are not considered constrained
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0582`.
index ea482d3667e2b575bc5c8fb9ef9b8d76db8c296a..66ebbd83ffa9e4546a0fcfd06b437a658b245dc1 100644 (file)
@@ -9,7 +9,7 @@ async fn foo<F>(fun: F)
 struct Struct;
 
 impl Struct {
-    pub async fn run_dummy_fn(&self) { //~ ERROR cannot infer
+    pub async fn run_dummy_fn(&self) { //~ ERROR E0759
         foo(|| self.bar()).await;
     }
 
index 0f58b158904db0a2fb3aa8fdb2e5c935c07e2707..56a28d904b91d57f29f79c8f6dba321a250422a5 100644 (file)
@@ -1,4 +1,4 @@
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
   --> $DIR/issue-62097.rs:12:31
    |
 LL |     pub async fn run_dummy_fn(&self) {
index 21368fad3b05848a47ae08cfaa1c02f3e006e264..3c4f9a1f5ee2c3c0a433022517176f4abc0b7c56 100644 (file)
@@ -1,5 +1,5 @@
 // run-pass
-// compile-flags: -Z control-flow-guard
+// compile-flags: -C control-flow-guard
 
 pub fn main() {
     println!("hello, world");
diff --git a/src/test/ui/const-generics/const-argument-non-static-lifetime.rs b/src/test/ui/const-generics/const-argument-non-static-lifetime.rs
new file mode 100644 (file)
index 0000000..bc09ba2
--- /dev/null
@@ -0,0 +1,17 @@
+// run-pass
+
+#![feature(const_generics)]
+//~^ WARN the feature `const_generics` is incomplete
+#![allow(dead_code)]
+
+fn test<const N: usize>() {}
+
+fn wow<'a>() -> &'a () {
+    test::<{
+        let _: &'a ();
+        3
+    }>();
+    &()
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/const-argument-non-static-lifetime.stderr b/src/test/ui/const-generics/const-argument-non-static-lifetime.stderr
new file mode 100644 (file)
index 0000000..53a7550
--- /dev/null
@@ -0,0 +1,11 @@
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/const-argument-non-static-lifetime.rs:3:12
+   |
+LL | #![feature(const_generics)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/const-generics/defaults/wrong-order.rs b/src/test/ui/const-generics/defaults/wrong-order.rs
new file mode 100644 (file)
index 0000000..7f17c63
--- /dev/null
@@ -0,0 +1,8 @@
+#![feature(const_generics)] //~ WARN the feature `const_generics` is incomplete
+
+struct A<T = u32, const N: usize> {
+    //~^ ERROR type parameters with a default must be trailing
+    arg: T,
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/defaults/wrong-order.stderr b/src/test/ui/const-generics/defaults/wrong-order.stderr
new file mode 100644 (file)
index 0000000..283f665
--- /dev/null
@@ -0,0 +1,19 @@
+error: type parameters with a default must be trailing
+  --> $DIR/wrong-order.rs:3:10
+   |
+LL | struct A<T = u32, const N: usize> {
+   |          ^
+   |
+   = note: using type defaults and const parameters in the same parameter list is currently not permitted
+
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/wrong-order.rs:1:12
+   |
+LL | #![feature(const_generics)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+
+error: aborting due to previous error; 1 warning emitted
+
diff --git a/src/test/ui/const-generics/issues/issue-62878.rs b/src/test/ui/const-generics/issues/issue-62878.rs
new file mode 100644 (file)
index 0000000..ccc05fd
--- /dev/null
@@ -0,0 +1,11 @@
+#![feature(const_generics)] //~ WARN the feature `const_generics` is incomplete
+
+fn foo<const N: usize, const A: [u8; N]>() {}
+//~^ ERROR the type of const parameters must not
+
+fn main() {
+    foo::<_, {[1]}>();
+    //~^ ERROR wrong number of const arguments
+    //~| ERROR wrong number of type arguments
+    //~| ERROR mismatched types
+}
diff --git a/src/test/ui/const-generics/issues/issue-62878.stderr b/src/test/ui/const-generics/issues/issue-62878.stderr
new file mode 100644 (file)
index 0000000..fe0990d
--- /dev/null
@@ -0,0 +1,37 @@
+error[E0770]: the type of const parameters must not depend on other generic parameters
+  --> $DIR/issue-62878.rs:3:38
+   |
+LL | fn foo<const N: usize, const A: [u8; N]>() {}
+   |                                      ^ the type must not depend on the parameter `N`
+
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-62878.rs:1:12
+   |
+LL | #![feature(const_generics)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+
+error[E0107]: wrong number of const arguments: expected 2, found 1
+  --> $DIR/issue-62878.rs:7:5
+   |
+LL |     foo::<_, {[1]}>();
+   |     ^^^^^^^^^^^^^^^ expected 2 const arguments
+
+error[E0107]: wrong number of type arguments: expected 0, found 1
+  --> $DIR/issue-62878.rs:7:11
+   |
+LL |     foo::<_, {[1]}>();
+   |           ^ unexpected type argument
+
+error[E0308]: mismatched types
+  --> $DIR/issue-62878.rs:7:15
+   |
+LL |     foo::<_, {[1]}>();
+   |               ^^^ expected `usize`, found array `[{integer}; 1]`
+
+error: aborting due to 4 previous errors; 1 warning emitted
+
+Some errors have detailed explanations: E0107, E0308, E0770.
+For more information about an error, try `rustc --explain E0107`.
diff --git a/src/test/ui/consts/const_unsafe_unreachable.rs b/src/test/ui/consts/const_unsafe_unreachable.rs
new file mode 100644 (file)
index 0000000..cfed6e5
--- /dev/null
@@ -0,0 +1,17 @@
+// run-pass
+
+#![feature(const_fn)]
+#![feature(const_unreachable_unchecked)]
+
+const unsafe fn foo(x: bool) -> bool {
+    match x {
+        true => true,
+        false => std::hint::unreachable_unchecked(),
+    }
+}
+
+const BAR: bool = unsafe { foo(true) };
+
+fn main() {
+  assert_eq!(BAR, true);
+}
diff --git a/src/test/ui/consts/const_unsafe_unreachable_ub.rs b/src/test/ui/consts/const_unsafe_unreachable_ub.rs
new file mode 100644 (file)
index 0000000..11920d8
--- /dev/null
@@ -0,0 +1,20 @@
+// build-fail
+
+#![feature(const_fn)]
+#![feature(const_unreachable_unchecked)]
+
+const unsafe fn foo(x: bool) -> bool {
+    match x {
+        true => true,
+        false => std::hint::unreachable_unchecked(),
+    }
+}
+
+#[warn(const_err)]
+const BAR: bool = unsafe { foo(false) };
+
+fn main() {
+  assert_eq!(BAR, true);
+  //~^ ERROR E0080
+  //~| ERROR erroneous constant
+}
diff --git a/src/test/ui/consts/const_unsafe_unreachable_ub.stderr b/src/test/ui/consts/const_unsafe_unreachable_ub.stderr
new file mode 100644 (file)
index 0000000..3ef8043
--- /dev/null
@@ -0,0 +1,44 @@
+warning: any use of this value will cause an error
+  --> $SRC_DIR/libcore/hint.rs:LL:COL
+   |
+LL |     unsafe { intrinsics::unreachable() }
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |              |
+   |              entering unreachable code
+   |              inside `std::hint::unreachable_unchecked` at $SRC_DIR/libcore/hint.rs:LL:COL
+   |              inside `foo` at $DIR/const_unsafe_unreachable_ub.rs:9:18
+   |              inside `BAR` at $DIR/const_unsafe_unreachable_ub.rs:14:28
+   | 
+  ::: $DIR/const_unsafe_unreachable_ub.rs:14:1
+   |
+LL | const BAR: bool = unsafe { foo(false) };
+   | ----------------------------------------
+   |
+note: the lint level is defined here
+  --> $DIR/const_unsafe_unreachable_ub.rs:13:8
+   |
+LL | #[warn(const_err)]
+   |        ^^^^^^^^^
+
+error[E0080]: evaluation of constant expression failed
+  --> $DIR/const_unsafe_unreachable_ub.rs:17:3
+   |
+LL |   assert_eq!(BAR, true);
+   |   ^^^^^^^^^^^---^^^^^^^^
+   |              |
+   |              referenced constant has errors
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: erroneous constant used
+  --> $DIR/const_unsafe_unreachable_ub.rs:17:3
+   |
+LL |   assert_eq!(BAR, true);
+   |   ^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors
+   |
+   = note: `#[deny(const_err)]` on by default
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 2 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/issue-73976-monomorphic.rs b/src/test/ui/consts/issue-73976-monomorphic.rs
new file mode 100644 (file)
index 0000000..7706a97
--- /dev/null
@@ -0,0 +1,36 @@
+// check-pass
+//
+// This test is complement to the test in issue-73976-polymorphic.rs.
+// In that test we ensure that polymorphic use of type_id and type_name in patterns
+// will be properly rejected. This test will ensure that monomorphic use of these
+// would not be wrongly rejected in patterns.
+
+#![feature(const_type_id)]
+#![feature(const_type_name)]
+
+use std::any::{self, TypeId};
+
+pub struct GetTypeId<T>(T);
+
+impl<T: 'static> GetTypeId<T> {
+    pub const VALUE: TypeId = TypeId::of::<T>();
+}
+
+const fn check_type_id<T: 'static>() -> bool {
+    matches!(GetTypeId::<T>::VALUE, GetTypeId::<usize>::VALUE)
+}
+
+pub struct GetTypeNameLen<T>(T);
+
+impl<T: 'static> GetTypeNameLen<T> {
+    pub const VALUE: usize = any::type_name::<T>().len();
+}
+
+const fn check_type_name_len<T: 'static>() -> bool {
+    matches!(GetTypeNameLen::<T>::VALUE, GetTypeNameLen::<usize>::VALUE)
+}
+
+fn main() {
+    assert!(check_type_id::<usize>());
+    assert!(check_type_name_len::<usize>());
+}
diff --git a/src/test/ui/consts/issue-73976-polymorphic.rs b/src/test/ui/consts/issue-73976-polymorphic.rs
new file mode 100644 (file)
index 0000000..28b8451
--- /dev/null
@@ -0,0 +1,40 @@
+// This test is from #73976. We previously did not check if a type is monomorphized
+// before calculating its type id, which leads to the bizzare behaviour below that
+// TypeId of a generic type does not match itself.
+//
+// This test case should either run-pass or be rejected at compile time.
+// Currently we just disallow this usage and require pattern is monomorphic.
+
+#![feature(const_type_id)]
+#![feature(const_type_name)]
+
+use std::any::{self, TypeId};
+
+pub struct GetTypeId<T>(T);
+
+impl<T: 'static> GetTypeId<T> {
+    pub const VALUE: TypeId = TypeId::of::<T>();
+}
+
+const fn check_type_id<T: 'static>() -> bool {
+    matches!(GetTypeId::<T>::VALUE, GetTypeId::<T>::VALUE)
+    //~^ ERROR could not evaluate constant pattern
+    //~| ERROR could not evaluate constant pattern
+}
+
+pub struct GetTypeNameLen<T>(T);
+
+impl<T: 'static> GetTypeNameLen<T> {
+    pub const VALUE: usize = any::type_name::<T>().len();
+}
+
+const fn check_type_name_len<T: 'static>() -> bool {
+    matches!(GetTypeNameLen::<T>::VALUE, GetTypeNameLen::<T>::VALUE)
+    //~^ ERROR could not evaluate constant pattern
+    //~| ERROR could not evaluate constant pattern
+}
+
+fn main() {
+    assert!(check_type_id::<usize>());
+    assert!(check_type_name_len::<usize>());
+}
diff --git a/src/test/ui/consts/issue-73976-polymorphic.stderr b/src/test/ui/consts/issue-73976-polymorphic.stderr
new file mode 100644 (file)
index 0000000..c90ce2b
--- /dev/null
@@ -0,0 +1,26 @@
+error: could not evaluate constant pattern
+  --> $DIR/issue-73976-polymorphic.rs:20:37
+   |
+LL |     matches!(GetTypeId::<T>::VALUE, GetTypeId::<T>::VALUE)
+   |                                     ^^^^^^^^^^^^^^^^^^^^^
+
+error: could not evaluate constant pattern
+  --> $DIR/issue-73976-polymorphic.rs:32:42
+   |
+LL |     matches!(GetTypeNameLen::<T>::VALUE, GetTypeNameLen::<T>::VALUE)
+   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: could not evaluate constant pattern
+  --> $DIR/issue-73976-polymorphic.rs:20:37
+   |
+LL |     matches!(GetTypeId::<T>::VALUE, GetTypeId::<T>::VALUE)
+   |                                     ^^^^^^^^^^^^^^^^^^^^^
+
+error: could not evaluate constant pattern
+  --> $DIR/issue-73976-polymorphic.rs:32:42
+   |
+LL |     matches!(GetTypeNameLen::<T>::VALUE, GetTypeNameLen::<T>::VALUE)
+   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/ui/error-codes/E0771.rs b/src/test/ui/error-codes/E0771.rs
new file mode 100644 (file)
index 0000000..ba35927
--- /dev/null
@@ -0,0 +1,8 @@
+#![feature(const_generics)]
+//~^ WARN the feature `const_generics` is incomplete
+
+fn function_with_str<'a, const STRING: &'a str>() {} //~ ERROR E0771
+
+fn main() {
+    function_with_str::<"Hello, world!">()
+}
diff --git a/src/test/ui/error-codes/E0771.stderr b/src/test/ui/error-codes/E0771.stderr
new file mode 100644 (file)
index 0000000..60220be
--- /dev/null
@@ -0,0 +1,20 @@
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/E0771.rs:1:12
+   |
+LL | #![feature(const_generics)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+
+error[E0771]: use of non-static lifetime `'a` in const generic
+  --> $DIR/E0771.rs:4:41
+   |
+LL | fn function_with_str<'a, const STRING: &'a str>() {}
+   |                                         ^^
+   |
+   = note: for more information, see issue #74052 <https://github.com/rust-lang/rust/issues/74052>
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0771`.
index cc00737ab591d58231daafe8bc43e5ac45fed0ec..3ba124159e0002d41d448fa6bc885da5ffc118ad 100644 (file)
@@ -1,6 +1,6 @@
 // run-pass
 #![allow(unused_variables)]
-// compile-flags: --extern LooksLikeExternCrate
+// compile-flags: --extern LooksLikeExternCrate=/path/to/nowhere
 
 mod m {
     pub struct LooksLikeExternCrate;
index d4ad706d01bc2359d73e7198f802bf7617d4aacc..89210fdf137e0d169203d61f79f1b6ff982686e0 100644 (file)
@@ -17,7 +17,7 @@ fn static_val<T: StaticTrait>(_: T) {
 }
 
 fn with_dyn_debug_static<'a>(x: Box<dyn Debug + 'a>) {
-    static_val(x); //~ ERROR cannot infer
+    static_val(x); //~ ERROR E0759
 }
 
 fn not_static_val<T: NotStaticTrait>(_: T) {
index 268008c211129e704f6a5412c127a1aa1a9bf573..b3bef677d19c1c84999b011663277607a8f44ec4 100644 (file)
@@ -1,30 +1,17 @@
-error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
+error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
   --> $DIR/dyn-trait.rs:20:16
    |
-LL |     static_val(x);
-   |                ^
-   |
-note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 19:26...
-  --> $DIR/dyn-trait.rs:19:26
-   |
 LL | fn with_dyn_debug_static<'a>(x: Box<dyn Debug + 'a>) {
-   |                          ^^
-note: ...so that the expression is assignable
-  --> $DIR/dyn-trait.rs:20:16
-   |
+   |                                 ------------------- this data with lifetime `'a`...
 LL |     static_val(x);
-   |                ^
-   = note: expected `std::boxed::Box<dyn std::fmt::Debug>`
-              found `std::boxed::Box<(dyn std::fmt::Debug + 'a)>`
-   = note: but, the lifetime must be valid for the static lifetime...
-note: ...so that the types are compatible
+   |                ^ ...is captured here...
+   |
+note: ...and is required to live as long as `'static` here
   --> $DIR/dyn-trait.rs:20:5
    |
 LL |     static_val(x);
    |     ^^^^^^^^^^
-   = note: expected `StaticTrait`
-              found `StaticTrait`
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0495`.
+For more information about this error, try `rustc --explain E0759`.
index 3b339c5c3d7fc69a75c6a1f00338b8b8a748f2f2..4372de245078fc930be3cb4a27dd1f30e337be7d 100644 (file)
@@ -12,7 +12,7 @@ LL | fn elided(x: &i32) -> impl Copy + '_ { x }
    |                       ^^^^^^^^^^^^^^
 
 error: lifetime may not live long enough
-  --> $DIR/must_outlive_least_region_or_bound.rs:6:32
+  --> $DIR/must_outlive_least_region_or_bound.rs:5:32
    |
 LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x }
    |             --                 ^^^^^^^^^ opaque type requires that `'a` must outlive `'static`
@@ -26,7 +26,7 @@ LL | fn explicit<'a>(x: &'a i32) -> impl Copy + 'a { x }
    |                                ^^^^^^^^^^^^^^
 
 error: lifetime may not live long enough
-  --> $DIR/must_outlive_least_region_or_bound.rs:9:46
+  --> $DIR/must_outlive_least_region_or_bound.rs:7:46
    |
 LL | fn elided2(x: &i32) -> impl Copy + 'static { x }
    |               -                              ^ returning this value requires that `'1` must outlive `'static`
@@ -36,7 +36,7 @@ LL | fn elided2(x: &i32) -> impl Copy + 'static { x }
    = help: consider replacing `'1` with `'static`
 
 error: lifetime may not live long enough
-  --> $DIR/must_outlive_least_region_or_bound.rs:12:55
+  --> $DIR/must_outlive_least_region_or_bound.rs:9:55
    |
 LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x }
    |              -- lifetime `'a` defined here            ^ returning this value requires that `'a` must outlive `'static`
@@ -45,7 +45,7 @@ LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x }
    = help: consider replacing `'a` with `'static`
 
 error[E0621]: explicit lifetime required in the type of `x`
-  --> $DIR/must_outlive_least_region_or_bound.rs:15:41
+  --> $DIR/must_outlive_least_region_or_bound.rs:11:41
    |
 LL | fn foo<'a>(x: &i32) -> impl Copy + 'a { x }
    |               ----                      ^ lifetime `'a` required
@@ -53,7 +53,7 @@ LL | fn foo<'a>(x: &i32) -> impl Copy + 'a { x }
    |               help: add explicit lifetime `'a` to the type of `x`: `&'a i32`
 
 error: lifetime may not live long enough
-  --> $DIR/must_outlive_least_region_or_bound.rs:30:24
+  --> $DIR/must_outlive_least_region_or_bound.rs:22:24
    |
 LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) }
    |               -        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ opaque type requires that `'1` must outlive `'static`
@@ -61,7 +61,7 @@ LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) }
    |               let's call the lifetime of this reference `'1`
 
 error: lifetime may not live long enough
-  --> $DIR/must_outlive_least_region_or_bound.rs:37:69
+  --> $DIR/must_outlive_least_region_or_bound.rs:28:69
    |
 LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
    |               -- lifetime `'a` defined here                         ^ returning this value requires that `'a` must outlive `'static`
@@ -70,7 +70,7 @@ LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
    = help: consider replacing `'a` with `'static`
 
 error: lifetime may not live long enough
-  --> $DIR/must_outlive_least_region_or_bound.rs:42:61
+  --> $DIR/must_outlive_least_region_or_bound.rs:32:61
    |
 LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) {
    |                          --  -- lifetime `'b` defined here  ^^^^^^^^^^^^^^^^ opaque type requires that `'b` must outlive `'a`
@@ -80,7 +80,7 @@ LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32
    = help: consider adding the following bound: `'b: 'a`
 
 error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/must_outlive_least_region_or_bound.rs:47:51
+  --> $DIR/must_outlive_least_region_or_bound.rs:37:51
    |
 LL | fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static {
    |                                                   ^^^^^^^^^^^^^^^^^^^^
index 9bf86fa66cdeda4c7ccd2cd6a55d18a2fbdc570a..51f488e45a6f3d14ce6cea95d318c3f06e126ef0 100644 (file)
@@ -1,41 +1,31 @@
 use std::fmt::Debug;
 
-fn elided(x: &i32) -> impl Copy { x }
-//~^ ERROR cannot infer an appropriate lifetime
+fn elided(x: &i32) -> impl Copy { x } //~ ERROR E0759
 
-fn explicit<'a>(x: &'a i32) -> impl Copy { x }
-//~^ ERROR cannot infer an appropriate lifetime
+fn explicit<'a>(x: &'a i32) -> impl Copy { x } //~ ERROR E0759
 
-fn elided2(x: &i32) -> impl Copy + 'static { x }
-//~^ ERROR cannot infer an appropriate lifetime
+fn elided2(x: &i32) -> impl Copy + 'static { x } //~ ERROR E0759
 
-fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x }
-//~^ ERROR cannot infer an appropriate lifetime
+fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x } //~ ERROR E0759
 
 fn foo<'a>(x: &i32) -> impl Copy + 'a { x }
 //~^ ERROR explicit lifetime required in the type of `x`
 
-fn elided3(x: &i32) -> Box<dyn Debug> { Box::new(x) }
-//~^ ERROR cannot infer an appropriate lifetime
+fn elided3(x: &i32) -> Box<dyn Debug> { Box::new(x) } //~ ERROR E0759
 
-fn explicit3<'a>(x: &'a i32) -> Box<dyn Debug> { Box::new(x) }
-//~^ ERROR cannot infer an appropriate lifetime
+fn explicit3<'a>(x: &'a i32) -> Box<dyn Debug> { Box::new(x) } //~ ERROR E0759
 
-fn elided4(x: &i32) -> Box<dyn Debug + 'static> { Box::new(x) }
-//~^ ERROR cannot infer an appropriate lifetime
+fn elided4(x: &i32) -> Box<dyn Debug + 'static> { Box::new(x) } //~ ERROR E0759
 
-fn explicit4<'a>(x: &'a i32) -> Box<dyn Debug + 'static> { Box::new(x) }
-//~^ ERROR cannot infer an appropriate lifetime
+fn explicit4<'a>(x: &'a i32) -> Box<dyn Debug + 'static> { Box::new(x) } //~ ERROR E0759
 
-fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) }
-//~^ ERROR cannot infer an appropriate lifetime
-//~| ERROR cannot infer an appropriate lifetime
+fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) } //~ ERROR E0759
+//~^ ERROR E0759
 
 trait LifetimeTrait<'a> {}
 impl<'a> LifetimeTrait<'a> for &'a i32 {}
 
-fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
-//~^ ERROR cannot infer an appropriate lifetime
+fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x } //~ ERROR E0759
 
 // Tests that a closure type containing 'b cannot be returned from a type where
 // only 'a was expected.
index ffadcaae08e05ed165636b369249098c140a5f37..b040889217e47032e23cfcffbd0b301ce63f31fa 100644 (file)
@@ -1,4 +1,4 @@
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
   --> $DIR/must_outlive_least_region_or_bound.rs:3:35
    |
 LL | fn elided(x: &i32) -> impl Copy { x }
@@ -16,8 +16,8 @@ help: to declare that the `impl Trait` captures data from argument `x`, you can
 LL | fn elided(x: &i32) -> impl Copy + '_ { x }
    |                                 ^^^^
 
-error[E0759]: cannot infer an appropriate lifetime
-  --> $DIR/must_outlive_least_region_or_bound.rs:6:44
+error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
+  --> $DIR/must_outlive_least_region_or_bound.rs:5:44
    |
 LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x }
    |                    -------                 ^ ...is captured here...
@@ -25,7 +25,7 @@ LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x }
    |                    this data with lifetime `'a`...
    |
 note: ...and is required to live as long as `'static` here
-  --> $DIR/must_outlive_least_region_or_bound.rs:6:32
+  --> $DIR/must_outlive_least_region_or_bound.rs:5:32
    |
 LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x }
    |                                ^^^^^^^^^
@@ -34,8 +34,8 @@ help: to declare that the `impl Trait` captures data from argument `x`, you can
 LL | fn explicit<'a>(x: &'a i32) -> impl Copy + 'a { x }
    |                                          ^^^^
 
-error[E0759]: cannot infer an appropriate lifetime
-  --> $DIR/must_outlive_least_region_or_bound.rs:9:46
+error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
+  --> $DIR/must_outlive_least_region_or_bound.rs:7:46
    |
 LL | fn elided2(x: &i32) -> impl Copy + 'static { x }
    |               ----                           ^ ...is captured here...
@@ -43,7 +43,7 @@ LL | fn elided2(x: &i32) -> impl Copy + 'static { x }
    |               this data with an anonymous lifetime `'_`...
    |
 note: ...and is required to live as long as `'static` here
-  --> $DIR/must_outlive_least_region_or_bound.rs:9:24
+  --> $DIR/must_outlive_least_region_or_bound.rs:7:24
    |
 LL | fn elided2(x: &i32) -> impl Copy + 'static { x }
    |                        ^^^^^^^^^^^^^^^^^^^
@@ -56,8 +56,8 @@ help: alternatively, add an explicit `'static` bound to this reference
 LL | fn elided2(x: &'static i32) -> impl Copy + 'static { x }
    |               ^^^^^^^^^^^^
 
-error[E0759]: cannot infer an appropriate lifetime
-  --> $DIR/must_outlive_least_region_or_bound.rs:12:55
+error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
+  --> $DIR/must_outlive_least_region_or_bound.rs:9:55
    |
 LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x }
    |                     -------                           ^ ...is captured here...
@@ -65,7 +65,7 @@ LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x }
    |                     this data with lifetime `'a`...
    |
 note: ...and is required to live as long as `'static` here
-  --> $DIR/must_outlive_least_region_or_bound.rs:12:33
+  --> $DIR/must_outlive_least_region_or_bound.rs:9:33
    |
 LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x }
    |                                 ^^^^^^^^^^^^^^^^^^^
@@ -79,15 +79,15 @@ LL | fn explicit2<'a>(x: &'static i32) -> impl Copy + 'static { x }
    |                     ^^^^^^^^^^^^
 
 error[E0621]: explicit lifetime required in the type of `x`
-  --> $DIR/must_outlive_least_region_or_bound.rs:15:24
+  --> $DIR/must_outlive_least_region_or_bound.rs:11:24
    |
 LL | fn foo<'a>(x: &i32) -> impl Copy + 'a { x }
    |               ----     ^^^^^^^^^^^^^^ lifetime `'a` required
    |               |
    |               help: add explicit lifetime `'a` to the type of `x`: `&'a i32`
 
-error[E0759]: cannot infer an appropriate lifetime
-  --> $DIR/must_outlive_least_region_or_bound.rs:30:65
+error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
+  --> $DIR/must_outlive_least_region_or_bound.rs:22:65
    |
 LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) }
    |               ---- this data with an anonymous lifetime `'_`... ^ ...is captured here, requiring it to live as long as `'static`
@@ -101,14 +101,14 @@ help: to declare that the `impl Trait` captures data from argument `x`, you can
 LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug + '_) { (Box::new(x), x) }
    |                                                    ^^^^
 
-error[E0759]: cannot infer an appropriate lifetime
-  --> $DIR/must_outlive_least_region_or_bound.rs:30:69
+error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
+  --> $DIR/must_outlive_least_region_or_bound.rs:22:69
    |
 LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) }
    |               ---- this data with an anonymous lifetime `'_`...     ^ ...is captured here...
    |
 note: ...and is required to live as long as `'static` here
-  --> $DIR/must_outlive_least_region_or_bound.rs:30:41
+  --> $DIR/must_outlive_least_region_or_bound.rs:22:41
    |
 LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) }
    |                                         ^^^^^^^^^^
@@ -121,14 +121,14 @@ help: to declare that the `impl Trait` captures data from argument `x`, you can
 LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug + '_) { (Box::new(x), x) }
    |                                                    ^^^^
 
-error[E0759]: cannot infer an appropriate lifetime
-  --> $DIR/must_outlive_least_region_or_bound.rs:37:69
+error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
+  --> $DIR/must_outlive_least_region_or_bound.rs:28:69
    |
 LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
    |                      ------- this data with lifetime `'a`...        ^ ...is captured here...
    |
 note: ...and is required to live as long as `'static` here
-  --> $DIR/must_outlive_least_region_or_bound.rs:37:34
+  --> $DIR/must_outlive_least_region_or_bound.rs:28:34
    |
 LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -142,7 +142,7 @@ LL | fn with_bound<'a>(x: &'static i32) -> impl LifetimeTrait<'a> + 'static { x
    |                      ^^^^^^^^^^^^
 
 error[E0623]: lifetime mismatch
-  --> $DIR/must_outlive_least_region_or_bound.rs:42:61
+  --> $DIR/must_outlive_least_region_or_bound.rs:32:61
    |
 LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) {
    |                                                 -------     ^^^^^^^^^^^^^^^^
@@ -151,15 +151,15 @@ LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32
    |                                                 this parameter and the return type are declared with different lifetimes...
 
 error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/must_outlive_least_region_or_bound.rs:47:51
+  --> $DIR/must_outlive_least_region_or_bound.rs:37:51
    |
 LL | fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static {
    |                                 --                ^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
    |                                 |
    |                                 help: consider adding an explicit lifetime bound...: `T: 'static +`
 
-error[E0759]: cannot infer an appropriate lifetime
-  --> $DIR/must_outlive_least_region_or_bound.rs:18:50
+error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
+  --> $DIR/must_outlive_least_region_or_bound.rs:14:50
    |
 LL | fn elided3(x: &i32) -> Box<dyn Debug> { Box::new(x) }
    |               ----                               ^ ...is captured here, requiring it to live as long as `'static`
@@ -171,8 +171,8 @@ help: to declare that the trait object captures data from argument `x`, you can
 LL | fn elided3(x: &i32) -> Box<dyn Debug + '_> { Box::new(x) }
    |                                      ^^^^
 
-error[E0759]: cannot infer an appropriate lifetime
-  --> $DIR/must_outlive_least_region_or_bound.rs:21:59
+error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
+  --> $DIR/must_outlive_least_region_or_bound.rs:16:59
    |
 LL | fn explicit3<'a>(x: &'a i32) -> Box<dyn Debug> { Box::new(x) }
    |                     -------                               ^ ...is captured here, requiring it to live as long as `'static`
@@ -184,8 +184,8 @@ help: to declare that the trait object captures data from argument `x`, you can
 LL | fn explicit3<'a>(x: &'a i32) -> Box<dyn Debug + 'a> { Box::new(x) }
    |                                               ^^^^
 
-error[E0759]: cannot infer an appropriate lifetime
-  --> $DIR/must_outlive_least_region_or_bound.rs:24:60
+error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
+  --> $DIR/must_outlive_least_region_or_bound.rs:18:60
    |
 LL | fn elided4(x: &i32) -> Box<dyn Debug + 'static> { Box::new(x) }
    |               ----                                         ^ ...is captured here, requiring it to live as long as `'static`
@@ -201,8 +201,8 @@ help: alternatively, add an explicit `'static` bound to this reference
 LL | fn elided4(x: &'static i32) -> Box<dyn Debug + 'static> { Box::new(x) }
    |               ^^^^^^^^^^^^
 
-error[E0759]: cannot infer an appropriate lifetime
-  --> $DIR/must_outlive_least_region_or_bound.rs:27:69
+error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
+  --> $DIR/must_outlive_least_region_or_bound.rs:20:69
    |
 LL | fn explicit4<'a>(x: &'a i32) -> Box<dyn Debug + 'static> { Box::new(x) }
    |                     ------- this data with lifetime `'a`...         ^ ...is captured here, requiring it to live as long as `'static`
index 123ea6af6b019f6e5f171cf54fe57f575a805bac..65178cc9d24c262f3b186f99310df4a36a8c5330 100644 (file)
@@ -12,7 +12,7 @@ LL |     fn iter_values_anon(&self) -> impl Iterator<Item=u32> + '_ {
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: lifetime may not live long enough
-  --> $DIR/static-return-lifetime-infered.rs:10:37
+  --> $DIR/static-return-lifetime-infered.rs:9:37
    |
 LL |     fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
    |                    --               ^^^^^^^^^^^^^^^^^^^^^^^ opaque type requires that `'a` must outlive `'static`
index 96f3652c226ea0b7eb09a02fab91689ee4158f5e..518c52f5de4d7bfb3b26ce59a59d6668a7259ced 100644 (file)
@@ -4,13 +4,11 @@ struct A {
 
 impl A {
     fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
-        self.x.iter().map(|a| a.0)
+        self.x.iter().map(|a| a.0) //~ ERROR E0759
     }
-    //~^^ ERROR cannot infer an appropriate lifetime
     fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
-        self.x.iter().map(|a| a.0)
+        self.x.iter().map(|a| a.0) //~ ERROR E0759
     }
-    //~^^ ERROR cannot infer an appropriate lifetime
 }
 
 fn main() {}
index df0db6e4fc6df927297d9793d271390de5bc21dd..7c289b388223a4b6ebff083f9f32210745ee7d6c 100644 (file)
@@ -1,4 +1,4 @@
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
   --> $DIR/static-return-lifetime-infered.rs:7:16
    |
 LL |     fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
@@ -18,8 +18,8 @@ help: to declare that the `impl Trait` captures data from argument `self`, you c
 LL |     fn iter_values_anon(&self) -> impl Iterator<Item=u32> + '_ {
    |                                                           ^^^^
 
-error[E0759]: cannot infer an appropriate lifetime
-  --> $DIR/static-return-lifetime-infered.rs:11:16
+error[E0759]: `self` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
+  --> $DIR/static-return-lifetime-infered.rs:10:16
    |
 LL |     fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
    |                        -------- this data with lifetime `'a`...
@@ -29,7 +29,7 @@ LL |         self.x.iter().map(|a| a.0)
    |         ...is captured here...
    |
 note: ...and is required to live as long as `'static` here
-  --> $DIR/static-return-lifetime-infered.rs:10:37
+  --> $DIR/static-return-lifetime-infered.rs:9:37
    |
 LL |     fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
    |                                     ^^^^^^^^^^^^^^^^^^^^^^^
index 827163ef83cf7cf4c7f3fff461b0d28fce7d2333..f048ccd2427cb052cc465de1b9a3302236334e6e 100644 (file)
@@ -1,8 +1,7 @@
 use std::any::Any;
 
 fn foo<T: Any>(value: &T) -> Box<dyn Any> {
-    Box::new(value) as Box<dyn Any>
-    //~^ ERROR cannot infer an appropriate lifetime
+    Box::new(value) as Box<dyn Any> //~ ERROR E0759
 }
 
 fn main() {
index 919594fc9af4b434967d1975e1a23b41346c5f6e..6decc751321f9abfd3a434d39873dd34af7b6b87 100644 (file)
@@ -1,4 +1,4 @@
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `value` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
   --> $DIR/issue-16922.rs:4:14
    |
 LL | fn foo<T: Any>(value: &T) -> Box<dyn Any> {
diff --git a/src/test/ui/issues/issue-74539.rs b/src/test/ui/issues/issue-74539.rs
new file mode 100644 (file)
index 0000000..75632d1
--- /dev/null
@@ -0,0 +1,12 @@
+enum E {
+    A(u8, u8),
+}
+
+fn main() {
+    let e = E::A(2, 3);
+    match e {
+        E::A(x @ ..) => {  //~ ERROR `x @` is not allowed in a tuple
+            x //~ ERROR cannot find value `x` in this scope
+        }
+    };
+}
diff --git a/src/test/ui/issues/issue-74539.stderr b/src/test/ui/issues/issue-74539.stderr
new file mode 100644 (file)
index 0000000..94526dc
--- /dev/null
@@ -0,0 +1,21 @@
+error[E0425]: cannot find value `x` in this scope
+  --> $DIR/issue-74539.rs:9:13
+   |
+LL |             x
+   |             ^ help: a local variable with a similar name exists: `e`
+
+error: `x @` is not allowed in a tuple struct
+  --> $DIR/issue-74539.rs:8:14
+   |
+LL |         E::A(x @ ..) => {
+   |              ^^^^^^ this is only allowed in slice patterns
+   |
+   = help: remove this and bind each tuple field independently
+help: if you don't need to use the contents of x, discard the tuple's remaining fields
+   |
+LL |         E::A(..) => {
+   |              ^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0425`.
diff --git a/src/test/ui/issues/issue-74614.rs b/src/test/ui/issues/issue-74614.rs
new file mode 100644 (file)
index 0000000..f5e8deb
--- /dev/null
@@ -0,0 +1,17 @@
+// build-pass
+
+fn test<T>() {
+    std::mem::size_of::<T>();
+}
+
+pub fn foo<T>(_: T) -> &'static fn() {
+    &(test::<T> as fn())
+}
+
+fn outer<T>() {
+    foo(|| ());
+}
+
+fn main() {
+    outer::<u8>();
+}
index bdf95350c70451c6a82eb66a03c8332f790b95e8..f485766bcd34e32d049ff3dd36ee7273bec8fa7d 100644 (file)
@@ -7,6 +7,7 @@
 
 use std::marker::PhantomData;
 
+trait Bar { }
 trait Mirror { type It: ?Sized; }
 impl<T: ?Sized> Mirror for T { type It = Self; }
 #[repr(C)]
@@ -53,7 +54,7 @@ pub struct StructWithProjectionAndLifetime<'a>(
     pub fn char_type(p: char); //~ ERROR uses type `char`
     pub fn i128_type(p: i128); //~ ERROR uses type `i128`
     pub fn u128_type(p: u128); //~ ERROR uses type `u128`
-    pub fn trait_type(p: &dyn Clone); //~ ERROR uses type `dyn std::clone::Clone`
+    pub fn trait_type(p: &dyn Bar); //~ ERROR uses type `dyn Bar`
     pub fn tuple_type(p: (i32, i32)); //~ ERROR uses type `(i32, i32)`
     pub fn tuple_type2(p: I32Pair); //~ ERROR uses type `(i32, i32)`
     pub fn zero_size(p: ZeroSize); //~ ERROR uses type `ZeroSize`
index 13b9adca3f9f5af7c4cd86f6d369daac55ae66b8..a54226a7fc4a2c7e9ebd557becc123166541d797 100644 (file)
@@ -1,5 +1,5 @@
 error: `extern` block uses type `Foo`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:46:28
+  --> $DIR/lint-ctypes.rs:47:28
    |
 LL |     pub fn ptr_type1(size: *const Foo);
    |                            ^^^^^^^^^^ not FFI-safe
@@ -12,13 +12,13 @@ LL | #![deny(improper_ctypes)]
    = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
    = note: this struct has unspecified layout
 note: the type is defined here
-  --> $DIR/lint-ctypes.rs:24:1
+  --> $DIR/lint-ctypes.rs:25:1
    |
 LL | pub struct Foo;
    | ^^^^^^^^^^^^^^^
 
 error: `extern` block uses type `Foo`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:47:28
+  --> $DIR/lint-ctypes.rs:48:28
    |
 LL |     pub fn ptr_type2(size: *const Foo);
    |                            ^^^^^^^^^^ not FFI-safe
@@ -26,13 +26,13 @@ LL |     pub fn ptr_type2(size: *const Foo);
    = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
    = note: this struct has unspecified layout
 note: the type is defined here
-  --> $DIR/lint-ctypes.rs:24:1
+  --> $DIR/lint-ctypes.rs:25:1
    |
 LL | pub struct Foo;
    | ^^^^^^^^^^^^^^^
 
 error: `extern` block uses type `[u32]`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:48:26
+  --> $DIR/lint-ctypes.rs:49:26
    |
 LL |     pub fn slice_type(p: &[u32]);
    |                          ^^^^^^ not FFI-safe
@@ -41,7 +41,7 @@ LL |     pub fn slice_type(p: &[u32]);
    = note: slices have no C equivalent
 
 error: `extern` block uses type `str`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:49:24
+  --> $DIR/lint-ctypes.rs:50:24
    |
 LL |     pub fn str_type(p: &str);
    |                        ^^^^ not FFI-safe
@@ -50,7 +50,7 @@ LL |     pub fn str_type(p: &str);
    = note: string slices have no C equivalent
 
 error: `extern` block uses type `std::boxed::Box<u32>`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:50:24
+  --> $DIR/lint-ctypes.rs:51:24
    |
 LL |     pub fn box_type(p: Box<u32>);
    |                        ^^^^^^^^ not FFI-safe
@@ -59,7 +59,7 @@ LL |     pub fn box_type(p: Box<u32>);
    = note: this struct has unspecified layout
 
 error: `extern` block uses type `std::option::Option<std::boxed::Box<u32>>`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:51:28
+  --> $DIR/lint-ctypes.rs:52:28
    |
 LL |     pub fn opt_box_type(p: Option<Box<u32>>);
    |                            ^^^^^^^^^^^^^^^^ not FFI-safe
@@ -68,7 +68,7 @@ LL |     pub fn opt_box_type(p: Option<Box<u32>>);
    = note: enum has no representation hint
 
 error: `extern` block uses type `char`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:53:25
+  --> $DIR/lint-ctypes.rs:54:25
    |
 LL |     pub fn char_type(p: char);
    |                         ^^^^ not FFI-safe
@@ -77,7 +77,7 @@ LL |     pub fn char_type(p: char);
    = note: the `char` type has no C equivalent
 
 error: `extern` block uses type `i128`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:54:25
+  --> $DIR/lint-ctypes.rs:55:25
    |
 LL |     pub fn i128_type(p: i128);
    |                         ^^^^ not FFI-safe
@@ -85,23 +85,23 @@ LL |     pub fn i128_type(p: i128);
    = note: 128-bit integers don't currently have a known stable ABI
 
 error: `extern` block uses type `u128`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:55:25
+  --> $DIR/lint-ctypes.rs:56:25
    |
 LL |     pub fn u128_type(p: u128);
    |                         ^^^^ not FFI-safe
    |
    = note: 128-bit integers don't currently have a known stable ABI
 
-error: `extern` block uses type `dyn std::clone::Clone`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:56:26
+error: `extern` block uses type `dyn Bar`, which is not FFI-safe
+  --> $DIR/lint-ctypes.rs:57:26
    |
-LL |     pub fn trait_type(p: &dyn Clone);
-   |                          ^^^^^^^^^^ not FFI-safe
+LL |     pub fn trait_type(p: &dyn Bar);
+   |                          ^^^^^^^^ not FFI-safe
    |
    = note: trait objects have no C equivalent
 
 error: `extern` block uses type `(i32, i32)`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:57:26
+  --> $DIR/lint-ctypes.rs:58:26
    |
 LL |     pub fn tuple_type(p: (i32, i32));
    |                          ^^^^^^^^^^ not FFI-safe
@@ -110,7 +110,7 @@ LL |     pub fn tuple_type(p: (i32, i32));
    = note: tuples have unspecified layout
 
 error: `extern` block uses type `(i32, i32)`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:58:27
+  --> $DIR/lint-ctypes.rs:59:27
    |
 LL |     pub fn tuple_type2(p: I32Pair);
    |                           ^^^^^^^ not FFI-safe
@@ -119,7 +119,7 @@ LL |     pub fn tuple_type2(p: I32Pair);
    = note: tuples have unspecified layout
 
 error: `extern` block uses type `ZeroSize`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:59:25
+  --> $DIR/lint-ctypes.rs:60:25
    |
 LL |     pub fn zero_size(p: ZeroSize);
    |                         ^^^^^^^^ not FFI-safe
@@ -127,26 +127,26 @@ LL |     pub 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.rs:20:1
+  --> $DIR/lint-ctypes.rs:21:1
    |
 LL | pub struct ZeroSize;
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: `extern` block uses type `ZeroSizeWithPhantomData`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:60:33
+  --> $DIR/lint-ctypes.rs:61:33
    |
 LL |     pub fn zero_size_phantom(p: ZeroSizeWithPhantomData);
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
    |
    = note: composed only of `PhantomData`
 note: the type is defined here
-  --> $DIR/lint-ctypes.rs:43:1
+  --> $DIR/lint-ctypes.rs:44:1
    |
 LL | pub struct ZeroSizeWithPhantomData(::std::marker::PhantomData<i32>);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `extern` block uses type `std::marker::PhantomData<bool>`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:63:12
+  --> $DIR/lint-ctypes.rs:64:12
    |
 LL |         -> ::std::marker::PhantomData<bool>;
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -154,7 +154,7 @@ LL |         -> ::std::marker::PhantomData<bool>;
    = note: composed only of `PhantomData`
 
 error: `extern` block uses type `fn()`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:64:23
+  --> $DIR/lint-ctypes.rs:65:23
    |
 LL |     pub fn fn_type(p: RustFn);
    |                       ^^^^^^ not FFI-safe
@@ -163,7 +163,7 @@ LL |     pub fn fn_type(p: RustFn);
    = note: this function pointer has Rust-specific calling convention
 
 error: `extern` block uses type `fn()`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:65:24
+  --> $DIR/lint-ctypes.rs:66:24
    |
 LL |     pub fn fn_type2(p: fn());
    |                        ^^^^ not FFI-safe
@@ -172,7 +172,7 @@ LL |     pub fn fn_type2(p: fn());
    = note: this function pointer has Rust-specific calling convention
 
 error: `extern` block uses type `std::boxed::Box<u32>`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:66:28
+  --> $DIR/lint-ctypes.rs:67:28
    |
 LL |     pub fn fn_contained(p: RustBadRet);
    |                            ^^^^^^^^^^ not FFI-safe
@@ -181,7 +181,7 @@ LL |     pub fn fn_contained(p: RustBadRet);
    = note: this struct has unspecified layout
 
 error: `extern` block uses type `i128`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:67:32
+  --> $DIR/lint-ctypes.rs:68:32
    |
 LL |     pub fn transparent_i128(p: TransparentI128);
    |                                ^^^^^^^^^^^^^^^ not FFI-safe
@@ -189,7 +189,7 @@ LL |     pub fn transparent_i128(p: TransparentI128);
    = note: 128-bit integers don't currently have a known stable ABI
 
 error: `extern` block uses type `str`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:68:31
+  --> $DIR/lint-ctypes.rs:69:31
    |
 LL |     pub fn transparent_str(p: TransparentStr);
    |                               ^^^^^^^^^^^^^^ not FFI-safe
@@ -198,7 +198,7 @@ LL |     pub fn transparent_str(p: TransparentStr);
    = note: string slices have no C equivalent
 
 error: `extern` block uses type `std::boxed::Box<u32>`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:69:30
+  --> $DIR/lint-ctypes.rs:70:30
    |
 LL |     pub fn transparent_fn(p: TransparentBadFn);
    |                              ^^^^^^^^^^^^^^^^ not FFI-safe
@@ -207,7 +207,7 @@ LL |     pub fn transparent_fn(p: TransparentBadFn);
    = note: this struct has unspecified layout
 
 error: `extern` block uses type `[u8; 8]`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:70:27
+  --> $DIR/lint-ctypes.rs:71:27
    |
 LL |     pub fn raw_array(arr: [u8; 8]);
    |                           ^^^^^^^ not FFI-safe
@@ -216,7 +216,7 @@ LL |     pub fn raw_array(arr: [u8; 8]);
    = note: passing raw arrays by value is not FFI-safe
 
 error: `extern` block uses type `u128`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:72:34
+  --> $DIR/lint-ctypes.rs:73:34
    |
 LL |     pub static static_u128_type: u128;
    |                                  ^^^^ not FFI-safe
@@ -224,7 +224,7 @@ LL |     pub static static_u128_type: u128;
    = note: 128-bit integers don't currently have a known stable ABI
 
 error: `extern` block uses type `u128`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:73:40
+  --> $DIR/lint-ctypes.rs:74:40
    |
 LL |     pub static static_u128_array_type: [u128; 16];
    |                                        ^^^^^^^^^^ not FFI-safe
index 8421dc1d0c1303921e0981db1c908c9c8e4aa4e9..1931934a2112a7ded99b5e6ff3dfc08a4f15732d 100644 (file)
@@ -1,28 +1,11 @@
-error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
+error[E0759]: `fn` parameter has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
   --> $DIR/constant-in-expr-inherent-1.rs:8:5
    |
-LL |     <Foo<'a>>::C
-   |     ^^^^^^^^^^^^
-   |
-note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 7:8...
-  --> $DIR/constant-in-expr-inherent-1.rs:7:8
-   |
 LL | fn foo<'a>(_: &'a u32) -> &'static u32 {
-   |        ^^
-note: ...so that the types are compatible
-  --> $DIR/constant-in-expr-inherent-1.rs:8:5
-   |
-LL |     <Foo<'a>>::C
-   |     ^^^^^^^^^^^^
-   = note: expected `Foo<'_>`
-              found `Foo<'a>`
-   = note: but, the lifetime must be valid for the static lifetime...
-note: ...so that reference does not outlive borrowed content
-  --> $DIR/constant-in-expr-inherent-1.rs:8:5
-   |
+   |               ------- this data with lifetime `'a`...
 LL |     <Foo<'a>>::C
-   |     ^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^ ...is captured and required to live as long as `'static` here
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0495`.
+For more information about this error, try `rustc --explain E0759`.
index 708ab1cf38297d2d3778de18bf1039063c09453c..4a2665d8e1694f2d68d04396c83127fe58b875b9 100644 (file)
@@ -15,7 +15,7 @@ fn load(ss: &mut SomeStruct) -> Box<dyn SomeTrait> {
     // `Box<SomeTrait>` defaults to a `'static` bound, so this return
     // is illegal.
 
-    ss.r //~ ERROR cannot infer an appropriate lifetime
+    ss.r //~ ERROR E0759
 }
 
 fn store(ss: &mut SomeStruct, b: Box<dyn SomeTrait>) {
index 1b1e0d9610724b6e83c1a48c19e2a0ff427fb158..70b99ef7869ca8cfab83e016c7463e4eb2ef17d9 100644 (file)
@@ -1,4 +1,4 @@
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `ss` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
   --> $DIR/object-lifetime-default-from-box-error.rs:18:5
    |
 LL | fn load(ss: &mut SomeStruct) -> Box<dyn SomeTrait> {
diff --git a/src/test/ui/polymorphization/const_parameters/closures.rs b/src/test/ui/polymorphization/const_parameters/closures.rs
new file mode 100644 (file)
index 0000000..f20605e
--- /dev/null
@@ -0,0 +1,67 @@
+// build-fail
+// compile-flags:-Zpolymorphize=on
+#![feature(const_generics, rustc_attrs)]
+//~^ WARN the feature `const_generics` is incomplete
+
+// This test checks that the polymorphization analysis correctly detects unused const
+// parameters in closures.
+
+// Function doesn't have any generic parameters to be unused.
+#[rustc_polymorphize_error]
+pub fn no_parameters() {
+    let _ = || {};
+}
+
+// Function has an unused generic parameter in parent and closure.
+#[rustc_polymorphize_error]
+pub fn unused<const T: usize>() -> usize {
+    //~^ ERROR item has unused generic parameters
+    let add_one = |x: usize| x + 1;
+    //~^ ERROR item has unused generic parameters
+    add_one(3)
+}
+
+// Function has an unused generic parameter in closure, but not in parent.
+#[rustc_polymorphize_error]
+pub fn used_parent<const T: usize>() -> usize {
+    let x: usize = T;
+    let add_one = |x: usize| x + 1;
+    //~^ ERROR item has unused generic parameters
+    x + add_one(3)
+}
+
+// Function uses generic parameter in value of a binding in closure.
+#[rustc_polymorphize_error]
+pub fn used_binding<const T: usize>() -> usize {
+    let x = || {
+        let y: usize = T;
+        y
+    };
+
+    x()
+}
+
+// Closure uses a value as an upvar, which used the generic parameter.
+#[rustc_polymorphize_error]
+pub fn unused_upvar<const T: usize>() -> usize {
+    let x: usize = T;
+    let y = || x;
+    //~^ ERROR item has unused generic parameters
+    y()
+}
+
+// Closure uses generic parameter in substitutions to another function.
+#[rustc_polymorphize_error]
+pub fn used_substs<const T: usize>() -> usize {
+    let x = || unused::<T>();
+    x()
+}
+
+fn main() {
+    no_parameters();
+    let _ = unused::<1>();
+    let _ = used_parent::<1>();
+    let _ = used_binding::<1>();
+    let _ = unused_upvar::<1>();
+    let _ = used_substs::<1>();
+}
diff --git a/src/test/ui/polymorphization/const_parameters/closures.stderr b/src/test/ui/polymorphization/const_parameters/closures.stderr
new file mode 100644 (file)
index 0000000..266b6e6
--- /dev/null
@@ -0,0 +1,44 @@
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/closures.rs:3:12
+   |
+LL | #![feature(const_generics, rustc_attrs)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+
+error: item has unused generic parameters
+  --> $DIR/closures.rs:19:19
+   |
+LL | pub fn unused<const T: usize>() -> usize {
+   |                     - generic parameter `T` is unused
+LL |
+LL |     let add_one = |x: usize| x + 1;
+   |                   ^^^^^^^^^^^^^^^^
+
+error: item has unused generic parameters
+  --> $DIR/closures.rs:17:8
+   |
+LL | pub fn unused<const T: usize>() -> usize {
+   |        ^^^^^^       - generic parameter `T` is unused
+
+error: item has unused generic parameters
+  --> $DIR/closures.rs:28:19
+   |
+LL | pub fn used_parent<const T: usize>() -> usize {
+   |                          - generic parameter `T` is unused
+LL |     let x: usize = T;
+LL |     let add_one = |x: usize| x + 1;
+   |                   ^^^^^^^^^^^^^^^^
+
+error: item has unused generic parameters
+  --> $DIR/closures.rs:48:13
+   |
+LL | pub fn unused_upvar<const T: usize>() -> usize {
+   |                           - generic parameter `T` is unused
+LL |     let x: usize = T;
+LL |     let y = || x;
+   |             ^^^^
+
+error: aborting due to 4 previous errors; 1 warning emitted
+
diff --git a/src/test/ui/polymorphization/const_parameters/functions.rs b/src/test/ui/polymorphization/const_parameters/functions.rs
new file mode 100644 (file)
index 0000000..04c279d
--- /dev/null
@@ -0,0 +1,37 @@
+// build-fail
+// compile-flags:-Zpolymorphize=on
+#![feature(const_generics, rustc_attrs)]
+//~^ WARN the feature `const_generics` is incomplete
+
+// This test checks that the polymorphization analysis correctly detects unused const
+// parameters in functions.
+
+// Function doesn't have any generic parameters to be unused.
+#[rustc_polymorphize_error]
+pub fn no_parameters() {}
+
+// Function has an unused generic parameter.
+#[rustc_polymorphize_error]
+pub fn unused<const T: usize>() {
+    //~^ ERROR item has unused generic parameters
+}
+
+// Function uses generic parameter in value of a binding.
+#[rustc_polymorphize_error]
+pub fn used_binding<const T: usize>() -> usize {
+    let x: usize = T;
+    x
+}
+
+// Function uses generic parameter in substitutions to another function.
+#[rustc_polymorphize_error]
+pub fn used_substs<const T: usize>() {
+    unused::<T>()
+}
+
+fn main() {
+    no_parameters();
+    unused::<1>();
+    used_binding::<1>();
+    used_substs::<1>();
+}
diff --git a/src/test/ui/polymorphization/const_parameters/functions.stderr b/src/test/ui/polymorphization/const_parameters/functions.stderr
new file mode 100644 (file)
index 0000000..e379e32
--- /dev/null
@@ -0,0 +1,17 @@
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/functions.rs:3:12
+   |
+LL | #![feature(const_generics, rustc_attrs)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+
+error: item has unused generic parameters
+  --> $DIR/functions.rs:15:8
+   |
+LL | pub fn unused<const T: usize>() {
+   |        ^^^^^^       - generic parameter `T` is unused
+
+error: aborting due to previous error; 1 warning emitted
+
diff --git a/src/test/ui/polymorphization/drop_shims/simple.rs b/src/test/ui/polymorphization/drop_shims/simple.rs
new file mode 100644 (file)
index 0000000..2695dc6
--- /dev/null
@@ -0,0 +1,22 @@
+// check-pass
+// compile-flags:-Zpolymorphize=on
+
+pub struct OnDrop<F: Fn()>(pub F);
+
+impl<F: Fn()> Drop for OnDrop<F> {
+    fn drop(&mut self) { }
+}
+
+fn foo<R, S: FnOnce()>(
+    _: R,
+    _: S,
+) {
+    let bar = || {
+        let _ = OnDrop(|| ());
+    };
+    let _ = bar();
+}
+
+fn main() {
+    foo(3u32, || {});
+}
diff --git a/src/test/ui/polymorphization/drop_shims/transitive.rs b/src/test/ui/polymorphization/drop_shims/transitive.rs
new file mode 100644 (file)
index 0000000..c228911
--- /dev/null
@@ -0,0 +1,27 @@
+// check-pass
+// compile-flags:-Zpolymorphize=on
+
+pub struct OnDrop<F: Fn()>(pub F);
+
+impl<F: Fn()> Drop for OnDrop<F> {
+    fn drop(&mut self) { }
+}
+
+fn bar<F: FnOnce()>(f: F) {
+    let _ = OnDrop(|| ());
+    f()
+}
+
+fn foo<R, S: FnOnce()>(
+    _: R,
+    _: S,
+) {
+    let bar = || {
+        bar(|| {})
+    };
+    let _ = bar();
+}
+
+fn main() {
+    foo(3u32, || {});
+}
diff --git a/src/test/ui/polymorphization/generators.rs b/src/test/ui/polymorphization/generators.rs
new file mode 100644 (file)
index 0000000..9eb34fb
--- /dev/null
@@ -0,0 +1,94 @@
+// build-fail
+// compile-flags:-Zpolymorphize=on
+#![feature(const_generics, generators, generator_trait, rustc_attrs)]
+//~^ WARN the feature `const_generics` is incomplete
+
+use std::marker::Unpin;
+use std::ops::{Generator, GeneratorState};
+use std::pin::Pin;
+
+enum YieldOrReturn<Y, R> {
+    Yield(Y),
+    Return(R),
+}
+
+fn finish<T, Y, R>(mut t: T) -> Vec<YieldOrReturn<Y, R>>
+where
+    T: Generator<(), Yield = Y, Return = R> + Unpin,
+{
+    let mut results = Vec::new();
+    loop {
+        match Pin::new(&mut t).resume(()) {
+            GeneratorState::Yielded(yielded) => results.push(YieldOrReturn::Yield(yielded)),
+            GeneratorState::Complete(returned) => {
+                results.push(YieldOrReturn::Return(returned));
+                return results;
+            }
+        }
+    }
+}
+
+// This test checks that the polymorphization analysis functions on generators.
+
+#[rustc_polymorphize_error]
+pub fn unused_type<T>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin {
+    //~^ ERROR item has unused generic parameters
+    || {
+        //~^ ERROR item has unused generic parameters
+        yield 1;
+        2
+    }
+}
+
+#[rustc_polymorphize_error]
+pub fn used_type_in_yield<Y: Default>() -> impl Generator<(), Yield = Y, Return = u32> + Unpin {
+    || {
+        yield Y::default();
+        2
+    }
+}
+
+#[rustc_polymorphize_error]
+pub fn used_type_in_return<R: Default>() -> impl Generator<(), Yield = u32, Return = R> + Unpin {
+    || {
+        yield 3;
+        R::default()
+    }
+}
+
+#[rustc_polymorphize_error]
+pub fn unused_const<const T: u32>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin {
+    //~^ ERROR item has unused generic parameters
+    || {
+        //~^ ERROR item has unused generic parameters
+        yield 1;
+        2
+    }
+}
+
+#[rustc_polymorphize_error]
+pub fn used_const_in_yield<const Y: u32>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin
+{
+    || {
+        yield Y;
+        2
+    }
+}
+
+#[rustc_polymorphize_error]
+pub fn used_const_in_return<const R: u32>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin
+{
+    || {
+        yield 4;
+        R
+    }
+}
+
+fn main() {
+    finish(unused_type::<u32>());
+    finish(used_type_in_yield::<u32>());
+    finish(used_type_in_return::<u32>());
+    finish(unused_const::<1u32>());
+    finish(used_const_in_yield::<1u32>());
+    finish(used_const_in_return::<1u32>());
+}
diff --git a/src/test/ui/polymorphization/generators.stderr b/src/test/ui/polymorphization/generators.stderr
new file mode 100644 (file)
index 0000000..c59055b
--- /dev/null
@@ -0,0 +1,49 @@
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/generators.rs:3:12
+   |
+LL | #![feature(const_generics, generators, generator_trait, rustc_attrs)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+
+error: item has unused generic parameters
+  --> $DIR/generators.rs:36:5
+   |
+LL |   pub fn unused_type<T>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin {
+   |                      - generic parameter `T` is unused
+LL |
+LL | /     || {
+LL | |
+LL | |         yield 1;
+LL | |         2
+LL | |     }
+   | |_____^
+
+error: item has unused generic parameters
+  --> $DIR/generators.rs:34:8
+   |
+LL | pub fn unused_type<T>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin {
+   |        ^^^^^^^^^^^ - generic parameter `T` is unused
+
+error: item has unused generic parameters
+  --> $DIR/generators.rs:62:5
+   |
+LL |   pub fn unused_const<const T: u32>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin {
+   |                             - generic parameter `T` is unused
+LL |
+LL | /     || {
+LL | |
+LL | |         yield 1;
+LL | |         2
+LL | |     }
+   | |_____^
+
+error: item has unused generic parameters
+  --> $DIR/generators.rs:60:8
+   |
+LL | pub fn unused_const<const T: u32>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin {
+   |        ^^^^^^^^^^^^       - generic parameter `T` is unused
+
+error: aborting due to 4 previous errors; 1 warning emitted
+
diff --git a/src/test/ui/polymorphization/lifetimes.rs b/src/test/ui/polymorphization/lifetimes.rs
new file mode 100644 (file)
index 0000000..f26df45
--- /dev/null
@@ -0,0 +1,25 @@
+// build-fail
+// compile-flags:-Zpolymorphize=on
+#![feature(rustc_attrs)]
+
+// This test checks that the polymorphization analysis doesn't break when the
+// function/closure doesn't just have generic parameters.
+
+// Function has an unused generic parameter.
+#[rustc_polymorphize_error]
+pub fn unused<'a, T>(_: &'a u32) {
+    //~^ ERROR item has unused generic parameters
+}
+
+#[rustc_polymorphize_error]
+pub fn used<'a, T: Default>(_: &'a u32) -> u32 {
+    let _: T = Default::default();
+    let add_one = |x: u32| x + 1;
+    //~^ ERROR item has unused generic parameters
+    add_one(3)
+}
+
+fn main() {
+    unused::<u32>(&3);
+    used::<u32>(&3);
+}
diff --git a/src/test/ui/polymorphization/lifetimes.stderr b/src/test/ui/polymorphization/lifetimes.stderr
new file mode 100644 (file)
index 0000000..2020256
--- /dev/null
@@ -0,0 +1,17 @@
+error: item has unused generic parameters
+  --> $DIR/lifetimes.rs:10:8
+   |
+LL | pub fn unused<'a, T>(_: &'a u32) {
+   |        ^^^^^^     - generic parameter `T` is unused
+
+error: item has unused generic parameters
+  --> $DIR/lifetimes.rs:17:19
+   |
+LL | pub fn used<'a, T: Default>(_: &'a u32) -> u32 {
+   |                 - generic parameter `T` is unused
+LL |     let _: T = Default::default();
+LL |     let add_one = |x: u32| x + 1;
+   |                   ^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/polymorphization/normalized_sig_types.rs b/src/test/ui/polymorphization/normalized_sig_types.rs
new file mode 100644 (file)
index 0000000..d732b10
--- /dev/null
@@ -0,0 +1,26 @@
+// build-pass
+// compile-flags:-Zpolymorphize=on
+
+pub trait ParallelIterator: Sized {
+    fn drive<C: Consumer<()>>(_: C) {
+        C::into_folder();
+    }
+}
+
+pub trait Consumer<T>: Sized {
+    type Result;
+    fn into_folder() -> Self::Result;
+}
+
+impl ParallelIterator for () {}
+
+impl<F: Fn(), T> Consumer<T> for F {
+    type Result = ();
+    fn into_folder() -> Self::Result {
+        unimplemented!()
+    }
+}
+
+fn main() {
+    <()>::drive(|| ());
+}
diff --git a/src/test/ui/polymorphization/predicates.rs b/src/test/ui/polymorphization/predicates.rs
new file mode 100644 (file)
index 0000000..82a9493
--- /dev/null
@@ -0,0 +1,24 @@
+// build-fail
+// compile-flags:-Zpolymorphize=on
+#![feature(rustc_attrs)]
+
+// This test checks that `T` is considered used in `foo`, because it is used in a predicate for
+// `I`, which is used.
+
+#[rustc_polymorphize_error]
+fn bar<I>() {
+    //~^ ERROR item has unused generic parameters
+}
+
+#[rustc_polymorphize_error]
+fn foo<I, T>(_: I)
+where
+    I: Iterator<Item = T>,
+{
+    bar::<I>()
+}
+
+fn main() {
+    let x = &[2u32];
+    foo(x.iter());
+}
diff --git a/src/test/ui/polymorphization/predicates.stderr b/src/test/ui/polymorphization/predicates.stderr
new file mode 100644 (file)
index 0000000..c23730f
--- /dev/null
@@ -0,0 +1,8 @@
+error: item has unused generic parameters
+  --> $DIR/predicates.rs:9:4
+   |
+LL | fn bar<I>() {
+   |    ^^^ - generic parameter `I` is unused
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/polymorphization/promoted-function.rs b/src/test/ui/polymorphization/promoted-function.rs
new file mode 100644 (file)
index 0000000..0d3af7a
--- /dev/null
@@ -0,0 +1,13 @@
+// run-pass
+fn fop<T>() {}
+
+fn bar<T>() -> &'static fn() {
+    &(fop::<T> as fn())
+}
+pub const FN: &'static fn() = &(fop::<i32> as fn());
+
+fn main() {
+    bar::<u32>();
+    bar::<i32>();
+    (FN)();
+}
diff --git a/src/test/ui/polymorphization/too-many-generic-params.rs b/src/test/ui/polymorphization/too-many-generic-params.rs
new file mode 100644 (file)
index 0000000..ec62446
--- /dev/null
@@ -0,0 +1,85 @@
+// build-pass
+#![feature(rustc_attrs)]
+
+// This test checks that the analysis doesn't panic when there are >64 generic parameters, but
+// instead considers those parameters used.
+
+#[rustc_polymorphize_error]
+fn bar<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, AA,
+       AB, AC, AD, AE, AF, AG, AH, AI, AJ, AK, AL, AM, AN, AO, AP, AQ, AR, AS, AT, AU, AV, AW,
+       AX, AY, AZ, BA, BB, BC, BD, BE, BF, BG, BH, BI, BJ, BK, BL, BM>()
+{
+    let _: Option<A> = None;
+    let _: Option<B> = None;
+    let _: Option<C> = None;
+    let _: Option<D> = None;
+    let _: Option<E> = None;
+    let _: Option<F> = None;
+    let _: Option<G> = None;
+    let _: Option<H> = None;
+    let _: Option<I> = None;
+    let _: Option<J> = None;
+    let _: Option<K> = None;
+    let _: Option<L> = None;
+    let _: Option<M> = None;
+    let _: Option<N> = None;
+    let _: Option<O> = None;
+    let _: Option<P> = None;
+    let _: Option<Q> = None;
+    let _: Option<R> = None;
+    let _: Option<S> = None;
+    let _: Option<T> = None;
+    let _: Option<U> = None;
+    let _: Option<V> = None;
+    let _: Option<W> = None;
+    let _: Option<X> = None;
+    let _: Option<Y> = None;
+    let _: Option<Z> = None;
+    let _: Option<AA> = None;
+    let _: Option<AB> = None;
+    let _: Option<AC> = None;
+    let _: Option<AD> = None;
+    let _: Option<AE> = None;
+    let _: Option<AF> = None;
+    let _: Option<AG> = None;
+    let _: Option<AH> = None;
+    let _: Option<AI> = None;
+    let _: Option<AJ> = None;
+    let _: Option<AK> = None;
+    let _: Option<AL> = None;
+    let _: Option<AM> = None;
+    let _: Option<AN> = None;
+    let _: Option<AO> = None;
+    let _: Option<AP> = None;
+    let _: Option<AQ> = None;
+    let _: Option<AR> = None;
+    let _: Option<AS> = None;
+    let _: Option<AT> = None;
+    let _: Option<AU> = None;
+    let _: Option<AV> = None;
+    let _: Option<AW> = None;
+    let _: Option<AX> = None;
+    let _: Option<AY> = None;
+    let _: Option<AZ> = None;
+    let _: Option<BA> = None;
+    let _: Option<BB> = None;
+    let _: Option<BC> = None;
+    let _: Option<BD> = None;
+    let _: Option<BE> = None;
+    let _: Option<BF> = None;
+    let _: Option<BG> = None;
+    let _: Option<BH> = None;
+    let _: Option<BI> = None;
+    let _: Option<BJ> = None;
+    let _: Option<BK> = None;
+    let _: Option<BL> = None;
+    let _: Option<BM> = None;
+}
+
+fn main() {
+    bar::<u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32,
+          u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32,
+          u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32,
+          u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32,
+          u32>();
+}
diff --git a/src/test/ui/polymorphization/type_parameters/closures.rs b/src/test/ui/polymorphization/type_parameters/closures.rs
new file mode 100644 (file)
index 0000000..07ab135
--- /dev/null
@@ -0,0 +1,161 @@
+// build-fail
+// compile-flags:-Zpolymorphize=on
+#![feature(stmt_expr_attributes, rustc_attrs)]
+
+// This test checks that the polymorphization analysis correctly detects unused type
+// parameters in closures.
+
+// Function doesn't have any generic parameters to be unused.
+#[rustc_polymorphize_error]
+pub fn no_parameters() {
+    let _ = || {};
+}
+
+// Function has an unused generic parameter in parent and closure.
+#[rustc_polymorphize_error]
+pub fn unused<T>() -> u32 {
+    //~^ ERROR item has unused generic parameters
+
+    let add_one = |x: u32| x + 1;
+    //~^ ERROR item has unused generic parameters
+    add_one(3)
+}
+
+// Function has an unused generic parameter in closure, but not in parent.
+#[rustc_polymorphize_error]
+pub fn used_parent<T: Default>() -> u32 {
+    let _: T = Default::default();
+    let add_one = |x: u32| x + 1;
+    //~^ ERROR item has unused generic parameters
+    add_one(3)
+}
+
+// Function uses generic parameter in value of a binding in closure.
+#[rustc_polymorphize_error]
+pub fn used_binding_value<T: Default>() -> T {
+    let x = || {
+        let y: T = Default::default();
+        y
+    };
+
+    x()
+}
+
+// Function uses generic parameter in generic of a binding in closure.
+#[rustc_polymorphize_error]
+pub fn used_binding_generic<T>() -> Option<T> {
+    let x = || {
+        let y: Option<T> = None;
+        y
+    };
+
+    x()
+}
+
+// Function and closure uses generic parameter in argument.
+#[rustc_polymorphize_error]
+pub fn used_argument<T>(t: T) -> u32 {
+    let x = |_: T| 3;
+    x(t)
+}
+
+// Closure uses generic parameter in argument.
+#[rustc_polymorphize_error]
+pub fn used_argument_closure<T: Default>() -> u32 {
+    let t: T = Default::default();
+
+    let x = |_: T| 3;
+    x(t)
+}
+
+// Closure uses generic parameter as upvar.
+#[rustc_polymorphize_error]
+pub fn used_upvar<T: Default>() -> T {
+    let x: T = Default::default();
+
+    let y = || x;
+    y()
+}
+
+// Closure uses generic parameter in substitutions to another function.
+#[rustc_polymorphize_error]
+pub fn used_substs<T>() -> u32 {
+    let x = || unused::<T>();
+    x()
+}
+
+struct Foo<F>(F);
+
+impl<F: Default> Foo<F> {
+    // Function has an unused generic parameter from impl and fn.
+    #[rustc_polymorphize_error]
+    pub fn unused_all<G: Default>() -> u32 {
+        //~^ ERROR item has unused generic parameters
+        let add_one = |x: u32| x + 1;
+        //~^ ERROR item has unused generic parameters
+        add_one(3)
+    }
+
+    // Function uses generic parameter from impl and fn in closure.
+    #[rustc_polymorphize_error]
+    pub fn used_both<G: Default>() -> u32 {
+        let add_one = |x: u32| {
+            let _: F = Default::default();
+            let _: G = Default::default();
+            x + 1
+        };
+
+        add_one(3)
+    }
+
+    // Function uses generic parameter from fn in closure.
+    #[rustc_polymorphize_error]
+    pub fn used_fn<G: Default>() -> u32 {
+        //~^ ERROR item has unused generic parameters
+        let add_one = |x: u32| {
+            //~^ ERROR item has unused generic parameters
+            let _: G = Default::default();
+            x + 1
+        };
+
+        add_one(3)
+    }
+
+    // Function uses generic parameter from impl in closure.
+    #[rustc_polymorphize_error]
+    pub fn used_impl<G: Default>() -> u32 {
+        //~^ ERROR item has unused generic parameters
+        let add_one = |x: u32| {
+            //~^ ERROR item has unused generic parameters
+            let _: F = Default::default();
+            x + 1
+        };
+
+        add_one(3)
+    }
+
+    // Closure uses generic parameter in substitutions to another function.
+    #[rustc_polymorphize_error]
+    pub fn used_substs() -> u32 {
+        let x = || unused::<F>();
+        x()
+    }
+}
+
+fn main() {
+    no_parameters();
+    let _ = unused::<u32>();
+    let _ = used_parent::<u32>();
+    let _ = used_binding_value::<u32>();
+    let _ = used_binding_generic::<u32>();
+    let _ = used_argument(3u32);
+    let _ = used_argument_closure::<u32>();
+    let _ = used_upvar::<u32>();
+    let _ = used_substs::<u32>();
+
+    let _ = Foo::<u32>::unused_all::<u32>();
+    let _ = Foo::<u32>::used_both::<u32>();
+    let _ = Foo::<u32>::used_impl::<u32>();
+    let _ = Foo::<u32>::used_fn::<u32>();
+    let _ = Foo::<u32>::used_substs();
+}
diff --git a/src/test/ui/polymorphization/type_parameters/closures.stderr b/src/test/ui/polymorphization/type_parameters/closures.stderr
new file mode 100644 (file)
index 0000000..417feeb
--- /dev/null
@@ -0,0 +1,90 @@
+error: item has unused generic parameters
+  --> $DIR/closures.rs:19:19
+   |
+LL | pub fn unused<T>() -> u32 {
+   |               - generic parameter `T` is unused
+...
+LL |     let add_one = |x: u32| x + 1;
+   |                   ^^^^^^^^^^^^^^
+
+error: item has unused generic parameters
+  --> $DIR/closures.rs:16:8
+   |
+LL | pub fn unused<T>() -> u32 {
+   |        ^^^^^^ - generic parameter `T` is unused
+
+error: item has unused generic parameters
+  --> $DIR/closures.rs:28:19
+   |
+LL | pub fn used_parent<T: Default>() -> u32 {
+   |                    - generic parameter `T` is unused
+LL |     let _: T = Default::default();
+LL |     let add_one = |x: u32| x + 1;
+   |                   ^^^^^^^^^^^^^^
+
+error: item has unused generic parameters
+  --> $DIR/closures.rs:94:23
+   |
+LL | impl<F: Default> Foo<F> {
+   |      - generic parameter `F` is unused
+...
+LL |     pub fn unused_all<G: Default>() -> u32 {
+   |                       - generic parameter `G` is unused
+LL |
+LL |         let add_one = |x: u32| x + 1;
+   |                       ^^^^^^^^^^^^^^
+
+error: item has unused generic parameters
+  --> $DIR/closures.rs:92:12
+   |
+LL | impl<F: Default> Foo<F> {
+   |      - generic parameter `F` is unused
+...
+LL |     pub fn unused_all<G: Default>() -> u32 {
+   |            ^^^^^^^^^^ - generic parameter `G` is unused
+
+error: item has unused generic parameters
+  --> $DIR/closures.rs:128:23
+   |
+LL |       pub fn used_impl<G: Default>() -> u32 {
+   |                        - generic parameter `G` is unused
+LL |
+LL |           let add_one = |x: u32| {
+   |  _______________________^
+LL | |
+LL | |             let _: F = Default::default();
+LL | |             x + 1
+LL | |         };
+   | |_________^
+
+error: item has unused generic parameters
+  --> $DIR/closures.rs:126:12
+   |
+LL |     pub fn used_impl<G: Default>() -> u32 {
+   |            ^^^^^^^^^ - generic parameter `G` is unused
+
+error: item has unused generic parameters
+  --> $DIR/closures.rs:115:23
+   |
+LL |   impl<F: Default> Foo<F> {
+   |        - generic parameter `F` is unused
+...
+LL |           let add_one = |x: u32| {
+   |  _______________________^
+LL | |
+LL | |             let _: G = Default::default();
+LL | |             x + 1
+LL | |         };
+   | |_________^
+
+error: item has unused generic parameters
+  --> $DIR/closures.rs:113:12
+   |
+LL | impl<F: Default> Foo<F> {
+   |      - generic parameter `F` is unused
+...
+LL |     pub fn used_fn<G: Default>() -> u32 {
+   |            ^^^^^^^
+
+error: aborting due to 9 previous errors
+
diff --git a/src/test/ui/polymorphization/type_parameters/functions.rs b/src/test/ui/polymorphization/type_parameters/functions.rs
new file mode 100644 (file)
index 0000000..aad957e
--- /dev/null
@@ -0,0 +1,96 @@
+// build-fail
+// compile-flags:-Zpolymorphize=on
+#![feature(rustc_attrs)]
+
+// This test checks that the polymorphization analysis correctly detects unused type
+// parameters in functions.
+
+// Function doesn't have any generic parameters to be unused.
+#[rustc_polymorphize_error]
+pub fn no_parameters() {}
+
+// Function has an unused generic parameter.
+#[rustc_polymorphize_error]
+pub fn unused<T>() {
+    //~^ ERROR item has unused generic parameters
+}
+
+// Function uses generic parameter in value of a binding.
+#[rustc_polymorphize_error]
+pub fn used_binding_value<T: Default>() {
+    let _: T = Default::default();
+}
+
+// Function uses generic parameter in generic of a binding.
+#[rustc_polymorphize_error]
+pub fn used_binding_generic<T>() {
+    let _: Option<T> = None;
+}
+
+// Function uses generic parameter in argument.
+#[rustc_polymorphize_error]
+pub fn used_argument<T>(_: T) {}
+
+// Function uses generic parameter in substitutions to another function.
+#[rustc_polymorphize_error]
+pub fn used_substs<T>() {
+    unused::<T>()
+}
+
+struct Foo<F>(F);
+
+impl<F: Default> Foo<F> {
+    // Function has an unused generic parameter from impl.
+    #[rustc_polymorphize_error]
+    pub fn unused_impl() {
+        //~^ ERROR item has unused generic parameters
+    }
+
+    // Function has an unused generic parameter from impl and fn.
+    #[rustc_polymorphize_error]
+    pub fn unused_both<G: Default>() {
+        //~^ ERROR item has unused generic parameters
+    }
+
+    // Function uses generic parameter from impl.
+    #[rustc_polymorphize_error]
+    pub fn used_impl() {
+        let _: F = Default::default();
+    }
+
+    // Function uses generic parameter from impl.
+    #[rustc_polymorphize_error]
+    pub fn used_fn<G: Default>() {
+        //~^ ERROR item has unused generic parameters
+        let _: G = Default::default();
+    }
+
+    // Function uses generic parameter from impl.
+    #[rustc_polymorphize_error]
+    pub fn used_both<G: Default>() {
+        let _: F = Default::default();
+        let _: G = Default::default();
+    }
+
+    // Function uses generic parameter in substitutions to another function.
+    #[rustc_polymorphize_error]
+    pub fn used_substs() {
+        unused::<F>()
+    }
+}
+
+fn main() {
+    no_parameters();
+    unused::<u32>();
+    used_binding_value::<u32>();
+    used_binding_generic::<u32>();
+    used_argument(3u32);
+    used_substs::<u32>();
+
+    Foo::<u32>::unused_impl();
+    Foo::<u32>::unused_both::<u32>();
+    Foo::<u32>::used_impl();
+    Foo::<u32>::used_fn::<u32>();
+    Foo::<u32>::used_both::<u32>();
+    Foo::<u32>::used_substs();
+}
diff --git a/src/test/ui/polymorphization/type_parameters/functions.stderr b/src/test/ui/polymorphization/type_parameters/functions.stderr
new file mode 100644 (file)
index 0000000..d629ff7
--- /dev/null
@@ -0,0 +1,35 @@
+error: item has unused generic parameters
+  --> $DIR/functions.rs:14:8
+   |
+LL | pub fn unused<T>() {
+   |        ^^^^^^ - generic parameter `T` is unused
+
+error: item has unused generic parameters
+  --> $DIR/functions.rs:45:12
+   |
+LL | impl<F: Default> Foo<F> {
+   |      - generic parameter `F` is unused
+...
+LL |     pub fn unused_impl() {
+   |            ^^^^^^^^^^^
+
+error: item has unused generic parameters
+  --> $DIR/functions.rs:51:12
+   |
+LL | impl<F: Default> Foo<F> {
+   |      - generic parameter `F` is unused
+...
+LL |     pub fn unused_both<G: Default>() {
+   |            ^^^^^^^^^^^ - generic parameter `G` is unused
+
+error: item has unused generic parameters
+  --> $DIR/functions.rs:63:12
+   |
+LL | impl<F: Default> Foo<F> {
+   |      - generic parameter `F` is unused
+...
+LL |     pub fn used_fn<G: Default>() {
+   |            ^^^^^^^
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/ui/polymorphization/unsized_cast.rs b/src/test/ui/polymorphization/unsized_cast.rs
new file mode 100644 (file)
index 0000000..b8facc1
--- /dev/null
@@ -0,0 +1,29 @@
+// build-fail
+// compile-flags:-Zpolymorphize=on
+#![feature(fn_traits, rustc_attrs, unboxed_closures)]
+
+// This test checks that the polymorphization analysis considers a closure
+// as using all generic parameters if it does an unsizing cast.
+
+#[rustc_polymorphize_error]
+fn foo<T: Default>() {
+    let _: T = Default::default();
+    (|| Box::new(|| {}) as Box<dyn Fn()>)();
+    //~^ ERROR item has unused generic parameters
+    //~^^ ERROR item has unused generic parameters
+}
+
+#[rustc_polymorphize_error]
+fn foo2<T: Default>() {
+    let _: T = Default::default();
+    (|| {
+        let call: extern "rust-call" fn(_, _) = Fn::call;
+        call(&|| {}, ());
+        //~^ ERROR item has unused generic parameters
+    })();
+}
+
+fn main() {
+    foo::<u32>();
+    foo2::<u32>();
+}
diff --git a/src/test/ui/polymorphization/unsized_cast.stderr b/src/test/ui/polymorphization/unsized_cast.stderr
new file mode 100644 (file)
index 0000000..d4727ac
--- /dev/null
@@ -0,0 +1,29 @@
+error: item has unused generic parameters
+  --> $DIR/unsized_cast.rs:11:18
+   |
+LL | fn foo<T: Default>() {
+   |        - generic parameter `T` is unused
+LL |     let _: T = Default::default();
+LL |     (|| Box::new(|| {}) as Box<dyn Fn()>)();
+   |                  ^^^^^
+
+error: item has unused generic parameters
+  --> $DIR/unsized_cast.rs:11:5
+   |
+LL | fn foo<T: Default>() {
+   |        - generic parameter `T` is unused
+LL |     let _: T = Default::default();
+LL |     (|| Box::new(|| {}) as Box<dyn Fn()>)();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: item has unused generic parameters
+  --> $DIR/unsized_cast.rs:21:15
+   |
+LL | fn foo2<T: Default>() {
+   |         - generic parameter `T` is unused
+...
+LL |         call(&|| {}, ());
+   |               ^^^^^
+
+error: aborting due to 3 previous errors
+
index 1894cd218ee347f94546d2b7fa32a878f5937ad1..301edc0d086b11fee1b251fd47b5ab7ebba36190 100644 (file)
@@ -8,12 +8,12 @@ print-type-size     variant `Some`: 12 bytes
 print-type-size         field `.0`: 12 bytes
 print-type-size     variant `None`: 0 bytes
 print-type-size type: `EmbeddedDiscr`: 8 bytes, alignment: 4 bytes
-print-type-size     discriminant: 1 bytes
 print-type-size     variant `Record`: 7 bytes
-print-type-size         field `.pre`: 1 bytes
-print-type-size         field `.post`: 2 bytes
 print-type-size         field `.val`: 4 bytes
+print-type-size         field `.post`: 2 bytes
+print-type-size         field `.pre`: 1 bytes
 print-type-size     variant `None`: 0 bytes
+print-type-size     end padding: 1 bytes
 print-type-size type: `MyOption<Union1<std::num::NonZeroU32>>`: 8 bytes, alignment: 4 bytes
 print-type-size     discriminant: 4 bytes
 print-type-size     variant `Some`: 4 bytes
index 5d199149c39b860d029bc80728988afe33c76b25..9d3f485e314385148fd081174954b3faaf1cedb7 100644 (file)
@@ -5,18 +5,18 @@ trait Foo {}
 impl<'a> Foo for &'a [u8] {}
 
 fn a(v: &[u8]) -> Box<dyn Foo + 'static> {
-    let x: Box<dyn Foo + 'static> = Box::new(v); //~ ERROR cannot infer an appropriate lifetime
+    let x: Box<dyn Foo + 'static> = Box::new(v); //~ ERROR E0759
     x
 }
 
 fn b(v: &[u8]) -> Box<dyn Foo + 'static> {
-    Box::new(v) //~ ERROR cannot infer an appropriate lifetime
+    Box::new(v) //~ ERROR E0759
 }
 
 fn c(v: &[u8]) -> Box<dyn Foo> {
     // same as previous case due to RFC 599
 
-    Box::new(v) //~ ERROR cannot infer an appropriate lifetime
+    Box::new(v) //~ ERROR E0759
 }
 
 fn d<'a,'b>(v: &'a [u8]) -> Box<dyn Foo+'b> {
index 7f5a3a47976c7d38f812fa9fb9a1232657dd2a1c..63fea1f41626d10e22dda55f34b9a949d772d92d 100644 (file)
@@ -1,4 +1,4 @@
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `v` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
   --> $DIR/region-object-lifetime-in-coercion.rs:8:46
    |
 LL | fn a(v: &[u8]) -> Box<dyn Foo + 'static> {
@@ -15,7 +15,7 @@ help: alternatively, add an explicit `'static` bound to this reference
 LL | fn a(v: &'static [u8]) -> Box<dyn Foo + 'static> {
    |         ^^^^^^^^^^^^^
 
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `v` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
   --> $DIR/region-object-lifetime-in-coercion.rs:13:14
    |
 LL | fn b(v: &[u8]) -> Box<dyn Foo + 'static> {
@@ -32,7 +32,7 @@ help: alternatively, add an explicit `'static` bound to this reference
 LL | fn b(v: &'static [u8]) -> Box<dyn Foo + 'static> {
    |         ^^^^^^^^^^^^^
 
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `v` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
   --> $DIR/region-object-lifetime-in-coercion.rs:19:14
    |
 LL | fn c(v: &[u8]) -> Box<dyn Foo> {
index 647212407fc8a5217178f5324d3a321039378f9c..4eb1b275f163ec77af5f50bb86c28b486e72644f 100644 (file)
@@ -4,7 +4,7 @@ struct Dog {
 
 impl Dog {
     pub fn chase_cat(&mut self) {
-        let p: &'static mut usize = &mut self.cats_chased; //~ ERROR cannot infer
+        let p: &'static mut usize = &mut self.cats_chased; //~ ERROR E0759
         *p += 1;
     }
 
index a0b8b6b51e5a1b36572ad8567ad4cbfd94ce81b7..738691fd695eb4fe2aa8e05f40fbbe675e108a1b 100644 (file)
@@ -1,29 +1,11 @@
-error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
+error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
   --> $DIR/regions-addr-of-self.rs:7:37
    |
+LL |     pub fn chase_cat(&mut self) {
+   |                      --------- this data with an anonymous lifetime `'_`...
 LL |         let p: &'static mut usize = &mut self.cats_chased;
-   |                                     ^^^^^^^^^^^^^^^^^^^^^
-   |
-note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 6:5...
-  --> $DIR/regions-addr-of-self.rs:6:5
-   |
-LL | /     pub fn chase_cat(&mut self) {
-LL | |         let p: &'static mut usize = &mut self.cats_chased;
-LL | |         *p += 1;
-LL | |     }
-   | |_____^
-note: ...so that reference does not outlive borrowed content
-  --> $DIR/regions-addr-of-self.rs:7:37
-   |
-LL |         let p: &'static mut usize = &mut self.cats_chased;
-   |                                     ^^^^^^^^^^^^^^^^^^^^^
-   = note: but, the lifetime must be valid for the static lifetime...
-note: ...so that reference does not outlive borrowed content
-  --> $DIR/regions-addr-of-self.rs:7:37
-   |
-LL |         let p: &'static mut usize = &mut self.cats_chased;
-   |                                     ^^^^^^^^^^^^^^^^^^^^^
+   |                                     ^^^^^^^^^^^^^^^^^^^^^ ...is captured and required to live as long as `'static` here
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0495`.
+For more information about this error, try `rustc --explain E0759`.
index 2364ba2728600e7f7a4478c3b4621318ee78689c..7144ab5a24c51443ec36b8dffda63669e12317a0 100644 (file)
@@ -7,7 +7,7 @@ trait X { }
 impl<'a, T> X for B<'a, T> {}
 
 fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'static> {
-    box B(&*v) as Box<dyn X> //~ ERROR cannot infer
+    box B(&*v) as Box<dyn X> //~ ERROR E0759
 }
 
 fn main() { }
index 114e4052aae09b63159cc61e3899af7c0e982403..aab7ce993aa3c3861a55018bbfb1b46912c75056 100644 (file)
@@ -1,4 +1,4 @@
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `v` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
   --> $DIR/regions-close-object-into-object-2.rs:10:11
    |
 LL | fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'static> {
index d5310770436866d544eae03d33347d6a3027b907..4c087f264f92b964010c16521d98fd6a97f92889 100644 (file)
@@ -7,7 +7,7 @@ trait X { }
 impl<'a, T> X for B<'a, T> {}
 
 fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
-    box B(&*v) as Box<dyn X> //~ ERROR cannot infer
+    box B(&*v) as Box<dyn X> //~ ERROR E0759
 }
 
 fn main() {}
index 850d81940791fd168afbe9224765cf642bbaaf61..90f807a41c5629f07d04aeb0d00a47b1491fa879 100644 (file)
@@ -1,4 +1,4 @@
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `v` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
   --> $DIR/regions-close-object-into-object-4.rs:10:11
    |
 LL | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
index 8617c0e9da8f76f51a6319847965b265e8aff148..55d964ac5340569b287a993d650fe88ba70b2f94 100644 (file)
@@ -6,7 +6,7 @@ fn borrowed_proc<'a>(x: &'a isize) -> Box<dyn FnMut()->(isize) + 'a> {
 
 fn static_proc(x: &isize) -> Box<dyn FnMut() -> (isize) + 'static> {
     // This is illegal, because the region bound on `proc` is 'static.
-    Box::new(move || { *x }) //~ ERROR cannot infer an appropriate lifetime
+    Box::new(move || { *x }) //~ ERROR E0759
 }
 
 fn main() { }
index 67eee3bb6e28127bbd8db3417d40386340b6a38f..e76073f4f6b13f5b6be54d1179799ef19cd2c63c 100644 (file)
@@ -1,4 +1,4 @@
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
   --> $DIR/regions-proc-bound-capture.rs:9:14
    |
 LL | fn static_proc(x: &isize) -> Box<dyn FnMut() -> (isize) + 'static> {
diff --git a/src/test/ui/regions/type-param-outlives-reempty-issue-74429-2.rs b/src/test/ui/regions/type-param-outlives-reempty-issue-74429-2.rs
new file mode 100644 (file)
index 0000000..a65c17e
--- /dev/null
@@ -0,0 +1,66 @@
+// Regression test for #74429, where we didn't think that a type parameter
+// outlived `ReEmpty`.
+
+// check-pass
+
+use std::marker::PhantomData;
+use std::ptr::NonNull;
+
+pub unsafe trait RawData {
+    type Elem;
+}
+
+unsafe impl<A> RawData for OwnedRepr<A> {
+    type Elem = A;
+}
+
+unsafe impl<'a, A> RawData for ViewRepr<&'a A> {
+    type Elem = A;
+}
+
+pub struct OwnedRepr<A> {
+    ptr: PhantomData<A>,
+}
+
+// these Copy impls are not necessary for the repro, but allow the code to compile without error
+// on 1.44.1
+#[derive(Copy, Clone)]
+pub struct ViewRepr<A> {
+    life: PhantomData<A>,
+}
+
+#[derive(Copy, Clone)]
+pub struct ArrayBase<S>
+where
+    S: RawData,
+{
+    ptr: NonNull<S::Elem>,
+}
+
+pub type Array<A> = ArrayBase<OwnedRepr<A>>;
+
+pub type ArrayView<'a, A> = ArrayBase<ViewRepr<&'a A>>;
+
+impl<A, S> ArrayBase<S>
+where
+    S: RawData<Elem = A>,
+{
+    pub fn index_axis(&self) -> ArrayView<'_, A> {
+        unimplemented!()
+    }
+
+    pub fn axis_iter<'a>(&'a self) -> std::iter::Empty<&'a A> {
+        unimplemented!()
+    }
+}
+
+pub fn x<T: Copy>(a: Array<T>) {
+    // drop just avoids a must_use warning
+    drop((0..1).filter(|_| true));
+    let y = a.index_axis();
+    a.axis_iter().for_each(|_| {
+        drop(y);
+    });
+}
+
+fn main() {}
diff --git a/src/test/ui/regions/type-param-outlives-reempty-issue-74429.rs b/src/test/ui/regions/type-param-outlives-reempty-issue-74429.rs
new file mode 100644 (file)
index 0000000..d463f31
--- /dev/null
@@ -0,0 +1,35 @@
+// Regression test for #74429, where we didn't think that a type parameter
+// outlived `ReEmpty`.
+
+// check-pass
+
+use std::marker::PhantomData;
+
+fn apply<T, F: FnOnce(T)>(_: T, _: F) {}
+
+#[derive(Clone, Copy)]
+struct Invariant<T> {
+    t: T,
+    p: PhantomData<fn(T) -> T>,
+}
+
+fn verify_reempty<T>(x: T) {
+    // r is inferred to have type `Invariant<&ReEmpty(U0) T>`
+    let r = Invariant { t: &x, p: PhantomData };
+    // Creates a new universe, all variables from now on are in `U1`, say.
+    let _: fn(&()) = |_| {};
+    // Closure parameter is of type `&ReEmpty(U1) T`, so the closure has an implied
+    // bound of `T: ReEmpty(U1)`
+    apply(&x, |_| {
+        // Requires `typeof(r)` is well-formed, i.e. `T: ReEmpty(U0)`. If we
+        // only have the implied bound from the closure parameter to use this
+        // requires `ReEmpty(U1): ReEmpty(U0)`, which isn't true so we reported
+        // an error.
+        //
+        // This doesn't happen any more because we ensure that `T: ReEmpty(U0)`
+        // is an implicit bound for all type parameters.
+        drop(r);
+    });
+}
+
+fn main() {}
index 3fb1cf9f557b2c86d71de72e61fa2c51c0895381..310545b92d5492d23f7d698790a9dfdcbe47001e 100644 (file)
@@ -1,6 +1,5 @@
 #![feature(non_ascii_idents)]
 
 extern crate ьаг; //~ ERROR cannot load a crate with a non-ascii name `ьаг`
-//~| ERROR can't find crate for `ьаг`
 
 fn main() {}
index 1e424237fd238480f5a37082015ed1f34df0f8f0..11108f2fb86789ce88b273be499e3a7c0a54b750 100644 (file)
@@ -4,12 +4,5 @@ error: cannot load a crate with a non-ascii name `ьаг`
 LL | extern crate ьаг;
    | ^^^^^^^^^^^^^^^^^
 
-error[E0463]: can't find crate for `ьаг`
-  --> $DIR/crate_name_nonascii_forbidden-1.rs:3:1
-   |
-LL | extern crate ьаг;
-   | ^^^^^^^^^^^^^^^^^ can't find crate
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0463`.
index e1acdbff06189efd8b07c8f493e927ec98596900..0249848b35ac0b12621a0b0739ba1e1dcd72f53f 100644 (file)
@@ -3,7 +3,5 @@
 #![feature(non_ascii_idents)]
 
 use му_сгате::baz; //~  ERROR cannot load a crate with a non-ascii name `му_сгате`
-                   //~| can't find crate for `му_сгате`
-
 
 fn main() {}
index c06405ebb37ec6a15e736c607e7387babfb0606d..8d3548ed33dcf8a70047df8c8cb1cbbe97382eab 100644 (file)
@@ -4,12 +4,5 @@ error: cannot load a crate with a non-ascii name `му_сгате`
 LL | use му_сгате::baz;
    |     ^^^^^^^^
 
-error[E0463]: can't find crate for `му_сгате`
-  --> $DIR/crate_name_nonascii_forbidden-2.rs:5:5
-   |
-LL | use му_сгате::baz;
-   |     ^^^^^^^^ can't find crate
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0463`.
index 64d6ccf34091681d386c7c3f746c7e529e2d15fb..9439df266d59bbe6c7da7b1d0a822e3462f55917 100644 (file)
@@ -2,7 +2,7 @@
 // being run when compiling with new LLVM pass manager and ThinLTO.
 // Note: The issue occurred only on non-zero opt-level.
 //
-// min-llvm-version 9.0
+// min-llvm-version: 9.0
 // needs-sanitizer-support
 // needs-sanitizer-address
 //
index 0afe631f1e3fc03921e8539f2eee46ca69cc546f..43998ca8c5784478dfca0e18aea561c2aab3ef40 100644 (file)
@@ -6,7 +6,7 @@
 
 impl Foo {
     async fn f(self: Pin<&Self>) -> impl Clone { self }
-    //~^ ERROR cannot infer an appropriate lifetime
+    //~^ ERROR E0759
 }
 
 fn main() {
index f2fbb0ba7d7556738dd6951afe48ea920e2553d7..9cd0fd328ffa007a37fda588dbed69e79ce2aca9 100644 (file)
@@ -1,4 +1,4 @@
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
   --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait-async.rs:8:16
    |
 LL |     async fn f(self: Pin<&Self>) -> impl Clone { self }
index 5054568b18970ca0331dfde31bed23c1de9c65ac..04935fc52ab9e31253bb8dce181cacfafdd589ac 100644 (file)
@@ -3,7 +3,7 @@
 struct Foo;
 
 impl Foo {
-    fn f(self: Pin<&Self>) -> impl Clone { self } //~ ERROR cannot infer an appropriate lifetime
+    fn f(self: Pin<&Self>) -> impl Clone { self } //~ ERROR E0759
 }
 
 fn main() {
index 2e10ab3d3f9b84a8c1802524008ab8020e311bd2..cb9d5b56dbc5cbd585691e8647bf4a224f660776 100644 (file)
@@ -1,4 +1,4 @@
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
   --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait.rs:6:44
    |
 LL |     fn f(self: Pin<&Self>) -> impl Clone { self }
diff --git a/src/test/ui/specialization/min_specialization/impl-on-nonexisting.rs b/src/test/ui/specialization/min_specialization/impl-on-nonexisting.rs
new file mode 100644 (file)
index 0000000..77a6432
--- /dev/null
@@ -0,0 +1,7 @@
+#![feature(min_specialization)]
+
+trait Trait {}
+impl Trait for NonExistent {}
+//~^ ERROR cannot find type `NonExistent` in this scope
+
+fn main() {}
diff --git a/src/test/ui/specialization/min_specialization/impl-on-nonexisting.stderr b/src/test/ui/specialization/min_specialization/impl-on-nonexisting.stderr
new file mode 100644 (file)
index 0000000..b032ccb
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0412]: cannot find type `NonExistent` in this scope
+  --> $DIR/impl-on-nonexisting.rs:4:16
+   |
+LL | impl Trait for NonExistent {}
+   |                ^^^^^^^^^^^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0412`.
index 5db924642e59df3d1f021b83f2f240d0529eef56..80d7ae6dc637d78723cdc17ab762f4d7945bc324 100644 (file)
@@ -62,7 +62,7 @@ fn multiple3() { }
 #[rustc_deprecated(since = "b", reason = "text")]
 #[rustc_const_unstable(feature = "c", issue = "none")]
 #[rustc_const_unstable(feature = "d", issue = "none")] //~ ERROR multiple stability levels
-pub const fn multiple4() { } //~ ERROR multiple rustc_deprecated attributes [E0540]
+pub const fn multiple4() { } //~ ERROR multiple deprecated attributes
 //~^ ERROR Invalid stability or deprecation version found
 
 #[rustc_deprecated(since = "a", reason = "text")]
index 3c5da3f14403503d00caf5533ede8b3624fd8f80..134c657c62015b51be3739ec0fa7ba2d048d14a1 100644 (file)
@@ -82,7 +82,7 @@ error[E0544]: multiple stability levels
 LL | #[stable(feature = "a", since = "b")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0540]: multiple rustc_deprecated attributes
+error[E0550]: multiple deprecated attributes
   --> $DIR/stability-attribute-sanity.rs:65:1
    |
 LL | pub const fn multiple4() { }
@@ -108,5 +108,5 @@ LL | fn deprecated_without_unstable_or_stable() { }
 
 error: aborting due to 18 previous errors
 
-Some errors have detailed explanations: E0539, E0541.
+Some errors have detailed explanations: E0539, E0541, E0550.
 For more information about an error, try `rustc --explain E0539`.
diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.nll.stderr b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.nll.stderr
new file mode 100644 (file)
index 0000000..acf0c0e
--- /dev/null
@@ -0,0 +1,37 @@
+error[E0597]: `val` does not live long enough
+  --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:21:9
+   |
+LL |     fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = i32>>) -> impl OtherTrait<'a> {
+   |               -- lifetime `'a` defined here                  ------------------- opaque type requires that `val` is borrowed for `'a`
+LL |         val.use_self()
+   |         ^^^ borrowed value does not live long enough
+LL |     }
+   |     - `val` dropped here while still borrowed
+   |
+help: you can add a bound to the opaque type to make it last less than `'static` and match `'a`
+   |
+LL |     fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = i32>>) -> impl OtherTrait<'a> + 'a {
+   |                                                                                  ^^^^
+
+error[E0515]: cannot return value referencing function parameter `val`
+  --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:43:9
+   |
+LL |         val.use_self()
+   |         ---^^^^^^^^^^^
+   |         |
+   |         returns a value referencing data owned by the current function
+   |         `val` is borrowed here
+
+error[E0515]: cannot return value referencing function parameter `val`
+  --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:109:9
+   |
+LL |         val.use_self()
+   |         ---^^^^^^^^^^^
+   |         |
+   |         returns a value referencing data owned by the current function
+   |         `val` is borrowed here
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0515, E0597.
+For more information about an error, try `rustc --explain E0515`.
diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs
new file mode 100644 (file)
index 0000000..b2dc16a
--- /dev/null
@@ -0,0 +1,113 @@
+// FIXME: the following cases need to suggest more things to make users reach a working end state.
+
+mod bav {
+    trait OtherTrait<'a> {}
+    impl<'a> OtherTrait<'a> for &'a () {}
+
+    trait ObjectTrait {
+        type Assoc: Bar;
+    }
+    trait MyTrait {
+        fn use_self(&self) -> &() { panic!() }
+    }
+    trait Bar {}
+
+    impl MyTrait for Box<dyn ObjectTrait<Assoc = i32>> {
+        fn use_self(&self) -> &() { panic!() }
+    }
+    impl Bar for i32 {}
+
+    fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = i32>>) -> impl OtherTrait<'a> {
+        val.use_self() //~ ERROR E0597
+    }
+}
+
+mod bap {
+    trait OtherTrait<'a> {}
+    impl<'a> OtherTrait<'a> for &'a () {}
+
+    trait ObjectTrait {
+        type Assoc: Bar;
+    }
+    trait MyTrait {
+        fn use_self(&self) -> &() { panic!() }
+    }
+    trait Bar {}
+
+    impl MyTrait for Box<dyn ObjectTrait<Assoc = i32>> {
+        fn use_self(&self) -> &() { panic!() }
+    }
+    impl Bar for i32 {}
+
+    fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = i32>>) -> impl OtherTrait<'a> + 'a {
+        val.use_self() //~ ERROR E0515
+    }
+}
+
+// This case in particular requires the user to write all of the bounds we have in `mod bax`.
+mod bay {
+    trait OtherTrait<'a> {}
+    impl<'a> OtherTrait<'a> for &'a () {}
+
+    trait ObjectTrait {
+        type Assoc: Bar;
+    }
+    trait MyTrait {
+        fn use_self(&self) -> &() { panic!() }
+    }
+    trait Bar {}
+
+    impl MyTrait for Box<dyn ObjectTrait<Assoc = i32>> {
+        fn use_self(&self) -> &() { panic!() }
+    }
+    impl Bar for i32 {}
+
+    fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = i32> + 'a>) -> &'a () {
+        val.use_self() //~ ERROR E0772
+    }
+}
+
+mod bax {
+    trait OtherTrait<'a> {}
+    impl<'a> OtherTrait<'a> for &'a () {}
+
+    trait ObjectTrait {
+        type Assoc: Bar;
+    }
+    trait MyTrait<'a> {
+        fn use_self(&'a self) -> &'a () { panic!() }
+    }
+    trait Bar {}
+
+    impl<'a> MyTrait<'a> for Box<dyn ObjectTrait<Assoc = i32> + 'a> {
+        fn use_self(&'a self) -> &'a () { panic!() }
+    }
+    impl Bar for i32 {}
+
+    fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = i32> + 'a>) -> &'a () {
+        val.use_self()
+    }
+}
+
+mod baw {
+    trait OtherTrait<'a> {}
+    impl<'a> OtherTrait<'a> for &'a () {}
+
+    trait ObjectTrait {
+        type Assoc: Bar;
+    }
+    trait MyTrait {
+        fn use_self(&self) -> &() { panic!() }
+    }
+    trait Bar {}
+
+    impl<'a> MyTrait for Box<dyn ObjectTrait<Assoc = Box<dyn Bar>>> {
+        fn use_self(&self) -> &() { panic!() }
+    }
+
+    fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = Box<dyn Bar>>>) -> impl OtherTrait<'a> + 'a{
+        val.use_self() //~ ERROR E0515
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr
new file mode 100644 (file)
index 0000000..00971b4
--- /dev/null
@@ -0,0 +1,57 @@
+error[E0597]: `val` does not live long enough
+  --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:21:9
+   |
+LL |     fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = i32>>) -> impl OtherTrait<'a> {
+   |               -- lifetime `'a` defined here                  ------------------- opaque type requires that `val` is borrowed for `'a`
+LL |         val.use_self()
+   |         ^^^ borrowed value does not live long enough
+LL |     }
+   |     - `val` dropped here while still borrowed
+   |
+help: you can add a bound to the opaque type to make it last less than `'static` and match `'a`
+   |
+LL |     fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = i32>>) -> impl OtherTrait<'a> + 'a {
+   |                                                                                  ^^^^
+
+error[E0515]: cannot return value referencing function parameter `val`
+  --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:43:9
+   |
+LL |         val.use_self()
+   |         ---^^^^^^^^^^^
+   |         |
+   |         returns a value referencing data owned by the current function
+   |         `val` is borrowed here
+
+error[E0515]: cannot return value referencing function parameter `val`
+  --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:109:9
+   |
+LL |         val.use_self()
+   |         ---^^^^^^^^^^^
+   |         |
+   |         returns a value referencing data owned by the current function
+   |         `val` is borrowed here
+
+error[E0772]: `val` has lifetime `'a` but calling `use_self` introduces an implicit `'static` lifetime requirement
+  --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:66:13
+   |
+LL |     fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = i32> + 'a>) -> &'a () {
+   |                        -------------------------------------- this data with lifetime `'a`...
+LL |         val.use_self()
+   |             ^^^^^^^^ ...is captured and required to live as long as `'static` here
+   |
+note: the used `impl` has a `'static` requirement
+  --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:60:30
+   |
+LL |     impl MyTrait for Box<dyn ObjectTrait<Assoc = i32>> {
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^ this has an implicit `'static` lifetime requirement
+LL |         fn use_self(&self) -> &() { panic!() }
+   |            -------- calling this method introduces the `impl`'s 'static` requirement
+help: consider relaxing the implicit `'static` requirement
+   |
+LL |     impl MyTrait for Box<dyn ObjectTrait<Assoc = i32> + '_> {
+   |                                                       ^^^^
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0515, E0597.
+For more information about an error, try `rustc --explain E0515`.
diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.fixed b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.fixed
new file mode 100644 (file)
index 0000000..3c10f85
--- /dev/null
@@ -0,0 +1,112 @@
+// run-rustfix
+#![allow(dead_code)]
+
+mod foo {
+    trait OtherTrait<'a> {}
+    impl<'a> OtherTrait<'a> for &'a () {}
+
+    trait ObjectTrait<T> {}
+    trait MyTrait<T> {
+        fn use_self<K>(&self) -> &();
+    }
+    trait Irrelevant {}
+
+    impl<T> MyTrait<T> for dyn ObjectTrait<T> + '_ {
+        fn use_self<K>(&self) -> &() { panic!() }
+    }
+    impl<T> Irrelevant for dyn ObjectTrait<T> {}
+
+    fn use_it<'a, T>(val: &'a dyn ObjectTrait<T>) -> impl OtherTrait<'a> + 'a {
+        val.use_self::<T>() //~ ERROR E0759
+    }
+}
+
+mod bar {
+    trait ObjectTrait {}
+    trait MyTrait {
+        fn use_self(&self) -> &();
+    }
+    trait Irrelevant {}
+
+    impl MyTrait for dyn ObjectTrait + '_ {
+        fn use_self(&self) -> &() { panic!() }
+    }
+    impl Irrelevant for dyn ObjectTrait {}
+
+    fn use_it<'a>(val: &'a dyn ObjectTrait) -> &'a () {
+        val.use_self() //~ ERROR E0772
+    }
+}
+
+mod baz {
+    trait ObjectTrait {}
+    trait MyTrait {
+        fn use_self(&self) -> &();
+    }
+    trait Irrelevant {}
+
+    impl MyTrait for Box<dyn ObjectTrait + '_> {
+        fn use_self(&self) -> &() { panic!() }
+    }
+    impl Irrelevant for Box<dyn ObjectTrait> {}
+
+    fn use_it<'a>(val: &'a Box<dyn ObjectTrait + 'a>) -> &'a () {
+        val.use_self() //~ ERROR E0772
+    }
+}
+
+mod bat {
+    trait OtherTrait<'a> {}
+    impl<'a> OtherTrait<'a> for &'a () {}
+
+    trait ObjectTrait {}
+
+    impl dyn ObjectTrait + '_ {
+        fn use_self(&self) -> &() { panic!() }
+    }
+
+    fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a {
+        val.use_self() //~ ERROR E0772
+    }
+}
+
+mod ban {
+    trait OtherTrait<'a> {}
+    impl<'a> OtherTrait<'a> for &'a () {}
+
+    trait ObjectTrait {}
+    trait MyTrait {
+        fn use_self(&self) -> &() { panic!() }
+    }
+    trait Irrelevant {
+        fn use_self(&self) -> &() { panic!() }
+    }
+
+    impl MyTrait for dyn ObjectTrait + '_ {}
+
+    fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a {
+        val.use_self() //~ ERROR E0759
+    }
+}
+
+mod bal {
+    trait OtherTrait<'a> {}
+    impl<'a> OtherTrait<'a> for &'a () {}
+
+    trait ObjectTrait {}
+    trait MyTrait {
+        fn use_self(&self) -> &() { panic!() }
+    }
+    trait Irrelevant {
+        fn use_self(&self) -> &() { panic!() }
+    }
+
+    impl MyTrait for dyn ObjectTrait + '_ {}
+    impl Irrelevant for dyn ObjectTrait {}
+
+    fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a {
+        MyTrait::use_self(val) //~ ERROR E0759
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.nll.stderr b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.nll.stderr
new file mode 100644 (file)
index 0000000..697467d
--- /dev/null
@@ -0,0 +1,42 @@
+error[E0521]: borrowed data escapes outside of function
+  --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:20:9
+   |
+LL |     fn use_it<'a, T>(val: &'a dyn ObjectTrait<T>) -> impl OtherTrait<'a> + 'a {
+   |                      --- `val` is a reference that is only valid in the function body
+LL |         val.use_self::<T>()
+   |         ^^^^^^^^^^^^^^^^^^^ `val` escapes the function body here
+   |
+   = help: consider replacing `'a` with `'static`
+
+error[E0521]: borrowed data escapes outside of function
+  --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:69:9
+   |
+LL |     fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a {
+   |                   --- `val` is a reference that is only valid in the function body
+LL |         val.use_self()
+   |         ^^^^^^^^^^^^^^ `val` escapes the function body here
+   |
+   = help: consider replacing `'a` with `'static`
+
+error[E0521]: borrowed data escapes outside of function
+  --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:88:9
+   |
+LL |     fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> {
+   |                   --- `val` is a reference that is only valid in the function body
+LL |         val.use_self()
+   |         ^^^^^^^^^^^^^^ `val` escapes the function body here
+   |
+   = help: consider replacing `'a` with `'static`
+
+error[E0521]: borrowed data escapes outside of function
+  --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:108:9
+   |
+LL |     fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a {
+   |                   --- `val` is a reference that is only valid in the function body
+LL |         MyTrait::use_self(val)
+   |         ^^^^^^^^^^^^^^^^^^^^^^ `val` escapes the function body here
+   |
+   = help: consider replacing `'a` with `'static`
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.rs b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.rs
new file mode 100644 (file)
index 0000000..88ab03d
--- /dev/null
@@ -0,0 +1,112 @@
+// run-rustfix
+#![allow(dead_code)]
+
+mod foo {
+    trait OtherTrait<'a> {}
+    impl<'a> OtherTrait<'a> for &'a () {}
+
+    trait ObjectTrait<T> {}
+    trait MyTrait<T> {
+        fn use_self<K>(&self) -> &();
+    }
+    trait Irrelevant {}
+
+    impl<T> MyTrait<T> for dyn ObjectTrait<T> {
+        fn use_self<K>(&self) -> &() { panic!() }
+    }
+    impl<T> Irrelevant for dyn ObjectTrait<T> {}
+
+    fn use_it<'a, T>(val: &'a dyn ObjectTrait<T>) -> impl OtherTrait<'a> + 'a {
+        val.use_self::<T>() //~ ERROR E0759
+    }
+}
+
+mod bar {
+    trait ObjectTrait {}
+    trait MyTrait {
+        fn use_self(&self) -> &();
+    }
+    trait Irrelevant {}
+
+    impl MyTrait for dyn ObjectTrait {
+        fn use_self(&self) -> &() { panic!() }
+    }
+    impl Irrelevant for dyn ObjectTrait {}
+
+    fn use_it<'a>(val: &'a dyn ObjectTrait) -> &'a () {
+        val.use_self() //~ ERROR E0772
+    }
+}
+
+mod baz {
+    trait ObjectTrait {}
+    trait MyTrait {
+        fn use_self(&self) -> &();
+    }
+    trait Irrelevant {}
+
+    impl MyTrait for Box<dyn ObjectTrait> {
+        fn use_self(&self) -> &() { panic!() }
+    }
+    impl Irrelevant for Box<dyn ObjectTrait> {}
+
+    fn use_it<'a>(val: &'a Box<dyn ObjectTrait + 'a>) -> &'a () {
+        val.use_self() //~ ERROR E0772
+    }
+}
+
+mod bat {
+    trait OtherTrait<'a> {}
+    impl<'a> OtherTrait<'a> for &'a () {}
+
+    trait ObjectTrait {}
+
+    impl dyn ObjectTrait {
+        fn use_self(&self) -> &() { panic!() }
+    }
+
+    fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a {
+        val.use_self() //~ ERROR E0772
+    }
+}
+
+mod ban {
+    trait OtherTrait<'a> {}
+    impl<'a> OtherTrait<'a> for &'a () {}
+
+    trait ObjectTrait {}
+    trait MyTrait {
+        fn use_self(&self) -> &() { panic!() }
+    }
+    trait Irrelevant {
+        fn use_self(&self) -> &() { panic!() }
+    }
+
+    impl MyTrait for dyn ObjectTrait {}
+
+    fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> {
+        val.use_self() //~ ERROR E0759
+    }
+}
+
+mod bal {
+    trait OtherTrait<'a> {}
+    impl<'a> OtherTrait<'a> for &'a () {}
+
+    trait ObjectTrait {}
+    trait MyTrait {
+        fn use_self(&self) -> &() { panic!() }
+    }
+    trait Irrelevant {
+        fn use_self(&self) -> &() { panic!() }
+    }
+
+    impl MyTrait for dyn ObjectTrait {}
+    impl Irrelevant for dyn ObjectTrait {}
+
+    fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a {
+        MyTrait::use_self(val) //~ ERROR E0759
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr
new file mode 100644 (file)
index 0000000..2fb6c25
--- /dev/null
@@ -0,0 +1,134 @@
+error[E0759]: `val` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
+  --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:20:13
+   |
+LL |     fn use_it<'a, T>(val: &'a dyn ObjectTrait<T>) -> impl OtherTrait<'a> + 'a {
+   |                           ---------------------- this data with lifetime `'a`...
+LL |         val.use_self::<T>()
+   |             ^^^^^^^^ ...is captured and required to live as long as `'static` here
+   |
+note: the used `impl` has a `'static` requirement
+  --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:14:32
+   |
+LL |     impl<T> MyTrait<T> for dyn ObjectTrait<T> {
+   |                                ^^^^^^^^^^^^^^ this has an implicit `'static` lifetime requirement
+LL |         fn use_self<K>(&self) -> &() { panic!() }
+   |            -------- calling this method introduces the `impl`'s 'static` requirement
+help: consider relaxing the implicit `'static` requirement
+   |
+LL |     impl<T> MyTrait<T> for dyn ObjectTrait<T> + '_ {
+   |                                               ^^^^
+
+error[E0772]: `val` has lifetime `'a` but calling `use_self` introduces an implicit `'static` lifetime requirement
+  --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:69:13
+   |
+LL |     fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a {
+   |                        ------------------- this data with lifetime `'a`...
+LL |         val.use_self()
+   |             ^^^^^^^^ ...is captured and required to live as long as `'static` here because of an implicit lifetime bound on the inherent `impl`
+   |
+note: the used `impl` has a `'static` requirement
+  --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:64:14
+   |
+LL |     impl dyn ObjectTrait {
+   |              ^^^^^^^^^^^ this has an implicit `'static` lifetime requirement
+LL |         fn use_self(&self) -> &() { panic!() }
+   |            -------- calling this method introduces the `impl`'s 'static` requirement
+help: consider relaxing the implicit `'static` requirement
+   |
+LL |     impl dyn ObjectTrait + '_ {
+   |                          ^^^^
+
+error[E0759]: `val` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
+  --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:88:13
+   |
+LL |     fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> {
+   |                        ------------------- this data with lifetime `'a`...
+LL |         val.use_self()
+   |             ^^^^^^^^ ...is captured and required to live as long as `'static` here
+   |
+note: the used `impl` has a `'static` requirement
+  --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:85:26
+   |
+LL |         fn use_self(&self) -> &() { panic!() }
+   |            -------- calling this method introduces the `impl`'s 'static` requirement
+...
+LL |     impl MyTrait for dyn ObjectTrait {}
+   |                          ^^^^^^^^^^^ this has an implicit `'static` lifetime requirement
+help: consider relaxing the implicit `'static` requirement
+   |
+LL |     impl MyTrait for dyn ObjectTrait + '_ {}
+   |                                      ^^^^
+help: to declare that the `impl Trait` captures data from argument `val`, you can add an explicit `'a` lifetime bound
+   |
+LL |     fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a {
+   |                                                                    ^^^^
+
+error[E0759]: `val` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
+  --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:108:27
+   |
+LL |     fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a {
+   |                        ------------------- this data with lifetime `'a`...
+LL |         MyTrait::use_self(val)
+   |                           ^^^ ...is captured here...
+   |
+note: ...and is required to live as long as `'static` here
+  --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:108:9
+   |
+LL |         MyTrait::use_self(val)
+   |         ^^^^^^^^^^^^^^^^^
+note: the used `impl` has a `'static` requirement
+  --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:104:26
+   |
+LL |         fn use_self(&self) -> &() { panic!() }
+   |            -------- calling this method introduces the `impl`'s 'static` requirement
+...
+LL |     impl MyTrait for dyn ObjectTrait {}
+   |                          ^^^^^^^^^^^ this has an implicit `'static` lifetime requirement
+help: consider relaxing the implicit `'static` requirement
+   |
+LL |     impl MyTrait for dyn ObjectTrait + '_ {}
+   |                                      ^^^^
+
+error[E0772]: `val` has lifetime `'a` but calling `use_self` introduces an implicit `'static` lifetime requirement
+  --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:37:13
+   |
+LL |     fn use_it<'a>(val: &'a dyn ObjectTrait) -> &'a () {
+   |                        ------------------- this data with lifetime `'a`...
+LL |         val.use_self()
+   |             ^^^^^^^^ ...is captured and required to live as long as `'static` here
+   |
+note: the used `impl` has a `'static` requirement
+  --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:31:26
+   |
+LL |     impl MyTrait for dyn ObjectTrait {
+   |                          ^^^^^^^^^^^ this has an implicit `'static` lifetime requirement
+LL |         fn use_self(&self) -> &() { panic!() }
+   |            -------- calling this method introduces the `impl`'s 'static` requirement
+help: consider relaxing the implicit `'static` requirement
+   |
+LL |     impl MyTrait for dyn ObjectTrait + '_ {
+   |                                      ^^^^
+
+error[E0772]: `val` has lifetime `'a` but calling `use_self` introduces an implicit `'static` lifetime requirement
+  --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:54:13
+   |
+LL |     fn use_it<'a>(val: &'a Box<dyn ObjectTrait + 'a>) -> &'a () {
+   |                        ----------------------------- this data with lifetime `'a`...
+LL |         val.use_self()
+   |             ^^^^^^^^ ...is captured and required to live as long as `'static` here
+   |
+note: the used `impl` has a `'static` requirement
+  --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:48:30
+   |
+LL |     impl MyTrait for Box<dyn ObjectTrait> {
+   |                              ^^^^^^^^^^^ this has an implicit `'static` lifetime requirement
+LL |         fn use_self(&self) -> &() { panic!() }
+   |            -------- calling this method introduces the `impl`'s 'static` requirement
+help: consider relaxing the implicit `'static` requirement
+   |
+LL |     impl MyTrait for Box<dyn ObjectTrait + '_> {
+   |                                          ^^^^
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0759`.
index d3853445dfdfebb01518eb66ac063a0872c38fcb..94dd826a15cae71be3d0881f4bbeba350e2c2c38 100644 (file)
@@ -16,7 +16,7 @@ fn foo<G, T>(g: G, dest: &mut T) -> impl FnOnce()
 where
     G: Get<T>
 {
-    move || { //~ ERROR cannot infer an appropriate lifetime
+    move || { //~ ERROR `dest`
         *dest = g.get();
     }
 }
index 9ab060328537b56b08f0f3dcf6b023edfcd3fea5..d7051515f11029c04401888c11f9407e529b5a60 100644 (file)
@@ -6,7 +6,7 @@ LL | fn baz<G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
    |        |
    |        help: consider introducing lifetime `'a` here: `'a,`
 
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `dest` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
   --> $DIR/missing-lifetimes-in-signature.rs:19:5
    |
 LL |   fn foo<G, T>(g: G, dest: &mut T) -> impl FnOnce()
index f78edb1c83a4c97e549713f99975b073b9b30144..d8446e58dbb63eb9e7b593d69e6ae660492a232e 100644 (file)
@@ -27,7 +27,7 @@ impl Bar {
     fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> {
         Iter {
             current: None,
-            remaining: self.0.iter(), //~ ERROR cannot infer an appropriate lifetime
+            remaining: self.0.iter(), //~ ERROR E0759
         }
     }
 }
@@ -38,7 +38,7 @@ impl Baz {
     fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> + '_ {
         Iter {
             current: None,
-            remaining: self.0.iter(), //~ ERROR cannot infer an appropriate lifetime
+            remaining: self.0.iter(), //~ ERROR E0759
         }
     }
 }
@@ -49,7 +49,7 @@ impl Bat {
     fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> + 'a {
         Iter {
             current: None,
-            remaining: self.0.iter(), //~ ERROR cannot infer an appropriate lifetime
+            remaining: self.0.iter(), //~ ERROR E0759
         }
     }
 }
@@ -60,7 +60,7 @@ impl Ban {
     fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> {
         Iter {
             current: None,
-            remaining: self.0.iter(), //~ ERROR cannot infer an appropriate lifetime
+            remaining: self.0.iter(), //~ ERROR E0759
         }
     }
 }
index 1257e9b172cf71ac9e4458f81fe212e6eb0d2744..9f30787f07cc6d9d9114805811f52a0b0323191a 100644 (file)
@@ -1,4 +1,4 @@
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
   --> $DIR/trait-object-nested-in-impl-trait.rs:30:31
    |
 LL |     fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> {
@@ -23,7 +23,7 @@ help: to declare that the trait object captures data from argument `self`, you c
 LL |     fn iter(&self) -> impl Iterator<Item = Box<dyn Foo + '_>> {
    |                                                        ^^^^
 
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
   --> $DIR/trait-object-nested-in-impl-trait.rs:41:31
    |
 LL |     fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> + '_ {
@@ -44,7 +44,7 @@ help: to declare that the trait object captures data from argument `self`, you c
 LL |     fn iter(&self) -> impl Iterator<Item = Box<dyn Foo + '_>> + '_ {
    |                                                        ^^^^
 
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `self` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
   --> $DIR/trait-object-nested-in-impl-trait.rs:52:31
    |
 LL |     fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> + 'a {
@@ -65,7 +65,7 @@ help: to declare that the trait object captures data from argument `self`, you c
 LL |     fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo + 'a>> + 'a {
    |                                                               ^^^^
 
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `self` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
   --> $DIR/trait-object-nested-in-impl-trait.rs:63:31
    |
 LL |     fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> {
diff --git a/src/test/ui/traits/issue-72410.rs b/src/test/ui/traits/issue-72410.rs
new file mode 100644 (file)
index 0000000..c95f1df
--- /dev/null
@@ -0,0 +1,18 @@
+// Regression test for #72410, this should be used with debug assertion enabled.
+
+// should be fine
+pub trait Foo {
+    fn map()
+    where
+        Self: Sized,
+        for<'a> &'a mut [u8]: ;
+}
+
+// should fail
+pub trait Bar {
+    fn map()
+    where for<'a> &'a mut [dyn Bar]: ;
+    //~^ ERROR: the trait `Bar` cannot be made into an object
+}
+
+fn main() {}
diff --git a/src/test/ui/traits/issue-72410.stderr b/src/test/ui/traits/issue-72410.stderr
new file mode 100644 (file)
index 0000000..1db2320
--- /dev/null
@@ -0,0 +1,18 @@
+error[E0038]: the trait `Bar` cannot be made into an object
+  --> $DIR/issue-72410.rs:14:19
+   |
+LL | pub trait Bar {
+   |           --- this trait cannot be made into an object...
+LL |     fn map()
+   |        --- ...because associated function `map` has no `self` parameter
+LL |     where for<'a> &'a mut [dyn Bar]: ;
+   |                   ^^^^^^^^^^^^^^^^^ the trait `Bar` cannot be made into an object
+   |
+help: consider turning `map` into a method by giving it a `&self` argument or constraining it so it does not apply to trait objects
+   |
+LL |     where for<'a> &'a mut [dyn Bar]:, Self: Sized ;
+   |                                     ^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0038`.
index 73a11a5e743f6a7f85810bfbcc0d86d54cf7fd3d..6a3f3c98f127a96d1b5e0a3c93e7d1e1f95b0018 100644 (file)
@@ -5,7 +5,6 @@
 #![feature(never_type)]
 
 use std::mem::size_of;
-use std::num::NonZeroU8;
 
 struct t {a: u8, b: i8}
 struct u {a: u8, b: i8, c: u8}
@@ -103,23 +102,6 @@ enum Option2<A, B> {
     None
 }
 
-// Two layouts are considered for `CanBeNicheFilledButShouldnt`:
-//   Niche-filling:
-//     { u32 (4 bytes), NonZeroU8 + tag in niche (1 byte), padding (3 bytes) }
-//   Tagged:
-//     { tag (1 byte), NonZeroU8 (1 byte), padding (2 bytes), u32 (4 bytes) }
-// Both are the same size (due to padding),
-// but the tagged layout is better as the tag creates a niche with 254 invalid values,
-// allowing types like `Option<Option<CanBeNicheFilledButShouldnt>>` to fit into 8 bytes.
-pub enum CanBeNicheFilledButShouldnt {
-    A(NonZeroU8, u32),
-    B
-}
-pub enum AlwaysTaggedBecauseItHasNoNiche {
-    A(u8, u32),
-    B
-}
-
 pub fn main() {
     assert_eq!(size_of::<u8>(), 1 as usize);
     assert_eq!(size_of::<u32>(), 4 as usize);
@@ -163,11 +145,4 @@ pub fn main() {
     assert_eq!(size_of::<Option<Option<(&(), bool)>>>(), size_of::<(bool, &())>());
     assert_eq!(size_of::<Option<Option2<bool, &()>>>(), size_of::<(bool, &())>());
     assert_eq!(size_of::<Option<Option2<&(), bool>>>(), size_of::<(bool, &())>());
-
-    assert_eq!(size_of::<CanBeNicheFilledButShouldnt>(), 8);
-    assert_eq!(size_of::<Option<CanBeNicheFilledButShouldnt>>(), 8);
-    assert_eq!(size_of::<Option<Option<CanBeNicheFilledButShouldnt>>>(), 8);
-    assert_eq!(size_of::<AlwaysTaggedBecauseItHasNoNiche>(), 8);
-    assert_eq!(size_of::<Option<AlwaysTaggedBecauseItHasNoNiche>>(), 8);
-    assert_eq!(size_of::<Option<Option<AlwaysTaggedBecauseItHasNoNiche>>>(), 8);
 }
index 133c5231031fd65a8d86b67159828b3b539d8362..2c8b1e76b1b82984d7a677a07d53c27b6c849f23 100644 (file)
@@ -194,6 +194,8 @@ trait Qux {
     const D: _ = 42;
     //~^ ERROR the type placeholder `_` is not allowed within types on item signatures
     // type E: _; // FIXME: make the parser propagate the existence of `B`
+    type F: std::ops::Fn(_);
+    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures
 }
 impl Qux for Struct {
     type A = _;
index a1945f2b9cf4e88b314f5d395d555a76f3a1ced4..782ff4948cda46e9032450e063bc65acbfbd44e8 100644 (file)
@@ -29,7 +29,7 @@ LL | struct BadStruct2<_, T>(_, T);
    |                   ^ expected identifier, found reserved identifier
 
 error: associated constant in `impl` without body
-  --> $DIR/typeck_type_placeholder_item.rs:203:5
+  --> $DIR/typeck_type_placeholder_item.rs:205:5
    |
 LL |     const C: _;
    |     ^^^^^^^^^^-
@@ -545,6 +545,12 @@ LL |     const D: _ = 42;
    |              not allowed in type signatures
    |              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:197:26
+   |
+LL |     type F: std::ops::Fn(_);
+   |                          ^ not allowed in type signatures
+
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
   --> $DIR/typeck_type_placeholder_item.rs:40:24
    |
@@ -582,25 +588,25 @@ LL |         fn clone(&self) -> _ { FnTest9 }
    |                            help: replace with the correct return type: `main::FnTest9`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:199:14
+  --> $DIR/typeck_type_placeholder_item.rs:201:14
    |
 LL |     type A = _;
    |              ^ not allowed in type signatures
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:201:14
+  --> $DIR/typeck_type_placeholder_item.rs:203:14
    |
 LL |     type B = _;
    |              ^ not allowed in type signatures
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:203:14
+  --> $DIR/typeck_type_placeholder_item.rs:205:14
    |
 LL |     const C: _;
    |              ^ not allowed in type signatures
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:206:14
+  --> $DIR/typeck_type_placeholder_item.rs:208:14
    |
 LL |     const D: _ = 42;
    |              ^
@@ -608,7 +614,7 @@ LL |     const D: _ = 42;
    |              not allowed in type signatures
    |              help: replace `_` with the correct type: `i32`
 
-error: aborting due to 66 previous errors
+error: aborting due to 67 previous errors
 
 Some errors have detailed explanations: E0121, E0282, E0403.
 For more information about an error, try `rustc --explain E0121`.
index d5aa18eb0f4e75f0e4c5969418ac03703d7f8fa4..e951adf030f5c2e9e958b2b45b31839832ec43e1 100644 (file)
@@ -5,7 +5,7 @@
 
 fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T>> {
     //                      ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to `'static`
-    Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime
+    Box::new(items.iter()) //~ ERROR E0759
 }
 
 fn b<T>(items: &[T]) -> Box<dyn Iterator<Item=&T> + '_> {
index dda5de431d30944e4e0f9a1f4f6c5c221773c609..dd804864dab4f59e0eb96f063b2223e50aa21978 100644 (file)
@@ -1,4 +1,4 @@
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `items` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
   --> $DIR/dyn-trait-underscore.rs:8:20
    |
 LL | fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T>> {
diff --git a/src/test/ui/wf/wf-foreign-fn-decl-ret.rs b/src/test/ui/wf/wf-foreign-fn-decl-ret.rs
new file mode 100644 (file)
index 0000000..b9d956c
--- /dev/null
@@ -0,0 +1,18 @@
+pub trait Unsatisfied {}
+
+#[repr(transparent)]
+pub struct Bar<T: Unsatisfied>(T);
+
+pub trait Foo {
+    type Assoc;
+}
+
+extern "C" {
+    pub fn lint_me() -> <() as Foo>::Assoc;
+    //~^ ERROR: the trait bound `(): Foo` is not satisfied [E0277]
+
+    pub fn lint_me_aswell() -> Bar<u32>;
+    //~^ ERROR: the trait bound `u32: Unsatisfied` is not satisfied [E0277]
+}
+
+fn main() {}
diff --git a/src/test/ui/wf/wf-foreign-fn-decl-ret.stderr b/src/test/ui/wf/wf-foreign-fn-decl-ret.stderr
new file mode 100644 (file)
index 0000000..9081b79
--- /dev/null
@@ -0,0 +1,18 @@
+error[E0277]: the trait bound `(): Foo` is not satisfied
+  --> $DIR/wf-foreign-fn-decl-ret.rs:11:5
+   |
+LL |     pub fn lint_me() -> <() as Foo>::Assoc;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `()`
+
+error[E0277]: the trait bound `u32: Unsatisfied` is not satisfied
+  --> $DIR/wf-foreign-fn-decl-ret.rs:14:32
+   |
+LL | pub struct Bar<T: Unsatisfied>(T);
+   |                   ----------- required by this bound in `Bar`
+...
+LL |     pub fn lint_me_aswell() -> Bar<u32>;
+   |                                ^^^^^^^^ the trait `Unsatisfied` is not implemented for `u32`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
index 43cf77395cad5b79887b20b7cf19d418bbd703a9..aa6872140ab0fa10f641ab0b981d5330d419e927 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 43cf77395cad5b79887b20b7cf19d418bbd703a9
+Subproject commit aa6872140ab0fa10f641ab0b981d5330d419e927
index 4b163fba52890a7aa341940f30d61198f732db94..a4bee1c278059a97329ef6a28e6426288ac426ef 100644 (file)
@@ -1346,7 +1346,7 @@ pub fn fn_has_unsatisfiable_preds(cx: &LateContext<'_>, did: DefId) -> bool {
             .predicates
             .iter()
             .filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None });
-    !traits::normalize_and_test_predicates(
+    traits::impossible_predicates(
         cx.tcx,
         traits::elaborate_predicates(cx.tcx, predicates)
             .map(|o| o.predicate)
index 703b87634cec37042e95db4d6428a3eccb47e187..9269a63b41aab9d29f3904c534b6538e213cd4bc 100644 (file)
@@ -186,6 +186,9 @@ pub struct Config {
     /// The rustdoc executable.
     pub rustdoc_path: Option<PathBuf>,
 
+    /// The rust-demangler executable.
+    pub rust_demangler_path: Option<PathBuf>,
+
     /// The Python executable to use for LLDB.
     pub lldb_python: String,
 
@@ -268,13 +271,13 @@ pub struct Config {
     pub gdb_native_rust: bool,
 
     /// Version of LLDB
-    pub lldb_version: Option<String>,
+    pub lldb_version: Option<u32>,
 
     /// Whether LLDB has native rust support
     pub lldb_native_rust: bool,
 
     /// Version of LLVM
-    pub llvm_version: Option<String>,
+    pub llvm_version: Option<u32>,
 
     /// Is LLVM a system LLVM
     pub system_llvm: bool,
index d6e28e93c96676aaf5ba632d17916e40d06c4b2f..2ab764eb9207c4fc96680aa20e99a1caac67e39d 100644 (file)
@@ -132,72 +132,46 @@ pub fn from_reader<R: Read>(config: &Config, testfile: &Path, rdr: R) -> Self {
 
         fn ignore_gdb(config: &Config, line: &str) -> bool {
             if let Some(actual_version) = config.gdb_version {
-                if line.starts_with("min-gdb-version") {
-                    let (start_ver, end_ver) = extract_gdb_version_range(line);
+                if let Some(rest) = line.strip_prefix("min-gdb-version:").map(str::trim) {
+                    let (start_ver, end_ver) = extract_version_range(rest, extract_gdb_version)
+                        .unwrap_or_else(|| {
+                            panic!("couldn't parse version range: {:?}", rest);
+                        });
 
                     if start_ver != end_ver {
                         panic!("Expected single GDB version")
                     }
                     // Ignore if actual version is smaller the minimum required
                     // version
-                    actual_version < start_ver
-                } else if line.starts_with("ignore-gdb-version") {
-                    let (min_version, max_version) = extract_gdb_version_range(line);
+                    return actual_version < start_ver;
+                } else if let Some(rest) = line.strip_prefix("ignore-gdb-version:").map(str::trim) {
+                    let (min_version, max_version) =
+                        extract_version_range(rest, extract_gdb_version).unwrap_or_else(|| {
+                            panic!("couldn't parse version range: {:?}", rest);
+                        });
 
                     if max_version < min_version {
                         panic!("Malformed GDB version range: max < min")
                     }
 
-                    actual_version >= min_version && actual_version <= max_version
-                } else {
-                    false
-                }
-            } else {
-                false
-            }
-        }
-
-        // Takes a directive of the form "ignore-gdb-version <version1> [- <version2>]",
-        // returns the numeric representation of <version1> and <version2> as
-        // tuple: (<version1> as u32, <version2> as u32)
-        // If the <version2> part is omitted, the second component of the tuple
-        // is the same as <version1>.
-        fn extract_gdb_version_range(line: &str) -> (u32, u32) {
-            const ERROR_MESSAGE: &'static str = "Malformed GDB version directive";
-
-            let range_components = line
-                .split(&[' ', '-'][..])
-                .filter(|word| !word.is_empty())
-                .map(extract_gdb_version)
-                .skip_while(Option::is_none)
-                .take(3) // 3 or more = invalid, so take at most 3.
-                .collect::<Vec<Option<u32>>>();
-
-            match range_components.len() {
-                1 => {
-                    let v = range_components[0].unwrap();
-                    (v, v)
-                }
-                2 => {
-                    let v_min = range_components[0].unwrap();
-                    let v_max = range_components[1].expect(ERROR_MESSAGE);
-                    (v_min, v_max)
+                    return actual_version >= min_version && actual_version <= max_version;
                 }
-                _ => panic!(ERROR_MESSAGE),
             }
+            false
         }
 
         fn ignore_lldb(config: &Config, line: &str) -> bool {
-            if let Some(ref actual_version) = config.lldb_version {
-                if line.starts_with("min-lldb-version") {
-                    let min_version = line
-                        .trim_end()
-                        .rsplit(' ')
-                        .next()
-                        .expect("Malformed lldb version directive");
+            if let Some(actual_version) = config.lldb_version {
+                if let Some(min_version) = line.strip_prefix("min-lldb-version:").map(str::trim) {
+                    let min_version = min_version.parse().unwrap_or_else(|e| {
+                        panic!(
+                            "Unexpected format of LLDB version string: {}\n{:?}",
+                            min_version, e
+                        );
+                    });
                     // Ignore if actual version is smaller the minimum required
                     // version
-                    lldb_version_to_int(actual_version) < lldb_version_to_int(min_version)
+                    actual_version < min_version
                 } else if line.starts_with("rust-lldb") && !config.lldb_native_rust {
                     true
                 } else {
@@ -212,48 +186,31 @@ fn ignore_llvm(config: &Config, line: &str) -> bool {
             if config.system_llvm && line.starts_with("no-system-llvm") {
                 return true;
             }
-            if let Some(ref actual_version) = config.llvm_version {
-                let actual_version = version_to_int(actual_version);
-                if line.starts_with("min-llvm-version") {
-                    let min_version = line
-                        .trim_end()
-                        .rsplit(' ')
-                        .next()
-                        .expect("Malformed llvm version directive");
+            if let Some(actual_version) = config.llvm_version {
+                if let Some(rest) = line.strip_prefix("min-llvm-version:").map(str::trim) {
+                    let min_version = extract_llvm_version(rest).unwrap();
                     // Ignore if actual version is smaller the minimum required
                     // version
-                    actual_version < version_to_int(min_version)
-                } else if line.starts_with("min-system-llvm-version") {
-                    let min_version = line
-                        .trim_end()
-                        .rsplit(' ')
-                        .next()
-                        .expect("Malformed llvm version directive");
+                    actual_version < min_version
+                } else if let Some(rest) =
+                    line.strip_prefix("min-system-llvm-version:").map(str::trim)
+                {
+                    let min_version = extract_llvm_version(rest).unwrap();
                     // Ignore if using system LLVM and actual version
                     // is smaller the minimum required version
-                    config.system_llvm && actual_version < version_to_int(min_version)
-                } else if line.starts_with("ignore-llvm-version") {
-                    // Syntax is: "ignore-llvm-version <version1> [- <version2>]"
-                    let range_components = line
-                        .split(' ')
-                        .skip(1) // Skip the directive.
-                        .map(|s| s.trim())
-                        .filter(|word| !word.is_empty() && word != &"-")
-                        .take(3) // 3 or more = invalid, so take at most 3.
-                        .collect::<Vec<&str>>();
-                    match range_components.len() {
-                        1 => actual_version == version_to_int(range_components[0]),
-                        2 => {
-                            let v_min = version_to_int(range_components[0]);
-                            let v_max = version_to_int(range_components[1]);
-                            if v_max < v_min {
-                                panic!("Malformed LLVM version range: max < min")
-                            }
-                            // Ignore if version lies inside of range.
-                            actual_version >= v_min && actual_version <= v_max
-                        }
-                        _ => panic!("Malformed LLVM version directive"),
+                    config.system_llvm && actual_version < min_version
+                } else if let Some(rest) = line.strip_prefix("ignore-llvm-version:").map(str::trim)
+                {
+                    // Syntax is: "ignore-llvm-version: <version1> [- <version2>]"
+                    let (v_min, v_max) = extract_version_range(rest, extract_llvm_version)
+                        .unwrap_or_else(|| {
+                            panic!("couldn't parse version range: {:?}", rest);
+                        });
+                    if v_max < v_min {
+                        panic!("Malformed LLVM version range: max < min")
                     }
+                    // Ignore if version lies inside of range.
+                    actual_version >= v_min && actual_version <= v_max
                 } else {
                     false
                 }
@@ -261,20 +218,6 @@ fn ignore_llvm(config: &Config, line: &str) -> bool {
                 false
             }
         }
-
-        fn version_to_int(version: &str) -> u32 {
-            let version_without_suffix = version.trim_end_matches("git").split('-').next().unwrap();
-            let components: Vec<u32> = version_without_suffix
-                .split('.')
-                .map(|s| s.parse().expect("Malformed version component"))
-                .collect();
-            match components.len() {
-                1 => components[0] * 10000,
-                2 => components[0] * 10000 + components[1] * 100,
-                3 => components[0] * 10000 + components[1] * 100 + components[2],
-                _ => panic!("Malformed version"),
-            }
-        }
     }
 }
 
@@ -944,12 +887,6 @@ fn parse_edition(&self, line: &str) -> Option<String> {
     }
 }
 
-pub fn lldb_version_to_int(version_string: &str) -> isize {
-    let error_string =
-        format!("Encountered LLDB version string with unexpected format: {}", version_string);
-    version_string.parse().expect(&error_string)
-}
-
 fn expand_variables(mut value: String, config: &Config) -> String {
     const CWD: &'static str = "{{cwd}}";
     const SRC_BASE: &'static str = "{{src-base}}";
@@ -990,3 +927,49 @@ fn parse_normalization_string(line: &mut &str) -> Option<String> {
     *line = &line[end + 1..];
     Some(result)
 }
+
+pub fn extract_llvm_version(version: &str) -> Option<u32> {
+    let version_without_suffix = version.trim_end_matches("git").split('-').next().unwrap();
+    let components: Vec<u32> = version_without_suffix
+        .split('.')
+        .map(|s| s.parse().expect("Malformed version component"))
+        .collect();
+    let version = match *components {
+        [a] => a * 10_000,
+        [a, b] => a * 10_000 + b * 100,
+        [a, b, c] => a * 10_000 + b * 100 + c,
+        _ => panic!("Malformed version"),
+    };
+    Some(version)
+}
+
+// Takes a directive of the form "<version1> [- <version2>]",
+// returns the numeric representation of <version1> and <version2> as
+// tuple: (<version1> as u32, <version2> as u32)
+// If the <version2> part is omitted, the second component of the tuple
+// is the same as <version1>.
+fn extract_version_range<F>(line: &str, parse: F) -> Option<(u32, u32)>
+where
+    F: Fn(&str) -> Option<u32>,
+{
+    let mut splits = line.splitn(2, "- ").map(str::trim);
+    let min = splits.next().unwrap();
+    if min.ends_with('-') {
+        return None;
+    }
+
+    let max = splits.next();
+
+    if min.is_empty() {
+        return None;
+    }
+
+    let min = parse(min)?;
+    let max = match max {
+        Some(max) if max.is_empty() => return None,
+        Some(max) => parse(max)?,
+        _ => min,
+    };
+
+    Some((min, max))
+}
index 72af34d78260ba6007a385300ba0c8be2aeb8622..1f82b137ee6cf1fb312375882c9fbc4e64678157 100644 (file)
@@ -119,17 +119,17 @@ fn no_system_llvm() {
 fn llvm_version() {
     let mut config = config();
 
-    config.llvm_version = Some("8.1.2-rust".to_owned());
-    assert!(parse_rs(&config, "// min-llvm-version 9.0").ignore);
+    config.llvm_version = Some(80102);
+    assert!(parse_rs(&config, "// min-llvm-version: 9.0").ignore);
 
-    config.llvm_version = Some("9.0.1-rust-1.43.0-dev".to_owned());
-    assert!(parse_rs(&config, "// min-llvm-version 9.2").ignore);
+    config.llvm_version = Some(90001);
+    assert!(parse_rs(&config, "// min-llvm-version: 9.2").ignore);
 
-    config.llvm_version = Some("9.3.1-rust-1.43.0-dev".to_owned());
-    assert!(!parse_rs(&config, "// min-llvm-version 9.2").ignore);
+    config.llvm_version = Some(90301);
+    assert!(!parse_rs(&config, "// min-llvm-version: 9.2").ignore);
 
-    config.llvm_version = Some("10.0.0-rust".to_owned());
-    assert!(!parse_rs(&config, "// min-llvm-version 9.0").ignore);
+    config.llvm_version = Some(100000);
+    assert!(!parse_rs(&config, "// min-llvm-version: 9.0").ignore);
 }
 
 #[test]
@@ -220,3 +220,18 @@ fn sanitizers() {
     assert!(parse_rs(&config, "// needs-sanitizer-memory").ignore);
     assert!(parse_rs(&config, "// needs-sanitizer-thread").ignore);
 }
+
+#[test]
+fn test_extract_version_range() {
+    use super::{extract_llvm_version, extract_version_range};
+
+    assert_eq!(extract_version_range("1.2.3 - 4.5.6", extract_llvm_version), Some((10203, 40506)));
+    assert_eq!(extract_version_range("0   - 4.5.6", extract_llvm_version), Some((0, 40506)));
+    assert_eq!(extract_version_range("1.2.3 -", extract_llvm_version), None);
+    assert_eq!(extract_version_range("1.2.3 - ", extract_llvm_version), None);
+    assert_eq!(extract_version_range("- 4.5.6", extract_llvm_version), None);
+    assert_eq!(extract_version_range("-", extract_llvm_version), None);
+    assert_eq!(extract_version_range(" - 4.5.6", extract_llvm_version), None);
+    assert_eq!(extract_version_range("   - 4.5.6", extract_llvm_version), None);
+    assert_eq!(extract_version_range("0  -", extract_llvm_version), None);
+}
index 97272f1a9c1b6e342f08adfcbc456fd3a14f9574..bf3510ea0894bfeb74b01b7de1a5fb731dbdc61d 100644 (file)
@@ -53,6 +53,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
         .reqopt("", "run-lib-path", "path to target shared libraries", "PATH")
         .reqopt("", "rustc-path", "path to rustc to use for compiling", "PATH")
         .optopt("", "rustdoc-path", "path to rustdoc to use for compiling", "PATH")
+        .optopt("", "rust-demangler-path", "path to rust-demangler to use in tests", "PATH")
         .reqopt("", "lldb-python", "path to python to use for doc tests", "PATH")
         .reqopt("", "docck-python", "path to python to use for doc tests", "PATH")
         .optopt("", "valgrind-path", "path to Valgrind executable for Valgrind tests", "PROGRAM")
@@ -165,14 +166,20 @@ fn make_absolute(path: PathBuf) -> PathBuf {
     let cdb = analyze_cdb(matches.opt_str("cdb"), &target);
     let (gdb, gdb_version, gdb_native_rust) =
         analyze_gdb(matches.opt_str("gdb"), &target, &android_cross_path);
-    let (lldb_version, lldb_native_rust) = extract_lldb_version(matches.opt_str("lldb-version"));
-
-    let color = match matches.opt_str("color").as_ref().map(|x| &**x) {
+    let (lldb_version, lldb_native_rust) = matches
+        .opt_str("lldb-version")
+        .as_deref()
+        .and_then(extract_lldb_version)
+        .map(|(v, b)| (Some(v), b))
+        .unwrap_or((None, false));
+    let color = match matches.opt_str("color").as_deref() {
         Some("auto") | None => ColorConfig::AutoColor,
         Some("always") => ColorConfig::AlwaysColor,
         Some("never") => ColorConfig::NeverColor,
         Some(x) => panic!("argument for --color must be auto, always, or never, but found `{}`", x),
     };
+    let llvm_version =
+        matches.opt_str("llvm-version").as_deref().and_then(header::extract_llvm_version);
 
     let src_base = opt_path(matches, "src-base");
     let run_ignored = matches.opt_present("ignored");
@@ -182,6 +189,7 @@ fn make_absolute(path: PathBuf) -> PathBuf {
         run_lib_path: make_absolute(opt_path(matches, "run-lib-path")),
         rustc_path: opt_path(matches, "rustc-path"),
         rustdoc_path: matches.opt_str("rustdoc-path").map(PathBuf::from),
+        rust_demangler_path: matches.opt_str("rust-demangler-path").map(PathBuf::from),
         lldb_python: matches.opt_str("lldb-python").unwrap(),
         docck_python: matches.opt_str("docck-python").unwrap(),
         valgrind_path: matches.opt_str("valgrind-path"),
@@ -213,7 +221,7 @@ fn make_absolute(path: PathBuf) -> PathBuf {
         gdb_native_rust,
         lldb_version,
         lldb_native_rust,
-        llvm_version: matches.opt_str("llvm-version"),
+        llvm_version,
         system_llvm: matches.opt_present("system-llvm"),
         android_cross_path,
         adb_path: opt_str2(matches.opt_str("adb-path")),
@@ -246,12 +254,13 @@ pub fn log_config(config: &Config) {
     logv(c, format!("run_lib_path: {:?}", config.run_lib_path));
     logv(c, format!("rustc_path: {:?}", config.rustc_path.display()));
     logv(c, format!("rustdoc_path: {:?}", config.rustdoc_path));
+    logv(c, format!("rust_demangler_path: {:?}", config.rust_demangler_path));
     logv(c, format!("src_base: {:?}", config.src_base.display()));
     logv(c, format!("build_base: {:?}", config.build_base.display()));
     logv(c, format!("stage_id: {}", config.stage_id));
     logv(c, format!("mode: {}", config.mode));
     logv(c, format!("run_ignored: {}", config.run_ignored));
-    logv(c, format!("filter: {}", opt_str(&config.filter.as_ref().map(|re| re.to_owned()))));
+    logv(c, format!("filter: {}", opt_str(&config.filter)));
     logv(c, format!("filter_exact: {}", config.filter_exact));
     logv(
         c,
@@ -400,17 +409,14 @@ fn configure_lldb(config: &Config) -> Option<Config> {
         return None;
     }
 
-    if let Some(lldb_version) = config.lldb_version.as_ref() {
-        if lldb_version == "350" {
-            println!(
-                "WARNING: The used version of LLDB ({}) has a \
-                 known issue that breaks debuginfo tests. See \
-                 issue #32520 for more information. Skipping all \
-                 LLDB-based tests!",
-                lldb_version
-            );
-            return None;
-        }
+    if let Some(350) = config.lldb_version {
+        println!(
+            "WARNING: The used version of LLDB (350) has a \
+             known issue that breaks debuginfo tests. See \
+             issue #32520 for more information. Skipping all \
+             LLDB-based tests!",
+        );
+        return None;
     }
 
     // Some older versions of LLDB seem to have problems with multiple
@@ -479,6 +485,8 @@ fn common_inputs_stamp(config: &Config) -> Stamp {
         stamp.add_path(&rustdoc_path);
         stamp.add_path(&rust_src_dir.join("src/etc/htmldocck.py"));
     }
+    // FIXME(richkadel): Do I need to add an `if let Some(rust_demangler_path) contribution to the
+    // stamp here as well?
 
     // Compiletest itself.
     stamp.add_dir(&rust_src_dir.join("src/tools/compiletest/"));
@@ -722,9 +730,7 @@ fn make_test_closure(
     let config = config.clone();
     let testpaths = testpaths.clone();
     let revision = revision.cloned();
-    test::DynTestFn(Box::new(move || {
-        runtest::run(config, &testpaths, revision.as_ref().map(|s| s.as_str()))
-    }))
+    test::DynTestFn(Box::new(move || runtest::run(config, &testpaths, revision.as_deref())))
 }
 
 /// Returns `true` if the given target is an Android target for the
@@ -840,75 +846,40 @@ fn extract_gdb_version(full_version_line: &str) -> Option<u32> {
     // This particular form is documented in the GNU coding standards:
     // https://www.gnu.org/prep/standards/html_node/_002d_002dversion.html#g_t_002d_002dversion
 
-    // don't start parsing in the middle of a number
-    let mut prev_was_digit = false;
-    let mut in_parens = false;
-    for (pos, c) in full_version_line.char_indices() {
-        if in_parens {
-            if c == ')' {
-                in_parens = false;
-            }
-            continue;
-        } else if c == '(' {
-            in_parens = true;
-            continue;
-        }
-
-        if prev_was_digit || !c.is_digit(10) {
-            prev_was_digit = c.is_digit(10);
-            continue;
+    let mut splits = full_version_line.rsplit(' ');
+    let version_string = splits.next().unwrap();
+
+    let mut splits = version_string.split('.');
+    let major = splits.next().unwrap();
+    let minor = splits.next().unwrap();
+    let patch = splits.next();
+
+    let major: u32 = major.parse().unwrap();
+    let (minor, patch): (u32, u32) = match minor.find(not_a_digit) {
+        None => {
+            let minor = minor.parse().unwrap();
+            let patch: u32 = match patch {
+                Some(patch) => match patch.find(not_a_digit) {
+                    None => patch.parse().unwrap(),
+                    Some(idx) if idx > 3 => 0,
+                    Some(idx) => patch[..idx].parse().unwrap(),
+                },
+                None => 0,
+            };
+            (minor, patch)
         }
-
-        prev_was_digit = true;
-
-        let line = &full_version_line[pos..];
-
-        let next_split = match line.find(|c: char| !c.is_digit(10)) {
-            Some(idx) => idx,
-            None => continue, // no minor version
-        };
-
-        if line.as_bytes()[next_split] != b'.' {
-            continue; // no minor version
+        // There is no patch version after minor-date (e.g. "4-2012").
+        Some(idx) => {
+            let minor = minor[..idx].parse().unwrap();
+            (minor, 0)
         }
+    };
 
-        let major = &line[..next_split];
-        let line = &line[next_split + 1..];
-
-        let (minor, patch) = match line.find(|c: char| !c.is_digit(10)) {
-            Some(idx) => {
-                if line.as_bytes()[idx] == b'.' {
-                    let patch = &line[idx + 1..];
-
-                    let patch_len =
-                        patch.find(|c: char| !c.is_digit(10)).unwrap_or_else(|| patch.len());
-                    let patch = &patch[..patch_len];
-                    let patch = if patch_len > 3 || patch_len == 0 { None } else { Some(patch) };
-
-                    (&line[..idx], patch)
-                } else {
-                    (&line[..idx], None)
-                }
-            }
-            None => (line, None),
-        };
-
-        if minor.is_empty() {
-            continue;
-        }
-
-        let major: u32 = major.parse().unwrap();
-        let minor: u32 = minor.parse().unwrap();
-        let patch: u32 = patch.unwrap_or("0").parse().unwrap();
-
-        return Some(((major * 1000) + minor) * 1000 + patch);
-    }
-
-    None
+    Some(((major * 1000) + minor) * 1000 + patch)
 }
 
 /// Returns (LLDB version, LLDB is rust-enabled)
-fn extract_lldb_version(full_version_line: Option<String>) -> (Option<String>, bool) {
+fn extract_lldb_version(full_version_line: &str) -> Option<(u32, bool)> {
     // Extract the major LLDB version from the given version string.
     // LLDB version strings are different for Apple and non-Apple platforms.
     // The Apple variant looks like this:
@@ -917,7 +888,7 @@ fn extract_lldb_version(full_version_line: Option<String>) -> (Option<String>, b
     // lldb-300.2.51 (new versions)
     //
     // We are only interested in the major version number, so this function
-    // will return `Some("179")` and `Some("300")` respectively.
+    // will return `Some(179)` and `Some(300)` respectively.
     //
     // Upstream versions look like:
     // lldb version 6.0.1
@@ -929,53 +900,24 @@ fn extract_lldb_version(full_version_line: Option<String>) -> (Option<String>, b
     // normally fine because the only non-Apple version we test is
     // rust-enabled.
 
-    if let Some(ref full_version_line) = full_version_line {
-        if !full_version_line.trim().is_empty() {
-            let full_version_line = full_version_line.trim();
-
-            for (pos, l) in full_version_line.char_indices() {
-                if l != 'l' && l != 'L' {
-                    continue;
-                }
-                if pos + 5 >= full_version_line.len() {
-                    continue;
-                }
-                let l = full_version_line[pos + 1..].chars().next().unwrap();
-                if l != 'l' && l != 'L' {
-                    continue;
-                }
-                let d = full_version_line[pos + 2..].chars().next().unwrap();
-                if d != 'd' && d != 'D' {
-                    continue;
-                }
-                let b = full_version_line[pos + 3..].chars().next().unwrap();
-                if b != 'b' && b != 'B' {
-                    continue;
-                }
-                let dash = full_version_line[pos + 4..].chars().next().unwrap();
-                if dash != '-' {
-                    continue;
-                }
-
-                let vers = full_version_line[pos + 5..]
-                    .chars()
-                    .take_while(|c| c.is_digit(10))
-                    .collect::<String>();
-                if !vers.is_empty() {
-                    return (Some(vers), full_version_line.contains("rust-enabled"));
-                }
-            }
+    let full_version_line = full_version_line.trim();
 
-            if full_version_line.starts_with("lldb version ") {
-                let vers = full_version_line[13..]
-                    .chars()
-                    .take_while(|c| c.is_digit(10))
-                    .collect::<String>();
-                if !vers.is_empty() {
-                    return (Some(vers + "00"), full_version_line.contains("rust-enabled"));
-                }
-            }
+    if let Some(apple_ver) =
+        full_version_line.strip_prefix("LLDB-").or_else(|| full_version_line.strip_prefix("lldb-"))
+    {
+        if let Some(idx) = apple_ver.find(not_a_digit) {
+            let version: u32 = apple_ver[..idx].parse().unwrap();
+            return Some((version, full_version_line.contains("rust-enabled")));
+        }
+    } else if let Some(lldb_ver) = full_version_line.strip_prefix("lldb version ") {
+        if let Some(idx) = lldb_ver.find(not_a_digit) {
+            let version: u32 = lldb_ver[..idx].parse().unwrap();
+            return Some((version * 100, full_version_line.contains("rust-enabled")));
         }
     }
-    (None, false)
+    None
+}
+
+fn not_a_digit(c: char) -> bool {
+    !c.is_digit(10)
 }
index dd0c68ecd4965121ec723ecdf0c0166399be8c92..f09f7621aa170ebc453b0508ee89f0fddaae0acf 100644 (file)
@@ -2739,6 +2739,10 @@ fn run_rmake_test(&self) {
             cmd.env("RUSTDOC", cwd.join(rustdoc));
         }
 
+        if let Some(ref rust_demangler) = self.config.rust_demangler_path {
+            cmd.env("RUST_DEMANGLER", cwd.join(rust_demangler));
+        }
+
         if let Some(ref node) = self.config.nodejs {
             cmd.env("NODE", node);
         }
index 31c151d29e916c75bc2607870bfa354ac5ecc0c3..ea9bc1c1a5b7f5a7413c26b0939db1bec0767d98 100644 (file)
@@ -1,8 +1,9 @@
+use super::header::extract_llvm_version;
 use super::*;
 
 #[test]
 fn test_extract_gdb_version() {
-    macro_rules! test { ($($expectation:tt: $input:tt,)*) => {{$(
+    macro_rules! test { ($($expectation:literal: $input:literal,)*) => {{$(
         assert_eq!(extract_gdb_version($input), Some($expectation));
     )*}}}
 
@@ -41,6 +42,17 @@ macro_rules! test { ($($expectation:tt: $input:tt,)*) => {{$(
     }
 }
 
+#[test]
+fn test_extract_lldb_version() {
+    // Apple variants
+    assert_eq!(extract_lldb_version("LLDB-179.5"), Some((179, false)));
+    assert_eq!(extract_lldb_version("lldb-300.2.51"), Some((300, false)));
+
+    // Upstream versions
+    assert_eq!(extract_lldb_version("lldb version 6.0.1"), Some((600, false)));
+    assert_eq!(extract_lldb_version("lldb version 9.0.0"), Some((900, false)));
+}
+
 #[test]
 fn is_test_test() {
     assert_eq!(true, is_test(&OsString::from("a_test.rs")));
@@ -49,3 +61,11 @@ fn is_test_test() {
     assert_eq!(false, is_test(&OsString::from("#a_dog_gif")));
     assert_eq!(false, is_test(&OsString::from("~a_temp_file")));
 }
+
+#[test]
+fn test_extract_llvm_version() {
+    assert_eq!(extract_llvm_version("8.1.2-rust"), Some(80102));
+    assert_eq!(extract_llvm_version("9.0.1-rust-1.43.0-dev"), Some(90001));
+    assert_eq!(extract_llvm_version("9.3.1-rust-1.43.0-dev"), Some(90301));
+    assert_eq!(extract_llvm_version("10.0.0-rust"), Some(100000));
+}
index 992af261b8352f1495f91e8f3d3d01515df40440..787e08404e1c61581768d4425129d939b96cbfb0 100644 (file)
@@ -3,7 +3,6 @@ authors = ["The Rust Project Developers"]
 name = "error_index_generator"
 version = "0.0.0"
 edition = "2018"
-build = "build.rs"
 
 [dependencies]
 rustdoc = { path = "../../librustdoc" }
index 74601f9e4c679f096eba3a8b5401d039e08fd78c..194318d7a59b5ec5c9ed56fd8df5f6ae4310084a 100644 (file)
 
 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
+// [(generated_documentation_page, &[broken_links])]
+const LINKCHECK_EXCEPTIONS: &[(&str, &[&str])] = &[
+    // These are methods on slice, and `Self` does not work on primitive impls
+    // in intra-doc links (primitive impls are weird)
+    // https://github.com/rust-lang/rust/issues/62834 is necessary to be
+    // able to link to slices
+    (
+        "std/io/struct.IoSlice.html",
+        &[
+            "#method.as_mut_ptr",
+            "#method.sort_by_key",
+            "#method.make_ascii_uppercase",
+            "#method.make_ascii_lowercase",
+        ],
+    ),
+    // These try to link to std::collections, but are defined in alloc
+    // https://github.com/rust-lang/rust/issues/74481
+    ("std/collections/btree_map/struct.BTreeMap.html", &["#insert-and-complex-keys"]),
+    ("std/collections/btree_set/struct.BTreeSet.html", &["#insert-and-complex-keys"]),
+    ("alloc/collections/btree_map/struct.BTreeMap.html", &["#insert-and-complex-keys"]),
+    ("alloc/collections/btree_set/struct.BTreeSet.html", &["#insert-and-complex-keys"]),
+];
+
 macro_rules! t {
     ($e:expr) => {
         match $e {
@@ -111,35 +137,20 @@ fn walk(cache: &mut Cache, root: &Path, dir: &Path, errors: &mut bool) {
     }
 }
 
+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 {
+        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;
     }
 
-    // Unfortunately we're not 100% full of valid links today to we need a few
-    // exceptions to get this past `make check` today.
-    // FIXME(#32129)
-    if file.ends_with("std/io/struct.IoSlice.html")
-        || file.ends_with("std/string/struct.String.html")
-    {
-        return None;
-    }
-    // FIXME(#32553)
-    if file.ends_with("alloc/string/struct.String.html") {
-        return None;
-    }
-    // FIXME(#32130)
-    if file.ends_with("alloc/collections/btree_map/struct.BTreeMap.html")
-        || file.ends_with("alloc/collections/btree_set/struct.BTreeSet.html")
-        || file.ends_with("std/collections/btree_map/struct.BTreeMap.html")
-        || file.ends_with("std/collections/btree_set/struct.BTreeSet.html")
-        || file.ends_with("std/collections/hash_map/struct.HashMap.html")
-        || file.ends_with("std/collections/hash_set/struct.HashSet.html")
-    {
-        return None;
-    }
-
     let res = load_file(cache, root, file, SkipRedirect);
     let (pretty_file, contents) = match res {
         Ok(res) => res,
@@ -254,17 +265,20 @@ fn check(cache: &mut Cache, root: &Path, file: &Path, errors: &mut bool) -> Opti
                 let entry = &mut cache.get_mut(&pretty_path).unwrap();
                 entry.parse_ids(&pretty_path, &contents, errors);
 
-                if !entry.ids.contains(*fragment) {
+                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());
                 };
             }
         } else {
-            *errors = true;
-            print!("{}:{}: broken link - ", pretty_file.display(), i + 1);
             let pretty_path = path.strip_prefix(root).unwrap_or(&path);
-            println!("{}", pretty_path.display());
+            if !is_exception(file, pretty_path.to_str().unwrap()) {
+                *errors = true;
+                print!("{}:{}: broken link - ", pretty_file.display(), i + 1);
+                println!("{}", pretty_path.display());
+            }
         }
     });
     Some(pretty_file)
index 72437e070044ce7aaf173136309d4fce87136a6f..c0631fcedd34973d259fce507d914851284e1eac 100755 (executable)
@@ -26,7 +26,7 @@ except ImportError:
 MAINTAINERS = {
     'miri': {'oli-obk', 'RalfJung', 'eddyb'},
     'rls': {'Xanewok'},
-    'rustfmt': {'topecongiro'},
+    'rustfmt': {'topecongiro', 'calebcartwright'},
     'book': {'carols10cents', 'steveklabnik'},
     'nomicon': {'frewsxcv', 'Gankra'},
     'reference': {'steveklabnik', 'Havvy', 'matthewjasper', 'ehuss'},
index 8b0983e89ad9a28b142eccf3755a8c9aaeb37852..c9c518e5e9761bf35d466c47c57c3a1358b56b3c 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 8b0983e89ad9a28b142eccf3755a8c9aaeb37852
+Subproject commit c9c518e5e9761bf35d466c47c57c3a1358b56b3c
diff --git a/src/tools/rust-demangler/Cargo.toml b/src/tools/rust-demangler/Cargo.toml
new file mode 100644 (file)
index 0000000..0b8d974
--- /dev/null
@@ -0,0 +1,12 @@
+[package]
+authors = ["The Rust Project Developers"]
+name = "rust-demangler"
+version = "0.0.0"
+edition = "2018"
+
+[dependencies]
+rustc-demangle = "0.1"
+
+[[bin]]
+name = "rust-demangler"
+path = "main.rs"
diff --git a/src/tools/rust-demangler/main.rs b/src/tools/rust-demangler/main.rs
new file mode 100644 (file)
index 0000000..a9f1011
--- /dev/null
@@ -0,0 +1,39 @@
+//! Demangles rustc mangled names.
+//!
+//! This tool uses https://crates.io/crates/rustc-demangle to convert an input buffer of
+//! newline-separated mangled names into their demangled translations.
+//!
+//! This tool can be leveraged by other applications that support third-party demanglers.
+//! It takes a list of mangled names (one per line) on standard input, and prints a corresponding
+//! list of demangled names. The tool is designed to support other programs that can leverage a
+//! third-party demangler, such as `llvm-cov`, via the `-Xdemangler=<path-to-demangler>` option.
+//!
+//! To use `rust-demangler`, first build the tool with:
+//!
+//! ```shell
+//! $ ./x.py build rust-demangler
+//! ```
+//!
+//! Then, with `llvm-cov` for example, add the `-Xdemangler=...` option:
+//!
+//! ```shell
+//! $ TARGET="${PWD}/build/x86_64-unknown-linux-gnu"
+//! $ "${TARGET}"/llvm/bin/llvm-cov show --Xdemangler="${TARGET}"/stage0-tools-bin/rust-demangler \
+//!   --instr-profile=main.profdata ./main --show-line-counts-or-regions
+//! ```
+
+use rustc_demangle::demangle;
+use std::io::{self, Read, Write};
+
+fn main() -> io::Result<()> {
+    let mut buffer = String::new();
+    io::stdin().read_to_string(&mut buffer)?;
+    let lines = buffer.lines();
+    let mut demangled = Vec::new();
+    for mangled in lines {
+        demangled.push(demangle(mangled).to_string());
+    }
+    demangled.push("".to_string());
+    io::stdout().write_all(demangled.join("\n").as_bytes())?;
+    Ok(())
+}
index 3af71f69d2457c162a6bd183f0609852b599fc90..51f135d37616125ad1b2e4a18aacf28631327c30 100644 (file)
@@ -8,11 +8,11 @@
 
 // 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", "E0456",
-    "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",
+    "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",
 ];
 
 // Some error codes don't have any tests apparently...
index 51a29553fdb3dc1f5de8a071bd16326f64a3b7f9..ce4ea895400acdd6dde24a8ec104cc559d538f88 100644 (file)
@@ -81,7 +81,7 @@ topic = "I-prioritize #{number} {title}"
 message_on_add = """\
 @*WG-prioritization/alerts* issue #{number} has been requested for prioritization.
 
-# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#Unprioritized-I-prioritize)
+# [Procedure](https://forge.rust-lang.org/compiler/prioritization/procedure.html#assign-priority-to-unprioritized-issues-with-i-prioritize-label)
 - Priority?
 - Regression?
 - Notify people/groups?
@@ -96,7 +96,7 @@ topic = "I-nominated #{number} {title}"
 message_on_add = """\
 @*WG-prioritization/alerts* #{number} has been nominated for discussion in `T-compiler` meeting.
 
-# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#I-nominated)
+# [Procedure](https://forge.rust-lang.org/compiler/prioritization/procedure.html#summarize-i-nominated-issues)
 - Already discussed?
 - Worth the meeting time?
 - Add agenda entry:
@@ -113,7 +113,7 @@ topic = "Backport #{number} {title}"
 message_on_add = """\
 @*WG-prioritization/alerts* PR #{number} has been requested for beta backport.
 
-# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#StableBeta-nominations)
+# [Procedure](https://forge.rust-lang.org/compiler/prioritization/procedure.html#summarize-stablebeta-nominations)
 Prepare agenda entry:
 - Why nominated?
 - Author, assignee?
@@ -127,7 +127,7 @@ topic = "Backport #{number} {title}"
 message_on_add = """\
 @*WG-prioritization/alerts* PR #{number} has been requested for stable backport.
 
-# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#StableBeta-nominations)
+# [Procedure](https://forge.rust-lang.org/compiler/prioritization/procedure.html#summarize-stablebeta-nominations)
 Prepare agenda entry:
 - Why nominated?
 - Author, assignee?
@@ -142,7 +142,7 @@ topic = "S-waiting-on-team #{number} {title}"
 message_on_add = """\
 @*WG-prioritization/alerts* PR #{number} is waiting on `T-compiler`.
 
-# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#PR%E2%80%99s-waiting-on-team)
+# [Procedure](https://forge.rust-lang.org/compiler/prioritization/procedure.html#summarize-prs-waiting-on-team)
 - Prepare agenda entry:
   - What is it waiting for?
   - Important details?
@@ -156,7 +156,7 @@ topic = "P-critical #{number} {title}"
 message_on_add = """\
 @*WG-prioritization/alerts* issue #{number} has been assigned `P-critical`.
 
-# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#P-critical-and-Unassigned-P-high-regressions)
+# [Procedure](https://forge.rust-lang.org/compiler/prioritization/procedure.html#summarize-p-critical-and-unassigned-p-high-regressions)
 - Notify people/groups?
 - Assign if possible?
 - Add to agenda:
@@ -172,7 +172,7 @@ topic = "P-high regression #{number} {title}"
 message_on_add = """\
 @*WG-prioritization/alerts* issue #{number} has been assigned `P-high` and is a regression.
 
-# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#P-critical-and-Unassigned-P-high-regressions)
+# [Procedure](https://forge.rust-lang.org/compiler/prioritization/procedure.html#summarize-p-critical-and-unassigned-p-high-regressions)
 Is issue assigned? If not:
 - Try to find an assignee?
 - Otherwise add to agenda: