]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #97577 - betrusted-io:add-xous-target, r=nagisa
authorbors <bors@rust-lang.org>
Sun, 5 Jun 2022 07:03:50 +0000 (07:03 +0000)
committerbors <bors@rust-lang.org>
Sun, 5 Jun 2022 07:03:50 +0000 (07:03 +0000)
riscv32imac-unknown-xous-elf: add target

This PR starts the process of upstreaming support for our operating system, thanks to a suggestion from `@yaahc` [on Twitter](https://twitter.com/yaahc_/status/1530558574706839567?s=20&t=Mgkn1LEYvGU6FEi5SpZRsA). We have maintained a fork of Rust and have made changes to improve support for our platform since Rust 1.51. Now we would like to upstream these changes.

Xous is a microkernel operating system designed to run on small systems. The kernel contains a wide range of userspace processes that provide common services such as console output, networking, and time access.

The kernel and its services are completely written in Rust using a custom build of libstd. This adds support for this target to upstream Rust so that we can drop support for our out-of-tree `target.json` file.

This first patch adds a Tier 3 target for Xous running on RISC-V. Future patches will add libstd support, but those patches require changes to `dlmalloc` and `compiler_builtins`.

> Tier 3 policy:
>
> A tier 3 target must have a designated developer or developers (the "target maintainers") on record to be CCed when issues arise regarding the target. (The mechanism to track and CC such developers may evolve over time.)

I will be the target maintainer for this target on matters that pertain to the `xous` part of the triple. For matters pertaining to the `riscv32imac` part of the triple, there should be no difference from all other `riscv` targets. If there are issues, I will address issues regarding the target.

> Targets must use naming consistent with any existing targets; for instance, a target for the same CPU or OS as an existing Rust target should use the same name for that CPU or OS. Targets should normally use the same names and naming conventions as used elsewhere in the broader ecosystem beyond Rust (such as in other toolchains), unless they have a very good reason to diverge. Changing the name of a target can be highly disruptive, especially once the target reaches a higher tier, so getting the name right is important even for a tier 3 target.

This is a new OS, so I have taken the `riscv32imac-unknown-none-elf` target and changed the `os` section of the triple. This follows convention on targets such as `riscv32gc-unknown-linux-gnu` and `mipsel-unknown-linux-uclibc`. An argument could be made for omitting the `-elf` section of the triple, such as `riscv32imc-esp-espidf`, however I'm not certain what benefit that has.

> Target names should not introduce undue confusion or ambiguity unless absolutely necessary to maintain ecosystem compatibility. For example, if the name of the target makes people extremely likely to form incorrect beliefs about what it targets, the name should be changed or augmented to disambiguate it.

I feel that the target name does not introduce any ambiguity.

> Tier 3 targets may have unusual requirements to build or use, but must not create legal issues or impose onerous legal terms for the Rust project or for Rust developers or users.

The only unusual requirement for building the `compiler-builtins` crate is a standard RISC-V C compiler supported by `cc-rs`, and using this target does not require any additional software beyond what is shipped by `rustup`.

> The target must not introduce license incompatibilities.

All of the additional code will use Apache-2.0.

> Anything added to the Rust repository must be under the standard Rust license (MIT OR Apache-2.0).

Agreed, and there is no problem here.

> The target must not cause the Rust tools or libraries built for any other host (even when supporting cross-compilation to the target) to depend on any new dependency less permissive than the Rust licensing policy. This applies whether the dependency is a Rust crate that would require adding new license exceptions (as specified by the tidy tool in the rust-lang/rust repository), or whether the dependency is a native library or binary. In other words, the introduction of the target must not cause a user installing or running a version of Rust or the Rust tools to be subject to any new license requirements.

The only new dependency will be the `xous` crate, which is licensed `MIT OR Apache-2.0`

> Compiling, linking, and emitting functional binaries, libraries, or other code for the target (whether hosted on the target itself or cross-compiling from another target) must not depend on proprietary (non-FOSS) libraries. Host tools built for the target itself may depend on the ordinary runtime libraries supplied by the platform and commonly used by other applications built for the target, but those libraries must not be required for code generation for the target; cross-compilation to the target must not require such libraries at all. For instance, rustc built for the target may depend on a common proprietary C runtime library or console output library, but must not depend on a proprietary code generation library or code optimization library. Rust's license permits such combinations, but the Rust project has no interest in maintaining such combinations within the scope of Rust itself, even at tier 3.

Linking is performed by `rust-lld`

> "onerous" here is an intentionally subjective term. At a minimum, "onerous" legal/licensing terms include but are not limited to: non-disclosure requirements, non-compete requirements, contributor license agreements (CLAs) or equivalent, "non-commercial"/"research-only"/etc terms, requirements conditional on the employer or employment of any particular Rust developers, revocable terms, any requirements that create liability for the Rust project or its developers or users, or any requirements that adversely affect the livelihood or prospects of the Rust project or its developers or users.

There are no terms. Xous is completely open. It runs on open hardware. We even provide the source to the CPU.

> Neither this policy nor any decisions made regarding targets shall create any binding agreement or estoppel by any party. If any member of an approving Rust team serves as one of the maintainers of a target, or has any legal or employment requirement (explicit or implicit) that might affect their decisions regarding a target, they must recuse themselves from any approval decisions regarding the target's tier status, though they may otherwise participate in discussions.

This paragraph makes sense, but I don't think it's directed at me.

> This requirement does not prevent part or all of this policy from being cited in an explicit contract or work agreement (e.g. to implement or maintain support for a target). This requirement exists to ensure that a developer or team responsible for reviewing and approving a target does not face any legal threats or obligations that would prevent them from freely exercising their judgment in such approval, even if such judgment involves subjective matters or goes beyond the letter of these requirements.

This paragraph also does not appear to be directed at me.

> Tier 3 targets should attempt to implement as much of the standard libraries as possible and appropriate (core for most targets, alloc for targets that can support dynamic memory allocation, std for targets with an operating system or equivalent layer of system-provided functionality), but may leave some code unimplemented (either unavailable or stubbed out as appropriate), whether because the target makes it impossible to implement or challenging to implement. The authors of pull requests are not obligated to avoid calling any portions of the standard library on the basis of a tier 3 target not implementing those portions.

So far we have:

 * Thread
 * Mutexex
 * Condvar
 * TcpStream
 * TcpListener
 * UdpSocket
 * DateTime
 * alloc

These will be merged as part of libstd in a future patch once I submit support for Xous in `dlmalloc` and `compiler-builtins`.

> The target must provide documentation for the Rust community explaining how to build for the target, using cross-compilation if possible. If the target supports running binaries, or running tests (even if they do not pass), the documentation must explain how to run such binaries or tests for the target, using emulation if possible or dedicated hardware if necessary.

Testing is currently done on real hardware or in a Renode emulator. I can add documentation on how to do this in a future patch, and I would need instructions on where to add said documentation.

> Tier 3 targets must not impose burden on the authors of pull requests, or other developers in the community, to maintain the target. In particular, do not post comments (automated or manual) on a PR that derail or suggest a block on the PR based on a tier 3 target. Do not send automated messages or notifications (via any medium, including via `@)` to a PR author or others involved with a PR regarding a tier 3 target, unless they have opted into such messages.

Alright.

> Backlinks such as those generated by the issue/PR tracker when linking to an issue or PR are not considered a violation of this policy, within reason. However, such messages (even on a separate repository) must not generate notifications to anyone involved with a PR who has not requested such notifications.

Sounds good.

> Patches adding or updating tier 3 targets must not break any existing tier 2 or tier 1 target, and must not knowingly break another tier 3 target without approval of either the compiler team or the maintainers of the other tier 3 target.

This shouldn't affect any other targets, so this is understood.

> In particular, this may come up when working on closely related targets, such as variations of the same architecture with different features. Avoid introducing unconditional uses of features that another variation of the target may not have; use conditional compilation or runtime detection, as appropriate, to let each target run code supported by that target.

This shouldn't come up right away. `xous` is a new operating system, and most features are keyed off of `target(os = "xous")` rather than a given architecture.

632 files changed:
Cargo.lock
compiler/rustc/Windows Manifest.xml [new file with mode: 0644]
compiler/rustc/build.rs [new file with mode: 0644]
compiler/rustc_ast/src/ast.rs
compiler/rustc_ast/src/ast/tests.rs [deleted file]
compiler/rustc_ast/src/token.rs
compiler/rustc_ast_lowering/src/expr.rs
compiler/rustc_ast_lowering/src/item.rs
compiler/rustc_ast_lowering/src/lib.rs
compiler/rustc_ast_lowering/src/path.rs
compiler/rustc_ast_passes/src/ast_validation.rs
compiler/rustc_ast_pretty/src/pprust/state.rs
compiler/rustc_borrowck/src/diagnostics/region_name.rs
compiler/rustc_borrowck/src/type_check/mod.rs
compiler/rustc_borrowck/src/universal_regions.rs
compiler/rustc_builtin_macros/src/assert.rs
compiler/rustc_builtin_macros/src/assert/context.rs [new file with mode: 0644]
compiler/rustc_builtin_macros/src/lib.rs
compiler/rustc_codegen_cranelift/src/base.rs
compiler/rustc_codegen_ssa/Cargo.toml
compiler/rustc_codegen_ssa/src/back/linker.rs
compiler/rustc_codegen_ssa/src/mir/rvalue.rs
compiler/rustc_const_eval/src/interpret/cast.rs
compiler/rustc_const_eval/src/interpret/memory.rs
compiler/rustc_const_eval/src/interpret/place.rs
compiler/rustc_const_eval/src/interpret/step.rs
compiler/rustc_const_eval/src/transform/check_consts/check.rs
compiler/rustc_const_eval/src/transform/promote_consts.rs
compiler/rustc_data_structures/src/base_n/tests.rs
compiler/rustc_data_structures/src/graph/scc/tests.rs
compiler/rustc_data_structures/src/owning_ref/tests.rs
compiler/rustc_data_structures/src/sip128.rs
compiler/rustc_data_structures/src/sso/set.rs
compiler/rustc_driver/Cargo.toml
compiler/rustc_driver/src/lib.rs
compiler/rustc_error_codes/src/error_codes/E0263.md
compiler/rustc_error_messages/locales/en-US/parser.ftl
compiler/rustc_errors/Cargo.toml
compiler/rustc_errors/src/emitter.rs
compiler/rustc_errors/src/json.rs
compiler/rustc_errors/src/json/tests.rs
compiler/rustc_expand/src/build.rs
compiler/rustc_feature/src/active.rs
compiler/rustc_feature/src/builtin_attrs.rs
compiler/rustc_hir/src/def.rs
compiler/rustc_hir/src/hir.rs
compiler/rustc_hir/src/intravisit.rs
compiler/rustc_hir/src/lib.rs
compiler/rustc_infer/src/infer/error_reporting/mod.rs
compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs
compiler/rustc_infer/src/lib.rs
compiler/rustc_interface/src/passes.rs
compiler/rustc_interface/src/tests.rs
compiler/rustc_lint_defs/Cargo.toml
compiler/rustc_lint_defs/src/lib.rs
compiler/rustc_macros/src/serialize.rs
compiler/rustc_metadata/src/rmeta/encoder.rs
compiler/rustc_middle/src/hir/map/mod.rs
compiler/rustc_middle/src/middle/resolve_lifetime.rs
compiler/rustc_middle/src/mir/interpret/value.rs
compiler/rustc_middle/src/mir/mod.rs
compiler/rustc_middle/src/mir/predecessors.rs
compiler/rustc_middle/src/mir/switch_sources.rs
compiler/rustc_middle/src/mir/tcx.rs
compiler/rustc_middle/src/mir/traversal.rs
compiler/rustc_middle/src/query/mod.rs
compiler/rustc_middle/src/ty/context.rs
compiler/rustc_middle/src/ty/diagnostics.rs
compiler/rustc_middle/src/ty/generics.rs
compiler/rustc_middle/src/ty/mod.rs
compiler/rustc_middle/src/ty/print/pretty.rs
compiler/rustc_middle/src/ty/query.rs
compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
compiler/rustc_mir_dataflow/src/impls/liveness.rs
compiler/rustc_mir_transform/src/dead_store_elimination.rs
compiler/rustc_mir_transform/src/inline.rs
compiler/rustc_parse/src/parser/diagnostics.rs
compiler/rustc_parse/src/parser/expr.rs
compiler/rustc_parse/src/parser/pat.rs
compiler/rustc_parse/src/parser/stmt.rs
compiler/rustc_parse/src/parser/ty.rs
compiler/rustc_passes/src/dead.rs
compiler/rustc_passes/src/reachable.rs
compiler/rustc_query_impl/src/on_disk_cache.rs
compiler/rustc_query_system/src/ich/impls_syntax.rs
compiler/rustc_resolve/src/diagnostics.rs
compiler/rustc_resolve/src/imports.rs
compiler/rustc_resolve/src/late.rs
compiler/rustc_resolve/src/late/diagnostics.rs
compiler/rustc_resolve/src/late/lifetimes.rs
compiler/rustc_resolve/src/lib.rs
compiler/rustc_resolve/src/macros.rs
compiler/rustc_serialize/src/collection_impls.rs
compiler/rustc_serialize/src/json.rs [deleted file]
compiler/rustc_serialize/src/json/tests.rs [deleted file]
compiler/rustc_serialize/src/lib.rs
compiler/rustc_serialize/src/opaque.rs
compiler/rustc_serialize/src/serialize.rs
compiler/rustc_serialize/tests/json.rs [deleted file]
compiler/rustc_session/src/options.rs
compiler/rustc_span/src/def_id.rs
compiler/rustc_span/src/lib.rs
compiler/rustc_span/src/source_map.rs
compiler/rustc_span/src/symbol.rs
compiler/rustc_span/src/tests.rs
compiler/rustc_target/Cargo.toml
compiler/rustc_target/src/abi/mod.rs
compiler/rustc_target/src/json.rs [new file with mode: 0644]
compiler/rustc_target/src/lib.rs
compiler/rustc_target/src/spec/crt_objects.rs
compiler/rustc_target/src/spec/mod.rs
compiler/rustc_target/src/tests.rs
compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
compiler/rustc_trait_selection/src/traits/misc.rs
compiler/rustc_trait_selection/src/traits/project.rs
compiler/rustc_trait_selection/src/traits/wf.rs
compiler/rustc_type_ir/src/sty.rs
compiler/rustc_typeck/src/astconv/mod.rs
compiler/rustc_typeck/src/check/check.rs
compiler/rustc_typeck/src/check/coercion.rs
compiler/rustc_typeck/src/check/compare_method.rs
compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
compiler/rustc_typeck/src/check/method/suggest.rs
compiler/rustc_typeck/src/check/wfcheck.rs
compiler/rustc_typeck/src/check_unused.rs
compiler/rustc_typeck/src/coherence/builtin.rs
compiler/rustc_typeck/src/coherence/mod.rs
compiler/rustc_typeck/src/collect.rs
compiler/rustc_typeck/src/collect/type_of.rs
compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs
config.toml.example
library/alloc/src/borrow.rs
library/alloc/src/boxed.rs
library/alloc/src/boxed/thin.rs
library/alloc/src/collections/binary_heap.rs
library/alloc/src/collections/btree/map.rs
library/alloc/src/collections/btree/set.rs
library/alloc/src/lib.rs
library/alloc/src/macros.rs
library/alloc/src/slice.rs
library/alloc/src/sync.rs
library/alloc/src/vec/mod.rs
library/alloc/tests/lib.rs
library/alloc/tests/thin_box.rs
library/core/benches/fmt.rs
library/core/src/array/mod.rs
library/core/src/fmt/mod.rs
library/core/src/intrinsics.rs
library/core/src/num/dec2flt/mod.rs
library/core/src/ptr/mod.rs
library/core/src/ptr/mut_ptr.rs
library/core/src/slice/mod.rs
library/core/src/slice/raw.rs
library/core/src/unicode/printable.py
library/core/src/unicode/printable.rs
library/core/tests/lib.rs
library/core/tests/ptr.rs
library/proc_macro/src/bridge/buffer.rs
library/proc_macro/src/lib.rs
library/std/Cargo.toml
library/std/src/collections/hash/map.rs
library/std/src/collections/hash/set.rs
library/std/src/fs.rs
library/std/src/lib.rs
library/std/src/sync/mpsc/cache_aligned.rs
library/std/src/sys/hermit/condvar.rs
library/std/src/sys/hermit/mutex.rs
library/std/src/sys/hermit/rwlock.rs
library/std/src/sys/itron/condvar.rs
library/std/src/sys/itron/mutex.rs
library/std/src/sys/sgx/condvar.rs
library/std/src/sys/sgx/mutex.rs
library/std/src/sys/sgx/rwlock.rs
library/std/src/sys/solid/rwlock.rs
library/std/src/sys/unix/locks/futex.rs
library/std/src/sys/unix/locks/futex_rwlock.rs
library/std/src/sys/unix/locks/mod.rs
library/std/src/sys/unix/locks/pthread_condvar.rs
library/std/src/sys/unix/locks/pthread_mutex.rs
library/std/src/sys/unix/locks/pthread_rwlock.rs
library/std/src/sys/unix/mod.rs
library/std/src/sys/unix/process/process_unix.rs
library/std/src/sys/unix/process/process_unix/tests.rs
library/std/src/sys/unsupported/locks/condvar.rs
library/std/src/sys/unsupported/locks/mutex.rs
library/std/src/sys/unsupported/locks/rwlock.rs
library/std/src/sys/wasm/mod.rs
library/std/src/sys/windows/locks/condvar.rs
library/std/src/sys/windows/locks/mutex.rs
library/std/src/sys/windows/locks/rwlock.rs
library/std/src/sys/windows/mod.rs
library/std/src/sys_common/condvar.rs
library/std/src/sys_common/condvar/check.rs
library/std/src/sys_common/lazy_box.rs [new file with mode: 0644]
library/std/src/sys_common/mod.rs
library/std/src/sys_common/mutex.rs
library/std/src/sys_common/remutex.rs
library/std/src/sys_common/rwlock.rs
src/bootstrap/Cargo.toml
src/bootstrap/bootstrap.py
src/bootstrap/builder.rs
src/bootstrap/config.rs
src/bootstrap/lib.rs
src/bootstrap/metrics.rs [new file with mode: 0644]
src/bootstrap/native.rs
src/ci/pgo.sh
src/ci/run.sh
src/ci/scripts/upload-artifacts.sh
src/etc/htmldocck.py
src/librustdoc/clean/mod.rs
src/librustdoc/clean/types.rs
src/librustdoc/formats/mod.rs
src/librustdoc/html/format.rs
src/librustdoc/html/render/mod.rs
src/librustdoc/html/render/print_item.rs
src/librustdoc/html/render/search_index.rs
src/librustdoc/html/static/.eslintrc.js
src/librustdoc/html/static/css/settings.css
src/librustdoc/html/static/css/themes/ayu.css
src/librustdoc/html/static/css/themes/dark.css
src/librustdoc/html/static/css/themes/light.css
src/librustdoc/html/static/js/settings.js
src/librustdoc/json/conversions.rs
src/librustdoc/json/mod.rs
src/librustdoc/passes/collect_trait_impls.rs
src/librustdoc/visit_ast.rs
src/llvm-project
src/test/debuginfo/thread-names.rs [new file with mode: 0644]
src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff
src/test/mir-opt/const_prop/reify_fn_ptr.main.ConstProp.diff
src/test/mir-opt/dead-store-elimination/provenance_soundness.pointer_to_int.DeadStoreElimination.diff
src/test/mir-opt/inst_combine_deref.deep_opt.InstCombine.diff [deleted file]
src/test/mir-opt/inst_combine_deref.do_not_miscompile.InstCombine.diff [deleted file]
src/test/mir-opt/inst_combine_deref.dont_opt.InstCombine.diff [deleted file]
src/test/mir-opt/inst_combine_deref.opt_struct.InstCombine.diff [deleted file]
src/test/mir-opt/inst_combine_deref.simple_opt.InstCombine.diff [deleted file]
src/test/mir-opt/tls-access.rs
src/test/mir-opt/tls_access.main.PreCodegen.after.mir [new file with mode: 0644]
src/test/mir-opt/tls_access.main.SimplifyCfg-final.after.mir [deleted file]
src/test/rustdoc-gui/settings.goml
src/test/rustdoc-js/impl-trait.js [new file with mode: 0644]
src/test/rustdoc-js/impl-trait.rs [new file with mode: 0644]
src/test/rustdoc-js/raw-pointer.js [new file with mode: 0644]
src/test/rustdoc-js/raw-pointer.rs [new file with mode: 0644]
src/test/rustdoc-json/reexport/same_type_reexported_more_than_once.rs [new file with mode: 0644]
src/test/rustdoc-ui/intra-doc/unresolved-import-recovery.stderr
src/test/rustdoc-ui/issue-61732.stderr
src/test/rustdoc/anonymous-reexport.rs [new file with mode: 0644]
src/test/rustdoc/inline_cross/auxiliary/implementors_inline.rs [new file with mode: 0644]
src/test/rustdoc/inline_cross/implementors-js.rs [new file with mode: 0644]
src/test/rustdoc/intra-doc/email-address.rs
src/test/rustdoc/issue-75588.rs
src/test/rustdoc/nested-modules.rs [new file with mode: 0644]
src/test/rustdoc/primitive-slice-auto-trait.rs [new file with mode: 0644]
src/test/rustdoc/slice-links.link_box_generic.html [new file with mode: 0644]
src/test/rustdoc/slice-links.link_box_u32.html [new file with mode: 0644]
src/test/rustdoc/slice-links.link_slice_generic.html [new file with mode: 0644]
src/test/rustdoc/slice-links.link_slice_u32.html [new file with mode: 0644]
src/test/rustdoc/slice-links.rs [new file with mode: 0644]
src/test/ui-fulldeps/extern-mod-syntax.rs
src/test/ui-fulldeps/issue-11881.rs
src/test/ui-fulldeps/issue-15924.rs
src/test/ui-fulldeps/issue-2804.rs
src/test/ui/array-slice-vec/infer_array_len.stderr
src/test/ui/array-slice-vec/vector-no-ann.stderr
src/test/ui/ast-json/ast-json-ice.rs [deleted file]
src/test/ui/ast-json/ast-json-noexpand-output.rs [deleted file]
src/test/ui/ast-json/ast-json-noexpand-output.stdout [deleted file]
src/test/ui/ast-json/ast-json-output.rs [deleted file]
src/test/ui/ast-json/ast-json-output.stdout [deleted file]
src/test/ui/async-await/issue-76547.base.stderr
src/test/ui/async-await/issue-76547.nll.stderr
src/test/ui/async-await/issues/issue-63388-1.base.stderr
src/test/ui/async-await/issues/issue-63388-1.nll.stderr
src/test/ui/async-await/issues/issue-63388-1.rs
src/test/ui/attributes/attrs-on-params.rs
src/test/ui/attributes/attrs-on-params.stderr
src/test/ui/attributes/field-attributes-vis-unresolved.stderr
src/test/ui/borrowck/issue-71546.rs [new file with mode: 0644]
src/test/ui/borrowck/issue-71546.stderr [new file with mode: 0644]
src/test/ui/closure-expected-type/expect-two-infer-vars-supply-ty-with-bound-region.stderr
src/test/ui/closures/add_semicolon_non_block_closure.rs [new file with mode: 0644]
src/test/ui/closures/add_semicolon_non_block_closure.stderr [new file with mode: 0644]
src/test/ui/closures/issue-52437.stderr
src/test/ui/codegen/auxiliary/issue-97708-aux.rs [new file with mode: 0644]
src/test/ui/codegen/issue-97708.rs [new file with mode: 0644]
src/test/ui/codemap_tests/two_files.stderr
src/test/ui/coherence/coherence-impls-sized.stderr
src/test/ui/conditional-compilation/cfg_accessible-bugs.rs [new file with mode: 0644]
src/test/ui/conditional-compilation/cfg_accessible-bugs.stderr [new file with mode: 0644]
src/test/ui/conditional-compilation/cfg_accessible-not_sure.edition2015.stderr [new file with mode: 0644]
src/test/ui/conditional-compilation/cfg_accessible-not_sure.edition2021.stderr [new file with mode: 0644]
src/test/ui/conditional-compilation/cfg_accessible-not_sure.rs [new file with mode: 0644]
src/test/ui/conditional-compilation/cfg_accessible-private.rs [new file with mode: 0644]
src/test/ui/conditional-compilation/cfg_accessible.rs
src/test/ui/conditional-compilation/cfg_accessible.stderr
src/test/ui/const-generics/defaults/doesnt_infer.stderr
src/test/ui/const-generics/generic_arg_infer/issue-91614.stderr
src/test/ui/const-generics/generic_const_exprs/const_eval_resolve_canonical.stderr
src/test/ui/const-generics/generic_const_exprs/issue-94287.stderr
src/test/ui/const-generics/infer/cannot-infer-const-args.stderr
src/test/ui/const-generics/infer/issue-77092.stderr
src/test/ui/const-generics/infer/method-chain.stderr
src/test/ui/const-generics/infer/one-param-uninferred.stderr
src/test/ui/const-generics/infer/uninferred-consts.stderr
src/test/ui/const-generics/issues/issue-83249.stderr
src/test/ui/const-ptr/allowed_slices.rs [new file with mode: 0644]
src/test/ui/const-ptr/forbidden_slices.32bit.stderr [new file with mode: 0644]
src/test/ui/const-ptr/forbidden_slices.64bit.stderr [new file with mode: 0644]
src/test/ui/const-ptr/forbidden_slices.rs [new file with mode: 0644]
src/test/ui/consts/issue-54387.rs [new file with mode: 0644]
src/test/ui/consts/issue-64662.stderr
src/test/ui/derive-uninhabited-enum-38885.stderr
src/test/ui/derives/clone-debug-dead-code.stderr
src/test/ui/derives/issue-97343.rs
src/test/ui/derives/issue-97343.stderr
src/test/ui/editions/edition-keywords-2015-2018-expansion.stderr
src/test/ui/editions/edition-keywords-2018-2018-expansion.stderr
src/test/ui/enum-discriminant/forbidden-discriminant-kind-impl.stderr
src/test/ui/error-codes/E0109.stderr
src/test/ui/error-codes/E0110.stderr
src/test/ui/error-codes/E0263.rs
src/test/ui/error-codes/E0263.stderr
src/test/ui/error-codes/E0282.stderr
src/test/ui/error-codes/E0283.stderr
src/test/ui/error-codes/E0308-2.stderr
src/test/ui/error-codes/E0401.stderr
src/test/ui/error-codes/E0432.stderr
src/test/ui/feature-gates/feature-gate-extern_absolute_paths.stderr
src/test/ui/for-loop-while/label_break_value.rs
src/test/ui/for-loop-while/label_break_value.stderr [deleted file]
src/test/ui/for-loop-while/label_break_value_invalid.rs
src/test/ui/for-loop-while/label_break_value_invalid.stderr
src/test/ui/for/for-loop-unconstrained-element-type.stderr
src/test/ui/generator/issue-87142.rs [new file with mode: 0644]
src/test/ui/generic-associated-types/gat-trait-path-parenthesised-args.rs
src/test/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr
src/test/ui/generic-associated-types/issue-91762.stderr
src/test/ui/generic-associated-types/parameter_number_and_kind_impl.stderr
src/test/ui/generic-associated-types/shadowing.stderr
src/test/ui/hygiene/duplicate_lifetimes.rs
src/test/ui/hygiene/duplicate_lifetimes.stderr
src/test/ui/hygiene/hygienic-labels-in-let.rs
src/test/ui/hygiene/hygienic-labels-in-let.stderr [deleted file]
src/test/ui/hygiene/hygienic-labels.rs
src/test/ui/hygiene/hygienic-labels.stderr [deleted file]
src/test/ui/impl-trait/cross-return-site-inference.rs
src/test/ui/impl-trait/cross-return-site-inference.stderr
src/test/ui/impl-trait/diagnostics/fully-qualified-path-impl-trait.rs [new file with mode: 0644]
src/test/ui/impl-trait/diagnostics/fully-qualified-path-impl-trait.stderr [new file with mode: 0644]
src/test/ui/impl-trait/fallback_inference.rs
src/test/ui/impl-trait/fallback_inference.stderr
src/test/ui/impl-trait/hidden-type-is-opaque-2.rs
src/test/ui/impl-trait/hidden-type-is-opaque-2.stderr
src/test/ui/impl-trait/issue-54966.rs [new file with mode: 0644]
src/test/ui/impl-trait/issue-54966.stderr [new file with mode: 0644]
src/test/ui/impl-trait/issues/issue-84073.stderr
src/test/ui/impl-trait/issues/issue-86719.stderr
src/test/ui/impl-trait/issues/issue-92305.stderr
src/test/ui/imports/import3.stderr
src/test/ui/imports/issue-1697.stderr
src/test/ui/imports/issue-26873-multifile/A/B.rs [new file with mode: 0644]
src/test/ui/imports/issue-26873-multifile/A/C.rs [new file with mode: 0644]
src/test/ui/imports/issue-26873-multifile/A/mod.rs [new file with mode: 0644]
src/test/ui/imports/issue-26873-multifile/compiletest-ignore-dir [new file with mode: 0644]
src/test/ui/imports/issue-26873-multifile/issue-26873-multifile.rs [new file with mode: 0644]
src/test/ui/imports/issue-26873-multifile/issue-26873-onefile.rs [new file with mode: 0644]
src/test/ui/imports/issue-26873-multifile/mod.rs [new file with mode: 0644]
src/test/ui/imports/issue-26873-onefile.rs [deleted file]
src/test/ui/imports/issue-33464.stderr
src/test/ui/imports/issue-36881.stderr
src/test/ui/imports/issue-37887.stderr
src/test/ui/imports/issue-53269.stderr
src/test/ui/imports/issue-55457.stderr
src/test/ui/imports/tool-mod-child.stderr
src/test/ui/imports/unresolved-imports-used.stderr
src/test/ui/inference/ambiguous_type_parameter.stderr
src/test/ui/inference/cannot-infer-async.stderr
src/test/ui/inference/cannot-infer-closure-circular.rs
src/test/ui/inference/cannot-infer-closure-circular.stderr
src/test/ui/inference/cannot-infer-closure.rs
src/test/ui/inference/cannot-infer-closure.stderr
src/test/ui/inference/cannot-infer-partial-try-return.rs
src/test/ui/inference/cannot-infer-partial-try-return.stderr
src/test/ui/inference/erase-type-params-in-label.stderr
src/test/ui/inference/issue-71732.stderr
src/test/ui/inference/issue-72616.stderr
src/test/ui/inference/issue-83606.stderr
src/test/ui/inference/issue-86162-1.stderr
src/test/ui/inference/issue-86162-2.stderr
src/test/ui/issues/issue-11319.rs [deleted file]
src/test/ui/issues/issue-11319.stderr [deleted file]
src/test/ui/issues/issue-12187-1.stderr
src/test/ui/issues/issue-12187-2.stderr
src/test/ui/issues/issue-13853-2.rs [deleted file]
src/test/ui/issues/issue-13853-2.stderr [deleted file]
src/test/ui/issues/issue-13853-5.rs [deleted file]
src/test/ui/issues/issue-13853-5.stderr [deleted file]
src/test/ui/issues/issue-13853.rs [deleted file]
src/test/ui/issues/issue-13853.stderr [deleted file]
src/test/ui/issues/issue-14933.rs [deleted file]
src/test/ui/issues/issue-14958.rs [deleted file]
src/test/ui/issues/issue-16966.stderr
src/test/ui/issues/issue-17551.stderr
src/test/ui/issues/issue-17905-2.stderr
src/test/ui/issues/issue-18159.stderr
src/test/ui/issues/issue-20261.stderr
src/test/ui/issues/issue-2151.rs
src/test/ui/issues/issue-2151.stderr
src/test/ui/issues/issue-22706.rs
src/test/ui/issues/issue-22706.stderr
src/test/ui/issues/issue-23046.stderr
src/test/ui/issues/issue-24036.stderr
src/test/ui/issues/issue-25368.rs
src/test/ui/issues/issue-25368.stderr
src/test/ui/issues/issue-26873-multifile.rs [deleted file]
src/test/ui/issues/issue-26873-multifile/A/B.rs [deleted file]
src/test/ui/issues/issue-26873-multifile/A/C.rs [deleted file]
src/test/ui/issues/issue-26873-multifile/A/mod.rs [deleted file]
src/test/ui/issues/issue-26873-multifile/compiletest-ignore-dir [deleted file]
src/test/ui/issues/issue-26873-multifile/mod.rs [deleted file]
src/test/ui/issues/issue-28098.rs [deleted file]
src/test/ui/issues/issue-28098.stderr [deleted file]
src/test/ui/issues/issue-47486.stderr
src/test/ui/issues/issue-5062.stderr
src/test/ui/issues/issue-51116.rs
src/test/ui/issues/issue-51116.stderr
src/test/ui/issues/issue-54387.rs [deleted file]
src/test/ui/issues/issue-54966.rs [deleted file]
src/test/ui/issues/issue-54966.stderr [deleted file]
src/test/ui/issues/issue-57924.rs
src/test/ui/issues/issue-57924.stderr
src/test/ui/issues/issue-60989.rs
src/test/ui/issues/issue-60989.stderr
src/test/ui/issues/issue-6458-2.stderr
src/test/ui/issues/issue-6458-3.stderr
src/test/ui/issues/issue-6458.stderr
src/test/ui/issues/issue-65230.stderr
src/test/ui/issues/issue-66706.stderr
src/test/ui/issues/issue-68091-unicode-ident-after-if.rs [deleted file]
src/test/ui/issues/issue-68091-unicode-ident-after-if.stderr [deleted file]
src/test/ui/issues/issue-68092-unicode-ident-after-incomplete-expr.rs [deleted file]
src/test/ui/issues/issue-68092-unicode-ident-after-incomplete-expr.stderr [deleted file]
src/test/ui/issues/issue-69455.stderr
src/test/ui/issues/issue-69683.stderr
src/test/ui/issues/issue-70724-add_type_neq_err_label-unwrap.stderr
src/test/ui/issues/issue-72690.stderr
src/test/ui/issues/issue-7813.stderr
src/test/ui/issues/issue-8153.rs [deleted file]
src/test/ui/issues/issue-8153.stderr [deleted file]
src/test/ui/iterators/issue-28098.rs [new file with mode: 0644]
src/test/ui/iterators/issue-28098.stderr [new file with mode: 0644]
src/test/ui/keyword/extern/keyword-extern-as-identifier-use.stderr
src/test/ui/lint/dead-code/unused-variant.stderr
src/test/ui/lint/rfc-2383-lint-reason/expect_on_fn_params.rs [new file with mode: 0644]
src/test/ui/lint/rfc-2383-lint-reason/expect_on_fn_params.stderr [new file with mode: 0644]
src/test/ui/lint/unused_labels.stderr
src/test/ui/loops/loops-reject-duplicate-labels-2.rs [deleted file]
src/test/ui/loops/loops-reject-duplicate-labels-2.stderr [deleted file]
src/test/ui/loops/loops-reject-duplicate-labels.rs [deleted file]
src/test/ui/loops/loops-reject-duplicate-labels.stderr [deleted file]
src/test/ui/loops/loops-reject-labels-shadowing-lifetimes.rs [deleted file]
src/test/ui/loops/loops-reject-labels-shadowing-lifetimes.stderr [deleted file]
src/test/ui/loops/loops-reject-lifetime-shadowing-label.rs [deleted file]
src/test/ui/loops/loops-reject-lifetime-shadowing-label.stderr [deleted file]
src/test/ui/macros/macro-lifetime-used-with-labels.rs
src/test/ui/macros/macro-lifetime-used-with-labels.stderr [deleted file]
src/test/ui/match/issue-11319.rs [new file with mode: 0644]
src/test/ui/match/issue-11319.stderr [new file with mode: 0644]
src/test/ui/match/match-unresolved-one-arm.stderr
src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr
src/test/ui/methods/method-on-ambiguous-numeric-type.stderr
src/test/ui/missing/missing-items/missing-type-parameter.stderr
src/test/ui/mod-subitem-as-enum-variant.rs
src/test/ui/mod-subitem-as-enum-variant.stderr
src/test/ui/moves/use_of_moved_value_copy_suggestions.fixed
src/test/ui/moves/use_of_moved_value_copy_suggestions.stderr
src/test/ui/nll/issue-52742.base.stderr
src/test/ui/nll/issue-52742.nll.stderr
src/test/ui/nll/issue-55394.base.stderr
src/test/ui/overloaded/issue-14958.rs [new file with mode: 0644]
src/test/ui/parser/issue-68091-unicode-ident-after-if.rs [new file with mode: 0644]
src/test/ui/parser/issue-68091-unicode-ident-after-if.stderr [new file with mode: 0644]
src/test/ui/parser/issue-68092-unicode-ident-after-incomplete-expr.rs [new file with mode: 0644]
src/test/ui/parser/issue-68092-unicode-ident-after-incomplete-expr.stderr [new file with mode: 0644]
src/test/ui/parser/issues/issue-67377-invalid-syntax-in-enum-discriminant.stderr
src/test/ui/parser/missing-closing-angle-bracket-eq-constraint.stderr
src/test/ui/pattern/pat-tuple-bad-type.rs
src/test/ui/pattern/pat-tuple-bad-type.stderr
src/test/ui/pattern/rest-pat-semantic-disallowed.stderr
src/test/ui/privacy/restricted/test.stderr
src/test/ui/proc-macro/auxiliary/expand-expr.rs
src/test/ui/proc-macro/capture-macro-rules-invoke.stdout
src/test/ui/proc-macro/capture-unglued-token.stdout
src/test/ui/proc-macro/expand-expr.rs
src/test/ui/proc-macro/expr-stmt-nonterminal-tokens.stdout
src/test/ui/proc-macro/issue-75734-pp-paren.stdout
src/test/ui/proc-macro/issue-78675-captured-inner-attrs.stdout
src/test/ui/proc-macro/issue-80760-empty-stmt.stdout
src/test/ui/proc-macro/nested-nonterminal-tokens.stdout
src/test/ui/proc-macro/nodelim-groups.stdout
src/test/ui/proc-macro/nonterminal-expansion.stdout
src/test/ui/proc-macro/nonterminal-token-hygiene.stdout
src/test/ui/proc-macro/parent-source-spans.rs
src/test/ui/proc-macro/parent-source-spans.stderr
src/test/ui/regions/regions-name-duplicated.rs
src/test/ui/regions/regions-name-duplicated.stderr
src/test/ui/resolve/editions-crate-root-2015.stderr
src/test/ui/resolve/extern-prelude-fail.stderr
src/test/ui/resolve/issue-82865.stderr
src/test/ui/resolve/issue-85348.stderr
src/test/ui/resolve/resolve-bad-visibility.stderr
src/test/ui/rfc-2011-nicer-assert-messages/feature-gate-generic_assert.rs [new file with mode: 0644]
src/test/ui/rfc-2565-param-attrs/param-attrs-builtin-attrs.rs
src/test/ui/rfc-2565-param-attrs/param-attrs-builtin-attrs.stderr
src/test/ui/rustdoc/check-doc-alias-attr-location.stderr
src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr
src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.base.stderr
src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.nll.stderr
src/test/ui/self/elision/lt-ref-self-async.base.stderr
src/test/ui/self/elision/lt-ref-self-async.nll.stderr
src/test/ui/self/elision/ref-mut-self-async.base.stderr
src/test/ui/self/elision/ref-mut-self-async.nll.stderr
src/test/ui/self/elision/ref-mut-struct-async.base.stderr
src/test/ui/self/elision/ref-mut-struct-async.nll.stderr
src/test/ui/self/elision/ref-self-async.base.stderr
src/test/ui/self/elision/ref-self-async.nll.stderr
src/test/ui/self/elision/ref-struct-async.base.stderr
src/test/ui/self/elision/ref-struct-async.nll.stderr
src/test/ui/simd/portable-intrinsics-arent-exposed.stderr
src/test/ui/span/issue-42234-unknown-receiver-type.full.stderr
src/test/ui/span/issue-42234-unknown-receiver-type.generic_arg.stderr
src/test/ui/span/issue-42234-unknown-receiver-type.rs
src/test/ui/span/method-and-field-eager-resolution.rs
src/test/ui/span/method-and-field-eager-resolution.stderr
src/test/ui/span/type-annotations-needed-expr.stderr
src/test/ui/structs/struct-path-associated-type.rs
src/test/ui/structs/struct-path-associated-type.stderr
src/test/ui/structs/struct-path-self.rs
src/test/ui/structs/struct-path-self.stderr
src/test/ui/suggestions/enum-method-probe.fixed [new file with mode: 0644]
src/test/ui/suggestions/enum-method-probe.rs [new file with mode: 0644]
src/test/ui/suggestions/enum-method-probe.stderr [new file with mode: 0644]
src/test/ui/suggestions/fn-needing-specified-return-type-param.rs
src/test/ui/suggestions/fn-needing-specified-return-type-param.stderr
src/test/ui/suggestions/missing-bound-in-derive-copy-impl-2.fixed [new file with mode: 0644]
src/test/ui/suggestions/missing-bound-in-derive-copy-impl-2.rs [new file with mode: 0644]
src/test/ui/suggestions/missing-bound-in-derive-copy-impl-2.stderr [new file with mode: 0644]
src/test/ui/suggestions/missing-bound-in-derive-copy-impl-3.fixed [new file with mode: 0644]
src/test/ui/suggestions/missing-bound-in-derive-copy-impl-3.rs [new file with mode: 0644]
src/test/ui/suggestions/missing-bound-in-derive-copy-impl-3.stderr [new file with mode: 0644]
src/test/ui/suggestions/missing-bound-in-derive-copy-impl.rs [new file with mode: 0644]
src/test/ui/suggestions/missing-bound-in-derive-copy-impl.stderr [new file with mode: 0644]
src/test/ui/suggestions/suggest-closure-return-type-1.rs
src/test/ui/suggestions/suggest-closure-return-type-1.stderr
src/test/ui/suggestions/suggest-closure-return-type-2.rs
src/test/ui/suggestions/suggest-closure-return-type-2.stderr
src/test/ui/suggestions/suggest-closure-return-type-3.rs
src/test/ui/suggestions/suggest-closure-return-type-3.stderr
src/test/ui/traits/do-not-mention-type-params-by-name-in-suggestion-issue-96292.stderr
src/test/ui/traits/issue-77982.stderr
src/test/ui/traits/issue-8153.rs [new file with mode: 0644]
src/test/ui/traits/issue-8153.stderr [new file with mode: 0644]
src/test/ui/traits/issue-97576.rs [new file with mode: 0644]
src/test/ui/traits/issue-97576.stderr [new file with mode: 0644]
src/test/ui/traits/issue-97695-double-trivial-bound.rs [new file with mode: 0644]
src/test/ui/traits/multidispatch-convert-ambig-dest.stderr
src/test/ui/traits/not-suggest-non-existing-fully-qualified-path.stderr
src/test/ui/traits/suggest-fully-qualified-path-with-adjustment.rs [new file with mode: 0644]
src/test/ui/traits/suggest-fully-qualified-path-with-adjustment.stderr [new file with mode: 0644]
src/test/ui/traits/suggest-fully-qualified-path-with-appropriate-params.rs [deleted file]
src/test/ui/traits/suggest-fully-qualified-path-with-appropriate-params.stderr [deleted file]
src/test/ui/traits/suggest-fully-qualified-path-without-adjustment.rs [new file with mode: 0644]
src/test/ui/traits/suggest-fully-qualified-path-without-adjustment.stderr [new file with mode: 0644]
src/test/ui/type-alias-enum-variants/enum-variant-generic-args.rs
src/test/ui/type-alias-enum-variants/enum-variant-generic-args.stderr
src/test/ui/type-alias-enum-variants/no-type-application-on-aliased-enum-variant.rs
src/test/ui/type-alias-enum-variants/no-type-application-on-aliased-enum-variant.stderr
src/test/ui/type-alias-impl-trait/closures_in_branches.stderr
src/test/ui/type-alias-impl-trait/incomplete-inference.stderr
src/test/ui/type-alias/issue-14933.rs [new file with mode: 0644]
src/test/ui/type-inference/or_else-multiple-type-params.stderr
src/test/ui/type-inference/sort_by_key.stderr
src/test/ui/type-inference/unbounded-associated-type.stderr
src/test/ui/type-inference/unbounded-type-param-in-fn-with-assoc-type.stderr
src/test/ui/type-inference/unbounded-type-param-in-fn.stderr
src/test/ui/type/ascription/issue-47666.stderr
src/test/ui/type/issue-91268.rs
src/test/ui/type/issue-91268.stderr
src/test/ui/type/type-annotation-needed.stderr
src/test/ui/type/type-check/cannot_infer_local_or_array.stderr
src/test/ui/type/type-check/cannot_infer_local_or_vec.stderr
src/test/ui/type/type-check/cannot_infer_local_or_vec_in_tuples.stderr
src/test/ui/type/type-check/unknown_type_for_closure.rs
src/test/ui/type/type-check/unknown_type_for_closure.stderr
src/test/ui/type/type-path-err-node-types.stderr
src/test/ui/typeck/issue-13853-2.rs [new file with mode: 0644]
src/test/ui/typeck/issue-13853-2.stderr [new file with mode: 0644]
src/test/ui/typeck/issue-13853-5.rs [new file with mode: 0644]
src/test/ui/typeck/issue-13853-5.stderr [new file with mode: 0644]
src/test/ui/typeck/issue-13853.rs [new file with mode: 0644]
src/test/ui/typeck/issue-13853.stderr [new file with mode: 0644]
src/test/ui/typeck/issue-65611.stderr
src/test/ui/typeck/prim-with-args.fixed [new file with mode: 0644]
src/test/ui/typeck/prim-with-args.rs
src/test/ui/typeck/prim-with-args.stderr
src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-2.rs
src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-2.stderr
src/test/ui/unconstrained-none.stderr
src/test/ui/unconstrained-ref.stderr
src/test/ui/union/union-copy.stderr
src/test/ui/unresolved/unresolved-asterisk-imports.stderr
src/test/ui/unresolved/unresolved-import.rs
src/test/ui/unresolved/unresolved-import.stderr
src/test/ui/usize-generic-argument-parent.rs
src/test/ui/usize-generic-argument-parent.stderr
src/tools/cargo
src/tools/clippy/clippy_lints/src/lifetimes.rs
src/tools/clippy/clippy_lints/src/ptr.rs
src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
src/tools/clippy/clippy_utils/src/diagnostics.rs
src/tools/clippy/clippy_utils/src/hir_utils.rs
src/tools/clippy/clippy_utils/src/lib.rs
src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
src/tools/miri
src/tools/rust-analyzer
src/tools/tidy/src/ui_tests.rs
triagebot.toml

index c066d1b0a5bd13baf0b123d04cd3650e02b5c5dd..bea0c13000ca6c8dba636dcaa325352bf3b83003 100644 (file)
@@ -223,6 +223,7 @@ dependencies = [
  "pretty_assertions 0.7.2",
  "serde",
  "serde_json",
+ "sysinfo",
  "tar",
  "toml",
  "winapi",
@@ -746,9 +747,9 @@ dependencies = [
 
 [[package]]
 name = "compiler_builtins"
-version = "0.1.71"
+version = "0.1.73"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "163437f05ca8f29d7e9128ea728dedf5eb620e445fbca273641d3a3050305f23"
+checksum = "71b72fde1d7792ca3bd654f7c3ea4508f9e4d0c826e24179eabb7fcc97a90bc3"
 dependencies = [
  "cc",
  "rustc-std-workspace-core",
@@ -3686,6 +3687,7 @@ dependencies = [
  "rustc_span",
  "rustc_symbol_mangling",
  "rustc_target",
+ "serde_json",
  "smallvec",
  "snap",
  "tempfile",
@@ -3774,6 +3776,7 @@ dependencies = [
  "rustc_span",
  "rustc_target",
  "rustc_typeck",
+ "serde_json",
  "tracing",
  "winapi",
 ]
@@ -3809,6 +3812,8 @@ dependencies = [
  "rustc_macros",
  "rustc_serialize",
  "rustc_span",
+ "serde",
+ "serde_json",
  "termcolor",
  "termize",
  "tracing",
@@ -4024,6 +4029,7 @@ dependencies = [
  "rustc_serialize",
  "rustc_span",
  "rustc_target",
+ "serde",
 ]
 
 [[package]]
@@ -4445,6 +4451,7 @@ dependencies = [
  "rustc_macros",
  "rustc_serialize",
  "rustc_span",
+ "serde_json",
  "tracing",
 ]
 
@@ -5120,6 +5127,21 @@ dependencies = [
  "unicode-xid",
 ]
 
+[[package]]
+name = "sysinfo"
+version = "0.24.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a6a8e71535da31837213ac114531d31def75d7aebd133264e420a3451fa7f703"
+dependencies = [
+ "cfg-if 1.0.0",
+ "core-foundation-sys",
+ "libc",
+ "ntapi",
+ "once_cell",
+ "rayon",
+ "winapi",
+]
+
 [[package]]
 name = "tar"
 version = "0.4.37"
@@ -5509,6 +5531,8 @@ dependencies = [
  "pretty_assertions 1.2.1",
  "regex",
  "rustc_version",
+ "serde",
+ "serde_json",
 ]
 
 [[package]]
diff --git a/compiler/rustc/Windows Manifest.xml b/compiler/rustc/Windows Manifest.xml
new file mode 100644 (file)
index 0000000..b37a2fd
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!--
+This is a Windows application manifest file.
+See: https://docs.microsoft.com/en-us/windows/win32/sbscs/application-manifests
+-->
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
+    <!-- Versions rustc supports as compiler hosts -->
+    <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> 
+        <application> 
+            <!-- Windows 7 --><supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
+            <!-- Windows 8 --><supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
+            <!-- Windows 8.1 --><supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
+            <!-- Windows 10 and 11 --><supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
+        </application> 
+    </compatibility>
+    <!-- Use UTF-8 code page -->
+    <asmv3:application>
+        <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings">
+            <activeCodePage>UTF-8</activeCodePage>
+        </asmv3:windowsSettings>
+    </asmv3:application>
+    <!-- Remove (most) legacy path limits -->
+    <asmv3:application>
+        <asmv3:windowsSettings xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
+            <ws2:longPathAware>true</ws2:longPathAware>
+        </asmv3:windowsSettings>
+    </asmv3:application>
+</assembly>
diff --git a/compiler/rustc/build.rs b/compiler/rustc/build.rs
new file mode 100644 (file)
index 0000000..24c06c0
--- /dev/null
@@ -0,0 +1,24 @@
+use std::env;
+
+fn main() {
+    let target_os = env::var("CARGO_CFG_TARGET_OS");
+    let target_env = env::var("CARGO_CFG_TARGET_ENV");
+    if Ok("windows") == target_os.as_deref() && Ok("msvc") == target_env.as_deref() {
+        set_windows_exe_options();
+    }
+}
+
+// Add a manifest file to rustc.exe.
+fn set_windows_exe_options() {
+    static WINDOWS_MANIFEST_FILE: &str = "Windows Manifest.xml";
+
+    let mut manifest = env::current_dir().unwrap();
+    manifest.push(WINDOWS_MANIFEST_FILE);
+
+    println!("cargo:rerun-if-changed={}", WINDOWS_MANIFEST_FILE);
+    // Embed the Windows application manifest file.
+    println!("cargo:rustc-link-arg-bin=rustc-main=/MANIFEST:EMBED");
+    println!("cargo:rustc-link-arg-bin=rustc-main=/MANIFESTINPUT:{}", manifest.to_str().unwrap());
+    // Turn linker warnings into errors.
+    println!("cargo:rustc-link-arg-bin=rustc-main=/WX");
+}
index b81f7a2427076a028a3cd5278d2f4a1880a877c8..b64f7b8ad1b113a213b1ecc90903c8d9d35e69fe 100644 (file)
@@ -41,9 +41,6 @@
 use std::fmt;
 use std::mem;
 
-#[cfg(test)]
-mod tests;
-
 /// A "Label" is an identifier of some point in sources,
 /// e.g. in the following code:
 ///
@@ -2476,8 +2473,8 @@ pub struct AttrId {
 }
 
 impl<S: Encoder> rustc_serialize::Encodable<S> for AttrId {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_unit()
+    fn encode(&self, _s: &mut S) -> Result<(), S::Error> {
+        Ok(())
     }
 }
 
diff --git a/compiler/rustc_ast/src/ast/tests.rs b/compiler/rustc_ast/src/ast/tests.rs
deleted file mode 100644 (file)
index 8ba55bf..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-use super::*;
-
-// Are ASTs encodable?
-#[test]
-fn check_asts_encodable() {
-    fn assert_encodable<
-        T: for<'a> rustc_serialize::Encodable<rustc_serialize::json::Encoder<'a>>,
-    >() {
-    }
-    assert_encodable::<Crate>();
-}
index 1522d12cbf92e819a437ea98008e55f77ac00bbf..85d9687c600dc72b526f5ac5f44ca8e823c1dbdc 100644 (file)
@@ -50,12 +50,11 @@ pub enum Delimiter {
     Brace,
     /// `[ ... ]`
     Bracket,
-    /// `/*«*/ ... /*»*/`
+    /// `Ø ... Ø`
     /// An invisible delimiter, that may, for example, appear around tokens coming from a
     /// "macro variable" `$var`. It is important to preserve operator priorities in cases like
     /// `$var * 3` where `$var` is `1 + 2`.
-    /// Invisible delimiters are not directly writable in normal Rust code except as comments.
-    /// Therefore, they might not survive a roundtrip of a token stream through a string.
+    /// Invisible delimiters might not survive roundtrip of a token stream through a string.
     Invisible,
 }
 
index 3aff04f78fb8500fcba53063bef1ab0f14bc1142..539e33702aa6735ff927ec8e919424cad123116c 100644 (file)
@@ -41,7 +41,22 @@ pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
                 }
                 ExprKind::Tup(ref elts) => hir::ExprKind::Tup(self.lower_exprs(elts)),
                 ExprKind::Call(ref f, ref args) => {
-                    if let Some(legacy_args) = self.resolver.legacy_const_generic_args(f) {
+                    if e.attrs.get(0).map_or(false, |a| a.has_name(sym::rustc_box)) {
+                        if let [inner] = &args[..] && e.attrs.len() == 1 {
+                            let kind = hir::ExprKind::Box(self.lower_expr(&inner));
+                            let hir_id = self.lower_node_id(e.id);
+                            return hir::Expr { hir_id, kind, span: self.lower_span(e.span) };
+                        } else {
+                            self.sess
+                                .struct_span_err(
+                                    e.span,
+                                    "#[rustc_box] requires precisely one argument \
+                                    and no other attributes are allowed",
+                                )
+                                .emit();
+                            hir::ExprKind::Err
+                        }
+                    } else if let Some(legacy_args) = self.resolver.legacy_const_generic_args(f) {
                         self.lower_legacy_const_generics((**f).clone(), args.clone(), &legacy_args)
                     } else {
                         let f = self.lower_expr(f);
index 12d1b8404eb8b9f17e4c287de56d3eaae30449f4..dab4d76857a50a18752673bdaa650c70c4b38eae 100644 (file)
@@ -83,6 +83,8 @@ fn with_lctx(
             task_context: None,
             current_item: None,
             captured_lifetimes: None,
+            impl_trait_defs: Vec::new(),
+            impl_trait_bounds: Vec::new(),
             allow_try_trait: Some([sym::try_trait_v2, sym::yeet_desugar_details][..].into()),
             allow_gen_future: Some([sym::gen_future][..].into()),
             allow_into_future: Some([sym::into_future][..].into()),
@@ -264,16 +266,11 @@ fn lower_item_kind(
                     let body_id =
                         this.lower_maybe_async_body(span, &decl, asyncness, body.as_deref());
 
-                    let (generics, decl) =
-                        this.add_implicit_generics(generics, id, |this, idty, idpb| {
-                            let ret_id = asyncness.opt_return_id();
-                            this.lower_fn_decl(
-                                &decl,
-                                Some((id, idty, idpb)),
-                                FnDeclKind::Fn,
-                                ret_id,
-                            )
-                        });
+                    let itctx = ImplTraitContext::Universal;
+                    let (generics, decl) = this.lower_generics(generics, id, itctx, |this| {
+                        let ret_id = asyncness.opt_return_id();
+                        this.lower_fn_decl(&decl, Some(id), FnDeclKind::Fn, ret_id)
+                    });
                     let sig = hir::FnSig {
                         decl,
                         header: this.lower_fn_header(header),
@@ -311,57 +308,59 @@ fn lower_item_kind(
                 //
                 // type Foo = Foo1
                 // opaque type Foo1: Trait
-                let ty = self.lower_ty(ty, ImplTraitContext::TypeAliasesOpaqueTy);
                 let mut generics = generics.clone();
                 add_ty_alias_where_clause(&mut generics, where_clauses, true);
-                let generics = self.lower_generics(
+                let (generics, ty) = self.lower_generics(
                     &generics,
+                    id,
                     ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+                    |this| this.lower_ty(ty, ImplTraitContext::TypeAliasesOpaqueTy),
                 );
                 hir::ItemKind::TyAlias(ty, generics)
             }
             ItemKind::TyAlias(box TyAlias {
                 ref generics, ref where_clauses, ty: None, ..
             }) => {
-                let ty = self.arena.alloc(self.ty(span, hir::TyKind::Err));
                 let mut generics = generics.clone();
                 add_ty_alias_where_clause(&mut generics, *where_clauses, true);
-                let generics = self.lower_generics(
+                let (generics, ty) = self.lower_generics(
                     &generics,
+                    id,
                     ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+                    |this| this.arena.alloc(this.ty(span, hir::TyKind::Err)),
                 );
                 hir::ItemKind::TyAlias(ty, generics)
             }
-            ItemKind::Enum(ref enum_definition, ref generics) => hir::ItemKind::Enum(
-                hir::EnumDef {
-                    variants: self.arena.alloc_from_iter(
-                        enum_definition.variants.iter().map(|x| self.lower_variant(x)),
-                    ),
-                },
-                self.lower_generics(
+            ItemKind::Enum(ref enum_definition, ref generics) => {
+                let (generics, variants) = self.lower_generics(
                     generics,
+                    id,
                     ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
-                ),
-            ),
+                    |this| {
+                        this.arena.alloc_from_iter(
+                            enum_definition.variants.iter().map(|x| this.lower_variant(x)),
+                        )
+                    },
+                );
+                hir::ItemKind::Enum(hir::EnumDef { variants }, generics)
+            }
             ItemKind::Struct(ref struct_def, ref generics) => {
-                let struct_def = self.lower_variant_data(hir_id, struct_def);
-                hir::ItemKind::Struct(
-                    struct_def,
-                    self.lower_generics(
-                        generics,
-                        ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
-                    ),
-                )
+                let (generics, struct_def) = self.lower_generics(
+                    generics,
+                    id,
+                    ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+                    |this| this.lower_variant_data(hir_id, struct_def),
+                );
+                hir::ItemKind::Struct(struct_def, generics)
             }
             ItemKind::Union(ref vdata, ref generics) => {
-                let vdata = self.lower_variant_data(hir_id, vdata);
-                hir::ItemKind::Union(
-                    vdata,
-                    self.lower_generics(
-                        generics,
-                        ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
-                    ),
-                )
+                let (generics, vdata) = self.lower_generics(
+                    generics,
+                    id,
+                    ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+                    |this| this.lower_variant_data(hir_id, vdata),
+                );
+                hir::ItemKind::Union(vdata, generics)
             }
             ItemKind::Impl(box Impl {
                 unsafety,
@@ -386,8 +385,9 @@ fn lower_item_kind(
                 // method, it will not be considered an in-band
                 // lifetime to be added, but rather a reference to a
                 // parent lifetime.
+                let itctx = ImplTraitContext::Universal;
                 let (generics, (trait_ref, lowered_ty)) =
-                    self.add_implicit_generics(ast_generics, id, |this, _, _| {
+                    self.lower_generics(ast_generics, id, itctx, |this| {
                         let trait_ref = trait_ref.as_ref().map(|trait_ref| {
                             this.lower_trait_ref(
                                 trait_ref,
@@ -432,34 +432,38 @@ fn lower_item_kind(
                 ref bounds,
                 ref items,
             }) => {
-                let bounds = self.lower_param_bounds(
-                    bounds,
-                    ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
+                let (generics, (unsafety, items, bounds)) = self.lower_generics(
+                    generics,
+                    id,
+                    ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+                    |this| {
+                        let bounds = this.lower_param_bounds(
+                            bounds,
+                            ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
+                        );
+                        let items = this.arena.alloc_from_iter(
+                            items.iter().map(|item| this.lower_trait_item_ref(item)),
+                        );
+                        let unsafety = this.lower_unsafety(unsafety);
+                        (unsafety, items, bounds)
+                    },
                 );
-                let items = self
-                    .arena
-                    .alloc_from_iter(items.iter().map(|item| self.lower_trait_item_ref(item)));
-                hir::ItemKind::Trait(
-                    is_auto,
-                    self.lower_unsafety(unsafety),
-                    self.lower_generics(
-                        generics,
-                        ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
-                    ),
-                    bounds,
-                    items,
-                )
+                hir::ItemKind::Trait(is_auto, unsafety, generics, bounds, items)
             }
-            ItemKind::TraitAlias(ref generics, ref bounds) => hir::ItemKind::TraitAlias(
-                self.lower_generics(
+            ItemKind::TraitAlias(ref generics, ref bounds) => {
+                let (generics, bounds) = self.lower_generics(
                     generics,
+                    id,
                     ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
-                ),
-                self.lower_param_bounds(
-                    bounds,
-                    ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
-                ),
-            ),
+                    |this| {
+                        this.lower_param_bounds(
+                            bounds,
+                            ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
+                        )
+                    },
+                );
+                hir::ItemKind::TraitAlias(generics, bounds)
+            }
             ItemKind::MacroDef(MacroDef { ref body, macro_rules }) => {
                 let body = P(self.lower_mac_args(body));
                 let macro_kind = self.resolver.decl_macro_kind(self.resolver.local_def_id(id));
@@ -651,8 +655,9 @@ fn lower_foreign_item(&mut self, i: &ForeignItem) -> &'hir hir::ForeignItem<'hir
             kind: match i.kind {
                 ForeignItemKind::Fn(box Fn { ref sig, ref generics, .. }) => {
                     let fdec = &sig.decl;
+                    let itctx = ImplTraitContext::Universal;
                     let (generics, (fn_dec, fn_args)) =
-                        self.add_implicit_generics(generics, i.id, |this, _, _| {
+                        self.lower_generics(generics, i.id, itctx, |this| {
                             (
                                 // Disallow `impl Trait` in foreign items.
                                 this.lower_fn_decl(fdec, None, FnDeclKind::ExternFn, None),
@@ -789,24 +794,25 @@ fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> {
                 ref ty,
                 ..
             }) => {
-                let ty = ty.as_ref().map(|x| {
-                    self.lower_ty(x, ImplTraitContext::Disallowed(ImplTraitPosition::Type))
-                });
                 let mut generics = generics.clone();
                 add_ty_alias_where_clause(&mut generics, where_clauses, false);
-                let generics = self.lower_generics(
+                self.lower_generics(
                     &generics,
+                    i.id,
                     ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
-                );
-                let kind = hir::TraitItemKind::Type(
-                    self.lower_param_bounds(
-                        bounds,
-                        ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
-                    ),
-                    ty,
-                );
-
-                (generics, kind)
+                    |this| {
+                        let ty = ty.as_ref().map(|x| {
+                            this.lower_ty(x, ImplTraitContext::Disallowed(ImplTraitPosition::Type))
+                        });
+                        hir::TraitItemKind::Type(
+                            this.lower_param_bounds(
+                                bounds,
+                                ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+                            ),
+                            ty,
+                        )
+                    },
+                )
             }
             AssocItemKind::MacCall(..) => panic!("macro item shouldn't exist at this point"),
         };
@@ -876,21 +882,21 @@ fn lower_impl_item(&mut self, i: &AssocItem) -> &'hir hir::ImplItem<'hir> {
             AssocItemKind::TyAlias(box TyAlias { generics, where_clauses, ty, .. }) => {
                 let mut generics = generics.clone();
                 add_ty_alias_where_clause(&mut generics, *where_clauses, false);
-                let generics = self.lower_generics(
+                self.lower_generics(
                     &generics,
+                    i.id,
                     ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
-                );
-                let kind = match ty {
-                    None => {
-                        let ty = self.arena.alloc(self.ty(i.span, hir::TyKind::Err));
-                        hir::ImplItemKind::TyAlias(ty)
-                    }
-                    Some(ty) => {
-                        let ty = self.lower_ty(ty, ImplTraitContext::TypeAliasesOpaqueTy);
-                        hir::ImplItemKind::TyAlias(ty)
-                    }
-                };
-                (generics, kind)
+                    |this| match ty {
+                        None => {
+                            let ty = this.arena.alloc(this.ty(i.span, hir::TyKind::Err));
+                            hir::ImplItemKind::TyAlias(ty)
+                        }
+                        Some(ty) => {
+                            let ty = this.lower_ty(ty, ImplTraitContext::TypeAliasesOpaqueTy);
+                            hir::ImplItemKind::TyAlias(ty)
+                        }
+                    },
+                )
             }
             AssocItemKind::MacCall(..) => panic!("`TyMac` should have been expanded by now"),
         };
@@ -1231,8 +1237,9 @@ fn lower_method_sig(
         is_async: Option<NodeId>,
     ) -> (&'hir hir::Generics<'hir>, hir::FnSig<'hir>) {
         let header = self.lower_fn_header(sig.header);
-        let (generics, decl) = self.add_implicit_generics(generics, id, |this, idty, idpb| {
-            this.lower_fn_decl(&sig.decl, Some((id, idty, idpb)), kind, is_async)
+        let itctx = ImplTraitContext::Universal;
+        let (generics, decl) = self.lower_generics(generics, id, itctx, |this| {
+            this.lower_fn_decl(&sig.decl, Some(id), kind, is_async)
         });
         (generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) })
     }
@@ -1289,11 +1296,18 @@ pub(super) fn lower_unsafety(&mut self, u: Unsafe) -> hir::Unsafety {
         }
     }
 
-    pub(super) fn lower_generics_mut(
+    /// Return the pair of the lowered `generics` as `hir::Generics` and the evaluation of `f` with
+    /// the carried impl trait definitions and bounds.
+    fn lower_generics<T>(
         &mut self,
         generics: &Generics,
-        mut itctx: ImplTraitContext<'_, 'hir>,
-    ) -> GenericsCtor<'hir> {
+        parent_node_id: NodeId,
+        itctx: ImplTraitContext,
+        f: impl FnOnce(&mut Self) -> T,
+    ) -> (&'hir hir::Generics<'hir>, T) {
+        debug_assert!(self.impl_trait_defs.is_empty());
+        debug_assert!(self.impl_trait_bounds.is_empty());
+
         // Error if `?Trait` bounds in where clauses don't refer directly to type parameters.
         // Note: we used to clone these bounds directly onto the type parameter (and avoid lowering
         // these into hir when we lower thee where clauses), but this makes it quite difficult to
@@ -1341,9 +1355,9 @@ pub(super) fn lower_generics_mut(
             }
         }
 
-        let mut predicates = SmallVec::new();
+        let mut predicates: SmallVec<[hir::WherePredicate<'hir>; 4]> = SmallVec::new();
         predicates.extend(generics.params.iter().filter_map(|param| {
-            let bounds = self.lower_param_bounds(&param.bounds, itctx.reborrow());
+            let bounds = self.lower_param_bounds(&param.bounds, itctx);
             self.lower_generic_bound_predicate(
                 param.ident,
                 param.id,
@@ -1360,22 +1374,32 @@ pub(super) fn lower_generics_mut(
                 .map(|predicate| self.lower_where_predicate(predicate)),
         );
 
-        GenericsCtor {
-            params: self.lower_generic_params_mut(&generics.params).collect(),
-            predicates,
-            has_where_clause: !generics.where_clause.predicates.is_empty(),
-            where_clause_span: self.lower_span(generics.where_clause.span),
-            span: self.lower_span(generics.span),
-        }
-    }
+        let mut params: SmallVec<[hir::GenericParam<'hir>; 4]> =
+            self.lower_generic_params_mut(&generics.params).collect();
+        let has_where_clause = !generics.where_clause.predicates.is_empty();
+        let where_clause_span = self.lower_span(generics.where_clause.span);
+        let span = self.lower_span(generics.span);
+        let res = f(self);
+
+        let extra_lifetimes = self.resolver.take_extra_lifetime_params(parent_node_id);
+        let impl_trait_defs = std::mem::take(&mut self.impl_trait_defs);
+        params.extend(extra_lifetimes.into_iter().filter_map(|(ident, node_id, res)| {
+            self.lifetime_res_to_generic_param(ident, node_id, res)
+        }));
+        params.extend(impl_trait_defs.into_iter());
 
-    pub(super) fn lower_generics(
-        &mut self,
-        generics: &Generics,
-        itctx: ImplTraitContext<'_, 'hir>,
-    ) -> &'hir hir::Generics<'hir> {
-        let generics_ctor = self.lower_generics_mut(generics, itctx);
-        generics_ctor.into_generics(self.arena)
+        let impl_trait_bounds = std::mem::take(&mut self.impl_trait_bounds);
+        predicates.extend(impl_trait_bounds.into_iter());
+
+        let lowered_generics = self.arena.alloc(hir::Generics {
+            params: self.arena.alloc_from_iter(params),
+            predicates: self.arena.alloc_from_iter(predicates),
+            has_where_clause,
+            where_clause_span,
+            span,
+        });
+
+        (lowered_generics, res)
     }
 
     pub(super) fn lower_generic_bound_predicate(
@@ -1491,24 +1515,3 @@ fn lower_where_predicate(&mut self, pred: &WherePredicate) -> hir::WherePredicat
         }
     }
 }
-
-/// Helper struct for delayed construction of Generics.
-pub(super) struct GenericsCtor<'hir> {
-    pub(super) params: SmallVec<[hir::GenericParam<'hir>; 4]>,
-    pub(super) predicates: SmallVec<[hir::WherePredicate<'hir>; 4]>,
-    has_where_clause: bool,
-    where_clause_span: Span,
-    span: Span,
-}
-
-impl<'hir> GenericsCtor<'hir> {
-    pub(super) fn into_generics(self, arena: &'hir Arena<'hir>) -> &'hir hir::Generics<'hir> {
-        arena.alloc(hir::Generics {
-            params: arena.alloc_from_iter(self.params),
-            predicates: arena.alloc_from_iter(self.predicates),
-            has_where_clause: self.has_where_clause,
-            where_clause_span: self.where_clause_span,
-            span: self.span,
-        })
-    }
-}
index e59bc9aa6b399af4626379c82741939a75976390..51e5c3384a7919701a8afe1a664ae74fc4e443b1 100644 (file)
@@ -46,7 +46,7 @@
 use rustc_data_structures::sorted_map::SortedMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::sync::Lrc;
-use rustc_errors::struct_span_err;
+use rustc_errors::{struct_span_err, Applicability};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Namespace, PartialRes, PerNS, Res};
 use rustc_hir::def_id::{DefId, DefPathHash, LocalDefId, CRATE_DEF_ID};
@@ -121,6 +121,9 @@ struct LoweringContext<'a, 'hir: 'a> {
     local_id_to_def_id: SortedMap<ItemLocalId, LocalDefId>,
     trait_map: FxHashMap<ItemLocalId, Box<[TraitCandidate]>>,
 
+    impl_trait_defs: Vec<hir::GenericParam<'hir>>,
+    impl_trait_bounds: Vec<hir::WherePredicate<'hir>>,
+
     /// NodeIds that are lowered inside the current HIR owner.
     node_id_to_local_id: FxHashMap<NodeId, hir::ItemLocalId>,
 
@@ -243,14 +246,14 @@ fn create_def(
 
 /// Context of `impl Trait` in code, which determines whether it is allowed in an HIR subtree,
 /// and if so, what meaning it has.
-#[derive(Debug)]
-enum ImplTraitContext<'b, 'a> {
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+enum ImplTraitContext {
     /// Treat `impl Trait` as shorthand for a new universal generic parameter.
     /// Example: `fn foo(x: impl Debug)`, where `impl Debug` is conceptually
     /// equivalent to a fresh universal parameter like `fn foo<T: Debug>(x: T)`.
     ///
     /// Newly generated parameters should be inserted into the given `Vec`.
-    Universal(&'b mut Vec<hir::GenericParam<'a>>, &'b mut Vec<hir::WherePredicate<'a>>, LocalDefId),
+    Universal,
 
     /// Treat `impl Trait` as shorthand for a new opaque type.
     /// Example: `fn foo() -> impl Debug`, where `impl Debug` is conceptually
@@ -290,18 +293,6 @@ enum ImplTraitPosition {
     ImplReturn,
 }
 
-impl<'a> ImplTraitContext<'_, 'a> {
-    fn reborrow<'this>(&'this mut self) -> ImplTraitContext<'this, 'a> {
-        use self::ImplTraitContext::*;
-        match self {
-            Universal(params, bounds, parent) => Universal(params, bounds, *parent),
-            ReturnPositionOpaqueTy { origin } => ReturnPositionOpaqueTy { origin: *origin },
-            TypeAliasesOpaqueTy => TypeAliasesOpaqueTy,
-            Disallowed(pos) => Disallowed(*pos),
-        }
-    }
-}
-
 impl std::fmt::Display for ImplTraitPosition {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         let name = match self {
@@ -479,6 +470,8 @@ fn with_hir_id_owner(
         let current_owner = std::mem::replace(&mut self.current_hir_id_owner, def_id);
         let current_local_counter =
             std::mem::replace(&mut self.item_local_id_counter, hir::ItemLocalId::new(1));
+        let current_impl_trait_defs = std::mem::take(&mut self.impl_trait_defs);
+        let current_impl_trait_bounds = std::mem::take(&mut self.impl_trait_bounds);
 
         // Always allocate the first `HirId` for the owner itself.
         let _old = self.node_id_to_local_id.insert(owner, hir::ItemLocalId::new(0));
@@ -486,6 +479,9 @@ fn with_hir_id_owner(
 
         let item = f(self);
         debug_assert_eq!(def_id, item.def_id());
+        // `f` should have consumed all the elements in these vectors when constructing `item`.
+        debug_assert!(self.impl_trait_defs.is_empty());
+        debug_assert!(self.impl_trait_bounds.is_empty());
         let info = self.make_owner_info(item);
 
         self.attrs = current_attrs;
@@ -495,6 +491,8 @@ fn with_hir_id_owner(
         self.trait_map = current_trait_map;
         self.current_hir_id_owner = current_owner;
         self.item_local_id_counter = current_local_counter;
+        self.impl_trait_defs = current_impl_trait_defs;
+        self.impl_trait_bounds = current_impl_trait_bounds;
 
         let _old = self.children.insert(def_id, hir::MaybeOwner::Owner(info));
         debug_assert!(_old.is_none())
@@ -674,9 +672,7 @@ fn lifetime_res_to_generic_param(
             LifetimeRes::Param { .. } => {
                 (hir::ParamName::Plain(ident), hir::LifetimeParamKind::Explicit)
             }
-            LifetimeRes::Fresh { param, .. } => {
-                (hir::ParamName::Fresh(param), hir::LifetimeParamKind::Elided)
-            }
+            LifetimeRes::Fresh { .. } => (hir::ParamName::Fresh, hir::LifetimeParamKind::Elided),
             LifetimeRes::Static | LifetimeRes::Error => return None,
             res => panic!(
                 "Unexpected lifetime resolution {:?} for {:?} at {:?}",
@@ -694,46 +690,6 @@ fn lifetime_res_to_generic_param(
         })
     }
 
-    /// Creates a new `hir::GenericParam` for every new `Fresh` lifetime and
-    /// universal `impl Trait` type parameter encountered while evaluating `f`.
-    /// Definitions are created with the provided `parent_def_id`.
-    fn add_implicit_generics<T>(
-        &mut self,
-        generics: &Generics,
-        parent_node_id: NodeId,
-        f: impl FnOnce(
-            &mut Self,
-            &mut Vec<hir::GenericParam<'hir>>,
-            &mut Vec<hir::WherePredicate<'hir>>,
-        ) -> T,
-    ) -> (&'hir hir::Generics<'hir>, T) {
-        let mut impl_trait_defs = Vec::new();
-        let mut impl_trait_bounds = Vec::new();
-        let mut lowered_generics = self.lower_generics_mut(
-            generics,
-            ImplTraitContext::Universal(
-                &mut impl_trait_defs,
-                &mut impl_trait_bounds,
-                self.current_hir_id_owner,
-            ),
-        );
-        let res = f(self, &mut impl_trait_defs, &mut impl_trait_bounds);
-
-        let extra_lifetimes = self.resolver.take_extra_lifetime_params(parent_node_id);
-        lowered_generics.params.extend(
-            extra_lifetimes
-                .into_iter()
-                .filter_map(|(ident, node_id, res)| {
-                    self.lifetime_res_to_generic_param(ident, node_id, res)
-                })
-                .chain(impl_trait_defs),
-        );
-        lowered_generics.predicates.extend(impl_trait_bounds);
-
-        let lowered_generics = lowered_generics.into_generics(self.arena);
-        (lowered_generics, res)
-    }
-
     /// Setup lifetime capture for and impl-trait.
     /// The captures will be added to `captures`.
     fn while_capturing_lifetimes<T>(
@@ -898,32 +854,21 @@ fn lower_mac_args(&self, args: &MacArgs) -> MacArgs {
     fn lower_assoc_ty_constraint(
         &mut self,
         constraint: &AssocConstraint,
-        mut itctx: ImplTraitContext<'_, 'hir>,
+        itctx: ImplTraitContext,
     ) -> hir::TypeBinding<'hir> {
         debug!("lower_assoc_ty_constraint(constraint={:?}, itctx={:?})", constraint, itctx);
-
         // lower generic arguments of identifier in constraint
         let gen_args = if let Some(ref gen_args) = constraint.gen_args {
             let gen_args_ctor = match gen_args {
                 GenericArgs::AngleBracketed(ref data) => {
-                    self.lower_angle_bracketed_parameter_data(
-                        data,
-                        ParamMode::Explicit,
-                        itctx.reborrow(),
-                    )
-                    .0
+                    self.lower_angle_bracketed_parameter_data(data, ParamMode::Explicit, itctx).0
                 }
                 GenericArgs::Parenthesized(ref data) => {
-                    let mut err = self.sess.struct_span_err(
-                        gen_args.span(),
-                        "parenthesized generic arguments cannot be used in associated type constraints"
-                    );
-                    // FIXME: try to write a suggestion here
-                    err.emit();
+                    self.assoc_ty_contraint_param_error_emit(data);
                     self.lower_angle_bracketed_parameter_data(
                         &data.as_angle_bracketed_args(),
                         ParamMode::Explicit,
-                        itctx.reborrow(),
+                        itctx,
                     )
                     .0
                 }
@@ -942,7 +887,6 @@ fn lower_assoc_ty_constraint(
                 hir::TypeBindingKind::Equality { term }
             }
             AssocConstraintKind::Bound { ref bounds } => {
-                let mut parent_def_id = self.current_hir_id_owner;
                 // Piggy-back on the `impl Trait` context to figure out the correct behavior.
                 let (desugar_to_impl_trait, itctx) = match itctx {
                     // We are in the return position:
@@ -962,10 +906,7 @@ fn lower_assoc_ty_constraint(
                     // so desugar to
                     //
                     //     fn foo(x: dyn Iterator<Item = impl Debug>)
-                    ImplTraitContext::Universal(_, _, parent) if self.is_in_dyn_type => {
-                        parent_def_id = parent;
-                        (true, itctx)
-                    }
+                    ImplTraitContext::Universal if self.is_in_dyn_type => (true, itctx),
 
                     // In `type Foo = dyn Iterator<Item: Debug>` we desugar to
                     // `type Foo = dyn Iterator<Item = impl Debug>` but we have to override the
@@ -991,6 +932,7 @@ fn lower_assoc_ty_constraint(
                     // Desugar `AssocTy: Bounds` into `AssocTy = impl Bounds`. We do this by
                     // constructing the HIR for `impl bounds...` and then lowering that.
 
+                    let parent_def_id = self.current_hir_id_owner;
                     let impl_trait_node_id = self.resolver.next_node_id();
                     self.resolver.create_def(
                         parent_def_id,
@@ -1033,10 +975,46 @@ fn lower_assoc_ty_constraint(
         }
     }
 
+    fn assoc_ty_contraint_param_error_emit(&self, data: &ParenthesizedArgs) -> () {
+        let mut err = self.sess.struct_span_err(
+            data.span,
+            "parenthesized generic arguments cannot be used in associated type constraints",
+        );
+        // Suggest removing empty parentheses: "Trait()" -> "Trait"
+        if data.inputs.is_empty() {
+            let parentheses_span =
+                data.inputs_span.shrink_to_lo().to(data.inputs_span.shrink_to_hi());
+            err.multipart_suggestion(
+                "remove these parentheses",
+                vec![(parentheses_span, String::new())],
+                Applicability::MaybeIncorrect,
+            );
+        }
+        // Suggest replacing parentheses with angle brackets `Trait(params...)` to `Trait<params...>`
+        else {
+            // Start of parameters to the 1st argument
+            let open_param = data.inputs_span.shrink_to_lo().to(data
+                .inputs
+                .first()
+                .unwrap()
+                .span
+                .shrink_to_lo());
+            // End of last argument to end of parameters
+            let close_param =
+                data.inputs.last().unwrap().span.shrink_to_hi().to(data.inputs_span.shrink_to_hi());
+            err.multipart_suggestion(
+                &format!("use angle brackets instead",),
+                vec![(open_param, String::from("<")), (close_param, String::from(">"))],
+                Applicability::MaybeIncorrect,
+            );
+        }
+        err.emit();
+    }
+
     fn lower_generic_arg(
         &mut self,
         arg: &ast::GenericArg,
-        itctx: ImplTraitContext<'_, 'hir>,
+        itctx: ImplTraitContext,
     ) -> hir::GenericArg<'hir> {
         match arg {
             ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(&lt)),
@@ -1103,7 +1081,7 @@ fn lower_generic_arg(
         }
     }
 
-    fn lower_ty(&mut self, t: &Ty, itctx: ImplTraitContext<'_, 'hir>) -> &'hir hir::Ty<'hir> {
+    fn lower_ty(&mut self, t: &Ty, itctx: ImplTraitContext) -> &'hir hir::Ty<'hir> {
         self.arena.alloc(self.lower_ty_direct(t, itctx))
     }
 
@@ -1113,7 +1091,7 @@ fn lower_path_ty(
         qself: &Option<QSelf>,
         path: &Path,
         param_mode: ParamMode,
-        itctx: ImplTraitContext<'_, 'hir>,
+        itctx: ImplTraitContext,
     ) -> hir::Ty<'hir> {
         let id = self.lower_node_id(t.id);
         let qpath = self.lower_qpath(t.id, qself, path, param_mode, itctx);
@@ -1128,7 +1106,7 @@ fn ty_tup(&mut self, span: Span, tys: &'hir [hir::Ty<'hir>]) -> hir::Ty<'hir> {
         self.ty(span, hir::TyKind::Tup(tys))
     }
 
-    fn lower_ty_direct(&mut self, t: &Ty, mut itctx: ImplTraitContext<'_, 'hir>) -> hir::Ty<'hir> {
+    fn lower_ty_direct(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir> {
         let kind = match t.kind {
             TyKind::Infer => hir::TyKind::Infer,
             TyKind::Err => hir::TyKind::Err,
@@ -1160,11 +1138,9 @@ fn lower_ty_direct(&mut self, t: &Ty, mut itctx: ImplTraitContext<'_, 'hir>) ->
                 }))
             }),
             TyKind::Never => hir::TyKind::Never,
-            TyKind::Tup(ref tys) => {
-                hir::TyKind::Tup(self.arena.alloc_from_iter(
-                    tys.iter().map(|ty| self.lower_ty_direct(ty, itctx.reborrow())),
-                ))
-            }
+            TyKind::Tup(ref tys) => hir::TyKind::Tup(
+                self.arena.alloc_from_iter(tys.iter().map(|ty| self.lower_ty_direct(ty, itctx))),
+            ),
             TyKind::Paren(ref ty) => {
                 return self.lower_ty_direct(ty, itctx);
             }
@@ -1198,7 +1174,7 @@ fn lower_ty_direct(&mut self, t: &Ty, mut itctx: ImplTraitContext<'_, 'hir>) ->
                                 GenericBound::Trait(
                                     ref ty,
                                     TraitBoundModifier::None | TraitBoundModifier::MaybeConst,
-                                ) => Some(this.lower_poly_trait_ref(ty, itctx.reborrow())),
+                                ) => Some(this.lower_poly_trait_ref(ty, itctx)),
                                 // `~const ?Bound` will cause an error during AST validation
                                 // anyways, so treat it like `?Bound` as compilation proceeds.
                                 GenericBound::Trait(
@@ -1235,32 +1211,24 @@ fn lower_ty_direct(&mut self, t: &Ty, mut itctx: ImplTraitContext<'_, 'hir>) ->
                             |this| this.lower_param_bounds(bounds, nested_itctx),
                         )
                     }
-                    ImplTraitContext::Universal(
-                        in_band_ty_params,
-                        in_band_ty_bounds,
-                        parent_def_id,
-                    ) => {
+                    ImplTraitContext::Universal => {
                         // Add a definition for the in-band `Param`.
                         let def_id = self.resolver.local_def_id(def_node_id);
 
-                        let hir_bounds = self.lower_param_bounds(
-                            bounds,
-                            ImplTraitContext::Universal(
-                                in_band_ty_params,
-                                in_band_ty_bounds,
-                                parent_def_id,
-                            ),
-                        );
+                        let hir_bounds =
+                            self.lower_param_bounds(bounds, ImplTraitContext::Universal);
                         // Set the name to `impl Bound1 + Bound2`.
                         let ident = Ident::from_str_and_span(&pprust::ty_to_string(t), span);
-                        in_band_ty_params.push(hir::GenericParam {
+                        let param = hir::GenericParam {
                             hir_id: self.lower_node_id(def_node_id),
                             name: ParamName::Plain(self.lower_ident(ident)),
                             pure_wrt_drop: false,
                             span: self.lower_span(span),
                             kind: hir::GenericParamKind::Type { default: None, synthetic: true },
                             colon_span: None,
-                        });
+                        };
+                        self.impl_trait_defs.push(param);
+
                         if let Some(preds) = self.lower_generic_bound_predicate(
                             ident,
                             def_node_id,
@@ -1268,7 +1236,7 @@ fn lower_ty_direct(&mut self, t: &Ty, mut itctx: ImplTraitContext<'_, 'hir>) ->
                             hir_bounds,
                             hir::PredicateOrigin::ImplTrait,
                         ) {
-                            in_band_ty_bounds.push(preds)
+                            self.impl_trait_bounds.push(preds)
                         }
 
                         hir::TyKind::Path(hir::QPath::Resolved(
@@ -1439,26 +1407,14 @@ fn lower_fn_params_to_names(&mut self, decl: &FnDecl) -> &'hir [Ident] {
     // `make_ret_async`: if `Some`, converts `-> T` into `-> impl Future<Output = T>` in the
     //      return type. This is used for `async fn` declarations. The `NodeId` is the ID of the
     //      return type `impl Trait` item.
+    #[tracing::instrument(level = "debug", skip(self))]
     fn lower_fn_decl(
         &mut self,
         decl: &FnDecl,
-        mut in_band_ty_params: Option<(
-            NodeId,
-            &mut Vec<hir::GenericParam<'hir>>,
-            &mut Vec<hir::WherePredicate<'hir>>,
-        )>,
+        fn_node_id: Option<NodeId>,
         kind: FnDeclKind,
         make_ret_async: Option<NodeId>,
     ) -> &'hir hir::FnDecl<'hir> {
-        debug!(
-            "lower_fn_decl(\
-            fn_decl: {:?}, \
-            in_band_ty_params: {:?}, \
-            kind: {:?}, \
-            make_ret_async: {:?})",
-            decl, in_band_ty_params, kind, make_ret_async,
-        );
-
         let c_variadic = decl.c_variadic();
 
         // Skip the `...` (`CVarArgs`) trailing arguments from the AST,
@@ -1469,11 +1425,8 @@ fn lower_fn_decl(
             inputs = &inputs[..inputs.len() - 1];
         }
         let inputs = self.arena.alloc_from_iter(inputs.iter().map(|param| {
-            if let Some((_, ibty, ibpb)) = &mut in_band_ty_params {
-                self.lower_ty_direct(
-                    &param.ty,
-                    ImplTraitContext::Universal(ibty, ibpb, self.current_hir_id_owner),
-                )
+            if fn_node_id.is_some() {
+                self.lower_ty_direct(&param.ty, ImplTraitContext::Universal)
             } else {
                 self.lower_ty_direct(
                     &param.ty,
@@ -1494,15 +1447,15 @@ fn lower_fn_decl(
         let output = if let Some(ret_id) = make_ret_async {
             self.lower_async_fn_ret_ty(
                 &decl.output,
-                in_band_ty_params.expect("`make_ret_async` but no `fn_def_id`").0,
+                fn_node_id.expect("`make_ret_async` but no `fn_def_id`"),
                 ret_id,
             )
         } else {
             match decl.output {
                 FnRetTy::Ty(ref ty) => {
-                    let context = match in_band_ty_params {
-                        Some((node_id, _, _)) if kind.impl_trait_return_allowed() => {
-                            let fn_def_id = self.resolver.local_def_id(node_id);
+                    let context = match fn_node_id {
+                        Some(fn_node_id) if kind.impl_trait_return_allowed() => {
+                            let fn_def_id = self.resolver.local_def_id(fn_node_id);
                             ImplTraitContext::ReturnPositionOpaqueTy {
                                 origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
                             }
@@ -1645,10 +1598,9 @@ fn lower_async_fn_ret_ty(
                     (hir::ParamName::Plain(ident), LifetimeRes::Param { param, binder: fn_node_id })
                 }
                 // Input lifetime like `'1`:
-                LifetimeRes::Fresh { param, .. } => (
-                    hir::ParamName::Fresh(outer_def_id),
-                    LifetimeRes::Fresh { param, binder: fn_node_id },
-                ),
+                LifetimeRes::Fresh { param, .. } => {
+                    (hir::ParamName::Fresh, LifetimeRes::Fresh { param, binder: fn_node_id })
+                }
                 LifetimeRes::Static | LifetimeRes::Error => continue,
                 res => {
                     panic!("Unexpected lifetime resolution {:?} for {:?} at {:?}", res, ident, span)
@@ -1788,7 +1740,7 @@ fn lower_async_fn_output_type_to_future_bound(
     fn lower_param_bound(
         &mut self,
         tpb: &GenericBound,
-        itctx: ImplTraitContext<'_, 'hir>,
+        itctx: ImplTraitContext,
     ) -> hir::GenericBound<'hir> {
         match tpb {
             GenericBound::Trait(p, modifier) => hir::GenericBound::Trait(
@@ -1818,7 +1770,7 @@ fn new_named_lifetime_with_res(
     ) -> hir::Lifetime {
         debug!(?self.captured_lifetimes);
         let name = match res {
-            LifetimeRes::Param { param, binder } => {
+            LifetimeRes::Param { mut param, binder } => {
                 debug_assert_ne!(ident.name, kw::UnderscoreLifetime);
                 let p_name = ParamName::Plain(ident);
                 if let Some(LifetimeCaptureContext { parent_def_id, captures, binders_to_ignore }) =
@@ -1826,10 +1778,10 @@ fn new_named_lifetime_with_res(
                     && !binders_to_ignore.contains(&binder)
                 {
                     match captures.entry(param) {
-                        Entry::Occupied(_) => {}
+                        Entry::Occupied(o) => param = self.resolver.local_def_id(o.get().1),
                         Entry::Vacant(v) => {
                             let p_id = self.resolver.next_node_id();
-                            self.resolver.create_def(
+                            let p_def_id = self.resolver.create_def(
                                 *parent_def_id,
                                 p_id,
                                 DefPathData::LifetimeNs(p_name.ident().name),
@@ -1838,10 +1790,11 @@ fn new_named_lifetime_with_res(
                             );
 
                             v.insert((span, p_id, p_name, res));
+                            param = p_def_id;
                         }
                     }
                 }
-                hir::LifetimeName::Param(p_name)
+                hir::LifetimeName::Param(param, p_name)
             }
             LifetimeRes::Fresh { mut param, binder } => {
                 debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
@@ -1861,21 +1814,14 @@ fn new_named_lifetime_with_res(
                                 span.with_parent(None),
                             );
 
-                            let p_name = ParamName::Fresh(param);
-                            v.insert((span, p_id, p_name, res));
+                            v.insert((span, p_id, ParamName::Fresh, res));
                             param = p_def_id;
                         }
                     }
                 }
-                let p_name = ParamName::Fresh(param);
-                hir::LifetimeName::Param(p_name)
+                hir::LifetimeName::Param(param, ParamName::Fresh)
             }
             LifetimeRes::Anonymous { binder, elided } => {
-                let l_name = if elided {
-                    hir::LifetimeName::Implicit
-                } else {
-                    hir::LifetimeName::Underscore
-                };
                 if let Some(LifetimeCaptureContext { parent_def_id, captures, binders_to_ignore }) =
                     &mut self.captured_lifetimes
                     && !binders_to_ignore.contains(&binder)
@@ -1888,11 +1834,12 @@ fn new_named_lifetime_with_res(
                         ExpnId::root(),
                         span.with_parent(None),
                     );
-                    let p_name = ParamName::Fresh(p_def_id);
-                    captures.insert(p_def_id, (span, p_id, p_name, res));
-                    hir::LifetimeName::Param(p_name)
+                    captures.insert(p_def_id, (span, p_id, ParamName::Fresh, res));
+                    hir::LifetimeName::Param(p_def_id, ParamName::Fresh)
+                } else if elided {
+                    hir::LifetimeName::Implicit
                 } else {
-                    l_name
+                    hir::LifetimeName::Underscore
                 }
             }
             LifetimeRes::Static => hir::LifetimeName::Static,
@@ -1900,6 +1847,7 @@ fn new_named_lifetime_with_res(
             res => panic!("Unexpected lifetime resolution {:?} for {:?} at {:?}", res, ident, span),
         };
         debug!(?self.captured_lifetimes);
+        debug!(?name);
         hir::Lifetime { hir_id: self.lower_node_id(id), span: self.lower_span(span), name }
     }
 
@@ -1917,14 +1865,15 @@ fn lower_generic_params(&mut self, params: &[GenericParam]) -> &'hir [hir::Gener
     fn lower_generic_param(&mut self, param: &GenericParam) -> hir::GenericParam<'hir> {
         let (name, kind) = match param.kind {
             GenericParamKind::Lifetime => {
-                let param_name = if param.ident.name == kw::StaticLifetime
-                    || param.ident.name == kw::UnderscoreLifetime
-                {
-                    ParamName::Error
-                } else {
-                    let ident = self.lower_ident(param.ident);
-                    ParamName::Plain(ident)
-                };
+                // AST resolution emitted an error on those parameters, so we lower them using
+                // `ParamName::Error`.
+                let param_name =
+                    if let Some(LifetimeRes::Error) = self.resolver.get_lifetime_res(param.id) {
+                        ParamName::Error
+                    } else {
+                        let ident = self.lower_ident(param.ident);
+                        ParamName::Plain(ident)
+                    };
                 let kind =
                     hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit };
 
@@ -1949,10 +1898,6 @@ fn lower_generic_param(&mut self, param: &GenericParam) -> hir::GenericParam<'hi
                 )
             }
         };
-        let name = match name {
-            hir::ParamName::Plain(ident) => hir::ParamName::Plain(self.lower_ident(ident)),
-            name => name,
-        };
 
         let hir_id = self.lower_node_id(param.id);
         self.lower_attrs(hir_id, &param.attrs);
@@ -1966,11 +1911,7 @@ fn lower_generic_param(&mut self, param: &GenericParam) -> hir::GenericParam<'hi
         }
     }
 
-    fn lower_trait_ref(
-        &mut self,
-        p: &TraitRef,
-        itctx: ImplTraitContext<'_, 'hir>,
-    ) -> hir::TraitRef<'hir> {
+    fn lower_trait_ref(&mut self, p: &TraitRef, itctx: ImplTraitContext) -> hir::TraitRef<'hir> {
         let path = match self.lower_qpath(p.ref_id, &None, &p.path, ParamMode::Explicit, itctx) {
             hir::QPath::Resolved(None, path) => path,
             qpath => panic!("lower_trait_ref: unexpected QPath `{:?}`", qpath),
@@ -1982,25 +1923,25 @@ fn lower_trait_ref(
     fn lower_poly_trait_ref(
         &mut self,
         p: &PolyTraitRef,
-        mut itctx: ImplTraitContext<'_, 'hir>,
+        itctx: ImplTraitContext,
     ) -> hir::PolyTraitRef<'hir> {
         let bound_generic_params = self.lower_generic_params(&p.bound_generic_params);
 
         let trait_ref = self.with_lifetime_binder(p.trait_ref.ref_id, |this| {
-            this.lower_trait_ref(&p.trait_ref, itctx.reborrow())
+            this.lower_trait_ref(&p.trait_ref, itctx)
         });
 
         hir::PolyTraitRef { bound_generic_params, trait_ref, span: self.lower_span(p.span) }
     }
 
-    fn lower_mt(&mut self, mt: &MutTy, itctx: ImplTraitContext<'_, 'hir>) -> hir::MutTy<'hir> {
+    fn lower_mt(&mut self, mt: &MutTy, itctx: ImplTraitContext) -> hir::MutTy<'hir> {
         hir::MutTy { ty: self.lower_ty(&mt.ty, itctx), mutbl: mt.mutbl }
     }
 
     fn lower_param_bounds(
         &mut self,
         bounds: &[GenericBound],
-        itctx: ImplTraitContext<'_, 'hir>,
+        itctx: ImplTraitContext,
     ) -> hir::GenericBounds<'hir> {
         self.arena.alloc_from_iter(self.lower_param_bounds_mut(bounds, itctx))
     }
@@ -2008,9 +1949,9 @@ fn lower_param_bounds(
     fn lower_param_bounds_mut<'s>(
         &'s mut self,
         bounds: &'s [GenericBound],
-        mut itctx: ImplTraitContext<'s, 'hir>,
+        itctx: ImplTraitContext,
     ) -> impl Iterator<Item = hir::GenericBound<'hir>> + Captures<'s> + Captures<'a> {
-        bounds.iter().map(move |bound| self.lower_param_bound(bound, itctx.reborrow()))
+        bounds.iter().map(move |bound| self.lower_param_bound(bound, itctx))
     }
 
     /// Lowers a block directly to an expression, presuming that it
index 7fc8aac5116f91f1c03909cfd49f57d34c37ef50..d56974b773de6f4268ebbb622a445c32602552f6 100644 (file)
@@ -21,11 +21,11 @@ pub(crate) fn lower_qpath(
         qself: &Option<QSelf>,
         p: &Path,
         param_mode: ParamMode,
-        mut itctx: ImplTraitContext<'_, 'hir>,
+        itctx: ImplTraitContext,
     ) -> hir::QPath<'hir> {
         debug!("lower_qpath(id: {:?}, qself: {:?}, p: {:?})", id, qself, p);
         let qself_position = qself.as_ref().map(|q| q.position);
-        let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx.reborrow()));
+        let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx));
 
         let partial_res =
             self.resolver.get_partial_res(id).unwrap_or_else(|| PartialRes::new(Res::Err));
@@ -70,7 +70,7 @@ pub(crate) fn lower_qpath(
                         segment,
                         param_mode,
                         parenthesized_generic_args,
-                        itctx.reborrow(),
+                        itctx,
                     )
                 },
             )),
@@ -116,7 +116,7 @@ pub(crate) fn lower_qpath(
                 segment,
                 param_mode,
                 ParenthesizedGenericArgs::Err,
-                itctx.reborrow(),
+                itctx,
             ));
             let qpath = hir::QPath::TypeRelative(ty, hir_segment);
 
@@ -180,7 +180,7 @@ pub(crate) fn lower_path_segment(
         segment: &PathSegment,
         param_mode: ParamMode,
         parenthesized_generic_args: ParenthesizedGenericArgs,
-        itctx: ImplTraitContext<'_, 'hir>,
+        itctx: ImplTraitContext,
     ) -> hir::PathSegment<'hir> {
         debug!("path_span: {:?}, lower_path_segment(segment: {:?})", path_span, segment,);
         let (mut generic_args, infer_args) = if let Some(ref generic_args) = segment.args {
@@ -318,7 +318,7 @@ pub(crate) fn lower_angle_bracketed_parameter_data(
         &mut self,
         data: &AngleBracketedArgs,
         param_mode: ParamMode,
-        mut itctx: ImplTraitContext<'_, 'hir>,
+        itctx: ImplTraitContext,
     ) -> (GenericArgsCtor<'hir>, bool) {
         let has_non_lt_args = data.args.iter().any(|arg| match arg {
             AngleBracketedArg::Arg(ast::GenericArg::Lifetime(_))
@@ -329,14 +329,12 @@ pub(crate) fn lower_angle_bracketed_parameter_data(
             .args
             .iter()
             .filter_map(|arg| match arg {
-                AngleBracketedArg::Arg(arg) => Some(self.lower_generic_arg(arg, itctx.reborrow())),
+                AngleBracketedArg::Arg(arg) => Some(self.lower_generic_arg(arg, itctx)),
                 AngleBracketedArg::Constraint(_) => None,
             })
             .collect();
         let bindings = self.arena.alloc_from_iter(data.args.iter().filter_map(|arg| match arg {
-            AngleBracketedArg::Constraint(c) => {
-                Some(self.lower_assoc_ty_constraint(c, itctx.reborrow()))
-            }
+            AngleBracketedArg::Constraint(c) => Some(self.lower_assoc_ty_constraint(c, itctx)),
             AngleBracketedArg::Arg(_) => None,
         }));
         let ctor = GenericArgsCtor { args, bindings, parenthesized: false, span: data.span };
index 0520c9ac60cf019ed29d4cb9894234d344771abb..21db7d0eebcc06fe0783b17bc94b71cf78d8964a 100644 (file)
@@ -420,7 +420,15 @@ fn check_decl_attrs(&self, fn_decl: &FnDecl) {
             .iter()
             .flat_map(|i| i.attrs.as_ref())
             .filter(|attr| {
-                let arr = [sym::allow, sym::cfg, sym::cfg_attr, sym::deny, sym::forbid, sym::warn];
+                let arr = [
+                    sym::allow,
+                    sym::cfg,
+                    sym::cfg_attr,
+                    sym::deny,
+                    sym::expect,
+                    sym::forbid,
+                    sym::warn,
+                ];
                 !arr.contains(&attr.name_or_empty()) && rustc_attr::is_builtin_attr(attr)
             })
             .for_each(|attr| {
@@ -435,7 +443,7 @@ fn check_decl_attrs(&self, fn_decl: &FnDecl) {
                 } else {
                     self.err_handler().span_err(
                         attr.span,
-                        "allow, cfg, cfg_attr, deny, \
+                        "allow, cfg, cfg_attr, deny, expect, \
                 forbid, and warn are the only allowed built-in attributes in function parameters",
                     );
                 }
index 7357ddf2134e48581a580afbc192b3f2542b3d90..b80a553b4185ce7f3b551b66c299470c15e83146 100644 (file)
@@ -590,28 +590,14 @@ fn print_mac_common(
                     self.nbsp();
                 }
                 self.word("{");
-                let empty = tts.is_empty();
-                if !empty {
+                if !tts.is_empty() {
                     self.space();
                 }
                 self.ibox(0);
                 self.print_tts(tts, convert_dollar_crate);
                 self.end();
-                self.bclose(span, empty);
-            }
-            Some(Delimiter::Invisible) => {
-                self.word("/*«*/");
                 let empty = tts.is_empty();
-                if !empty {
-                    self.space();
-                }
-                self.ibox(0);
-                self.print_tts(tts, convert_dollar_crate);
-                self.end();
-                if !empty {
-                    self.space();
-                }
-                self.word("/*»*/");
+                self.bclose(span, empty);
             }
             Some(delim) => {
                 let token_str = self.token_kind_to_string(&token::OpenDelim(delim));
@@ -786,8 +772,9 @@ fn token_kind_to_string_ext(
             token::CloseDelim(Delimiter::Bracket) => "]".into(),
             token::OpenDelim(Delimiter::Brace) => "{".into(),
             token::CloseDelim(Delimiter::Brace) => "}".into(),
-            token::OpenDelim(Delimiter::Invisible) => "/*«*/".into(),
-            token::CloseDelim(Delimiter::Invisible) => "/*»*/".into(),
+            token::OpenDelim(Delimiter::Invisible) | token::CloseDelim(Delimiter::Invisible) => {
+                "".into()
+            }
             token::Pound => "#".into(),
             token::Dollar => "$".into(),
             token::Question => "?".into(),
index 4d2a16aa609846a1e1931b062add52cb2a6ee032..fcb6ae438fed9768726737a68858817e8593d9de 100644 (file)
@@ -567,15 +567,17 @@ fn match_adt_and_segment<'hir>(
         let lifetime =
             self.try_match_adt_and_generic_args(substs, needle_fr, args, search_stack)?;
         match lifetime.name {
-            hir::LifetimeName::Param(_)
+            hir::LifetimeName::Param(_, hir::ParamName::Plain(_) | hir::ParamName::Error)
             | hir::LifetimeName::Error
-            | hir::LifetimeName::Static
-            | hir::LifetimeName::Underscore => {
+            | hir::LifetimeName::Static => {
                 let lifetime_span = lifetime.span;
                 Some(RegionNameHighlight::MatchedAdtAndSegment(lifetime_span))
             }
 
-            hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Implicit => {
+            hir::LifetimeName::Param(_, hir::ParamName::Fresh)
+            | hir::LifetimeName::ImplicitObjectLifetimeDefault
+            | hir::LifetimeName::Implicit
+            | hir::LifetimeName::Underscore => {
                 // In this case, the user left off the lifetime; so
                 // they wrote something like:
                 //
index 4a2b2942008b874266d3c70d616a22b4b5244dc5..e5aed1b60ddc1fe56a3e9b451346315ea1077246 100644 (file)
@@ -2147,24 +2147,62 @@ fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: L
                         }
                     }
 
-                    CastKind::Misc => {
+                    CastKind::PointerExposeAddress => {
                         let ty_from = op.ty(body, tcx);
                         let cast_ty_from = CastTy::from_ty(ty_from);
                         let cast_ty_to = CastTy::from_ty(*ty);
                         match (cast_ty_from, cast_ty_to) {
-                            (None, _)
-                            | (_, None | Some(CastTy::FnPtr))
-                            | (Some(CastTy::Float), Some(CastTy::Ptr(_)))
-                            | (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Float)) => {
-                                span_mirbug!(self, rvalue, "Invalid cast {:?} -> {:?}", ty_from, ty,)
+                            (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Int(_))) => (),
+                            _ => {
+                                span_mirbug!(
+                                    self,
+                                    rvalue,
+                                    "Invalid PointerExposeAddress cast {:?} -> {:?}",
+                                    ty_from,
+                                    ty
+                                )
                             }
+                        }
+                    }
+
+                    CastKind::PointerFromExposedAddress => {
+                        let ty_from = op.ty(body, tcx);
+                        let cast_ty_from = CastTy::from_ty(ty_from);
+                        let cast_ty_to = CastTy::from_ty(*ty);
+                        match (cast_ty_from, cast_ty_to) {
+                            (Some(CastTy::Int(_)), Some(CastTy::Ptr(_))) => (),
+                            _ => {
+                                span_mirbug!(
+                                    self,
+                                    rvalue,
+                                    "Invalid PointerFromExposedAddress cast {:?} -> {:?}",
+                                    ty_from,
+                                    ty
+                                )
+                            }
+                        }
+                    }
+
+                    CastKind::Misc => {
+                        let ty_from = op.ty(body, tcx);
+                        let cast_ty_from = CastTy::from_ty(ty_from);
+                        let cast_ty_to = CastTy::from_ty(*ty);
+                        // Misc casts are either between floats and ints, or one ptr type to another.
+                        match (cast_ty_from, cast_ty_to) {
                             (
-                                Some(CastTy::Int(_)),
-                                Some(CastTy::Int(_) | CastTy::Float | CastTy::Ptr(_)),
+                                Some(CastTy::Int(_) | CastTy::Float),
+                                Some(CastTy::Int(_) | CastTy::Float),
                             )
-                            | (Some(CastTy::Float), Some(CastTy::Int(_) | CastTy::Float))
-                            | (Some(CastTy::Ptr(_)), Some(CastTy::Int(_) | CastTy::Ptr(_)))
-                            | (Some(CastTy::FnPtr), Some(CastTy::Int(_) | CastTy::Ptr(_))) => (),
+                            | (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Ptr(_))) => (),
+                            _ => {
+                                span_mirbug!(
+                                    self,
+                                    rvalue,
+                                    "Invalid Misc cast {:?} -> {:?}",
+                                    ty_from,
+                                    ty,
+                                )
+                            }
                         }
                     }
                 }
index 7b63ec516b8c44c4561190cf9be2558bde94bb63..c2c093f9f2fc74e685b1589063b809c772f09702 100644 (file)
@@ -830,11 +830,11 @@ fn for_each_late_bound_region_defined_on<'tcx>(
     fn_def_id: DefId,
     mut f: impl FnMut(ty::Region<'tcx>),
 ) {
-    if let Some((owner, late_bounds)) = tcx.is_late_bound_map(fn_def_id.expect_local()) {
+    if let Some(late_bounds) = tcx.is_late_bound_map(fn_def_id.expect_local()) {
         for &region_def_id in late_bounds.iter() {
             let name = tcx.item_name(region_def_id.to_def_id());
             let liberated_region = tcx.mk_region(ty::ReFree(ty::FreeRegion {
-                scope: owner.to_def_id(),
+                scope: fn_def_id,
                 bound_region: ty::BoundRegionKind::BrNamed(region_def_id.to_def_id(), name),
             }));
             f(liberated_region);
index a984980dea9bf79fbb8f2bb91286d0fbf315aa03..0c75187193c38857904b1e0f316b9408e82469c1 100644 (file)
@@ -1,11 +1,13 @@
+mod context;
+
 use crate::edition_panic::use_panic_2021;
 use rustc_ast::ptr::P;
 use rustc_ast::token;
 use rustc_ast::tokenstream::{DelimSpan, TokenStream};
-use rustc_ast::{self as ast, *};
+use rustc_ast::{Expr, ExprKind, MacArgs, MacCall, MacDelimiter, Path, PathSegment, UnOp};
 use rustc_ast_pretty::pprust;
 use rustc_errors::{Applicability, PResult};
-use rustc_expand::base::*;
+use rustc_expand::base::{DummyResult, ExtCtxt, MacEager, MacResult};
 use rustc_parse::parser::Parser;
 use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
@@ -25,13 +27,13 @@ pub fn expand_assert<'cx>(
 
     // `core::panic` and `std::panic` are different macros, so we use call-site
     // context to pick up whichever is currently in scope.
-    let sp = cx.with_call_site_ctxt(span);
+    let call_site_span = cx.with_call_site_ctxt(span);
 
-    let panic_call = if let Some(tokens) = custom_message {
-        let path = if use_panic_2021(span) {
+    let panic_path = || {
+        if use_panic_2021(span) {
             // On edition 2021, we always call `$crate::panic::panic_2021!()`.
             Path {
-                span: sp,
+                span: call_site_span,
                 segments: cx
                     .std_path(&[sym::panic, sym::panic_2021])
                     .into_iter()
@@ -42,27 +44,40 @@ pub fn expand_assert<'cx>(
         } else {
             // Before edition 2021, we call `panic!()` unqualified,
             // such that it calls either `std::panic!()` or `core::panic!()`.
-            Path::from_ident(Ident::new(sym::panic, sp))
-        };
-        // Pass the custom message to panic!().
-        cx.expr(
-            sp,
+            Path::from_ident(Ident::new(sym::panic, call_site_span))
+        }
+    };
+
+    // Simply uses the user provided message instead of generating custom outputs
+    let expr = if let Some(tokens) = custom_message {
+        let then = cx.expr(
+            call_site_span,
             ExprKind::MacCall(MacCall {
-                path,
+                path: panic_path(),
                 args: P(MacArgs::Delimited(
-                    DelimSpan::from_single(sp),
+                    DelimSpan::from_single(call_site_span),
                     MacDelimiter::Parenthesis,
                     tokens,
                 )),
                 prior_type_ascription: None,
             }),
-        )
-    } else {
+        );
+        expr_if_not(cx, call_site_span, cond_expr, then, None)
+    }
+    // If `generic_assert` is enabled, generates rich captured outputs
+    //
+    // FIXME(c410-f3r) See https://github.com/rust-lang/rust/issues/96949
+    else if let Some(features) = cx.ecfg.features && features.generic_assert {
+        context::Context::new(cx, call_site_span).build(cond_expr, panic_path())
+    }
+    // If `generic_assert` is not enabled, only outputs a literal "assertion failed: ..."
+    // string
+    else {
         // Pass our own message directly to $crate::panicking::panic(),
         // because it might contain `{` and `}` that should always be
         // passed literally.
-        cx.expr_call_global(
-            sp,
+        let then = cx.expr_call_global(
+            call_site_span,
             cx.std_path(&[sym::panicking, sym::panic]),
             vec![cx.expr_str(
                 DUMMY_SP,
@@ -71,18 +86,29 @@ pub fn expand_assert<'cx>(
                     pprust::expr_to_string(&cond_expr).escape_debug()
                 )),
             )],
-        )
+        );
+        expr_if_not(cx, call_site_span, cond_expr, then, None)
     };
-    let if_expr =
-        cx.expr_if(sp, cx.expr(sp, ExprKind::Unary(UnOp::Not, cond_expr)), panic_call, None);
-    MacEager::expr(if_expr)
+
+    MacEager::expr(expr)
 }
 
 struct Assert {
-    cond_expr: P<ast::Expr>,
+    cond_expr: P<Expr>,
     custom_message: Option<TokenStream>,
 }
 
+// if !{ ... } { ... } else { ... }
+fn expr_if_not(
+    cx: &ExtCtxt<'_>,
+    span: Span,
+    cond: P<Expr>,
+    then: P<Expr>,
+    els: Option<P<Expr>>,
+) -> P<Expr> {
+    cx.expr_if(span, cx.expr(span, ExprKind::Unary(UnOp::Not, cond)), then, els)
+}
+
 fn parse_assert<'a>(cx: &mut ExtCtxt<'a>, sp: Span, stream: TokenStream) -> PResult<'a, Assert> {
     let mut parser = cx.new_parser_from_tts(stream);
 
diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs
new file mode 100644 (file)
index 0000000..8d187a4
--- /dev/null
@@ -0,0 +1,44 @@
+use rustc_ast::{ptr::P, Expr, Path};
+use rustc_expand::base::ExtCtxt;
+use rustc_span::Span;
+
+pub(super) struct Context<'cx, 'a> {
+    cx: &'cx ExtCtxt<'a>,
+    span: Span,
+}
+
+impl<'cx, 'a> Context<'cx, 'a> {
+    pub(super) fn new(cx: &'cx ExtCtxt<'a>, span: Span) -> Self {
+        Self { cx, span }
+    }
+
+    /// Builds the whole `assert!` expression.
+    ///
+    /// {
+    ///    use ::core::asserting::{ ... };
+    ///
+    ///    let mut __capture0 = Capture::new();
+    ///    ...
+    ///    ...
+    ///    ...
+    ///
+    ///    if !{
+    ///       ...
+    ///       ...
+    ///       ...
+    ///    } {
+    ///        panic!(
+    ///            "Assertion failed: ... \n With expansion: ...",
+    ///            __capture0,
+    ///            ...
+    ///            ...
+    ///            ...
+    ///        );
+    ///    }
+    /// }
+    pub(super) fn build(self, _cond_expr: P<Expr>, _panic_path: Path) -> P<Expr> {
+        let Self { cx, span, .. } = self;
+        let stmts = Vec::new();
+        cx.expr_block(cx.block(span, stmts))
+    }
+}
index 0c9e3c22bcf3c43a875b91559b2bcc44e45733bd..48b1470ced5a05716181d6394ee0bb82ef5a48da 100644 (file)
@@ -1,17 +1,18 @@
 //! This crate contains implementations of built-in macros and other code generating facilities
 //! injecting code into the crate before it is lowered to HIR.
 
+#![allow(rustc::potential_query_instability)]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(array_windows)]
 #![feature(box_patterns)]
 #![feature(decl_macro)]
 #![feature(is_sorted)]
-#![feature(nll)]
+#![feature(let_chains)]
 #![feature(let_else)]
+#![feature(nll)]
 #![feature(proc_macro_internals)]
 #![feature(proc_macro_quote)]
 #![recursion_limit = "256"]
-#![allow(rustc::potential_query_instability)]
 
 extern crate proc_macro;
 
index 3fe112d794b4413c67f311c3aff143057a591d18..07136e1b76a9f0895780db655019cc6326fce889 100644 (file)
@@ -607,7 +607,13 @@ fn codegen_stmt<'tcx>(
                     let operand = codegen_operand(fx, operand);
                     lval.write_cvalue(fx, operand.cast_pointer_to(to_layout));
                 }
-                Rvalue::Cast(CastKind::Misc, ref operand, to_ty) => {
+                Rvalue::Cast(
+                    CastKind::Misc
+                    | CastKind::PointerExposeAddress
+                    | CastKind::PointerFromExposedAddress,
+                    ref operand,
+                    to_ty,
+                ) => {
                     let operand = codegen_operand(fx, operand);
                     let from_ty = operand.layout().ty;
                     let to_ty = fx.monomorphize(to_ty);
index 93b10a07e449d1be6977cd61cae8fd1f24463086..fd8c4f78b2fc20fe98ed487de57b8c09025a99c4 100644 (file)
@@ -16,6 +16,7 @@ jobserver = "0.1.22"
 tempfile = "3.2"
 thorin-dwp = "0.2"
 pathdiff = "0.2.0"
+serde_json = "1.0.59"
 snap = "1"
 smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
 regex = "1.4"
index e4236876463fc9abd89b3ba2c14e360d8ea11539..a24e4347839c7ac1ff42f85950d2516cf92256fc 100644 (file)
@@ -14,7 +14,6 @@
 use rustc_middle::middle::dependency_format::Linkage;
 use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo, SymbolExportKind};
 use rustc_middle::ty::TyCtxt;
-use rustc_serialize::{json, Encoder};
 use rustc_session::config::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel, Strip};
 use rustc_session::Session;
 use rustc_span::symbol::Symbol;
@@ -1152,21 +1151,12 @@ fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[
         self.cmd.arg("-s");
 
         let mut arg = OsString::from("EXPORTED_FUNCTIONS=");
-        let mut encoded = String::new();
-
-        {
-            let mut encoder = json::Encoder::new(&mut encoded);
-            let res = encoder.emit_seq(symbols.len(), |encoder| {
-                for (i, sym) in symbols.iter().enumerate() {
-                    encoder.emit_seq_elt(i, |encoder| encoder.emit_str(&("_".to_owned() + sym)))?;
-                }
-                Ok(())
-            });
-            if let Err(e) = res {
-                self.sess.fatal(&format!("failed to encode exported symbols: {}", e));
-            }
-        }
+        let encoded = serde_json::to_string(
+            &symbols.iter().map(|sym| "_".to_owned() + sym).collect::<Vec<_>>(),
+        )
+        .unwrap();
         debug!("{}", encoded);
+
         arg.push(encoded);
 
         self.cmd.arg(arg);
index fd29c9e281b920dba741834c28a1703753631785..81c1897694ce61773aef5d0fc3344bf5aa825b6d 100644 (file)
@@ -181,6 +181,13 @@ pub fn codegen_rvalue_operand(
                 let cast = bx.cx().layout_of(self.monomorphize(mir_cast_ty));
 
                 let val = match *kind {
+                    mir::CastKind::PointerExposeAddress => {
+                        assert!(bx.cx().is_backend_immediate(cast));
+                        let llptr = operand.immediate();
+                        let llcast_ty = bx.cx().immediate_backend_type(cast);
+                        let lladdr = bx.ptrtoint(llptr, llcast_ty);
+                        OperandValue::Immediate(lladdr)
+                    }
                     mir::CastKind::Pointer(PointerCast::ReifyFnPointer) => {
                         match *operand.layout.ty.kind() {
                             ty::FnDef(def_id, substs) => {
@@ -262,7 +269,11 @@ pub fn codegen_rvalue_operand(
                     mir::CastKind::Pointer(
                         PointerCast::MutToConstPointer | PointerCast::ArrayToPointer,
                     )
-                    | mir::CastKind::Misc => {
+                    | mir::CastKind::Misc
+                    // Since int2ptr can have arbitrary integer types as input (so we have to do
+                    // sign extension and all that), it is currently best handled in the same code
+                    // path as the other integer-to-X casts.
+                    | mir::CastKind::PointerFromExposedAddress => {
                         assert!(bx.cx().is_backend_immediate(cast));
                         let ll_t_out = bx.cx().immediate_backend_type(cast);
                         if operand.layout.abi.is_uninhabited() {
@@ -362,9 +373,6 @@ pub fn codegen_rvalue_operand(
                             (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Ptr(_)) => {
                                 bx.pointercast(llval, ll_t_out)
                             }
-                            (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) => {
-                                bx.ptrtoint(llval, ll_t_out)
-                            }
                             (CastTy::Int(_), CastTy::Ptr(_)) => {
                                 let usize_llval = bx.intcast(llval, bx.cx().type_isize(), signed);
                                 bx.inttoptr(usize_llval, ll_t_out)
index be34a77bdba966e265ccec946bec6b464ef9ef64..73cc59ad1e674361a78c6d9d26af95b60e4c4043 100644 (file)
@@ -1,3 +1,4 @@
+use std::assert_matches::assert_matches;
 use std::convert::TryFrom;
 
 use rustc_apfloat::ieee::{Double, Single};
@@ -30,6 +31,18 @@ pub fn cast(
                 self.unsize_into(src, cast_ty, dest)?;
             }
 
+            PointerExposeAddress => {
+                let src = self.read_immediate(src)?;
+                let res = self.pointer_expose_address_cast(&src, cast_ty)?;
+                self.write_immediate(res, dest)?;
+            }
+
+            PointerFromExposedAddress => {
+                let src = self.read_immediate(src)?;
+                let res = self.pointer_from_exposed_address_cast(&src, cast_ty)?;
+                self.write_immediate(res, dest)?;
+            }
+
             Misc => {
                 let src = self.read_immediate(src)?;
                 let res = self.misc_cast(&src, cast_ty)?;
@@ -174,26 +187,44 @@ pub fn misc_cast(
 
         // # The remaining source values are scalar and "int-like".
         let scalar = src.to_scalar()?;
+        Ok(self.cast_from_int_like(scalar, src.layout, cast_ty)?.into())
+    }
 
-        // If we are casting from a pointer to something
-        // that is not a pointer, mark the pointer as exposed
-        if src.layout.ty.is_any_ptr() && !cast_ty.is_any_ptr() {
-            let ptr = self.scalar_to_ptr(scalar)?;
-
-            match ptr.into_pointer_or_addr() {
-                Ok(ptr) => {
-                    M::expose_ptr(self, ptr)?;
-                }
-                Err(_) => {
-                    // do nothing, exposing an invalid pointer
-                    // has no meaning
-                }
-            };
-        }
+    pub fn pointer_expose_address_cast(
+        &mut self,
+        src: &ImmTy<'tcx, M::PointerTag>,
+        cast_ty: Ty<'tcx>,
+    ) -> InterpResult<'tcx, Immediate<M::PointerTag>> {
+        assert_matches!(src.layout.ty.kind(), ty::RawPtr(_) | ty::FnPtr(_));
+        assert!(cast_ty.is_integral());
 
+        let scalar = src.to_scalar()?;
+        let ptr = self.scalar_to_ptr(scalar)?;
+        match ptr.into_pointer_or_addr() {
+            Ok(ptr) => M::expose_ptr(self, ptr)?,
+            Err(_) => {} // do nothing, exposing an invalid pointer has no meaning
+        };
         Ok(self.cast_from_int_like(scalar, src.layout, cast_ty)?.into())
     }
 
+    pub fn pointer_from_exposed_address_cast(
+        &mut self,
+        src: &ImmTy<'tcx, M::PointerTag>,
+        cast_ty: Ty<'tcx>,
+    ) -> InterpResult<'tcx, Immediate<M::PointerTag>> {
+        assert!(src.layout.ty.is_integral());
+        assert_matches!(cast_ty.kind(), ty::RawPtr(_));
+
+        // First cast to usize.
+        let scalar = src.to_scalar()?;
+        let addr = self.cast_from_int_like(scalar, src.layout, self.tcx.types.usize)?;
+        let addr = addr.to_machine_usize(self)?;
+
+        // Then turn address into pointer.
+        let ptr = M::ptr_from_addr_cast(&self, addr);
+        Ok(Scalar::from_maybe_pointer(ptr, self).into())
+    }
+
     pub fn cast_from_int_like(
         &self,
         scalar: Scalar<M::PointerTag>, // input value (there is no ScalarTy so we separate data+layout)
@@ -218,16 +249,6 @@ pub fn cast_from_int_like(
                 Scalar::from_uint(v, size)
             }
 
-            RawPtr(_) => {
-                assert!(src_layout.ty.is_integral());
-
-                let size = self.pointer_size();
-                let addr = u64::try_from(size.truncate(v)).unwrap();
-
-                let ptr = M::ptr_from_addr_cast(&self, addr);
-                Scalar::from_maybe_pointer(ptr, self)
-            }
-
             Float(FloatTy::F32) if signed => Scalar::from_f32(Single::from_i128(v as i128).value),
             Float(FloatTy::F64) if signed => Scalar::from_f64(Double::from_i128(v as i128).value),
             Float(FloatTy::F32) => Scalar::from_f32(Single::from_u128(v).value),
index 977b55a0890584e1e48f21c4a4a4508ac185355f..9c032c55fe54491478b0918e925da6fe257b6208 100644 (file)
@@ -441,6 +441,10 @@ fn check_offset_align<'tcx>(offset: u64, align: Align) -> InterpResult<'tcx> {
                         msg,
                     })
                 }
+                // Ensure we never consider the null pointer dereferencable.
+                if M::PointerTag::OFFSET_IS_ADDR {
+                    assert_ne!(ptr.addr(), Size::ZERO);
+                }
                 // Test align. Check this last; if both bounds and alignment are violated
                 // we want the error to be about the bounds.
                 if let Some(align) = align {
index 955480a1a7411631f29b3bdf0103cb1427e3f93c..ae7180b674ffd01464a058461e36cd777cdaf28e 100644 (file)
@@ -869,8 +869,6 @@ fn copy_op_no_validate(
             Ok(src_val) => {
                 assert!(!src.layout.is_unsized(), "cannot have unsized immediates");
                 // Yay, we got a value that we can write directly.
-                // FIXME: Add a check to make sure that if `src` is indirect,
-                // it does not overlap with `dest`.
                 return self.write_immediate_no_validate(*src_val, dest);
             }
             Err(mplace) => mplace,
@@ -890,7 +888,7 @@ fn copy_op_no_validate(
         });
         assert_eq!(src.meta, dest.meta, "Can only copy between equally-sized instances");
 
-        self.mem_copy(src.ptr, src.align, dest.ptr, dest.align, size, /*nonoverlapping*/ true)
+        self.mem_copy(src.ptr, src.align, dest.ptr, dest.align, size, /*nonoverlapping*/ false)
     }
 
     /// Copies the data from an operand to a place. The layouts may disagree, but they must
index e6dfdf54a32d136c7dbf70edb52ba4c9bbeb9ab3..9ac86911c7d968f718654af8d232415632dc2b4d 100644 (file)
@@ -158,6 +158,8 @@ pub fn eval_rvalue_into_place(
         place: mir::Place<'tcx>,
     ) -> InterpResult<'tcx> {
         let dest = self.eval_place(place)?;
+        // FIXME: ensure some kind of non-aliasing between LHS and RHS?
+        // Also see https://github.com/rust-lang/rust/issues/68364.
 
         use rustc_middle::mir::Rvalue::*;
         match *rvalue {
index eea6e2a47a94bcc92ed9087d2eceba67093ba4e5..4b98e19376dda0d18b63cfccc009d4a7afc0bde2 100644 (file)
@@ -8,7 +8,6 @@
 use rustc_infer::traits::{ImplSource, Obligation, ObligationCause};
 use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::*;
-use rustc_middle::ty::cast::CastTy;
 use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
 use rustc_middle::ty::{self, adjustment::PointerCast, Instance, InstanceDef, Ty, TyCtxt};
 use rustc_middle::ty::{Binder, TraitPredicate, TraitRef, TypeFoldable};
@@ -520,38 +519,32 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
                 }
             }
 
-            Rvalue::Cast(
-                CastKind::Pointer(PointerCast::MutToConstPointer | PointerCast::ArrayToPointer),
-                _,
-                _,
-            ) => {}
-
             Rvalue::Cast(
                 CastKind::Pointer(
-                    PointerCast::UnsafeFnPointer
+                    PointerCast::MutToConstPointer
+                    | PointerCast::ArrayToPointer
+                    | PointerCast::UnsafeFnPointer
                     | PointerCast::ClosureFnPointer(_)
                     | PointerCast::ReifyFnPointer,
                 ),
                 _,
                 _,
             ) => {
-                // Nothing to do here. Function pointer casts are allowed now.
+                // These are all okay; they only change the type, not the data.
             }
 
             Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), _, _) => {
-                // Nothing to check here (`check_local_or_return_ty` ensures no trait objects occur
-                // in the type of any local, which also excludes casts).
+                // Unsizing is implemented for CTFE.
             }
 
-            Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) => {
-                let operand_ty = operand.ty(self.body, self.tcx);
-                let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast");
-                let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
-
-                if let (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) = (cast_in, cast_out) {
-                    self.check_op(ops::RawPtrToIntCast);
-                }
+            Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => {
+                self.check_op(ops::RawPtrToIntCast);
             }
+            Rvalue::Cast(CastKind::PointerFromExposedAddress, _, _) => {
+                // Since no pointer can ever get exposed (rejected above), this is easy to support.
+            }
+
+            Rvalue::Cast(CastKind::Misc, _, _) => {}
 
             Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => {}
             Rvalue::ShallowInitBox(_, _) => {}
index fc6b8a1a7234c917acfd8592ee349a3b97f03a5a..d1e776854b231dac7c579f9c0bb751b74e5147b1 100644 (file)
@@ -16,7 +16,6 @@
 use rustc_middle::mir::traversal::ReversePostorderIter;
 use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::*;
-use rustc_middle::ty::cast::CastTy;
 use rustc_middle::ty::subst::InternalSubsts;
 use rustc_middle::ty::{self, List, TyCtxt, TypeFoldable};
 use rustc_span::Span;
@@ -502,18 +501,12 @@ fn validate_rvalue(&mut self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable>
 
             Rvalue::ThreadLocalRef(_) => return Err(Unpromotable),
 
-            Rvalue::Cast(kind, operand, cast_ty) => {
-                if matches!(kind, CastKind::Misc) {
-                    let operand_ty = operand.ty(self.body, self.tcx);
-                    let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast");
-                    let cast_out = CastTy::from_ty(*cast_ty).expect("bad output type for cast");
-                    if let (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) = (cast_in, cast_out) {
-                        // ptr-to-int casts are not possible in consts and thus not promotable
-                        return Err(Unpromotable);
-                    }
-                    // int-to-ptr casts are fine, they just use the integer value at pointer type.
-                }
+            // ptr-to-int casts are not possible in consts and thus not promotable
+            Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => return Err(Unpromotable),
 
+            // all other casts including int-to-ptr casts are fine, they just use the integer value
+            // at pointer type.
+            Rvalue::Cast(_, operand, _) => {
                 self.validate_operand(operand)?;
             }
 
index b68ef1eb7f4c4da88d381afdd2ba2f86c9dfaff2..2be2f0532c99ca321ff590931fadb700ce0bc5ef 100644 (file)
@@ -15,7 +15,9 @@ fn test(n: u128, base: usize) {
         test(u64::MAX as u128, base);
         test(u128::MAX, base);
 
-        for i in 0..1_000 {
+        const N: u128 = if cfg!(miri) { 10 } else { 1000 };
+
+        for i in 0..N {
             test(i * 983, base);
         }
     }
index 364005e67e63f91f0dd5dc2a563ef7f0b465d6db..9940fee60d7d8209a56a988a0bb52278d434302b 100644 (file)
@@ -156,7 +156,10 @@ fn test_deep_linear() {
     v
     …
      */
+    #[cfg(not(miri))]
     const NR_NODES: usize = 1 << 14;
+    #[cfg(miri)]
+    const NR_NODES: usize = 1 << 3;
     let mut nodes = vec![];
     for i in 1..NR_NODES {
         nodes.push((i - 1, i));
index 7b8179e90bd0729f3609cc9d039cf65866c27882..320c03d5139f4ba0985dbaae066f61c3b92c0fe8 100644 (file)
@@ -1,3 +1,5 @@
+// FIXME: owning_ref is not sound under stacked borrows. Preferably, get rid of it.
+#[cfg(not(miri))]
 mod owning_ref {
     use super::super::OwningRef;
     use super::super::{BoxRef, Erased, ErasedBoxRef, RcRef};
@@ -361,6 +363,8 @@ fn owning_handle_safe_2() {
     }
 }
 
+// FIXME: owning_ref is not sound under stacked borrows. Preferably, get rid of it.
+#[cfg(not(miri))]
 mod owning_ref_mut {
     use super::super::BoxRef;
     use super::super::{BoxRefMut, Erased, ErasedBoxRefMut, OwningRefMut};
index abd25f46ad54fa2d60b065e6fddcbc71b74dcb7f..90793a97ed0d894d5422403ea241a1d8db7072c7 100644 (file)
@@ -255,8 +255,9 @@ pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher128 {
         // elements from spill (at most LEN - 1 bytes could have overflowed
         // into the spill). The memcpy call is optimized away because the size
         // is known. And the whole copy is optimized away for LEN == 1.
+        let dst = self.buf.as_mut_ptr() as *mut u8;
         let src = self.buf.get_unchecked(BUFFER_SPILL_INDEX) as *const _ as *const u8;
-        ptr::copy_nonoverlapping(src, self.buf.as_mut_ptr() as *mut u8, LEN - 1);
+        ptr::copy_nonoverlapping(src, dst, LEN - 1);
 
         // This function should only be called when the write fills the buffer.
         // Therefore, when LEN == 1, the new `self.nbuf` must be zero.
index f71522d37148ad8b86217000570356f4b0540a2b..4fda3adb7b87829deda1f3f00fe9f82c5e245a71 100644 (file)
@@ -126,9 +126,10 @@ pub fn get(&self, value: &T) -> Option<&T> {
 
     /// Adds a value to the set.
     ///
-    /// If the set did not have this value present, `true` is returned.
+    /// Returns whether the value was newly inserted. That is:
     ///
-    /// If the set did have this value present, `false` is returned.
+    /// - If the set did not previously contain this value, `true` is returned.
+    /// - If the set already contained this value, `false` is returned.
     #[inline]
     pub fn insert(&mut self, elem: T) -> bool {
         self.map.insert(elem, ()).is_none()
index fd2ca5beadea3d013613968186be88f9cd412efd..a2cbd9abc9047e525ed4933226cd7ca4b203998d 100644 (file)
@@ -9,6 +9,7 @@ crate-type = ["dylib"]
 [dependencies]
 libc = "0.2"
 tracing = { version = "0.1.28" }
+serde_json = "1.0.59"
 rustc_log = { path = "../rustc_log" }
 rustc_middle = { path = "../rustc_middle" }
 rustc_ast_pretty = { path = "../rustc_ast_pretty" }
index 904d6f8cfd80889bdcc18b702daa2405e93ff9ea..179a184536efa5c0904666fae87a4cc8b280c620 100644 (file)
@@ -30,7 +30,6 @@
 use rustc_metadata::locator;
 use rustc_save_analysis as save;
 use rustc_save_analysis::DumpHandler;
-use rustc_serialize::json::ToJson;
 use rustc_session::config::{nightly_options, CG_OPTIONS, DB_OPTIONS};
 use rustc_session::config::{ErrorOutputType, Input, OutputType, PrintRequest, TrimmedDefPaths};
 use rustc_session::cstore::MetadataLoader;
@@ -40,6 +39,7 @@
 use rustc_session::{early_error, early_error_no_abort, early_warn};
 use rustc_span::source_map::{FileLoader, FileName};
 use rustc_span::symbol::sym;
+use rustc_target::json::ToJson;
 
 use std::borrow::Cow;
 use std::cmp::max;
@@ -343,10 +343,7 @@ fn run_compiler(
                 return early_exit();
             }
 
-            if sess.opts.debugging_opts.parse_only
-                || sess.opts.debugging_opts.show_span.is_some()
-                || sess.opts.debugging_opts.ast_json_noexpand
-            {
+            if sess.opts.debugging_opts.parse_only || sess.opts.debugging_opts.show_span.is_some() {
                 return early_exit();
             }
 
@@ -375,7 +372,7 @@ fn run_compiler(
 
             queries.global_ctxt()?;
 
-            if sess.opts.debugging_opts.no_analysis || sess.opts.debugging_opts.ast_json {
+            if sess.opts.debugging_opts.no_analysis {
                 return early_exit();
             }
 
@@ -665,7 +662,9 @@ fn print_crate_info(
             }
             Sysroot => println!("{}", sess.sysroot.display()),
             TargetLibdir => println!("{}", sess.target_tlib_path.dir.display()),
-            TargetSpec => println!("{}", sess.target.to_json().pretty()),
+            TargetSpec => {
+                println!("{}", serde_json::to_string_pretty(&sess.target.to_json()).unwrap());
+            }
             FileNames | CrateName => {
                 let input = input.unwrap_or_else(|| {
                     early_error(ErrorOutputType::default(), "no input file provided")
index 37271ac692d55fdbd1b4921c94a9311cf958ed4a..2d1ac40264de19f4326d5a473ef99842e8920cf5 100644 (file)
@@ -1,8 +1,10 @@
+#### Note: this error code is no longer emitted by the compiler.
+
 A lifetime was declared more than once in the same scope.
 
 Erroneous code example:
 
-```compile_fail,E0263
+```compile_fail,E0403
 fn foo<'a, 'b, 'a>(x: &'a str, y: &'b str, z: &'a str) { // error!
 }
 ```
index c98989b23c1a5edde8a615e7066103bc490e6903..076b1b1caed7278645fbe808cf3510cac370c2a5 100644 (file)
@@ -14,3 +14,21 @@ parser-add-paren = try adding parentheses
 parser-forgot-paren = perhaps you forgot parentheses?
 
 parser-expect-path = expected a path
+
+parser-maybe-recover-from-bad-qpath-stage-2 =
+    missing angle brackets in associated item path
+    .suggestion = try: `{$ty}`
+
+parser-incorrect-semicolon =
+    expected item, found `;`
+    .suggestion = remove this semicolon
+    .help = {$name} declarations are not followed by a semicolon
+
+parser-incorrect-use-of-await =
+    incorrect use of `await`
+    .parentheses-suggestion = `await` is not a method call, remove the parentheses
+    .postfix-suggestion = `await` is a postfix operation
+
+parser-in-in-typo =
+    expected iterable, found keyword `in`
+    .suggestion = remove the duplicated `in`
index 5f919982890e0305d7f75bd9170011870dbe0cb3..89557626057133ccbd2d623bcf7e46105d21521e 100644 (file)
@@ -19,6 +19,8 @@ atty = "0.2"
 termcolor = "1.0"
 annotate-snippets = "0.8.0"
 termize = "0.1.1"
+serde = { version = "1.0.125", features = ["derive"] }
+serde_json = "1.0.59"
 
 [target.'cfg(windows)'.dependencies]
 winapi = { version = "0.3", features = ["handleapi", "synchapi", "winbase"] }
index 3fdc8cf8ac25fb9cd30da027b104e59844f92164..e9e7065ec03cc744b90b8bda4a96c903926b8ec2 100644 (file)
@@ -1715,6 +1715,7 @@ fn emit_message_default(
 
     fn emit_suggestion_default(
         &mut self,
+        span: &MultiSpan,
         suggestion: &CodeSuggestion,
         args: &FluentArgs<'_>,
         level: &Level,
@@ -1766,6 +1767,30 @@ enum DisplaySuggestion {
                 None,
             }
 
+            if let Some(span) = span.primary_span() {
+                // Compare the primary span of the diagnostic with the span of the suggestion
+                // being emitted.  If they belong to the same file, we don't *need* to show the
+                // file name, saving in verbosity, but if it *isn't* we do need it, otherwise we're
+                // telling users to make a change but not clarifying *where*.
+                let loc = sm.lookup_char_pos(parts[0].span.lo());
+                if loc.file.name != sm.span_to_filename(span) && loc.file.name.is_real() {
+                    buffer.puts(row_num - 1, 0, "--> ", Style::LineNumber);
+                    buffer.append(
+                        row_num - 1,
+                        &format!(
+                            "{}:{}:{}",
+                            sm.filename_for_diagnostics(&loc.file.name),
+                            sm.doctest_offset_line(&loc.file.name, loc.line),
+                            loc.col.0 + 1,
+                        ),
+                        Style::LineAndColumn,
+                    );
+                    for _ in 0..max_line_num_len {
+                        buffer.prepend(row_num - 1, " ", Style::NoStyle);
+                    }
+                    row_num += 1;
+                }
+            }
             let show_code_change = if has_deletion && !is_multiline {
                 DisplaySuggestion::Diff
             } else if (parts.len() != 1 || parts[0].snippet.trim() != complete.trim())
@@ -1787,7 +1812,7 @@ enum DisplaySuggestion {
             assert!(!file_lines.lines.is_empty() || parts[0].span.is_dummy());
 
             let line_start = sm.lookup_char_pos(parts[0].span.lo()).line;
-            draw_col_separator_no_space(&mut buffer, 1, max_line_num_len + 1);
+            draw_col_separator_no_space(&mut buffer, row_num - 1, max_line_num_len + 1);
             let mut lines = complete.lines();
             if lines.clone().next().is_none() {
                 // Account for a suggestion to completely remove a line(s) with whitespace (#94192).
@@ -2046,9 +2071,13 @@ fn emit_messages_default(
                             ) {
                                 panic!("failed to emit error: {}", e);
                             }
-                        } else if let Err(e) =
-                            self.emit_suggestion_default(sugg, args, &Level::Help, max_line_num_len)
-                        {
+                        } else if let Err(e) = self.emit_suggestion_default(
+                            span,
+                            sugg,
+                            args,
+                            &Level::Help,
+                            max_line_num_len,
+                        ) {
                             panic!("failed to emit error: {}", e);
                         };
                     }
index 6ff52182d6b037d6e713a66fee467af41ce8a05a..fff35ac6ac894be46a2ae26678a410b188661aab 100644 (file)
@@ -28,7 +28,7 @@
 use std::sync::{Arc, Mutex};
 use std::vec;
 
-use rustc_serialize::json::{as_json, as_pretty_json};
+use serde::Serialize;
 
 #[cfg(test)]
 mod tests;
@@ -126,9 +126,9 @@ impl Emitter for JsonEmitter {
     fn emit_diagnostic(&mut self, diag: &crate::Diagnostic) {
         let data = Diagnostic::from_errors_diagnostic(diag, self);
         let result = if self.pretty {
-            writeln!(&mut self.dst, "{}", as_pretty_json(&data))
+            writeln!(&mut self.dst, "{}", serde_json::to_string_pretty(&data).unwrap())
         } else {
-            writeln!(&mut self.dst, "{}", as_json(&data))
+            writeln!(&mut self.dst, "{}", serde_json::to_string(&data).unwrap())
         }
         .and_then(|_| self.dst.flush());
         if let Err(e) = result {
@@ -139,9 +139,9 @@ fn emit_diagnostic(&mut self, diag: &crate::Diagnostic) {
     fn emit_artifact_notification(&mut self, path: &Path, artifact_type: &str) {
         let data = ArtifactNotification { artifact: path, emit: artifact_type };
         let result = if self.pretty {
-            writeln!(&mut self.dst, "{}", as_pretty_json(&data))
+            writeln!(&mut self.dst, "{}", serde_json::to_string_pretty(&data).unwrap())
         } else {
-            writeln!(&mut self.dst, "{}", as_json(&data))
+            writeln!(&mut self.dst, "{}", serde_json::to_string(&data).unwrap())
         }
         .and_then(|_| self.dst.flush());
         if let Err(e) = result {
@@ -161,9 +161,9 @@ fn emit_future_breakage_report(&mut self, diags: Vec<crate::Diagnostic>) {
             .collect();
         let report = FutureIncompatReport { future_incompat_report: data };
         let result = if self.pretty {
-            writeln!(&mut self.dst, "{}", as_pretty_json(&report))
+            writeln!(&mut self.dst, "{}", serde_json::to_string_pretty(&report).unwrap())
         } else {
-            writeln!(&mut self.dst, "{}", as_json(&report))
+            writeln!(&mut self.dst, "{}", serde_json::to_string(&report).unwrap())
         }
         .and_then(|_| self.dst.flush());
         if let Err(e) = result {
@@ -175,9 +175,9 @@ fn emit_unused_externs(&mut self, lint_level: rustc_lint_defs::Level, unused_ext
         let lint_level = lint_level.as_str();
         let data = UnusedExterns { lint_level, unused_extern_names: unused_externs };
         let result = if self.pretty {
-            writeln!(&mut self.dst, "{}", as_pretty_json(&data))
+            writeln!(&mut self.dst, "{}", serde_json::to_string_pretty(&data).unwrap())
         } else {
-            writeln!(&mut self.dst, "{}", as_json(&data))
+            writeln!(&mut self.dst, "{}", serde_json::to_string(&data).unwrap())
         }
         .and_then(|_| self.dst.flush());
         if let Err(e) = result {
@@ -204,7 +204,7 @@ fn should_show_explain(&self) -> bool {
 
 // The following data types are provided just for serialisation.
 
-#[derive(Encodable)]
+#[derive(Serialize)]
 struct Diagnostic {
     /// The primary error message.
     message: String,
@@ -218,7 +218,7 @@ struct Diagnostic {
     rendered: Option<String>,
 }
 
-#[derive(Encodable)]
+#[derive(Serialize)]
 struct DiagnosticSpan {
     file_name: String,
     byte_start: u32,
@@ -245,7 +245,7 @@ struct DiagnosticSpan {
     expansion: Option<Box<DiagnosticSpanMacroExpansion>>,
 }
 
-#[derive(Encodable)]
+#[derive(Serialize)]
 struct DiagnosticSpanLine {
     text: String,
 
@@ -255,7 +255,7 @@ struct DiagnosticSpanLine {
     highlight_end: usize,
 }
 
-#[derive(Encodable)]
+#[derive(Serialize)]
 struct DiagnosticSpanMacroExpansion {
     /// span where macro was applied to generate this code; note that
     /// this may itself derive from a macro (if
@@ -269,7 +269,7 @@ struct DiagnosticSpanMacroExpansion {
     def_site_span: DiagnosticSpan,
 }
 
-#[derive(Encodable)]
+#[derive(Serialize)]
 struct DiagnosticCode {
     /// The code itself.
     code: String,
@@ -277,7 +277,7 @@ struct DiagnosticCode {
     explanation: Option<&'static str>,
 }
 
-#[derive(Encodable)]
+#[derive(Serialize)]
 struct ArtifactNotification<'a> {
     /// The path of the artifact.
     artifact: &'a Path,
@@ -285,12 +285,12 @@ struct ArtifactNotification<'a> {
     emit: &'a str,
 }
 
-#[derive(Encodable)]
+#[derive(Serialize)]
 struct FutureBreakageItem {
     diagnostic: Diagnostic,
 }
 
-#[derive(Encodable)]
+#[derive(Serialize)]
 struct FutureIncompatReport {
     future_incompat_report: Vec<FutureBreakageItem>,
 }
@@ -299,7 +299,7 @@ struct FutureIncompatReport {
 // doctest component (as well as cargo).
 // We could unify this struct the one in rustdoc but they have different
 // ownership semantics, so doing so would create wasteful allocations.
-#[derive(Encodable)]
+#[derive(Serialize)]
 struct UnusedExterns<'a, 'b, 'c> {
     /// The severity level of the unused dependencies lint
     lint_level: &'a str,
index 7eb6a4975fe97b1c075bef047d09796066cd4786..d940d14e1db91f26b8e803a48cdb10b9c4874b6f 100644 (file)
@@ -5,12 +5,18 @@
 
 use crate::emitter::{ColorConfig, HumanReadableErrorType};
 use crate::Handler;
-use rustc_serialize::json;
 use rustc_span::{BytePos, Span};
 
 use std::str;
 
-#[derive(Debug, PartialEq, Eq)]
+use serde::Deserialize;
+
+#[derive(Deserialize, Debug, PartialEq, Eq)]
+struct TestData {
+    spans: Vec<SpanTestData>,
+}
+
+#[derive(Deserialize, Debug, PartialEq, Eq)]
 struct SpanTestData {
     pub byte_start: u32,
     pub byte_end: u32,
@@ -61,19 +67,11 @@ fn test_positions(code: &str, span: (u32, u32), expected_output: SpanTestData) {
 
         let bytes = output.lock().unwrap();
         let actual_output = str::from_utf8(&bytes).unwrap();
-        let actual_output = json::from_str(&actual_output).unwrap();
-        let spans = actual_output["spans"].as_array().unwrap();
+        let actual_output: TestData = serde_json::from_str(actual_output).unwrap();
+        let spans = actual_output.spans;
         assert_eq!(spans.len(), 1);
-        let obj = &spans[0];
-        let actual_output = SpanTestData {
-            byte_start: obj["byte_start"].as_u64().unwrap() as u32,
-            byte_end: obj["byte_end"].as_u64().unwrap() as u32,
-            line_start: obj["line_start"].as_u64().unwrap() as u32,
-            line_end: obj["line_end"].as_u64().unwrap() as u32,
-            column_start: obj["column_start"].as_u64().unwrap() as u32,
-            column_end: obj["column_end"].as_u64().unwrap() as u32,
-        };
-        assert_eq!(expected_output, actual_output);
+
+        assert_eq!(expected_output, spans[0])
     })
 }
 
index 56d0263269b53daacc2ab974dd6e557143bdefdf..e73c31c98fe32040a4cd21aac375b43947e03a22 100644 (file)
@@ -160,7 +160,7 @@ pub fn stmt_let(&self, sp: Span, mutbl: bool, ident: Ident, ex: P<ast::Expr>) ->
             attrs: AttrVec::new(),
             tokens: None,
         });
-        ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Local(local), span: sp }
+        self.stmt_local(local, sp)
     }
 
     // Generates `let _: Type;`, which is usually used for type assertions.
@@ -174,6 +174,10 @@ pub fn stmt_let_type_only(&self, span: Span, ty: P<ast::Ty>) -> ast::Stmt {
             attrs: AttrVec::new(),
             tokens: None,
         });
+        self.stmt_local(local, span)
+    }
+
+    pub fn stmt_local(&self, local: P<ast::Local>, span: Span) -> ast::Stmt {
         ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Local(local), span }
     }
 
index 5a02661513ca72f416dbf5e078af7538ca9ab0ad..1466e8dfc92e4d59a36ae587b9b1d3aedbf32419 100644 (file)
@@ -150,6 +150,8 @@ pub fn set(&self, features: &mut Features, span: Span) {
     (active, allow_internal_unstable, "1.0.0", None, None),
     /// Allows identifying the `compiler_builtins` crate.
     (active, compiler_builtins, "1.13.0", None, None),
+    /// Outputs useful `assert!` messages
+    (active, generic_assert, "1.63.0", None, None),
     /// Allows using the `rust-intrinsic`'s "ABI".
     (active, intrinsics, "1.0.0", None, None),
     /// Allows using `#[lang = ".."]` attribute for linking items to special compiler logic.
index 8155e65a6dbf573e8813b8b1f20d8b302cbe5990..5eb2be97f8b92b80fd372f7d00015263fba568d3 100644 (file)
@@ -675,6 +675,12 @@ pub struct BuiltinAttribute {
         "#[rustc_has_incoherent_inherent_impls] allows the addition of incoherent inherent impls for \
          the given type by annotating all impl items with #[rustc_allow_incoherent_impl]."
     ),
+    rustc_attr!(
+        rustc_box, AttributeType::Normal, template!(Word), ErrorFollowing,
+        "#[rustc_box] allows creating boxes \
+        and it is only intended to be used in `alloc`."
+    ),
+
     BuiltinAttribute {
         name: sym::rustc_diagnostic_item,
         // FIXME: This can be `true` once we always use `tcx.is_diagnostic_item`.
index 68876e89c4b1fe3a1c9784c64a507ced7794816a..414f6272591966b60d9fdb49e21e6473ca1f92b6 100644 (file)
@@ -671,7 +671,10 @@ pub fn apply_id<R, E>(self, mut map: impl FnMut(Id) -> Result<R, E>) -> Result<R
 
     #[track_caller]
     pub fn expect_non_local<OtherId>(self) -> Res<OtherId> {
-        self.map_id(|_| panic!("unexpected `Res::Local`"))
+        self.map_id(
+            #[track_caller]
+            |_| panic!("unexpected `Res::Local`"),
+        )
     }
 
     pub fn macro_kind(self) -> Option<MacroKind> {
index bda7affe52983b5ab1ca08b0f20b702a3219292f..cb2e66090e7c393317c45563b4ad6a8add3d45db 100644 (file)
@@ -26,7 +26,7 @@
 use smallvec::SmallVec;
 use std::fmt;
 
-#[derive(Copy, Clone, Encodable, HashStable_Generic)]
+#[derive(Debug, Copy, Clone, Encodable, HashStable_Generic)]
 pub struct Lifetime {
     pub hir_id: HirId,
     pub span: Span,
@@ -60,7 +60,7 @@ pub enum ParamName {
     /// ```
     /// where `'f` is something like `Fresh(0)`. The indices are
     /// unique per impl, but not necessarily continuous.
-    Fresh(LocalDefId),
+    Fresh,
 
     /// Indicates an illegal name was given and an error has been
     /// reported (so we should squelch other derived errors). Occurs
@@ -72,9 +72,7 @@ impl ParamName {
     pub fn ident(&self) -> Ident {
         match *self {
             ParamName::Plain(ident) => ident,
-            ParamName::Fresh(_) | ParamName::Error => {
-                Ident::with_dummy_span(kw::UnderscoreLifetime)
-            }
+            ParamName::Fresh | ParamName::Error => Ident::with_dummy_span(kw::UnderscoreLifetime),
         }
     }
 
@@ -90,7 +88,7 @@ pub fn normalize_to_macros_2_0(&self) -> ParamName {
 #[derive(HashStable_Generic)]
 pub enum LifetimeName {
     /// User-given names or fresh (synthetic) names.
-    Param(ParamName),
+    Param(LocalDefId, ParamName),
 
     /// User wrote nothing (e.g., the lifetime in `&u32`).
     Implicit,
@@ -127,7 +125,18 @@ pub fn ident(&self) -> Ident {
             | LifetimeName::Error => Ident::empty(),
             LifetimeName::Underscore => Ident::with_dummy_span(kw::UnderscoreLifetime),
             LifetimeName::Static => Ident::with_dummy_span(kw::StaticLifetime),
-            LifetimeName::Param(param_name) => param_name.ident(),
+            LifetimeName::Param(_, param_name) => param_name.ident(),
+        }
+    }
+
+    pub fn is_anonymous(&self) -> bool {
+        match *self {
+            LifetimeName::ImplicitObjectLifetimeDefault
+            | LifetimeName::Implicit
+            | LifetimeName::Underscore
+            | LifetimeName::Param(_, ParamName::Fresh)
+            | LifetimeName::Error => true,
+            LifetimeName::Static | LifetimeName::Param(..) => false,
         }
     }
 
@@ -137,12 +146,12 @@ pub fn is_elided(&self) -> bool {
             | LifetimeName::Implicit
             | LifetimeName::Underscore => true,
 
-            // It might seem surprising that `Fresh(_)` counts as
+            // It might seem surprising that `Fresh` counts as
             // *not* elided -- but this is because, as far as the code
-            // in the compiler is concerned -- `Fresh(_)` variants act
+            // in the compiler is concerned -- `Fresh` variants act
             // equivalently to "some fresh name". They correspond to
             // early-bound regions on an impl, in other words.
-            LifetimeName::Error | LifetimeName::Param(_) | LifetimeName::Static => false,
+            LifetimeName::Error | LifetimeName::Param(..) | LifetimeName::Static => false,
         }
     }
 
@@ -152,8 +161,8 @@ fn is_static(&self) -> bool {
 
     pub fn normalize_to_macros_2_0(&self) -> LifetimeName {
         match *self {
-            LifetimeName::Param(param_name) => {
-                LifetimeName::Param(param_name.normalize_to_macros_2_0())
+            LifetimeName::Param(def_id, param_name) => {
+                LifetimeName::Param(def_id, param_name.normalize_to_macros_2_0())
             }
             lifetime_name => lifetime_name,
         }
@@ -166,12 +175,6 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     }
 }
 
-impl fmt::Debug for Lifetime {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "lifetime({}: {})", self.hir_id, self.name.ident())
-    }
-}
-
 impl Lifetime {
     pub fn is_elided(&self) -> bool {
         self.name.is_elided()
@@ -617,6 +620,16 @@ pub fn bounds_for_param(
         })
     }
 
+    pub fn outlives_for_param(
+        &self,
+        param_def_id: LocalDefId,
+    ) -> impl Iterator<Item = &WhereRegionPredicate<'_>> {
+        self.predicates.iter().filter_map(move |pred| match pred {
+            WherePredicate::RegionPredicate(rp) if rp.is_param_bound(param_def_id) => Some(rp),
+            _ => None,
+        })
+    }
+
     pub fn bounds_span_for_suggestions(&self, param_def_id: LocalDefId) -> Option<Span> {
         self.bounds_for_param(param_def_id).flat_map(|bp| bp.bounds.iter().rev()).find_map(
             |bound| {
@@ -758,6 +771,16 @@ pub struct WhereRegionPredicate<'hir> {
     pub bounds: GenericBounds<'hir>,
 }
 
+impl<'hir> WhereRegionPredicate<'hir> {
+    /// Returns `true` if `param_def_id` matches the `lifetime` of this predicate.
+    pub fn is_param_bound(&self, param_def_id: LocalDefId) -> bool {
+        match self.lifetime.name {
+            LifetimeName::Param(id, _) => id == param_def_id,
+            _ => false,
+        }
+    }
+}
+
 /// An equality predicate (e.g., `T = int`); currently unsupported.
 #[derive(Debug, HashStable_Generic)]
 pub struct WhereEqPredicate<'hir> {
@@ -2981,13 +3004,12 @@ pub fn generics(&self) -> Option<&Generics<'_>> {
         Some(match *self {
             ItemKind::Fn(_, ref generics, _)
             | ItemKind::TyAlias(_, ref generics)
-            | ItemKind::OpaqueTy(OpaqueTy {
-                ref generics, origin: OpaqueTyOrigin::TyAlias, ..
-            })
+            | ItemKind::OpaqueTy(OpaqueTy { ref generics, .. })
             | ItemKind::Enum(_, ref generics)
             | ItemKind::Struct(_, ref generics)
             | ItemKind::Union(_, ref generics)
             | ItemKind::Trait(_, _, ref generics, _, _)
+            | ItemKind::TraitAlias(ref generics, _)
             | ItemKind::Impl(Impl { ref generics, .. }) => generics,
             _ => return None,
         })
@@ -3187,13 +3209,8 @@ pub fn body_id(&self) -> Option<BodyId> {
         }
     }
 
-    pub fn generics(&self) -> Option<&'hir Generics<'hir>> {
-        match self {
-            OwnerNode::TraitItem(TraitItem { generics, .. })
-            | OwnerNode::ImplItem(ImplItem { generics, .. }) => Some(generics),
-            OwnerNode::Item(item) => item.kind.generics(),
-            _ => None,
-        }
+    pub fn generics(self) -> Option<&'hir Generics<'hir>> {
+        Node::generics(self.into())
     }
 
     pub fn def_id(self) -> LocalDefId {
@@ -3380,9 +3397,12 @@ pub fn body_id(&self) -> Option<BodyId> {
         }
     }
 
-    pub fn generics(&self) -> Option<&'hir Generics<'hir>> {
+    pub fn generics(self) -> Option<&'hir Generics<'hir>> {
         match self {
-            Node::TraitItem(TraitItem { generics, .. })
+            Node::ForeignItem(ForeignItem {
+                kind: ForeignItemKind::Fn(_, _, generics), ..
+            })
+            | Node::TraitItem(TraitItem { generics, .. })
             | Node::ImplItem(ImplItem { generics, .. }) => Some(generics),
             Node::Item(item) => item.kind.generics(),
             _ => None,
index 5b83a29bb33c30bc027398b9068ba7632085e9a3..bd8587f1106e9ad708fbf007bbbec54e73d64e1c 100644 (file)
@@ -510,11 +510,11 @@ pub fn walk_label<'v, V: Visitor<'v>>(visitor: &mut V, label: &'v Label) {
 pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime) {
     visitor.visit_id(lifetime.hir_id);
     match lifetime.name {
-        LifetimeName::Param(ParamName::Plain(ident)) => {
+        LifetimeName::Param(_, ParamName::Plain(ident)) => {
             visitor.visit_ident(ident);
         }
-        LifetimeName::Param(ParamName::Fresh(_))
-        | LifetimeName::Param(ParamName::Error)
+        LifetimeName::Param(_, ParamName::Fresh)
+        | LifetimeName::Param(_, ParamName::Error)
         | LifetimeName::Static
         | LifetimeName::Error
         | LifetimeName::Implicit
@@ -879,7 +879,7 @@ pub fn walk_generic_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v Generi
     visitor.visit_id(param.hir_id);
     match param.name {
         ParamName::Plain(ident) => visitor.visit_ident(ident),
-        ParamName::Error | ParamName::Fresh(_) => {}
+        ParamName::Error | ParamName::Fresh => {}
     }
     match param.kind {
         GenericParamKind::Lifetime { .. } => {}
index 7833571f88d4348efdf242cbdcd1859a2b1a7d3d..d845c433d8c5f6874f7ff8e739a3582afca9579d 100644 (file)
@@ -3,6 +3,7 @@
 //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html
 
 #![feature(associated_type_defaults)]
+#![feature(closure_track_caller)]
 #![feature(const_btree_new)]
 #![feature(let_else)]
 #![feature(once_cell)]
index e156930cc89fdd8f7d5ce9dfd63c9b714dddcc5c..579d7efb56803ec26da25fa6aa5e82cbf1f74f91 100644 (file)
@@ -72,7 +72,7 @@
     subst::{GenericArgKind, Subst, SubstsRef},
     Binder, EarlyBinder, List, Region, Ty, TyCtxt, TypeFoldable,
 };
-use rustc_span::{sym, BytePos, DesugaringKind, Pos, Span};
+use rustc_span::{sym, symbol::kw, BytePos, DesugaringKind, Pos, Span};
 use rustc_target::spec::abi;
 use std::ops::ControlFlow;
 use std::{cmp, fmt, iter};
@@ -161,35 +161,45 @@ fn msg_span_from_early_bound_and_free_regions<'tcx>(
             {
                 sp = param.span;
             }
-            (format!("the lifetime `{}` as defined here", br.name), sp)
+            let text = if br.has_name() {
+                format!("the lifetime `{}` as defined here", br.name)
+            } else {
+                format!("the anonymous lifetime as defined here")
+            };
+            (text, sp)
         }
-        ty::ReFree(ty::FreeRegion {
-            bound_region: ty::BoundRegionKind::BrNamed(_, name), ..
-        }) => {
-            let mut sp = sm.guess_head_span(tcx.def_span(scope));
-            if let Some(param) =
-                tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(name))
+        ty::ReFree(ref fr) => {
+            if !fr.bound_region.is_named()
+                && let Some((ty, _)) = find_anon_type(tcx, region, &fr.bound_region)
             {
-                sp = param.span;
-            }
-            (format!("the lifetime `{}` as defined here", name), sp)
-        }
-        ty::ReFree(ref fr) => match fr.bound_region {
-            ty::BrAnon(idx) => {
-                if let Some((ty, _)) = find_anon_type(tcx, region, &fr.bound_region) {
-                    ("the anonymous lifetime defined here".to_string(), ty.span)
-                } else {
-                    (
+                ("the anonymous lifetime defined here".to_string(), ty.span)
+            } else {
+                match fr.bound_region {
+                    ty::BoundRegionKind::BrNamed(_, name) => {
+                        let mut sp = sm.guess_head_span(tcx.def_span(scope));
+                        if let Some(param) =
+                            tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(name))
+                        {
+                            sp = param.span;
+                        }
+                        let text = if name == kw::UnderscoreLifetime {
+                            format!("the anonymous lifetime as defined here")
+                        } else {
+                            format!("the lifetime `{}` as defined here", name)
+                        };
+                        (text, sp)
+                    }
+                    ty::BrAnon(idx) => (
                         format!("the anonymous lifetime #{} defined here", idx + 1),
-                        tcx.def_span(scope),
-                    )
+                        tcx.def_span(scope)
+                    ),
+                    _ => (
+                        format!("the lifetime `{}` as defined here", region),
+                        sm.guess_head_span(tcx.def_span(scope)),
+                    ),
                 }
             }
-            _ => (
-                format!("the lifetime `{}` as defined here", region),
-                sm.guess_head_span(tcx.def_span(scope)),
-            ),
-        },
+        }
         _ => bug!(),
     }
 }
@@ -2552,7 +2562,7 @@ enum SubOrigin<'hir> {
                 ty::ReEarlyBound(ty::EarlyBoundRegion { name, .. })
                 | ty::ReFree(ty::FreeRegion { bound_region: ty::BrNamed(_, name), .. }),
                 _,
-            ) => {
+            ) if name != kw::UnderscoreLifetime => {
                 // Does the required lifetime have a nice name we can print?
                 let mut err = struct_span_err!(
                     self.tcx.sess,
index e1a2a237c2324525d6d0ef882b96a1a9cfbb0706..7b5c377f7b4caa25ffd21921d538c5e877f23806 100644 (file)
 use crate::infer::type_variable::TypeVariableOriginKind;
-use crate::infer::{InferCtxt, Symbol};
-use rustc_errors::{
-    pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
-};
+use crate::infer::InferCtxt;
+use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
 use rustc_hir as hir;
-use rustc_hir::def::{DefKind, Namespace};
+use rustc_hir::def::{CtorOf, DefKind, Namespace};
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local, MatchSource, Pat};
+use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local, LocalSource};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::infer::unify_key::ConstVariableOriginKind;
-use rustc_middle::ty::print::Print;
-use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
-use rustc_middle::ty::{self, Const, DefIdTree, InferConst, Ty, TyCtxt, TypeFoldable, TypeFolder};
-use rustc_span::symbol::kw;
-use rustc_span::{sym, Span};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
+use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Print, Printer};
+use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef};
+use rustc_middle::ty::{self, DefIdTree, GenericParamDefKind, InferConst};
+use rustc_middle::ty::{Ty, TyCtxt, TypeckResults};
+use rustc_span::symbol::{kw, Ident};
+use rustc_span::{BytePos, Span};
 use std::borrow::Cow;
-
-struct FindHirNodeVisitor<'a, 'tcx> {
-    infcx: &'a InferCtxt<'a, 'tcx>,
-    target: GenericArg<'tcx>,
-    target_span: Span,
-    found_node_ty: Option<Ty<'tcx>>,
-    found_local_pattern: Option<&'tcx Pat<'tcx>>,
-    found_arg_pattern: Option<&'tcx Pat<'tcx>>,
-    found_closure: Option<&'tcx Expr<'tcx>>,
-    found_method_call: Option<&'tcx Expr<'tcx>>,
-    found_exact_method_call: Option<&'tcx Expr<'tcx>>,
-    found_for_loop_iter: Option<&'tcx Expr<'tcx>>,
-    found_use_diagnostic: Option<UseDiagnostic<'tcx>>,
-}
-
-impl<'a, 'tcx> FindHirNodeVisitor<'a, 'tcx> {
-    fn new(infcx: &'a InferCtxt<'a, 'tcx>, target: GenericArg<'tcx>, target_span: Span) -> Self {
-        Self {
-            infcx,
-            target,
-            target_span,
-            found_node_ty: None,
-            found_local_pattern: None,
-            found_arg_pattern: None,
-            found_closure: None,
-            found_method_call: None,
-            found_exact_method_call: None,
-            found_for_loop_iter: None,
-            found_use_diagnostic: None,
-        }
-    }
-
-    fn node_type_opt(&self, hir_id: HirId) -> Option<Ty<'tcx>> {
-        self.infcx.in_progress_typeck_results?.borrow().node_type_opt(hir_id)
-    }
-
-    fn node_ty_contains_target(&self, hir_id: HirId) -> Option<Ty<'tcx>> {
-        self.node_type_opt(hir_id).map(|ty| self.infcx.resolve_vars_if_possible(ty)).filter(|ty| {
-            ty.walk().any(|inner| {
-                inner == self.target
-                    || match (inner.unpack(), self.target.unpack()) {
-                        (GenericArgKind::Type(inner_ty), GenericArgKind::Type(target_ty)) => {
-                            use ty::{Infer, TyVar};
-                            match (inner_ty.kind(), target_ty.kind()) {
-                                (&Infer(TyVar(a_vid)), &Infer(TyVar(b_vid))) => self
-                                    .infcx
-                                    .inner
-                                    .borrow_mut()
-                                    .type_variables()
-                                    .sub_unified(a_vid, b_vid),
-                                _ => false,
-                            }
-                        }
-                        _ => false,
-                    }
-            })
-        })
-    }
-
-    /// Determine whether the expression, assumed to be the callee within a `Call`,
-    /// corresponds to the `From::from` emitted in desugaring of the `?` operator.
-    fn is_try_conversion(&self, callee: &Expr<'tcx>) -> bool {
-        self.infcx
-            .trait_def_from_hir_fn(callee.hir_id)
-            .map_or(false, |def_id| self.infcx.is_try_conversion(callee.span, def_id))
-    }
-}
-
-impl<'a, 'tcx> Visitor<'tcx> for FindHirNodeVisitor<'a, 'tcx> {
-    type NestedFilter = nested_filter::OnlyBodies;
-
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.infcx.tcx.hir()
-    }
-
-    fn visit_local(&mut self, local: &'tcx Local<'tcx>) {
-        if let (None, Some(ty)) =
-            (self.found_local_pattern, self.node_ty_contains_target(local.hir_id))
-        {
-            self.found_local_pattern = Some(&*local.pat);
-            self.found_node_ty = Some(ty);
-        }
-        intravisit::walk_local(self, local);
-    }
-
-    fn visit_body(&mut self, body: &'tcx Body<'tcx>) {
-        for param in body.params {
-            if let (None, Some(ty)) =
-                (self.found_arg_pattern, self.node_ty_contains_target(param.hir_id))
-            {
-                self.found_arg_pattern = Some(&*param.pat);
-                self.found_node_ty = Some(ty);
-            }
-        }
-        intravisit::walk_body(self, body);
-    }
-
-    fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
-        if let ExprKind::Match(scrutinee, [_, arm], MatchSource::ForLoopDesugar) = expr.kind
-            && let Some(pat) = arm.pat.for_loop_some()
-            && let Some(ty) = self.node_ty_contains_target(pat.hir_id)
-        {
-            self.found_for_loop_iter = Some(scrutinee);
-            self.found_node_ty = Some(ty);
-            return;
-        }
-        if let ExprKind::MethodCall(segment, exprs, _) = expr.kind
-            && segment.ident.span == self.target_span
-            && Some(self.target) == self.infcx.in_progress_typeck_results.and_then(|typeck_results| {
-                typeck_results
-                    .borrow()
-                    .node_type_opt(exprs.first().unwrap().hir_id)
-                    .map(Into::into)
-            })
-        {
-            self.found_exact_method_call = Some(&expr);
-            return;
-        }
-
-        // FIXME(const_generics): Currently, any uninferred `const` generics arguments
-        // are handled specially, but instead they should be handled in `annotate_method_call`,
-        // which currently doesn't work because this evaluates to `false` for const arguments.
-        // See https://github.com/rust-lang/rust/pull/77758 for more details.
-        if let Some(ty) = self.node_ty_contains_target(expr.hir_id) {
-            match expr.kind {
-                ExprKind::Closure(..) => self.found_closure = Some(&expr),
-                ExprKind::MethodCall(..) => self.found_method_call = Some(&expr),
-
-                // If the given expression falls within the target span and is a
-                // `From::from(e)` call emitted during desugaring of the `?` operator,
-                // extract the types inferred before and after the call
-                ExprKind::Call(callee, [arg])
-                    if self.target_span.contains(expr.span)
-                        && self.found_use_diagnostic.is_none()
-                        && self.is_try_conversion(callee) =>
-                {
-                    self.found_use_diagnostic = self.node_type_opt(arg.hir_id).map(|pre_ty| {
-                        UseDiagnostic::TryConversion { pre_ty, post_ty: ty, span: callee.span }
-                    });
-                }
-                _ => {}
-            }
-        }
-        intravisit::walk_expr(self, expr);
-    }
-}
-
-/// An observation about the use site of a type to be emitted as an additional
-/// note in an inference failure error.
-enum UseDiagnostic<'tcx> {
-    /// Records the types inferred before and after `From::from` is called on the
-    /// error value within the desugaring of the `?` operator.
-    TryConversion { pre_ty: Ty<'tcx>, post_ty: Ty<'tcx>, span: Span },
-}
-
-impl UseDiagnostic<'_> {
-    /// Return a descriptor of the value at the use site
-    fn descr(&self) -> &'static str {
-        match self {
-            Self::TryConversion { .. } => "error for `?` operator",
-        }
-    }
-
-    /// Return a descriptor of the type at the use site
-    fn type_descr(&self) -> &'static str {
-        match self {
-            Self::TryConversion { .. } => "error type for `?` operator",
-        }
-    }
-
-    fn applies_to(&self, span: Span) -> bool {
-        match *self {
-            // In some cases the span for an inference failure due to try
-            // conversion contains the antecedent expression as well as the `?`
-            Self::TryConversion { span: s, .. } => span.contains(s) && span.hi() == s.hi(),
-        }
-    }
-
-    fn attach_note(&self, err: &mut Diagnostic) {
-        match *self {
-            Self::TryConversion { pre_ty, post_ty, .. } => {
-                let intro = "`?` implicitly converts the error value";
-
-                let msg = match (pre_ty.is_ty_infer(), post_ty.is_ty_infer()) {
-                    (true, true) => format!("{} using the `From` trait", intro),
-                    (false, true) => {
-                        format!("{} into a type implementing `From<{}>`", intro, pre_ty)
-                    }
-                    (true, false) => {
-                        format!("{} into `{}` using the `From` trait", intro, post_ty)
-                    }
-                    (false, false) => {
-                        format!(
-                            "{} into `{}` using its implementation of `From<{}>`",
-                            intro, post_ty, pre_ty
-                        )
-                    }
-                };
-
-                err.note(&msg);
-            }
-        }
-    }
-}
-
-/// Suggest giving an appropriate return type to a closure expression.
-fn closure_return_type_suggestion(
-    err: &mut Diagnostic,
-    output: &FnRetTy<'_>,
-    body: &Body<'_>,
-    ret: &str,
-) {
-    let (arrow, post) = match output {
-        FnRetTy::DefaultReturn(_) => ("-> ", " "),
-        _ => ("", ""),
-    };
-    let suggestion = match body.value.kind {
-        ExprKind::Block(..) => vec![(output.span(), format!("{}{}{}", arrow, ret, post))],
-        _ => vec![
-            (output.span(), format!("{}{}{}{{ ", arrow, ret, post)),
-            (body.value.span.shrink_to_hi(), " }".to_string()),
-        ],
-    };
-    err.multipart_suggestion(
-        "give this closure an explicit return type without `_` placeholders",
-        suggestion,
-        Applicability::HasPlaceholders,
-    );
-}
-
-/// Given a closure signature, return a `String` containing a list of all its argument types.
-fn closure_args(fn_sig: &ty::PolyFnSig<'_>) -> String {
-    fn_sig
-        .inputs()
-        .skip_binder()
-        .iter()
-        .next()
-        .map(|args| {
-            args.tuple_fields().iter().map(|arg| arg.to_string()).collect::<Vec<_>>().join(", ")
-        })
-        .unwrap_or_default()
-}
+use std::iter;
 
 pub enum TypeAnnotationNeeded {
     /// ```compile_fail,E0282
@@ -296,9 +55,8 @@ pub struct InferenceDiagnosticsData {
 
 /// Data on the parent definition where a generic argument was declared.
 pub struct InferenceDiagnosticsParentData {
-    pub prefix: &'static str,
-    pub name: String,
-    pub def_id: DefId,
+    prefix: &'static str,
+    name: String,
 }
 
 pub enum UnderspecifiedArgKind {
@@ -306,52 +64,58 @@ pub enum UnderspecifiedArgKind {
     Const { is_parameter: bool },
 }
 
-impl UnderspecifiedArgKind {
-    fn descr(&self) -> &'static str {
-        match self {
-            Self::Type { .. } => "type",
-            Self::Const { .. } => "const",
-        }
-    }
-}
-
 impl InferenceDiagnosticsData {
     /// Generate a label for a generic argument which can't be inferred. When not
     /// much is known about the argument, `use_diag` may be used to describe the
     /// labeled value.
-    fn cannot_infer_msg(&self, use_diag: Option<&UseDiagnostic<'_>>) -> String {
+    fn cannot_infer_msg(&self) -> String {
         if self.name == "_" && matches!(self.kind, UnderspecifiedArgKind::Type { .. }) {
-            if let Some(use_diag) = use_diag {
-                return format!("cannot infer type of {}", use_diag.descr());
-            }
-
             return "cannot infer type".to_string();
         }
 
-        let suffix = match (&self.parent, use_diag) {
-            (Some(parent), _) => format!(" declared on the {} `{}`", parent.prefix, parent.name),
-            (None, Some(use_diag)) => format!(" in {}", use_diag.type_descr()),
-            (None, None) => String::new(),
+        let suffix = match &self.parent {
+            Some(parent) => parent.suffix_string(),
+            None => String::new(),
         };
 
         // For example: "cannot infer type for type parameter `T`"
         format!("cannot infer {} `{}`{}", self.kind.prefix_string(), self.name, suffix)
     }
+
+    fn where_x_is_specified(&self, in_type: Ty<'_>) -> String {
+        if in_type.is_ty_infer() {
+            String::new()
+        } else if self.name == "_" {
+            // FIXME: Consider specializing this message if there is a single `_`
+            // in the type.
+            ", where the placeholders `_` are specified".to_string()
+        } else {
+            format!(", where the {} `{}` is specified", self.kind.prefix_string(), self.name)
+        }
+    }
 }
 
 impl InferenceDiagnosticsParentData {
-    fn for_def_id(tcx: TyCtxt<'_>, def_id: DefId) -> Option<InferenceDiagnosticsParentData> {
-        let parent_def_id = tcx.parent(def_id);
-
+    fn for_parent_def_id(
+        tcx: TyCtxt<'_>,
+        parent_def_id: DefId,
+    ) -> Option<InferenceDiagnosticsParentData> {
         let parent_name =
             tcx.def_key(parent_def_id).disambiguated_data.data.get_opt_name()?.to_string();
 
         Some(InferenceDiagnosticsParentData {
             prefix: tcx.def_kind(parent_def_id).descr(parent_def_id),
             name: parent_name,
-            def_id: parent_def_id,
         })
     }
+
+    fn for_def_id(tcx: TyCtxt<'_>, def_id: DefId) -> Option<InferenceDiagnosticsParentData> {
+        Self::for_parent_def_id(tcx, tcx.parent(def_id))
+    }
+
+    fn suffix_string(&self) -> String {
+        format!(" declared on the {} `{}`", self.prefix, self.name)
+    }
 }
 
 impl UnderspecifiedArgKind {
@@ -364,6 +128,80 @@ fn prefix_string(&self) -> Cow<'static, str> {
     }
 }
 
+fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'_, 'tcx>, ns: Namespace) -> FmtPrinter<'a, 'tcx> {
+    let mut printer = FmtPrinter::new(infcx.tcx, ns);
+    let ty_getter = move |ty_vid| {
+        if infcx.probe_ty_var(ty_vid).is_ok() {
+            warn!("resolved ty var in error message");
+        }
+        if let TypeVariableOriginKind::TypeParameterDefinition(name, _) =
+            infcx.inner.borrow_mut().type_variables().var_origin(ty_vid).kind
+        {
+            Some(name.to_string())
+        } else {
+            None
+        }
+    };
+    printer.ty_infer_name_resolver = Some(Box::new(ty_getter));
+    let const_getter = move |ct_vid| {
+        if infcx.probe_const_var(ct_vid).is_ok() {
+            warn!("resolved const var in error message");
+        }
+        if let ConstVariableOriginKind::ConstParameterDefinition(name, _) =
+            infcx.inner.borrow_mut().const_unification_table().probe_value(ct_vid).origin.kind
+        {
+            return Some(name.to_string());
+        } else {
+            None
+        }
+    };
+    printer.const_infer_name_resolver = Some(Box::new(const_getter));
+    printer
+}
+
+fn ty_to_string<'tcx>(infcx: &InferCtxt<'_, 'tcx>, ty: Ty<'tcx>) -> String {
+    let printer = fmt_printer(infcx, Namespace::TypeNS);
+    let ty = infcx.resolve_vars_if_possible(ty);
+    match ty.kind() {
+        // We don't want the regular output for `fn`s because it includes its path in
+        // invalid pseudo-syntax, we want the `fn`-pointer output instead.
+        ty::FnDef(..) => ty.fn_sig(infcx.tcx).print(printer).unwrap().into_buffer(),
+        // FIXME: The same thing for closures, but this only works when the closure
+        // does not capture anything.
+        //
+        // We do have to hide the `extern "rust-call"` ABI in that case though,
+        // which is too much of a bother for now.
+        _ => ty.print(printer).unwrap().into_buffer(),
+    }
+}
+
+/// We don't want to directly use `ty_to_string` for closures as their type isn't really
+/// something users are familar with. Directly printing the `fn_sig` of closures also
+/// doesn't work as they actually use the "rust-call" API.
+fn closure_as_fn_str<'tcx>(infcx: &InferCtxt<'_, 'tcx>, ty: Ty<'tcx>) -> String {
+    let ty::Closure(_, substs) = ty.kind() else { unreachable!() };
+    let fn_sig = substs.as_closure().sig();
+    let args = fn_sig
+        .inputs()
+        .skip_binder()
+        .iter()
+        .next()
+        .map(|args| {
+            args.tuple_fields()
+                .iter()
+                .map(|arg| ty_to_string(infcx, arg))
+                .collect::<Vec<_>>()
+                .join(", ")
+        })
+        .unwrap_or_default();
+    let ret = if fn_sig.output().skip_binder().is_unit() {
+        String::new()
+    } else {
+        format!(" -> {}", ty_to_string(infcx, fn_sig.output().skip_binder()))
+    };
+    format!("fn({}){}", args, ret)
+}
+
 impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     /// Extracts data used by diagnostic for either types or constants
     /// which were stuck during inference.
@@ -400,79 +238,55 @@ pub fn extract_inference_diagnostics_data(
                 if let Some(highlight) = highlight {
                     printer.region_highlight_mode = highlight;
                 }
-                let name = ty.print(printer).unwrap().into_buffer();
                 InferenceDiagnosticsData {
-                    name,
+                    name: ty.print(printer).unwrap().into_buffer(),
                     span: None,
                     kind: UnderspecifiedArgKind::Type { prefix: ty.prefix_string(self.tcx) },
                     parent: None,
                 }
             }
             GenericArgKind::Const(ct) => {
-                match ct.val() {
-                    ty::ConstKind::Infer(InferConst::Var(vid)) => {
-                        let origin = self
-                            .inner
-                            .borrow_mut()
-                            .const_unification_table()
-                            .probe_value(vid)
-                            .origin;
-                        if let ConstVariableOriginKind::ConstParameterDefinition(name, def_id) =
-                            origin.kind
-                        {
-                            return InferenceDiagnosticsData {
-                                name: name.to_string(),
-                                span: Some(origin.span),
-                                kind: UnderspecifiedArgKind::Const { is_parameter: true },
-                                parent: InferenceDiagnosticsParentData::for_def_id(
-                                    self.tcx, def_id,
-                                ),
-                            };
-                        }
-
-                        debug_assert!(!origin.span.is_dummy());
-                        let mut printer = ty::print::FmtPrinter::new(self.tcx, Namespace::ValueNS);
-                        if let Some(highlight) = highlight {
-                            printer.region_highlight_mode = highlight;
-                        }
-                        let name = ct.print(printer).unwrap().into_buffer();
-                        InferenceDiagnosticsData {
-                            name,
+                if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.val() {
+                    let origin =
+                        self.inner.borrow_mut().const_unification_table().probe_value(vid).origin;
+                    if let ConstVariableOriginKind::ConstParameterDefinition(name, def_id) =
+                        origin.kind
+                    {
+                        return InferenceDiagnosticsData {
+                            name: name.to_string(),
                             span: Some(origin.span),
-                            kind: UnderspecifiedArgKind::Const { is_parameter: false },
-                            parent: None,
-                        }
+                            kind: UnderspecifiedArgKind::Const { is_parameter: true },
+                            parent: InferenceDiagnosticsParentData::for_def_id(self.tcx, def_id),
+                        };
                     }
-                    ty::ConstKind::Unevaluated(ty::Unevaluated { substs, .. }) => {
-                        assert!(substs.has_infer_types_or_consts());
-
-                        // FIXME: We only use the first inference variable we encounter in
-                        // `substs` here, this gives insufficiently informative diagnostics
-                        // in case there are multiple inference variables
-                        for s in substs.iter() {
-                            match s.unpack() {
-                                GenericArgKind::Type(t) => match t.kind() {
-                                    ty::Infer(_) => {
-                                        return self.extract_inference_diagnostics_data(s, None);
-                                    }
-                                    _ => {}
-                                },
-                                GenericArgKind::Const(c) => match c.val() {
-                                    ty::ConstKind::Infer(InferConst::Var(_)) => {
-                                        return self.extract_inference_diagnostics_data(s, None);
-                                    }
-                                    _ => {}
-                                },
-                                _ => {}
-                            }
-                        }
-                        bug!(
-                            "expected an inference variable in substs of unevaluated const {:?}",
-                            ct
-                        );
+
+                    debug_assert!(!origin.span.is_dummy());
+                    let mut printer = ty::print::FmtPrinter::new(self.tcx, Namespace::ValueNS);
+                    if let Some(highlight) = highlight {
+                        printer.region_highlight_mode = highlight;
+                    }
+                    InferenceDiagnosticsData {
+                        name: ct.print(printer).unwrap().into_buffer(),
+                        span: Some(origin.span),
+                        kind: UnderspecifiedArgKind::Const { is_parameter: false },
+                        parent: None,
+                    }
+                } else {
+                    // If we end up here the `FindInferSourceVisitor`
+                    // won't work, as its expected argument isn't an inference variable.
+                    //
+                    // FIXME: Ideally we should look into the generic constant
+                    // to figure out which inference var is actually unresolved so that
+                    // this path is unreachable.
+                    let mut printer = ty::print::FmtPrinter::new(self.tcx, Namespace::ValueNS);
+                    if let Some(highlight) = highlight {
+                        printer.region_highlight_mode = highlight;
                     }
-                    _ => {
-                        bug!("unexpect const: {:?}", ct);
+                    InferenceDiagnosticsData {
+                        name: ct.print(printer).unwrap().into_buffer(),
+                        span: None,
+                        kind: UnderspecifiedArgKind::Const { is_parameter: false },
+                        parent: None,
                     }
                 }
             }
@@ -480,482 +294,183 @@ pub fn extract_inference_diagnostics_data(
         }
     }
 
+    /// Used as a fallback in [InferCtxt::emit_inference_failure_err]
+    /// in case we weren't able to get a better error.
+    fn bad_inference_failure_err(
+        &self,
+        span: Span,
+        arg_data: InferenceDiagnosticsData,
+        error_code: TypeAnnotationNeeded,
+    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
+        let error_code = error_code.into();
+        let mut err = self.tcx.sess.struct_span_err_with_code(
+            span,
+            &format!("type annotations needed"),
+            error_code,
+        );
+        err.span_label(span, arg_data.cannot_infer_msg());
+        err
+    }
+
     pub fn emit_inference_failure_err(
         &self,
         body_id: Option<hir::BodyId>,
         span: Span,
         arg: GenericArg<'tcx>,
-        impl_candidates: Vec<ty::TraitRef<'tcx>>,
+        // FIXME(#94483): Either use this or remove it.
+        _impl_candidates: Vec<ty::TraitRef<'tcx>>,
         error_code: TypeAnnotationNeeded,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         let arg = self.resolve_vars_if_possible(arg);
         let arg_data = self.extract_inference_diagnostics_data(arg, None);
 
-        let mut local_visitor = FindHirNodeVisitor::new(&self, arg, span);
-        let ty_to_string = |ty: Ty<'tcx>| -> String {
-            let mut printer = ty::print::FmtPrinter::new(self.tcx, Namespace::TypeNS);
-            let ty_getter = move |ty_vid| {
-                if let TypeVariableOriginKind::TypeParameterDefinition(name, _) =
-                    self.inner.borrow_mut().type_variables().var_origin(ty_vid).kind
-                {
-                    Some(name.to_string())
-                } else {
-                    None
-                }
-            };
-            printer.ty_infer_name_resolver = Some(Box::new(ty_getter));
-            let const_getter = move |ct_vid| {
-                if let ConstVariableOriginKind::ConstParameterDefinition(name, _) = self
-                    .inner
-                    .borrow_mut()
-                    .const_unification_table()
-                    .probe_value(ct_vid)
-                    .origin
-                    .kind
-                {
-                    return Some(name.to_string());
-                } else {
-                    None
-                }
-            };
-            printer.const_infer_name_resolver = Some(Box::new(const_getter));
-
-            if let ty::FnDef(..) = ty.kind() {
-                // We don't want the regular output for `fn`s because it includes its path in
-                // invalid pseudo-syntax, we want the `fn`-pointer output instead.
-                ty.fn_sig(self.tcx).print(printer).unwrap().into_buffer()
-            } else {
-                ty.print(printer).unwrap().into_buffer()
-            }
+        let Some(typeck_results) = self.in_progress_typeck_results else {
+            // If we don't have any typeck results we're outside
+            // of a body, so we won't be able to get better info
+            // here.
+            return self.bad_inference_failure_err(span, arg_data, error_code);
         };
+        let typeck_results = typeck_results.borrow();
+        let typeck_results = &typeck_results;
 
+        let mut local_visitor = FindInferSourceVisitor::new(&self, typeck_results, arg);
         if let Some(body_id) = body_id {
             let expr = self.tcx.hir().expect_expr(body_id.hir_id);
+            debug!(?expr);
             local_visitor.visit_expr(expr);
         }
-        let err_span = if let Some(pattern) = local_visitor.found_arg_pattern {
-            pattern.span
-        } else if let Some(span) = arg_data.span {
-            // `span` here lets us point at `sum` instead of the entire right hand side expr:
-            // error[E0282]: type annotations needed
-            //  --> file2.rs:3:15
-            //   |
-            // 3 |     let _ = x.sum() as f64;
-            //   |               ^^^ cannot infer type for `S`
-            span
-        } else if let Some(ExprKind::MethodCall(segment, ..)) =
-            local_visitor.found_method_call.map(|e| &e.kind)
-        {
-            // Point at the call instead of the whole expression:
-            // error[E0284]: type annotations needed
-            //  --> file.rs:2:5
-            //   |
-            // 2 |     [Ok(2)].into_iter().collect()?;
-            //   |                         ^^^^^^^ cannot infer type
-            //   |
-            //   = note: cannot resolve `<_ as std::ops::Try>::Ok == _`
-            if span.contains(segment.ident.span) { segment.ident.span } else { span }
-        } else {
-            span
-        };
 
-        let is_named_and_not_impl_trait =
-            |ty: Ty<'_>| &ty.to_string() != "_" && !ty.is_impl_trait();
-
-        let ty_msg = match (local_visitor.found_node_ty, local_visitor.found_exact_method_call) {
-            (_, Some(_)) => String::new(),
-            (Some(ty), _) if ty.is_closure() => {
-                let ty::Closure(_, substs) = *ty.kind() else { unreachable!() };
-                let fn_sig = substs.as_closure().sig();
-                let args = closure_args(&fn_sig);
-                let ret = fn_sig.output().skip_binder().to_string();
-                format!(" for the closure `fn({}) -> {}`", args, ret)
-            }
-            (Some(ty), _) if is_named_and_not_impl_trait(ty) => {
-                let ty = ty_to_string(ty);
-                format!(" for `{}`", ty)
-            }
-            _ => String::new(),
+        let Some(InferSource { span, kind }) = local_visitor.infer_source else {
+            return self.bad_inference_failure_err(span, arg_data, error_code)
         };
 
-        // When `arg_data.name` corresponds to a type argument, show the path of the full type we're
-        // trying to infer. In the following example, `ty_msg` contains
-        // " for `std::result::Result<i32, E>`":
-        // ```
-        // error[E0282]: type annotations needed for `std::result::Result<i32, E>`
-        //  --> file.rs:L:CC
-        //   |
-        // L |     let b = Ok(4);
-        //   |         -   ^^ cannot infer type for `E` in `std::result::Result<i32, E>`
-        //   |         |
-        //   |         consider giving `b` the explicit type `std::result::Result<i32, E>`, where
-        //   |         the type parameter `E` is specified
-        // ```
         let error_code = error_code.into();
         let mut err = self.tcx.sess.struct_span_err_with_code(
-            err_span,
-            &format!("type annotations needed{}", ty_msg),
+            span,
+            &format!("type annotations needed{}", kind.ty_msg(self)),
             error_code,
         );
-
-        let use_diag = local_visitor.found_use_diagnostic.as_ref();
-        if let Some(use_diag) = use_diag && use_diag.applies_to(err_span) {
-            use_diag.attach_note(&mut err);
-        }
-
-        let param_type = arg_data.kind.descr();
-        let suffix = match local_visitor.found_node_ty {
-            Some(ty) if ty.is_closure() => {
-                let ty::Closure(_, substs) = *ty.kind() else { unreachable!() };
-                let fn_sig = substs.as_closure().sig();
-                let ret = fn_sig.output().skip_binder().to_string();
-
-                let closure_decl_and_body_id =
-                    local_visitor.found_closure.and_then(|closure| match &closure.kind {
-                        ExprKind::Closure(_, decl, body_id, ..) => Some((decl, *body_id)),
-                        _ => None,
-                    });
-
-                if let Some((decl, body_id)) = closure_decl_and_body_id {
-                    closure_return_type_suggestion(
-                        &mut err,
-                        &decl.output,
-                        self.tcx.hir().body(body_id),
-                        &ret,
-                    );
-                    // We don't want to give the other suggestions when the problem is the
-                    // closure return type.
-                    err.span_label(
-                        span,
-                        arg_data.cannot_infer_msg(use_diag.filter(|d| d.applies_to(span))),
-                    );
-                    return err;
-                }
-
-                // This shouldn't be reachable, but just in case we leave a reasonable fallback.
-                let args = closure_args(&fn_sig);
-                // This suggestion is incomplete, as the user will get further type inference
-                // errors due to the `_` placeholders and the introduction of `Box`, but it does
-                // nudge them in the right direction.
-                format!("a boxed closure type like `Box<dyn Fn({}) -> {}>`", args, ret)
+        match kind {
+            InferSourceKind::LetBinding { insert_span, pattern_name, ty } => {
+                let suggestion_msg = if let Some(name) = pattern_name {
+                    format!(
+                        "consider giving `{}` an explicit type{}",
+                        name,
+                        arg_data.where_x_is_specified(ty)
+                    )
+                } else {
+                    format!(
+                        "consider giving this pattern a type{}",
+                        arg_data.where_x_is_specified(ty)
+                    )
+                };
+                err.span_suggestion_verbose(
+                    insert_span,
+                    &suggestion_msg,
+                    format!(": {}", ty_to_string(self, ty)),
+                    Applicability::HasPlaceholders,
+                );
             }
-            Some(ty) if is_named_and_not_impl_trait(ty) && arg_data.name == "_" => {
-                let ty = ty_to_string(ty);
-                format!("the explicit type `{}`, with the {} parameters specified", ty, param_type)
+            InferSourceKind::ClosureArg { insert_span, ty } => {
+                err.span_suggestion_verbose(
+                    insert_span,
+                    &format!(
+                        "consider giving this closure parameter an explicit type{}",
+                        arg_data.where_x_is_specified(ty)
+                    ),
+                    format!(": {}", ty_to_string(self, ty)),
+                    Applicability::HasPlaceholders,
+                );
             }
-            Some(ty) if is_named_and_not_impl_trait(ty) && ty.to_string() != arg_data.name => {
-                let ty = ResolvedTypeParamEraser::new(self.tcx).fold_ty(ty);
-                let ty = ErrTypeParamEraser(self.tcx).fold_ty(ty);
-                let ty = ty_to_string(ty);
-                format!(
-                    "the explicit type `{}`, where the {} parameter `{}` is specified",
-                    ty, param_type, arg_data.name,
-                )
+            InferSourceKind::GenericArg {
+                insert_span,
+                argument_index,
+                generics_def_id,
+                def_id: _,
+                generic_args,
+            } => {
+                let generics = self.tcx.generics_of(generics_def_id);
+                let is_type = matches!(arg.unpack(), GenericArgKind::Type(_));
+
+                let cannot_infer_msg = format!(
+                    "cannot infer {} of the {} parameter `{}`{}",
+                    if is_type { "type" } else { "the value" },
+                    if is_type { "type" } else { "const" },
+                    generics.params[argument_index].name,
+                    // We use the `generics_def_id` here, as even when suggesting `None::<T>`,
+                    // the type parameter `T` was still declared on the enum, not on the
+                    // variant.
+                    InferenceDiagnosticsParentData::for_parent_def_id(self.tcx, generics_def_id)
+                        .map_or(String::new(), |parent| parent.suffix_string()),
+                );
+
+                err.span_label(span, cannot_infer_msg);
+
+                let printer = fmt_printer(self, Namespace::TypeNS);
+                let args = printer.comma_sep(generic_args.iter().copied()).unwrap().into_buffer();
+                err.span_suggestion_verbose(
+                    insert_span,
+                    &format!("consider specifying the generic argument{}", pluralize!(args.len()),),
+                    format!("::<{}>", args),
+                    Applicability::HasPlaceholders,
+                );
             }
-            _ => "a type".to_string(),
-        };
+            InferSourceKind::FullyQualifiedMethodCall { receiver, successor, substs, def_id } => {
+                let printer = fmt_printer(self, Namespace::ValueNS);
+                let def_path = printer.print_def_path(def_id, substs).unwrap().into_buffer();
+
+                // We only care about whether we have to add `&` or `&mut ` for now.
+                // This is the case if the last adjustment is a borrow and the
+                // first adjustment was not a builtin deref.
+                let adjustment = match typeck_results.expr_adjustments(receiver) {
+                    [
+                        Adjustment { kind: Adjust::Deref(None), target: _ },
+                        ..,
+                        Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), target: _ },
+                    ] => "",
+                    [
+                        ..,
+                        Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(_, mut_)), target: _ },
+                    ] => match mut_ {
+                        AutoBorrowMutability::Mut { .. } => "&mut ",
+                        AutoBorrowMutability::Not => "&",
+                    },
+                    _ => "",
+                };
 
-        if let Some(e) = local_visitor.found_exact_method_call {
-            if let ExprKind::MethodCall(segment, ..) = &e.kind {
-                // Suggest specifying type params or point out the return type of the call:
-                //
-                // error[E0282]: type annotations needed
-                //   --> $DIR/type-annotations-needed-expr.rs:2:39
-                //    |
-                // LL |     let _ = x.into_iter().sum() as f64;
-                //    |                           ^^^
-                //    |                           |
-                //    |                           cannot infer type for `S`
-                //    |                           help: consider specifying the type argument in
-                //    |                           the method call: `sum::<S>`
-                //    |
-                //    = note: type must be known at this point
-                //
-                // or
-                //
-                // error[E0282]: type annotations needed
-                //   --> $DIR/issue-65611.rs:59:20
-                //    |
-                // LL |     let x = buffer.last().unwrap().0.clone();
-                //    |             -------^^^^--
-                //    |             |      |
-                //    |             |      cannot infer type for `T`
-                //    |             this method call resolves to `std::option::Option<&T>`
-                //    |
-                //    = note: type must be known at this point
-                self.annotate_method_call(segment, e, &mut err);
-            }
-        } else if let Some(pattern) = local_visitor.found_arg_pattern {
-            // We don't want to show the default label for closures.
-            //
-            // So, before clearing, the output would look something like this:
-            // ```
-            // let x = |_| {  };
-            //          -  ^^^^ cannot infer type for `[_; 0]`
-            //          |
-            //          consider giving this closure parameter a type
-            // ```
-            //
-            // After clearing, it looks something like this:
-            // ```
-            // let x = |_| {  };
-            //          ^ consider giving this closure parameter the type `[_; 0]`
-            //            with the type parameter `_` specified
-            // ```
-            err.span_label(
-                pattern.span,
-                format!("consider giving this closure parameter {}", suffix),
-            );
-        } else if let Some(pattern) = local_visitor.found_local_pattern {
-            let msg = if let Some(simple_ident) = pattern.simple_ident() {
-                match pattern.span.desugaring_kind() {
-                    None => format!("consider giving `{}` {}", simple_ident, suffix),
-                    Some(_) => format!("this needs {}", suffix),
-                }
-            } else {
-                format!("consider giving this pattern {}", suffix)
-            };
-            err.span_label(pattern.span, msg);
-        } else if let Some(e) = local_visitor.found_method_call {
-            if let ExprKind::MethodCall(segment, exprs, _) = &e.kind {
-                // Suggest impl candidates:
-                //
-                // error[E0283]: type annotations needed
-                //   --> $DIR/E0283.rs:35:24
-                //    |
-                // LL |     let bar = foo_impl.into() * 1u32;
-                //    |               ---------^^^^--
-                //    |               |        |
-                //    |               |        cannot infer type for type parameter `T` declared on the trait `Into`
-                //    |               this method call resolves to `T`
-                //    |               help: specify type like: `<Impl as Into<u32>>::into(foo_impl)`
-                //    |
-                //    = note: cannot satisfy `Impl: Into<_>`
-                debug!(?segment);
-                if !impl_candidates.is_empty() && e.span.contains(span)
-                    && let Some(expr) = exprs.first()
-                    && let ExprKind::Path(hir::QPath::Resolved(_, path)) = expr.kind
-                    && let [_] = path.segments
-                {
-                    let mut eraser = TypeParamEraser(self.tcx);
-                    let candidate_len = impl_candidates.len();
-                    let mut suggestions: Vec<_> = impl_candidates.iter().filter_map(|candidate| {
-                        let trait_item = self.tcx
-                            .associated_items(candidate.def_id)
-                            .find_by_name_and_kind(
-                                self.tcx,
-                                segment.ident,
-                                ty::AssocKind::Fn,
-                                candidate.def_id
-                            );
-                        if trait_item.is_none() {
-                            return None;
-                        }
-                        let prefix = if let Some(trait_item) = trait_item
-                            && let Some(trait_m) = trait_item.def_id.as_local()
-                            && let hir::TraitItemKind::Fn(fn_, _) = &self.tcx.hir().trait_item(hir::TraitItemId { def_id: trait_m }).kind
-                        {
-                            match fn_.decl.implicit_self {
-                                hir::ImplicitSelfKind::ImmRef => "&",
-                                hir::ImplicitSelfKind::MutRef => "&mut ",
-                                _ => "",
-                            }
-                        } else {
-                            ""
-                        };
-                        let candidate = candidate.super_fold_with(&mut eraser);
-                        Some(vec![
-                            (expr.span.shrink_to_lo(), format!("{}::{}({}", candidate, segment.ident, prefix)),
-                            if exprs.len() == 1 {
-                                (expr.span.shrink_to_hi().with_hi(e.span.hi()), ")".to_string())
-                            } else {
-                                (expr.span.shrink_to_hi().with_hi(exprs[1].span.lo()), ", ".to_string())
-                            },
-                        ])
-                    }).collect();
-                    suggestions.sort_by(|a, b| a[0].1.cmp(&b[0].1));
-                    if !suggestions.is_empty() {
-                        err.multipart_suggestions(
-                            &format!(
-                                "use the fully qualified path for the potential candidate{}",
-                                pluralize!(candidate_len),
-                            ),
-                            suggestions.into_iter(),
-                            Applicability::MaybeIncorrect,
-                        );
-                    }
-                }
-                // Suggest specifying type params or point out the return type of the call:
-                //
-                // error[E0282]: type annotations needed
-                //   --> $DIR/type-annotations-needed-expr.rs:2:39
-                //    |
-                // LL |     let _ = x.into_iter().sum() as f64;
-                //    |                           ^^^
-                //    |                           |
-                //    |                           cannot infer type for `S`
-                //    |                           help: consider specifying the type argument in
-                //    |                           the method call: `sum::<S>`
-                //    |
-                //    = note: type must be known at this point
-                //
-                // or
-                //
-                // error[E0282]: type annotations needed
-                //   --> $DIR/issue-65611.rs:59:20
-                //    |
-                // LL |     let x = buffer.last().unwrap().0.clone();
-                //    |             -------^^^^--
-                //    |             |      |
-                //    |             |      cannot infer type for `T`
-                //    |             this method call resolves to `std::option::Option<&T>`
-                //    |
-                //    = note: type must be known at this point
-                self.annotate_method_call(segment, e, &mut err);
+                let suggestion = vec![
+                    (receiver.span.shrink_to_lo(), format!("{def_path}({adjustment}")),
+                    (receiver.span.shrink_to_hi().with_hi(successor.1), successor.0.to_string()),
+                ];
+                err.multipart_suggestion_verbose(
+                    "try using a fully qualified path to specify the expected types",
+                    suggestion,
+                    Applicability::HasPlaceholders,
+                );
             }
-        } else if let Some(scrutinee) = local_visitor.found_for_loop_iter {
-            err.span_label(
-                scrutinee.span,
-                "the element type for this iterator is not specified".to_string(),
-            );
-        }
-        // Instead of the following:
-        // error[E0282]: type annotations needed
-        //  --> file2.rs:3:15
-        //   |
-        // 3 |     let _ = x.sum() as f64;
-        //   |             --^^^--------- cannot infer type for `S`
-        //   |
-        //   = note: type must be known at this point
-        // We want:
-        // error[E0282]: type annotations needed
-        //  --> file2.rs:3:15
-        //   |
-        // 3 |     let _ = x.sum() as f64;
-        //   |               ^^^ cannot infer type for `S`
-        //   |
-        //   = note: type must be known at this point
-        let span = arg_data.span.unwrap_or(err_span);
-
-        // Avoid multiple labels pointing at `span`.
-        if !err
-            .span
-            .span_labels()
-            .iter()
-            .any(|span_label| span_label.label.is_some() && span_label.span == span)
-            && local_visitor.found_arg_pattern.is_none()
-        {
-            // FIXME(const_generics): we would like to handle const arguments
-            // as part of the normal diagnostics flow below, but there appear to
-            // be subtleties in doing so, so for now we special-case const args
-            // here.
-            if let (UnderspecifiedArgKind::Const { .. }, Some(parent_data)) =
-                (&arg_data.kind, &arg_data.parent)
-            {
-                // (#83606): Do not emit a suggestion if the parent has an `impl Trait`
-                // as an argument otherwise it will cause the E0282 error.
-                if !self.tcx.generics_of(parent_data.def_id).has_impl_trait()
-                    || self.tcx.features().explicit_generic_args_with_impl_trait
-                {
-                    err.span_suggestion_verbose(
-                        span,
-                        "consider specifying the const argument",
-                        format!("{}::<{}>", parent_data.name, arg_data.name),
-                        Applicability::MaybeIncorrect,
-                    );
-                }
+            InferSourceKind::ClosureReturn { ty, data, should_wrap_expr } => {
+                let ret = ty_to_string(self, ty);
+                let (arrow, post) = match data {
+                    FnRetTy::DefaultReturn(_) => ("-> ", " "),
+                    _ => ("", ""),
+                };
+                let suggestion = match should_wrap_expr {
+                    Some(end_span) => vec![
+                        (data.span(), format!("{}{}{}{{ ", arrow, ret, post)),
+                        (end_span, " }".to_string()),
+                    ],
+                    None => vec![(data.span(), format!("{}{}{}", arrow, ret, post))],
+                };
+                err.multipart_suggestion_verbose(
+                    "try giving this closure an explicit return type",
+                    suggestion,
+                    Applicability::HasPlaceholders,
+                );
             }
-
-            self.report_ambiguous_type_parameter(&mut err, arg);
-            err.span_label(
-                span,
-                arg_data.cannot_infer_msg(use_diag.filter(|d| d.applies_to(span))),
-            );
         }
-
         err
     }
 
-    fn trait_def_from_hir_fn(&self, hir_id: hir::HirId) -> Option<DefId> {
-        // The DefId will be the method's trait item ID unless this is an inherent impl
-        if let Some((DefKind::AssocFn, def_id)) =
-            self.in_progress_typeck_results?.borrow().type_dependent_def(hir_id)
-        {
-            let parent_def_id = self.tcx.parent(def_id);
-            return self.tcx.is_trait(parent_def_id).then_some(parent_def_id);
-        }
-
-        None
-    }
-
-    /// If the `FnSig` for the method call can be found and type arguments are identified as
-    /// needed, suggest annotating the call, otherwise point out the resulting type of the call.
-    fn annotate_method_call(
-        &self,
-        segment: &hir::PathSegment<'_>,
-        e: &Expr<'_>,
-        err: &mut Diagnostic,
-    ) {
-        if let (Some(typeck_results), None) = (self.in_progress_typeck_results, &segment.args) {
-            let borrow = typeck_results.borrow();
-            if let Some((DefKind::AssocFn, did)) = borrow.type_dependent_def(e.hir_id) {
-                let generics = self.tcx.generics_of(did);
-                if !generics.params.is_empty() && !generics.has_impl_trait() {
-                    err.span_suggestion_verbose(
-                        segment.ident.span.shrink_to_hi(),
-                        &format!(
-                            "consider specifying the type argument{} in the method call",
-                            pluralize!(generics.params.len()),
-                        ),
-                        format!(
-                            "::<{}>",
-                            generics
-                                .params
-                                .iter()
-                                .map(|p| p.name.to_string())
-                                .collect::<Vec<String>>()
-                                .join(", ")
-                        ),
-                        Applicability::HasPlaceholders,
-                    );
-                } else {
-                    let sig = self.tcx.fn_sig(did);
-                    let bound_output = sig.output();
-                    let output = bound_output.skip_binder();
-                    err.span_label(e.span, &format!("this method call resolves to `{}`", output));
-                    let kind = output.kind();
-                    if let ty::Projection(proj) = kind {
-                        if let Some(span) = self.tcx.hir().span_if_local(proj.item_def_id) {
-                            err.span_label(span, &format!("`{}` defined here", output));
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    fn report_ambiguous_type_parameter(&self, err: &mut Diagnostic, arg: GenericArg<'tcx>) {
-        if let GenericArgKind::Type(ty) = arg.unpack()
-            && let ty::Infer(ty::TyVar(ty_vid)) = *ty.kind()
-        {
-            let mut inner = self.inner.borrow_mut();
-            let ty_vars = &inner.type_variables();
-            let var_origin = ty_vars.var_origin(ty_vid);
-            if let TypeVariableOriginKind::TypeParameterDefinition(_, Some(def_id)) =
-                var_origin.kind
-                && let Some(parent_def_id) = self.tcx.parent(def_id).as_local()
-                && let Some(node) = self.tcx.hir().find_by_def_id(parent_def_id)
-            {
-                match node {
-                    hir::Node::Item(item) if matches!(item.kind, hir::ItemKind::Impl(_) | hir::ItemKind::Fn(..)) => (),
-                    hir::Node::ImplItem(impl_item) if matches!(impl_item.kind, hir::ImplItemKind::Fn(..)) => (),
-                    _ => return,
-                }
-                err.span_help(self.tcx.def_span(def_id), "type parameter declared here");
-            }
-        }
-    }
-
     pub fn need_type_info_err_in_generator(
         &self,
         kind: hir::GeneratorKind,
@@ -972,136 +487,564 @@ pub fn need_type_info_err_in_generator(
             "type inside {} must be known in this context",
             kind,
         );
-        err.span_label(span, data.cannot_infer_msg(None));
+        err.span_label(span, data.cannot_infer_msg());
         err
     }
 }
 
-/// Turn *resolved* type params into `[type error]` to signal we don't want to display them. After
-/// performing that replacement, we'll turn all remaining infer type params to use their name from
-/// their definition, and replace all the `[type error]`s back to being infer so they display in
-/// the output as `_`. If we didn't go through `[type error]`, we would either show all type params
-/// by their name *or* `_`, neither of which is desirable: we want to show all types that we could
-/// infer as `_` to reduce verbosity and avoid telling the user about unnecessary type annotations.
-struct ResolvedTypeParamEraser<'tcx> {
-    tcx: TyCtxt<'tcx>,
-    level: usize,
+#[derive(Debug)]
+struct InferSource<'tcx> {
+    span: Span,
+    kind: InferSourceKind<'tcx>,
 }
 
-impl<'tcx> ResolvedTypeParamEraser<'tcx> {
-    fn new(tcx: TyCtxt<'tcx>) -> Self {
-        ResolvedTypeParamEraser { tcx, level: 0 }
-    }
+#[derive(Debug)]
+enum InferSourceKind<'tcx> {
+    LetBinding {
+        insert_span: Span,
+        pattern_name: Option<Ident>,
+        ty: Ty<'tcx>,
+    },
+    ClosureArg {
+        insert_span: Span,
+        ty: Ty<'tcx>,
+    },
+    GenericArg {
+        insert_span: Span,
+        argument_index: usize,
+        generics_def_id: DefId,
+        def_id: DefId,
+        generic_args: &'tcx [GenericArg<'tcx>],
+    },
+    FullyQualifiedMethodCall {
+        receiver: &'tcx Expr<'tcx>,
+        /// If the method has other arguments, this is ", " and the start of the first argument,
+        /// while for methods without arguments this is ")" and the end of the method call.
+        successor: (&'static str, BytePos),
+        substs: SubstsRef<'tcx>,
+        def_id: DefId,
+    },
+    ClosureReturn {
+        ty: Ty<'tcx>,
+        data: &'tcx FnRetTy<'tcx>,
+        should_wrap_expr: Option<Span>,
+    },
+}
 
-    /// Replace not yet inferred const params with their def name.
-    fn replace_infers(&self, c: Const<'tcx>, index: u32, name: Symbol) -> Const<'tcx> {
-        match c.val() {
-            ty::ConstKind::Infer(..) => self.tcx().mk_const_param(index, name, c.ty()),
-            _ => c,
+impl<'tcx> InferSourceKind<'tcx> {
+    fn ty_msg(&self, infcx: &InferCtxt<'_, 'tcx>) -> String {
+        match *self {
+            InferSourceKind::LetBinding { ty, .. }
+            | InferSourceKind::ClosureArg { ty, .. }
+            | InferSourceKind::ClosureReturn { ty, .. } => {
+                if ty.is_closure() {
+                    format!(" for the closure `{}`", closure_as_fn_str(infcx, ty))
+                } else if !ty.is_ty_infer() {
+                    format!(" for `{}`", ty_to_string(infcx, ty))
+                } else {
+                    String::new()
+                }
+            }
+            // FIXME: We should be able to add some additional info here.
+            InferSourceKind::GenericArg { .. }
+            | InferSourceKind::FullyQualifiedMethodCall { .. } => String::new(),
         }
     }
 }
 
-impl<'tcx> TypeFolder<'tcx> for ResolvedTypeParamEraser<'tcx> {
-    fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
-        self.tcx
+struct InsertableGenericArgs<'tcx> {
+    insert_span: Span,
+    substs: SubstsRef<'tcx>,
+    generics_def_id: DefId,
+    def_id: DefId,
+}
+
+/// A visitor which searches for the "best" spot to use in the inference error.
+///
+/// For this it walks over the hir body and tries to check all places where
+/// inference variables could be bound.
+///
+/// While doing so, the currently best spot is stored in `infer_source`.
+/// For details on how we rank spots, see [Self::source_cost]
+struct FindInferSourceVisitor<'a, 'tcx> {
+    infcx: &'a InferCtxt<'a, 'tcx>,
+    typeck_results: &'a TypeckResults<'tcx>,
+
+    target: GenericArg<'tcx>,
+
+    attempt: usize,
+    infer_source_cost: usize,
+    infer_source: Option<InferSource<'tcx>>,
+}
+
+impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
+    fn new(
+        infcx: &'a InferCtxt<'a, 'tcx>,
+        typeck_results: &'a TypeckResults<'tcx>,
+        target: GenericArg<'tcx>,
+    ) -> Self {
+        FindInferSourceVisitor {
+            infcx,
+            typeck_results,
+
+            target,
+
+            attempt: 0,
+            infer_source_cost: usize::MAX,
+            infer_source: None,
+        }
     }
-    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
-        self.level += 1;
-        let t = match t.kind() {
-            // We'll hide this type only if all its type params are hidden as well.
-            ty::Adt(def, substs) => {
-                let generics = self.tcx().generics_of(def.did());
-                // Account for params with default values, like `Vec`, where we
-                // want to show `Vec<T>`, not `Vec<T, _>`. If we replaced that
-                // subst, then we'd get the incorrect output, so we passthrough.
-                let substs: Vec<_> = substs
-                    .iter()
-                    .zip(generics.params.iter())
-                    .map(|(subst, param)| match &(subst.unpack(), &param.kind) {
-                        (_, ty::GenericParamDefKind::Type { has_default: true, .. }) => subst,
-                        (crate::infer::GenericArgKind::Const(c), _) => {
-                            self.replace_infers(*c, param.index, param.name).into()
-                        }
-                        _ => subst.super_fold_with(self),
-                    })
-                    .collect();
-                let should_keep = |subst: &GenericArg<'_>| match subst.unpack() {
-                    ty::subst::GenericArgKind::Type(t) => match t.kind() {
-                        ty::Error(_) => false,
-                        _ => true,
-                    },
-                    // Account for `const` params here, otherwise `doesnt_infer.rs`
-                    // shows `_` instead of `Foo<{ _: u32 }>`
-                    ty::subst::GenericArgKind::Const(_) => true,
-                    _ => false,
+
+    /// Computes cost for the given source.
+    ///
+    /// Sources with a small cost are prefer and should result
+    /// in a clearer and idiomatic suggestion.
+    fn source_cost(&self, source: &InferSource<'tcx>) -> usize {
+        let tcx = self.infcx.tcx;
+
+        fn arg_cost<'tcx>(arg: GenericArg<'tcx>) -> usize {
+            match arg.unpack() {
+                GenericArgKind::Lifetime(_) => 0, // erased
+                GenericArgKind::Type(ty) => ty_cost(ty),
+                GenericArgKind::Const(_) => 3, // some non-zero value
+            }
+        }
+        fn ty_cost<'tcx>(ty: Ty<'tcx>) -> usize {
+            match ty.kind() {
+                ty::Closure(..) => 100,
+                ty::FnDef(..) => 20,
+                ty::FnPtr(..) => 10,
+                ty::Infer(..) => 0,
+                _ => 1,
+            }
+        }
+
+        // The sources are listed in order of preference here.
+        match source.kind {
+            InferSourceKind::LetBinding { ty, .. } => ty_cost(ty),
+            InferSourceKind::ClosureArg { ty, .. } => 5 + ty_cost(ty),
+            InferSourceKind::GenericArg { def_id, generic_args, .. } => {
+                let variant_cost = match tcx.def_kind(def_id) {
+                    DefKind::Variant | DefKind::Ctor(CtorOf::Variant, _) => 15, // `None::<u32>` and friends are ugly.
+                    _ => 12,
                 };
-                if self.level == 1 || substs.iter().any(should_keep) {
-                    let substs = self.tcx().intern_substs(&substs[..]);
-                    self.tcx().mk_ty(ty::Adt(*def, substs))
-                } else {
-                    self.tcx().ty_error()
+                variant_cost + generic_args.iter().map(|&arg| arg_cost(arg)).sum::<usize>()
+            }
+            InferSourceKind::FullyQualifiedMethodCall { substs, .. } => {
+                20 + substs.iter().map(|arg| arg_cost(arg)).sum::<usize>()
+            }
+            InferSourceKind::ClosureReturn { ty, should_wrap_expr, .. } => {
+                30 + ty_cost(ty) + if should_wrap_expr.is_some() { 10 } else { 0 }
+            }
+        }
+    }
+
+    /// Uses `fn source_cost` to determine whether this inference source is preferable to
+    /// previous sources. We generally prefer earlier sources.
+    #[instrument(level = "debug", skip(self))]
+    fn update_infer_source(&mut self, new_source: InferSource<'tcx>) {
+        let cost = self.source_cost(&new_source) + self.attempt;
+        self.attempt += 1;
+        if cost < self.infer_source_cost {
+            self.infer_source_cost = cost;
+            self.infer_source = Some(new_source);
+        }
+    }
+
+    fn opt_node_type(&self, hir_id: HirId) -> Option<Ty<'tcx>> {
+        let ty = self.typeck_results.node_type_opt(hir_id);
+        self.infcx.resolve_vars_if_possible(ty)
+    }
+
+    // Check whether this generic argument is the inference variable we
+    // are looking for.
+    fn generic_arg_is_target(&self, arg: GenericArg<'tcx>) -> bool {
+        if arg == self.target {
+            return true;
+        }
+
+        match (arg.unpack(), self.target.unpack()) {
+            (GenericArgKind::Type(inner_ty), GenericArgKind::Type(target_ty)) => {
+                use ty::{Infer, TyVar};
+                match (inner_ty.kind(), target_ty.kind()) {
+                    (&Infer(TyVar(a_vid)), &Infer(TyVar(b_vid))) => {
+                        self.infcx.inner.borrow_mut().type_variables().sub_unified(a_vid, b_vid)
+                    }
+                    _ => false,
+                }
+            }
+            (GenericArgKind::Const(inner_ct), GenericArgKind::Const(target_ct)) => {
+                use ty::InferConst::*;
+                match (inner_ct.val(), target_ct.val()) {
+                    (ty::ConstKind::Infer(Var(a_vid)), ty::ConstKind::Infer(Var(b_vid))) => self
+                        .infcx
+                        .inner
+                        .borrow_mut()
+                        .const_unification_table()
+                        .unioned(a_vid, b_vid),
+                    _ => false,
+                }
+            }
+            _ => false,
+        }
+    }
+
+    /// Does this generic argument contain our target inference variable
+    /// in a way which can be written by the user.
+    fn generic_arg_contains_target(&self, arg: GenericArg<'tcx>) -> bool {
+        let mut walker = arg.walk();
+        while let Some(inner) = walker.next() {
+            if self.generic_arg_is_target(inner) {
+                return true;
+            }
+            match inner.unpack() {
+                GenericArgKind::Lifetime(_) => {}
+                GenericArgKind::Type(ty) => {
+                    if matches!(ty.kind(), ty::Opaque(..) | ty::Closure(..) | ty::Generator(..)) {
+                        // Opaque types can't be named by the user right now.
+                        //
+                        // Both the generic arguments of closures and generators can
+                        // also not be named. We may want to only look into the closure
+                        // signature in case it has no captures, as that can be represented
+                        // using `fn(T) -> R`.
+
+                        // FIXME(type_alias_impl_trait): These opaque types
+                        // can actually be named, so it would make sense to
+                        // adjust this case and add a test for it.
+                        walker.skip_current_subtree();
+                    }
+                }
+                GenericArgKind::Const(ct) => {
+                    if matches!(ct.val(), ty::ConstKind::Unevaluated(..)) {
+                        // You can't write the generic arguments for
+                        // unevaluated constants.
+                        walker.skip_current_subtree();
+                    }
                 }
             }
-            ty::Ref(_, ty, _) => {
-                let ty = self.fold_ty(*ty);
-                match ty.kind() {
-                    // Avoid `&_`, these can be safely presented as `_`.
-                    ty::Error(_) => self.tcx().ty_error(),
-                    _ => t.super_fold_with(self),
+        }
+        false
+    }
+
+    fn expr_inferred_subst_iter(
+        &self,
+        expr: &'tcx hir::Expr<'tcx>,
+    ) -> Box<dyn Iterator<Item = InsertableGenericArgs<'tcx>> + 'a> {
+        let tcx = self.infcx.tcx;
+        match expr.kind {
+            hir::ExprKind::Path(ref path) => {
+                if let Some(substs) = self.typeck_results.node_substs_opt(expr.hir_id) {
+                    return self.path_inferred_subst_iter(expr.hir_id, substs, path);
                 }
             }
-            // We could account for `()` if we wanted to replace it, but it's assured to be short.
-            ty::Tuple(_)
-            | ty::Slice(_)
-            | ty::RawPtr(_)
-            | ty::FnDef(..)
-            | ty::FnPtr(_)
-            | ty::Opaque(..)
-            | ty::Projection(_)
-            | ty::Never => t.super_fold_with(self),
-            ty::Array(ty, c) => {
-                self.tcx().mk_ty(ty::Array(self.fold_ty(*ty), self.replace_infers(*c, 0, sym::N)))
+            hir::ExprKind::Struct(path, _, _) => {
+                if let Some(ty) = self.opt_node_type(expr.hir_id) {
+                    if let ty::Adt(_, substs) = ty.kind() {
+                        return self.path_inferred_subst_iter(expr.hir_id, substs, path);
+                    }
+                }
+            }
+            hir::ExprKind::MethodCall(segment, _, _) => {
+                if let Some(def_id) = self.typeck_results.type_dependent_def_id(expr.hir_id) {
+                    let generics = tcx.generics_of(def_id);
+                    let insertable: Option<_> = try {
+                        if generics.has_impl_trait() {
+                            None?
+                        }
+                        let substs = self.typeck_results.node_substs_opt(expr.hir_id)?;
+                        let span = tcx.hir().span(segment.hir_id?);
+                        let insert_span = segment.ident.span.shrink_to_hi().with_hi(span.hi());
+                        InsertableGenericArgs {
+                            insert_span,
+                            substs,
+                            generics_def_id: def_id,
+                            def_id,
+                        }
+                    };
+                    return Box::new(insertable.into_iter());
+                }
+            }
+            _ => {}
+        }
+
+        Box::new(iter::empty())
+    }
+
+    fn resolved_path_inferred_subst_iter(
+        &self,
+        path: &'tcx hir::Path<'tcx>,
+        substs: SubstsRef<'tcx>,
+    ) -> impl Iterator<Item = InsertableGenericArgs<'tcx>> + 'a {
+        let tcx = self.infcx.tcx;
+        // The last segment of a path often has `Res::Err` and the
+        // correct `Res` is the one of the whole path.
+        //
+        // FIXME: We deal with that one separately for now,
+        // would be good to remove this special case.
+        let last_segment_using_path_data: Option<_> = try {
+            let generics_def_id = tcx.res_generics_def_id(path.res)?;
+            let generics = tcx.generics_of(generics_def_id);
+            if generics.has_impl_trait() {
+                None?
+            }
+            let insert_span =
+                path.segments.last().unwrap().ident.span.shrink_to_hi().with_hi(path.span.hi());
+            InsertableGenericArgs {
+                insert_span,
+                substs,
+                generics_def_id,
+                def_id: path.res.def_id(),
             }
-            // We don't want to hide type params that haven't been resolved yet.
-            // This would be the type that will be written out with the type param
-            // name in the output.
-            ty::Infer(_) => t,
-            // We don't want to hide the outermost type, only its type params.
-            _ if self.level == 1 => t.super_fold_with(self),
-            // Hide this type
-            _ => self.tcx().ty_error(),
         };
-        self.level -= 1;
-        t
+
+        path.segments
+            .iter()
+            .filter_map(move |segment| {
+                let res = segment.res?;
+                let generics_def_id = tcx.res_generics_def_id(res)?;
+                let generics = tcx.generics_of(generics_def_id);
+                if generics.has_impl_trait() {
+                    return None;
+                }
+                let span = tcx.hir().span(segment.hir_id?);
+                let insert_span = segment.ident.span.shrink_to_hi().with_hi(span.hi());
+                Some(InsertableGenericArgs {
+                    insert_span,
+                    substs,
+                    generics_def_id,
+                    def_id: res.def_id(),
+                })
+            })
+            .chain(last_segment_using_path_data)
+    }
+
+    fn path_inferred_subst_iter(
+        &self,
+        hir_id: HirId,
+        substs: SubstsRef<'tcx>,
+        qpath: &'tcx hir::QPath<'tcx>,
+    ) -> Box<dyn Iterator<Item = InsertableGenericArgs<'tcx>> + 'a> {
+        let tcx = self.infcx.tcx;
+        match qpath {
+            hir::QPath::Resolved(_self_ty, path) => {
+                Box::new(self.resolved_path_inferred_subst_iter(path, substs))
+            }
+            hir::QPath::TypeRelative(ty, segment) => {
+                let Some(def_id) = self.typeck_results.type_dependent_def_id(hir_id) else {
+                    return Box::new(iter::empty());
+                };
+
+                let generics = tcx.generics_of(def_id);
+                let segment: Option<_> = try {
+                    if !segment.infer_args || generics.has_impl_trait() {
+                        None?;
+                    }
+                    let span = tcx.hir().span(segment.hir_id?);
+                    let insert_span = segment.ident.span.shrink_to_hi().with_hi(span.hi());
+                    InsertableGenericArgs { insert_span, substs, generics_def_id: def_id, def_id }
+                };
+
+                let parent_def_id = generics.parent.unwrap();
+                if tcx.def_kind(parent_def_id) == DefKind::Impl {
+                    let parent_ty = tcx.bound_type_of(parent_def_id).subst(tcx, substs);
+                    match (parent_ty.kind(), &ty.kind) {
+                        (
+                            ty::Adt(def, substs),
+                            hir::TyKind::Path(hir::QPath::Resolved(_self_ty, path)),
+                        ) => {
+                            if tcx.res_generics_def_id(path.res) != Some(def.did()) {
+                                bug!(
+                                    "unexpected path: def={:?} substs={:?} path={:?}",
+                                    def,
+                                    substs,
+                                    path,
+                                );
+                            } else {
+                                return Box::new(
+                                    self.resolved_path_inferred_subst_iter(path, substs)
+                                        .chain(segment),
+                                );
+                            }
+                        }
+                        _ => (),
+                    }
+                }
+
+                Box::new(segment.into_iter())
+            }
+            hir::QPath::LangItem(_, _, _) => Box::new(iter::empty()),
+        }
     }
 }
 
-/// Replace `[type error]` with `ty::Infer(ty::Var)` to display `_`.
-struct ErrTypeParamEraser<'tcx>(TyCtxt<'tcx>);
-impl<'tcx> TypeFolder<'tcx> for ErrTypeParamEraser<'tcx> {
-    fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
-        self.0
+impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
+    type NestedFilter = nested_filter::OnlyBodies;
+
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.infcx.tcx.hir()
     }
-    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
-        match t.kind() {
-            ty::Error(_) => self.tcx().mk_ty_var(ty::TyVid::from_u32(0)),
-            _ => t.super_fold_with(self),
+
+    fn visit_local(&mut self, local: &'tcx Local<'tcx>) {
+        intravisit::walk_local(self, local);
+
+        if let Some(ty) = self.opt_node_type(local.hir_id) {
+            if self.generic_arg_contains_target(ty.into()) {
+                match local.source {
+                    LocalSource::Normal if local.ty.is_none() => {
+                        self.update_infer_source(InferSource {
+                            span: local.pat.span,
+                            kind: InferSourceKind::LetBinding {
+                                insert_span: local.pat.span.shrink_to_hi(),
+                                pattern_name: local.pat.simple_ident(),
+                                ty,
+                            },
+                        })
+                    }
+                    _ => {}
+                }
+            }
         }
     }
-}
 
-/// Replace type parameters with `ty::Infer(ty::Var)` to display `_`.
-struct TypeParamEraser<'tcx>(TyCtxt<'tcx>);
+    /// For closures, we first visit the parameters and then the content,
+    /// as we prefer those.
+    fn visit_body(&mut self, body: &'tcx Body<'tcx>) {
+        for param in body.params {
+            debug!(
+                "param: span {:?}, ty_span {:?}, pat.span {:?}",
+                param.span, param.ty_span, param.pat.span
+            );
+            if param.ty_span != param.pat.span {
+                debug!("skipping param: has explicit type");
+                continue;
+            }
+
+            let Some(param_ty) = self.opt_node_type(param.hir_id) else {
+                continue
+            };
 
-impl<'tcx> TypeFolder<'tcx> for TypeParamEraser<'tcx> {
-    fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
-        self.0
+            if self.generic_arg_contains_target(param_ty.into()) {
+                self.update_infer_source(InferSource {
+                    span: param.pat.span,
+                    kind: InferSourceKind::ClosureArg {
+                        insert_span: param.pat.span.shrink_to_hi(),
+                        ty: param_ty,
+                    },
+                })
+            }
+        }
+        intravisit::walk_body(self, body);
     }
-    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
-        match t.kind() {
-            ty::Param(_) | ty::Error(_) => self.tcx().mk_ty_var(ty::TyVid::from_u32(0)),
-            _ => t.super_fold_with(self),
+
+    fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
+        let tcx = self.infcx.tcx;
+        match expr.kind {
+            // When encountering `func(arg)` first look into `arg` and then `func`,
+            // as `arg` is "more specific".
+            ExprKind::Call(func, args) => {
+                for arg in args {
+                    self.visit_expr(arg);
+                }
+                self.visit_expr(func);
+            }
+            _ => intravisit::walk_expr(self, expr),
+        }
+
+        for InsertableGenericArgs { insert_span, substs, generics_def_id, def_id } in
+            self.expr_inferred_subst_iter(expr)
+        {
+            let generics = tcx.generics_of(generics_def_id);
+            if let Some(argument_index) =
+                generics.own_substs(substs).iter().position(|&arg| self.generic_arg_is_target(arg))
+            {
+                let substs = self.infcx.resolve_vars_if_possible(substs);
+                let num_args = generics
+                    .params
+                    .iter()
+                    .rev()
+                    .filter(|&p| !matches!(p.kind, GenericParamDefKind::Lifetime))
+                    .skip_while(|&param| {
+                        if let Some(default) = param.default_value(tcx) {
+                            // FIXME: Using structural comparisions has a bunch of false negatives.
+                            //
+                            // We should instead try to replace inference variables with placeholders and
+                            // then use `infcx.can_eq`. That probably should be a separate method
+                            // generally used during error reporting.
+                            default.subst(tcx, substs) == substs[param.index as usize]
+                        } else {
+                            false
+                        }
+                    })
+                    .count();
+                let generic_args =
+                    &generics.own_substs(substs)[generics.own_counts().lifetimes..][..num_args];
+                let span = match expr.kind {
+                    ExprKind::MethodCall(path, _, _) => path.ident.span,
+                    _ => expr.span,
+                };
+
+                self.update_infer_source(InferSource {
+                    span,
+                    kind: InferSourceKind::GenericArg {
+                        insert_span,
+                        argument_index,
+                        generics_def_id,
+                        def_id,
+                        generic_args,
+                    },
+                });
+            }
+        }
+
+        if let Some(node_ty) = self.opt_node_type(expr.hir_id) {
+            if let (&ExprKind::Closure(_, decl, body_id, span, _), ty::Closure(_, substs)) =
+                (&expr.kind, node_ty.kind())
+            {
+                let output = substs.as_closure().sig().output().skip_binder();
+                if self.generic_arg_contains_target(output.into()) {
+                    let body = self.infcx.tcx.hir().body(body_id);
+                    let should_wrap_expr = if matches!(body.value.kind, ExprKind::Block(..)) {
+                        None
+                    } else {
+                        Some(body.value.span.shrink_to_hi())
+                    };
+                    self.update_infer_source(InferSource {
+                        span,
+                        kind: InferSourceKind::ClosureReturn {
+                            ty: output,
+                            data: &decl.output,
+                            should_wrap_expr,
+                        },
+                    })
+                }
+            }
+        }
+
+        let has_impl_trait = |def_id| {
+            iter::successors(Some(tcx.generics_of(def_id)), |generics| {
+                generics.parent.map(|def_id| tcx.generics_of(def_id))
+            })
+            .any(|generics| generics.has_impl_trait())
+        };
+        if let ExprKind::MethodCall(path, args, span) = expr.kind
+            && let Some(substs) = self.typeck_results.node_substs_opt(expr.hir_id)
+            && substs.iter().any(|arg| self.generic_arg_contains_target(arg))
+            && let Some(def_id) = self.typeck_results.type_dependent_def_id(expr.hir_id)
+            && self.infcx.tcx.trait_of_item(def_id).is_some()
+            && !has_impl_trait(def_id)
+        {
+            let successor =
+                args.get(1).map_or_else(|| (")", span.hi()), |arg| (", ", arg.span.lo()));
+            let substs = self.infcx.resolve_vars_if_possible(substs);
+            self.update_infer_source(InferSource {
+                span: path.ident.span,
+                kind: InferSourceKind::FullyQualifiedMethodCall {
+                    receiver: args.first().unwrap(),
+                    successor,
+                    substs,
+                    def_id,
+                }
+            })
         }
     }
 }
index cb72cb41a7c00540f1a4a490eeb7d891bf43a6a5..b744594ddb7e6b0e6bd2548c5b87c77a22394254 100644 (file)
@@ -12,6 +12,7 @@
 use rustc_hir as hir;
 use rustc_hir::{GenericParamKind, Ty};
 use rustc_middle::ty::Region;
+use rustc_span::symbol::kw;
 
 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
     /// Print the error message for lifetime errors when both the concerned regions are anonymous.
@@ -169,7 +170,7 @@ pub fn suggest_adding_lifetime_params<'tcx>(
         return false;
     };
 
-    if !lifetime_sub.name.is_elided() || !lifetime_sup.name.is_elided() {
+    if !lifetime_sub.name.is_anonymous() || !lifetime_sup.name.is_anonymous() {
         return false;
     };
 
@@ -188,32 +189,37 @@ pub fn suggest_adding_lifetime_params<'tcx>(
         _ => return false,
     };
 
-    let (suggestion_param_name, introduce_new) = generics
+    let suggestion_param_name = generics
         .params
         .iter()
-        .find(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
-        .and_then(|p| tcx.sess.source_map().span_to_snippet(p.span).ok())
-        .map(|name| (name, false))
-        .unwrap_or_else(|| ("'a".to_string(), true));
-
-    let mut suggestions = vec![
-        if let hir::LifetimeName::Underscore = lifetime_sub.name {
-            (lifetime_sub.span, suggestion_param_name.clone())
+        .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
+        .map(|p| p.name.ident().name)
+        .find(|i| *i != kw::UnderscoreLifetime);
+    let introduce_new = suggestion_param_name.is_none();
+    let suggestion_param_name =
+        suggestion_param_name.map(|n| n.to_string()).unwrap_or_else(|| "'a".to_owned());
+
+    debug!(?lifetime_sup.span);
+    debug!(?lifetime_sub.span);
+    let make_suggestion = |span: rustc_span::Span| {
+        if span.is_empty() {
+            (span, format!("{}, ", suggestion_param_name))
+        } else if let Ok("&") = tcx.sess.source_map().span_to_snippet(span).as_deref() {
+            (span.shrink_to_hi(), format!("{} ", suggestion_param_name))
         } else {
-            (lifetime_sub.span.shrink_to_hi(), suggestion_param_name.clone() + " ")
-        },
-        if let hir::LifetimeName::Underscore = lifetime_sup.name {
-            (lifetime_sup.span, suggestion_param_name.clone())
-        } else {
-            (lifetime_sup.span.shrink_to_hi(), suggestion_param_name.clone() + " ")
-        },
-    ];
+            (span, suggestion_param_name.clone())
+        }
+    };
+    let mut suggestions =
+        vec![make_suggestion(lifetime_sub.span), make_suggestion(lifetime_sup.span)];
 
     if introduce_new {
-        let new_param_suggestion = match &generics.params {
-            [] => (generics.span, format!("<{}>", suggestion_param_name)),
-            [first, ..] => (first.span.shrink_to_lo(), format!("{}, ", suggestion_param_name)),
-        };
+        let new_param_suggestion =
+            if let Some(first) = generics.params.iter().find(|p| !p.name.ident().span.is_empty()) {
+                (first.span.shrink_to_lo(), format!("{}, ", suggestion_param_name))
+            } else {
+                (generics.span, format!("<{}>", suggestion_param_name))
+            };
 
         suggestions.push(new_param_suggestion);
     }
index 3de5273d8c78c6c377a61b404e8feab7bfbcdcae..375ad8d3736dc2fb2f266956346d42d6d1cfabec 100644 (file)
@@ -4,6 +4,7 @@
 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
 use rustc_middle::ty;
+use rustc_span::symbol::kw;
 
 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
     /// When given a `ConcreteFailure` for a function with parameters containing a named region and
@@ -67,7 +68,7 @@ pub(super) fn try_report_named_anon_conflict(
         let is_impl_item = region_info.is_impl_item;
 
         match br {
-            ty::BrAnon(_) => {}
+            ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(_) => {}
             _ => {
                 /* not an anonymous region */
                 debug!("try_report_named_anon_conflict: not an anonymous region");
index 0f13a9b1388006ab9da1a5002e85dcaf8916ac32..7769a68ba2a66086bc269d40c1383c17d5e7ecbf 100644 (file)
@@ -22,6 +22,7 @@
 #![feature(let_else)]
 #![feature(min_specialization)]
 #![feature(never_type)]
+#![feature(try_blocks)]
 #![recursion_limit = "512"] // For rustdoc
 
 #[macro_use]
index e6c9c6693c5ab68cb4b072ac38f41771dbec0bdd..3c867e308c40e8666b7451a70a4cd8024f0f13fd 100644 (file)
@@ -27,7 +27,6 @@
 use rustc_plugin_impl as plugin;
 use rustc_query_impl::{OnDiskCache, Queries as TcxQueries};
 use rustc_resolve::{Resolver, ResolverArenas};
-use rustc_serialize::json;
 use rustc_session::config::{CrateType, Input, OutputFilenames, OutputType};
 use rustc_session::cstore::{MetadataLoader, MetadataLoaderDyn};
 use rustc_session::output::{filename_for_input, filename_for_metadata};
@@ -59,10 +58,6 @@ pub fn parse<'a>(sess: &'a Session, input: &Input) -> PResult<'a, ast::Crate> {
         }
     })?;
 
-    if sess.opts.debugging_opts.ast_json_noexpand {
-        println!("{}", json::as_json(&krate));
-    }
-
     if sess.opts.debugging_opts.input_stats {
         eprintln!("Lines of code:             {}", sess.source_map().count_lines());
         eprintln!("Pre-expansion node count:  {}", count_nodes(&krate));
@@ -423,10 +418,6 @@ pub fn configure_and_expand(
         hir_stats::print_ast_stats(&krate, "POST EXPANSION AST STATS");
     }
 
-    if sess.opts.debugging_opts.ast_json {
-        println!("{}", json::as_json(&krate));
-    }
-
     resolver.resolve_crate(&krate);
 
     // Needs to go *after* expansion to be able to check the results of macro expansion.
index 1327bf6fcd427a9523213875f9ae02fec1fce78d..a178cca6d108953633b02707ad48e4fd32e45f8c 100644 (file)
@@ -644,8 +644,6 @@ macro_rules! untracked {
     // Make sure that changing an [UNTRACKED] option leaves the hash unchanged.
     // This list is in alphabetical order.
     untracked!(assert_incr_state, Some(String::from("loaded")));
-    untracked!(ast_json, true);
-    untracked!(ast_json_noexpand, true);
     untracked!(borrowck, String::from("other"));
     untracked!(deduplicate_diagnostics, false);
     untracked!(dep_tasks, true);
index fcd8c37d6774ab78722f348f2f148781f18dae23..2bf34d82f395c0c91772d319b781e97ef6c661aa 100644 (file)
@@ -4,6 +4,7 @@ version = "0.0.0"
 edition = "2021"
 
 [dependencies]
+serde = { version = "1.0.125", features = ["derive"] }
 rustc_ast = { path = "../rustc_ast" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_error_messages = { path = "../rustc_error_messages" }
index e50abf6cf25595f7bcec18ca7bcb5934d7e6ae59..913dc58a1025953f7c2ba130c0066ac3723d743a 100644 (file)
@@ -14,6 +14,8 @@
 use rustc_span::{sym, symbol::Ident, Span, Symbol};
 use rustc_target::spec::abi::Abi;
 
+use serde::{Deserialize, Serialize};
+
 pub mod builtin;
 
 #[macro_export]
@@ -34,7 +36,7 @@ macro_rules! pluralize {
 /// All suggestions are marked with an `Applicability`. Tools use the applicability of a suggestion
 /// to determine whether it should be automatically applied or if the user should be consulted
 /// before applying the suggestion.
-#[derive(Copy, Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
+#[derive(Copy, Clone, Debug, PartialEq, Hash, Encodable, Decodable, Serialize, Deserialize)]
 pub enum Applicability {
     /// The suggestion is definitely what the user intended, or maintains the exact meaning of the code.
     /// This suggestion should be automatically applied.
index a39b44139811ebc8fee1445ea7ddb572897ad2c4..e99fa6c113b0d260a996ad58a42fc67cd82340a4 100644 (file)
@@ -140,79 +140,56 @@ fn encodable_body(
 
     let encode_body = match s.variants() {
         [_] => {
-            let mut field_idx = 0usize;
             let encode_inner = s.each_variant(|vi| {
                 vi.bindings()
                     .iter()
                     .map(|binding| {
                         let bind_ident = &binding.binding;
-                        let field_name = binding
-                            .ast()
-                            .ident
-                            .as_ref()
-                            .map_or_else(|| field_idx.to_string(), |i| i.to_string());
-                        let first = field_idx == 0;
                         let result = quote! {
-                            match ::rustc_serialize::Encoder::emit_struct_field(
+                            match ::rustc_serialize::Encodable::<#encoder_ty>::encode(
+                                #bind_ident,
                                 __encoder,
-                                #field_name,
-                                #first,
-                                |__encoder|
-                                ::rustc_serialize::Encodable::<#encoder_ty>::encode(#bind_ident, __encoder),
                             ) {
                                 ::std::result::Result::Ok(()) => (),
                                 ::std::result::Result::Err(__err)
                                     => return ::std::result::Result::Err(__err),
                             }
                         };
-                        field_idx += 1;
                         result
                     })
                     .collect::<TokenStream>()
             });
-            let no_fields = field_idx == 0;
             quote! {
-                ::rustc_serialize::Encoder::emit_struct(__encoder, #no_fields, |__encoder| {
-                    ::std::result::Result::Ok(match *self { #encode_inner })
-                })
+                ::std::result::Result::Ok(match *self { #encode_inner })
             }
         }
         _ => {
             let mut variant_idx = 0usize;
             let encode_inner = s.each_variant(|vi| {
-                let variant_name = vi.ast().ident.to_string();
-                let mut field_idx = 0usize;
-
                 let encode_fields: TokenStream = vi
                     .bindings()
                     .iter()
                     .map(|binding| {
                         let bind_ident = &binding.binding;
-                        let first = field_idx == 0;
                         let result = quote! {
-                            match ::rustc_serialize::Encoder::emit_enum_variant_arg(
+                            match ::rustc_serialize::Encodable::<#encoder_ty>::encode(
+                                #bind_ident,
                                 __encoder,
-                                #first,
-                                |__encoder|
-                                ::rustc_serialize::Encodable::<#encoder_ty>::encode(#bind_ident, __encoder),
                             ) {
                                 ::std::result::Result::Ok(()) => (),
                                 ::std::result::Result::Err(__err)
                                     => return ::std::result::Result::Err(__err),
                             }
                         };
-                        field_idx += 1;
                         result
                     })
                     .collect();
 
-                let result = if field_idx != 0 {
+                let result = if !vi.bindings().is_empty() {
                     quote! {
                         ::rustc_serialize::Encoder::emit_enum_variant(
                             __encoder,
-                            #variant_name,
                             #variant_idx,
-                            #field_idx,
                             |__encoder| { ::std::result::Result::Ok({ #encode_fields }) }
                         )
                     }
@@ -220,7 +197,6 @@ fn encodable_body(
                     quote! {
                         ::rustc_serialize::Encoder::emit_fieldless_enum_variant::<#variant_idx>(
                             __encoder,
-                            #variant_name,
                         )
                     }
                 };
@@ -228,11 +204,9 @@ fn encodable_body(
                 result
             });
             quote! {
-                ::rustc_serialize::Encoder::emit_enum(__encoder, |__encoder| {
-                    match *self {
-                        #encode_inner
-                    }
-                })
+                match *self {
+                    #encode_inner
+                }
             }
         }
     };
index f67e1cab16d9c02d0290cd35bc0362f3030ac55e..1425c5467af873902896ad16a26f64234b3407f1 100644 (file)
@@ -95,11 +95,6 @@ macro_rules! encoder_methods {
 impl<'a, 'tcx> Encoder for EncodeContext<'a, 'tcx> {
     type Error = <opaque::Encoder as Encoder>::Error;
 
-    #[inline]
-    fn emit_unit(&mut self) -> Result<(), Self::Error> {
-        Ok(())
-    }
-
     encoder_methods! {
         emit_usize(usize);
         emit_u128(u128);
index 97f429cfd3fa6df2ec2b7d6c70df1e8088002b1a..779af7a382765f08f45144107174edf0ee8c2d7a 100644 (file)
@@ -361,23 +361,7 @@ pub fn get_if_local(self, id: DefId) -> Option<Node<'hir>> {
 
     pub fn get_generics(self, id: LocalDefId) -> Option<&'hir Generics<'hir>> {
         let node = self.tcx.hir_owner(id)?;
-        match node.node {
-            OwnerNode::ImplItem(impl_item) => Some(&impl_item.generics),
-            OwnerNode::TraitItem(trait_item) => Some(&trait_item.generics),
-            OwnerNode::Item(Item {
-                kind:
-                    ItemKind::Fn(_, generics, _)
-                    | ItemKind::TyAlias(_, generics)
-                    | ItemKind::Enum(_, generics)
-                    | ItemKind::Struct(_, generics)
-                    | ItemKind::Union(_, generics)
-                    | ItemKind::Trait(_, _, generics, ..)
-                    | ItemKind::TraitAlias(generics, _)
-                    | ItemKind::Impl(Impl { generics, .. }),
-                ..
-            }) => Some(generics),
-            _ => None,
-        }
+        node.node.generics()
     }
 
     pub fn item(self, id: ItemId) -> &'hir Item<'hir> {
@@ -983,7 +967,11 @@ pub fn opt_span(self, hir_id: HirId) -> Option<Span> {
             Node::AnonConst(constant) => self.body(constant.body).value.span,
             Node::Expr(expr) => expr.span,
             Node::Stmt(stmt) => stmt.span,
-            Node::PathSegment(seg) => seg.ident.span,
+            Node::PathSegment(seg) => {
+                let ident_span = seg.ident.span;
+                ident_span
+                    .with_hi(seg.args.map_or_else(|| ident_span.hi(), |args| args.span_ext.hi()))
+            }
             Node::Ty(ty) => ty.span,
             Node::TraitRef(tr) => tr.path.span,
             Node::Binding(pat) => pat.span,
index 70586cefaeee1fea4c5158b2794c011aa67a61de..cdc0d07680193ef54818efa149a235e4d4b8b0db 100644 (file)
@@ -6,7 +6,6 @@
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::ItemLocalId;
 use rustc_macros::HashStable;
-use rustc_span::symbol::Symbol;
 
 #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, HashStable)]
 pub enum Region {
@@ -22,12 +21,12 @@ pub enum Region {
 /// so that we can e.g. suggest elided-lifetimes-in-paths of the form <'_, '_> e.g.
 #[derive(Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, HashStable)]
 pub enum LifetimeScopeForPath {
-    // Contains all lifetime names that are in scope and could possibly be used in generics
-    // arguments of path.
-    NonElided(Vec<Symbol>),
+    /// Contains all lifetime names that are in scope and could possibly be used in generics
+    /// arguments of path.
+    NonElided(Vec<LocalDefId>),
 
-    // Information that allows us to suggest args of the form `<'_>` in case
-    // no generic arguments were provided for a path.
+    /// Information that allows us to suggest args of the form `<'_>` in case
+    /// no generic arguments were provided for a path.
     Elided,
 }
 
index d00dae85367b8fe08fc2b557ac7e2d332832696d..146ae45e46898ffaae61e9fffd9f37ebe759d50c 100644 (file)
@@ -315,7 +315,7 @@ pub fn to_bits_or_ptr_internal(
                 ScalarSizeMismatch { target_size: target_size.bytes(), data_size: size.bytes() }
             })?),
             Scalar::Ptr(ptr, sz) => {
-                if target_size.bytes() != sz.into() {
+                if target_size.bytes() != u64::from(sz) {
                     return Err(ScalarSizeMismatch {
                         target_size: target_size.bytes(),
                         data_size: sz.into(),
index b09d39996f4dea0ed72c48e572528ba416ba3d2e..f3db359ec334829a39e313b79d655854eb2be56a 100644 (file)
@@ -2604,10 +2604,27 @@ pub enum Rvalue<'tcx> {
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
 static_assert_size!(Rvalue<'_>, 40);
 
+impl<'tcx> Rvalue<'tcx> {
+    #[inline]
+    pub fn is_pointer_int_cast(&self) -> bool {
+        matches!(self, Rvalue::Cast(CastKind::PointerExposeAddress, _, _))
+    }
+}
+
 #[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
 pub enum CastKind {
-    Misc,
+    /// An exposing pointer to address cast. A cast between a pointer and an integer type, or
+    /// between a function pointer and an integer type.
+    /// See the docs on `expose_addr` for more details.
+    PointerExposeAddress,
+    /// An address-to-pointer cast that picks up an exposed provenance.
+    /// See the docs on `from_exposed_addr` for more details.
+    PointerFromExposedAddress,
+    /// All sorts of pointer-to-pointer casts. Note that reference-to-raw-ptr casts are
+    /// translated into `&raw mut/const *r`, i.e., they are not actually casts.
     Pointer(PointerCast),
+    /// Remaining unclassified casts.
+    Misc,
 }
 
 #[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
index ad09328585d27bda542ed76b50273588a3ef1f54..0b9ddaf64d4e26faeb9031f953061672bb9baa18 100644 (file)
@@ -56,8 +56,8 @@ pub(super) fn compute(
 
 impl<S: serialize::Encoder> serialize::Encodable<S> for PredecessorCache {
     #[inline]
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_unit()
+    fn encode(&self, _s: &mut S) -> Result<(), S::Error> {
+        Ok(())
     }
 }
 
index adeeec70d1c0bb80b6af435db5519818b2d57eae..fbb26800e29c9fba22507c53ea3a4833ac413776 100644 (file)
@@ -56,8 +56,8 @@ pub(super) fn compute(
 
 impl<S: serialize::Encoder> serialize::Encodable<S> for SwitchSourceCache {
     #[inline]
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_unit()
+    fn encode(&self, _s: &mut S) -> Result<(), S::Error> {
+        Ok(())
     }
 }
 
index f1fb484a801ba97c2c723d5166dfef813176b2a3..c93b7a955022925bd0b01d2168dd9a2f8a7ac3b2 100644 (file)
@@ -4,7 +4,6 @@
  */
 
 use crate::mir::*;
-use crate::ty::cast::CastTy;
 use crate::ty::subst::Subst;
 use crate::ty::{self, Ty, TyCtxt};
 use rustc_hir as hir;
@@ -224,22 +223,6 @@ pub fn initialization_state(&self) -> RvalueInitializationState {
             _ => RvalueInitializationState::Deep,
         }
     }
-
-    pub fn is_pointer_int_cast<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> bool
-    where
-        D: HasLocalDecls<'tcx>,
-    {
-        if let Rvalue::Cast(CastKind::Misc, src_op, dest_ty) = self {
-            if let Some(CastTy::Int(_)) = CastTy::from_ty(*dest_ty) {
-                let src_ty = src_op.ty(local_decls, tcx);
-                if let Some(CastTy::FnPtr | CastTy::Ptr(_)) = CastTy::from_ty(src_ty) {
-                    return true;
-                }
-            }
-        }
-
-        false
-    }
 }
 
 impl<'tcx> Operand<'tcx> {
index 1cbfed621560d6a516edb278817535b54f2a03c4..5e8226d356f56c8172936cd8aadd3266dcafd769 100644 (file)
@@ -367,8 +367,8 @@ pub(super) fn compute(&self, body: &Body<'_>) -> &Vec<BasicBlock> {
 
 impl<S: serialize::Encoder> serialize::Encodable<S> for PostorderCache {
     #[inline]
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_unit()
+    fn encode(&self, _s: &mut S) -> Result<(), S::Error> {
+        Ok(())
     }
 }
 
index 38d8e0b5819530f00a7914fa7936f7e2c426984e..24531e461896be80703ba4101f824f975bfa5281 100644 (file)
         Option<&'tcx FxHashMap<ItemLocalId, Region>> {
         desc { "looking up a named region" }
     }
-    query is_late_bound_map(_: LocalDefId) -> Option<(LocalDefId, &'tcx FxHashSet<LocalDefId>)> {
+    query is_late_bound_map(_: LocalDefId) -> Option<&'tcx FxHashSet<LocalDefId>> {
         desc { "testing if a region is late bound" }
     }
     /// For a given item (like a struct), gets the default lifetimes to be used
     query upvars_mentioned(def_id: DefId) -> Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>> {
         desc { |tcx| "collecting upvars mentioned in `{}`", tcx.def_path_str(def_id) }
     }
-    query maybe_unused_trait_import(def_id: LocalDefId) -> bool {
-        desc { |tcx| "maybe_unused_trait_import for `{}`", tcx.def_path_str(def_id.to_def_id()) }
+    query maybe_unused_trait_imports(_: ()) -> &'tcx FxIndexSet<LocalDefId> {
+        desc { "fetching potentially unused trait imports" }
     }
     query maybe_unused_extern_crates(_: ()) -> &'tcx [(LocalDefId, Span)] {
         desc { "looking up all possibly unused extern crates" }
index a0d92e2a5dd94fc89102ac8bff7cf5e11b858560..ac71146303ac2940007b4765dcb3683ba6f0f5f6 100644 (file)
@@ -2803,6 +2803,13 @@ pub fn named_region(self, id: HirId) -> Option<resolve_lifetime::Region> {
         self.named_region_map(id.owner).and_then(|map| map.get(&id.local_id).cloned())
     }
 
+    pub fn is_late_bound(self, id: HirId) -> bool {
+        self.is_late_bound_map(id.owner).map_or(false, |set| {
+            let def_id = self.hir().local_def_id(id);
+            set.contains(&def_id)
+        })
+    }
+
     pub fn late_bound_vars(self, id: HirId) -> &'tcx List<ty::BoundVariableKind> {
         self.mk_bound_variable_kinds(
             self.late_bound_vars_map(id.owner)
@@ -2886,8 +2893,8 @@ pub fn provide(providers: &mut ty::query::Providers) {
         assert_eq!(id, LOCAL_CRATE);
         tcx.crate_name
     };
-    providers.maybe_unused_trait_import =
-        |tcx, id| tcx.resolutions(()).maybe_unused_trait_imports.contains(&id);
+    providers.maybe_unused_trait_imports =
+        |tcx, ()| &tcx.resolutions(()).maybe_unused_trait_imports;
     providers.maybe_unused_extern_crates =
         |tcx, ()| &tcx.resolutions(()).maybe_unused_extern_crates[..];
     providers.names_imported_by_glob_use = |tcx, id| {
index 462fc27009de9ce1b9c462519ab6308c1d0c8b33..9bb64d4023bcabec70e7b6fdd110c2d4c2ac17d3 100644 (file)
@@ -272,7 +272,10 @@ pub fn suggest_constraining_type_params<'a>(
             continue;
         }
 
-        let constraint = constraints.iter().map(|&(c, _)| c).collect::<Vec<_>>().join(" + ");
+        let mut constraint = constraints.iter().map(|&(c, _)| c).collect::<Vec<_>>();
+        constraint.sort();
+        constraint.dedup();
+        let constraint = constraint.join(" + ");
         let mut suggest_restrict = |span, bound_list_non_empty| {
             suggestions.push((
                 span,
index d9b82ee0a76801e57e0ba70ee34328231489b40d..1feabb2d6b122e73e80eefead895c23c67907dd8 100644 (file)
@@ -63,6 +63,29 @@ pub fn to_early_bound_region_data(&self) -> ty::EarlyBoundRegion {
             bug!("cannot convert a non-lifetime parameter def to an early bound region")
         }
     }
+
+    pub fn has_default(&self) -> bool {
+        match self.kind {
+            GenericParamDefKind::Type { has_default, .. }
+            | GenericParamDefKind::Const { has_default } => has_default,
+            GenericParamDefKind::Lifetime => false,
+        }
+    }
+
+    pub fn default_value<'tcx>(
+        &self,
+        tcx: TyCtxt<'tcx>,
+    ) -> Option<EarlyBinder<ty::GenericArg<'tcx>>> {
+        match self.kind {
+            GenericParamDefKind::Type { has_default, .. } if has_default => {
+                Some(EarlyBinder(tcx.type_of(self.def_id).into()))
+            }
+            GenericParamDefKind::Const { has_default } if has_default => {
+                Some(EarlyBinder(tcx.const_param_default(self.def_id).into()))
+            }
+            _ => None,
+        }
+    }
 }
 
 #[derive(Default)]
@@ -204,6 +227,12 @@ pub fn has_impl_trait(&'tcx self) -> bool {
             matches!(param.kind, ty::GenericParamDefKind::Type { synthetic: true, .. })
         })
     }
+
+    /// Returns the substs corresponding to the generic parameters of this item, excluding `Self`.
+    pub fn own_substs(&'tcx self, substs: SubstsRef<'tcx>) -> &'tcx [ty::GenericArg<'tcx>] {
+        let own = &substs[self.parent_count..][..self.params.len()];
+        if self.has_self && self.parent.is_none() { &own[1..] } else { &own }
+    }
 }
 
 /// Bounds on generics.
index a493aaac276b1a3e8f0cf9cb533ee27b61128829..3a2d3408b9d9365325e793afd223604ccc90ee2c 100644 (file)
@@ -28,7 +28,7 @@
 use rustc_ast as ast;
 use rustc_attr as attr;
 use rustc_data_structures::fingerprint::Fingerprint;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_data_structures::intern::{Interned, WithStableHash};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::tagged_ptr::CopyTaggedPtr;
@@ -138,7 +138,7 @@ pub struct ResolverOutputs {
     pub has_pub_restricted: bool,
     pub access_levels: AccessLevels,
     pub extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
-    pub maybe_unused_trait_imports: FxHashSet<LocalDefId>,
+    pub maybe_unused_trait_imports: FxIndexSet<LocalDefId>,
     pub maybe_unused_extern_crates: Vec<(LocalDefId, Span)>,
     pub reexport_map: FxHashMap<LocalDefId, Vec<ModChild>>,
     pub glob_map: FxHashMap<LocalDefId, FxHashSet<Symbol>>,
index 4c0bc2e4337c712ffd96f09cc6d90f744c4abf20..08879afa64a0ebaa601d0e5e24e2a9a1fbd27a51 100644 (file)
@@ -2177,61 +2177,53 @@ fn name_by_region_index(index: usize) -> Symbol {
         define_scoped_cx!(self);
 
         let mut region_index = self.region_index;
+        let mut next_name = |this: &Self| loop {
+            let name = name_by_region_index(region_index);
+            region_index += 1;
+            if !this.used_region_names.contains(&name) {
+                break name;
+            }
+        };
+
         // If we want to print verbosely, then print *all* binders, even if they
         // aren't named. Eventually, we might just want this as the default, but
         // this is not *quite* right and changes the ordering of some output
         // anyways.
         let (new_value, map) = if self.tcx().sess.verbose() {
-            // anon index + 1 (BrEnv takes 0) -> name
-            let mut region_map: BTreeMap<u32, Symbol> = BTreeMap::default();
-            let bound_vars = value.bound_vars();
-            for var in bound_vars {
-                match var {
-                    ty::BoundVariableKind::Region(ty::BrNamed(_, name)) => {
-                        start_or_continue(&mut self, "for<", ", ");
-                        do_continue(&mut self, name);
-                    }
-                    ty::BoundVariableKind::Region(ty::BrAnon(i)) => {
-                        start_or_continue(&mut self, "for<", ", ");
-                        let name = loop {
-                            let name = name_by_region_index(region_index);
-                            region_index += 1;
-                            if !self.used_region_names.contains(&name) {
-                                break name;
-                            }
-                        };
-                        do_continue(&mut self, name);
-                        region_map.insert(i + 1, name);
-                    }
-                    ty::BoundVariableKind::Region(ty::BrEnv) => {
-                        start_or_continue(&mut self, "for<", ", ");
-                        let name = loop {
-                            let name = name_by_region_index(region_index);
-                            region_index += 1;
-                            if !self.used_region_names.contains(&name) {
-                                break name;
-                            }
-                        };
-                        do_continue(&mut self, name);
-                        region_map.insert(0, name);
+            let regions: Vec<_> = value
+                .bound_vars()
+                .into_iter()
+                .map(|var| {
+                    let ty::BoundVariableKind::Region(var) = var else {
+                    // This doesn't really matter because it doesn't get used,
+                    // it's just an empty value
+                    return ty::BrAnon(0);
+                };
+                    match var {
+                        ty::BrAnon(_) | ty::BrEnv => {
+                            start_or_continue(&mut self, "for<", ", ");
+                            let name = next_name(&self);
+                            do_continue(&mut self, name);
+                            ty::BrNamed(CRATE_DEF_ID.to_def_id(), name)
+                        }
+                        ty::BrNamed(def_id, kw::UnderscoreLifetime) => {
+                            start_or_continue(&mut self, "for<", ", ");
+                            let name = next_name(&self);
+                            do_continue(&mut self, name);
+                            ty::BrNamed(def_id, name)
+                        }
+                        ty::BrNamed(def_id, name) => {
+                            start_or_continue(&mut self, "for<", ", ");
+                            do_continue(&mut self, name);
+                            ty::BrNamed(def_id, name)
+                        }
                     }
-                    _ => continue,
-                }
-            }
+                })
+                .collect();
             start_or_continue(&mut self, "", "> ");
 
             self.tcx.replace_late_bound_regions(value.clone(), |br| {
-                let kind = match br.kind {
-                    ty::BrNamed(_, _) => br.kind,
-                    ty::BrAnon(i) => {
-                        let name = region_map[&(i + 1)];
-                        ty::BrNamed(CRATE_DEF_ID.to_def_id(), name)
-                    }
-                    ty::BrEnv => {
-                        let name = region_map[&0];
-                        ty::BrNamed(CRATE_DEF_ID.to_def_id(), name)
-                    }
-                };
+                let kind = regions[br.var.as_usize()];
                 self.tcx.mk_region(ty::ReLateBound(
                     ty::INNERMOST,
                     ty::BoundRegion { var: br.var, kind },
@@ -2242,21 +2234,20 @@ fn name_by_region_index(index: usize) -> Symbol {
             let mut name = |br: ty::BoundRegion| {
                 start_or_continue(&mut self, "for<", ", ");
                 let kind = match br.kind {
-                    ty::BrNamed(_, name) => {
-                        do_continue(&mut self, name);
-                        br.kind
-                    }
                     ty::BrAnon(_) | ty::BrEnv => {
-                        let name = loop {
-                            let name = name_by_region_index(region_index);
-                            region_index += 1;
-                            if !self.used_region_names.contains(&name) {
-                                break name;
-                            }
-                        };
+                        let name = next_name(&self);
                         do_continue(&mut self, name);
                         ty::BrNamed(CRATE_DEF_ID.to_def_id(), name)
                     }
+                    ty::BrNamed(def_id, kw::UnderscoreLifetime) => {
+                        let name = next_name(&self);
+                        do_continue(&mut self, name);
+                        ty::BrNamed(def_id, name)
+                    }
+                    ty::BrNamed(_, name) => {
+                        do_continue(&mut self, name);
+                        br.kind
+                    }
                 };
                 tcx.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BoundRegion { var: br.var, kind }))
             };
index 65f41c5266d17d808300c1a142526146cf457f54..59794c4d3f0d83adc9814608ef1017efa5bdd185 100644 (file)
@@ -37,7 +37,7 @@
 use rustc_ast as ast;
 use rustc_ast::expand::allocator::AllocatorKind;
 use rustc_attr as attr;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_data_structures::steal::Steal;
 use rustc_data_structures::svh::Svh;
 use rustc_data_structures::sync::Lrc;
index 0a0c7659b086dc926c05cea97b564c23b31b762b..8e87ecd27d2853a113ff22e38365d384dee2f579 100644 (file)
@@ -11,6 +11,7 @@
 use rustc_middle::mir::Place;
 use rustc_middle::mir::*;
 use rustc_middle::thir::*;
+use rustc_middle::ty::cast::CastTy;
 use rustc_middle::ty::{self, Ty, UpvarSubsts};
 use rustc_span::Span;
 
@@ -188,11 +189,22 @@ pub(crate) fn as_rvalue(
                 block.and(Rvalue::Use(Operand::Move(Place::from(result))))
             }
             ExprKind::Cast { source } => {
+                let source = &this.thir[source];
+                let from_ty = CastTy::from_ty(source.ty);
+                let cast_ty = CastTy::from_ty(expr.ty);
+                let cast_kind = match (from_ty, cast_ty) {
+                    (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Int(_))) => {
+                        CastKind::PointerExposeAddress
+                    }
+                    (Some(CastTy::Int(_)), Some(CastTy::Ptr(_))) => {
+                        CastKind::PointerFromExposedAddress
+                    }
+                    (_, _) => CastKind::Misc,
+                };
                 let source = unpack!(
-                    block =
-                        this.as_operand(block, scope, &this.thir[source], None, NeedsTemporary::No)
+                    block = this.as_operand(block, scope, source, None, NeedsTemporary::No)
                 );
-                block.and(Rvalue::Cast(CastKind::Misc, source, expr.ty))
+                block.and(Rvalue::Cast(cast_kind, source, expr.ty))
             }
             ExprKind::Pointer { cast, source } => {
                 let source = unpack!(
index 4350eb6cdd3b1fa3943beb4bb612f6aaba32ba92..7076fbe1bdb535ffa895a0fdb92478a1c0971de1 100644 (file)
@@ -1,7 +1,6 @@
 use rustc_index::bit_set::{BitSet, ChunkedBitSet};
 use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
-use rustc_middle::mir::{self, Local, LocalDecls, Location, Place, StatementKind};
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::mir::{self, Local, Location, Place, StatementKind};
 
 use crate::{Analysis, AnalysisDomain, Backward, CallReturnPlaces, GenKill, GenKillAnalysis};
 
@@ -193,27 +192,21 @@ fn for_place<'tcx>(place: Place<'tcx>, context: PlaceContext) -> Option<DefUse>
 /// This is basically written for dead store elimination and nothing else.
 ///
 /// All of the caveats of `MaybeLiveLocals` apply.
-pub struct MaybeTransitiveLiveLocals<'a, 'tcx> {
+pub struct MaybeTransitiveLiveLocals<'a> {
     always_live: &'a BitSet<Local>,
-    local_decls: &'a LocalDecls<'tcx>,
-    tcx: TyCtxt<'tcx>,
 }
 
-impl<'a, 'tcx> MaybeTransitiveLiveLocals<'a, 'tcx> {
+impl<'a> MaybeTransitiveLiveLocals<'a> {
     /// The `always_alive` set is the set of locals to which all stores should unconditionally be
     /// considered live.
     ///
     /// This should include at least all locals that are ever borrowed.
-    pub fn new(
-        always_live: &'a BitSet<Local>,
-        local_decls: &'a LocalDecls<'tcx>,
-        tcx: TyCtxt<'tcx>,
-    ) -> Self {
-        MaybeTransitiveLiveLocals { always_live, local_decls, tcx }
+    pub fn new(always_live: &'a BitSet<Local>) -> Self {
+        MaybeTransitiveLiveLocals { always_live }
     }
 }
 
-impl<'a, 'tcx> AnalysisDomain<'tcx> for MaybeTransitiveLiveLocals<'a, 'tcx> {
+impl<'a, 'tcx> AnalysisDomain<'tcx> for MaybeTransitiveLiveLocals<'a> {
     type Domain = ChunkedBitSet<Local>;
     type Direction = Backward;
 
@@ -241,7 +234,7 @@ fn kill(&mut self, l: Local) {
     }
 }
 
-impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a, 'tcx> {
+impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
     fn apply_statement_effect(
         &self,
         trans: &mut Self::Domain,
@@ -251,7 +244,7 @@ fn apply_statement_effect(
         // Compute the place that we are storing to, if any
         let destination = match &statement.kind {
             StatementKind::Assign(assign) => {
-                if assign.1.is_pointer_int_cast(self.local_decls, self.tcx) {
+                if assign.1.is_pointer_int_cast() {
                     // Pointer to int casts may be side-effects due to exposing the provenance.
                     // While the model is undecided, we should be conservative. See
                     // <https://www.ralfj.de/blog/2022/04/11/provenance-exposed.html>
index 84f2ee639e4d8a2ca3b8998185b4cf5be8ec74a2..8becac34ed7ee3a7846dc32352bb90ea324845e4 100644 (file)
@@ -24,7 +24,7 @@
 /// The `borrowed` set must be a `BitSet` of all the locals that are ever borrowed in this body. It
 /// can be generated via the [`get_borrowed_locals`] function.
 pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitSet<Local>) {
-    let mut live = MaybeTransitiveLiveLocals::new(borrowed, &body.local_decls, tcx)
+    let mut live = MaybeTransitiveLiveLocals::new(borrowed)
         .into_engine(tcx, body)
         .iterate_to_fixpoint()
         .into_results_cursor(body);
@@ -34,7 +34,7 @@ pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitS
         for (statement_index, statement) in bb_data.statements.iter().enumerate().rev() {
             let loc = Location { block: bb, statement_index };
             if let StatementKind::Assign(assign) = &statement.kind {
-                if assign.1.is_pointer_int_cast(&body.local_decls, tcx) {
+                if assign.1.is_pointer_int_cast() {
                     continue;
                 }
             }
index 9526c0acc66d6fdfe22fac72eaba026dc1c994e7..a1490d77ccb5b7436d089bcb90f4535cd227f2e0 100644 (file)
@@ -158,11 +158,13 @@ fn try_inlining(
             return Err("optimization fuel exhausted");
         }
 
-        let callee_body = callsite.callee.subst_mir_and_normalize_erasing_regions(
+        let Ok(callee_body) = callsite.callee.try_subst_mir_and_normalize_erasing_regions(
             self.tcx,
             self.param_env,
             callee_body.clone(),
-        );
+        ) else {
+            return Err("failed to normalize callee body");
+        };
 
         let old_blocks = caller_body.basic_blocks().next_index();
         self.inline_call(caller_body, &callsite, callee_body);
@@ -253,7 +255,7 @@ fn resolve_callsite(
             let func_ty = func.ty(caller_body, self.tcx);
             if let ty::FnDef(def_id, substs) = *func_ty.kind() {
                 // To resolve an instance its substs have to be fully normalized.
-                let substs = self.tcx.normalize_erasing_regions(self.param_env, substs);
+                let substs = self.tcx.try_normalize_erasing_regions(self.param_env, substs).ok()?;
                 let callee =
                     Instance::resolve(self.tcx, self.param_env, def_id, substs).ok().flatten()?;
 
@@ -408,14 +410,17 @@ fn check_mir_body(
                     if let ty::FnDef(def_id, substs) =
                         *callsite.callee.subst_mir(self.tcx, &f.literal.ty()).kind()
                     {
-                        let substs = self.tcx.normalize_erasing_regions(self.param_env, substs);
-                        if let Ok(Some(instance)) =
-                            Instance::resolve(self.tcx, self.param_env, def_id, substs)
+                        if let Ok(substs) =
+                            self.tcx.try_normalize_erasing_regions(self.param_env, substs)
                         {
-                            if callsite.callee.def_id() == instance.def_id() {
-                                return Err("self-recursion");
-                            } else if self.history.contains(&instance) {
-                                return Err("already inlined");
+                            if let Ok(Some(instance)) =
+                                Instance::resolve(self.tcx, self.param_env, def_id, substs)
+                            {
+                                if callsite.callee.def_id() == instance.def_id() {
+                                    return Err("self-recursion");
+                                } else if self.history.contains(&instance) {
+                                    return Err("already inlined");
+                                }
                             }
                         }
                         // Don't give intrinsics the extra penalty for calls
index 12302315e9044a73c6dc50eba0aeeefa264acbaf..a4cdfdf55f9df393c64df2b6ac3dca9449ec6c0b 100644 (file)
@@ -1,8 +1,7 @@
 use super::pat::Expected;
-use super::ty::{AllowPlus, RecoverQuestionMark};
 use super::{
-    BlockMode, CommaRecoveryMode, Parser, PathStyle, RecoverColon, RecoverComma, Restrictions,
-    SemiColonMode, SeqSep, TokenExpectType, TokenType,
+    BlockMode, CommaRecoveryMode, Parser, PathStyle, Restrictions, SemiColonMode, SeqSep,
+    TokenExpectType, TokenType,
 };
 
 use crate::lexer::UnmatchedBrace;
@@ -286,6 +285,54 @@ pub enum BadTypePlusSub {
     },
 }
 
+#[derive(SessionDiagnostic)]
+#[error(slug = "parser-maybe-recover-from-bad-qpath-stage-2")]
+struct BadQPathStage2 {
+    #[primary_span]
+    #[suggestion(applicability = "maybe-incorrect")]
+    span: Span,
+    ty: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(slug = "parser-incorrect-semicolon")]
+struct IncorrectSemicolon<'a> {
+    #[primary_span]
+    #[suggestion_short(applicability = "machine-applicable")]
+    span: Span,
+    #[help]
+    opt_help: Option<()>,
+    name: &'a str,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(slug = "parser-incorrect-use-of-await")]
+struct IncorrectUseOfAwait {
+    #[primary_span]
+    #[suggestion(message = "parentheses-suggestion", applicability = "machine-applicable")]
+    span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(slug = "parser-incorrect-use-of-await")]
+struct IncorrectAwait {
+    #[primary_span]
+    span: Span,
+    #[suggestion(message = "postfix-suggestion", code = "{expr}.await{question_mark}")]
+    sugg_span: (Span, Applicability),
+    expr: String,
+    question_mark: &'static str,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(slug = "parser-in-in-typo")]
+struct InInTypo {
+    #[primary_span]
+    span: Span,
+    #[suggestion(applicability = "machine-applicable")]
+    sugg_span: Span,
+}
+
 // SnapshotParser is used to create a snapshot of the parser
 // without causing duplicate errors being emitted when the `Parser`
 // is dropped.
@@ -1233,26 +1280,14 @@ fn consume_fn_args(&mut self) -> Result<(), ()> {
         }
     }
 
-    pub(super) fn maybe_report_ambiguous_plus(
-        &mut self,
-        allow_plus: AllowPlus,
-        impl_dyn_multi: bool,
-        ty: &Ty,
-    ) {
-        if matches!(allow_plus, AllowPlus::No) && impl_dyn_multi {
+    pub(super) fn maybe_report_ambiguous_plus(&mut self, impl_dyn_multi: bool, ty: &Ty) {
+        if impl_dyn_multi {
             self.sess.emit_err(AmbiguousPlus { sum_ty: pprust::ty_to_string(&ty), span: ty.span });
         }
     }
 
     /// Swift lets users write `Ty?` to mean `Option<Ty>`. Parse the construct and recover from it.
-    pub(super) fn maybe_recover_from_question_mark(
-        &mut self,
-        ty: P<Ty>,
-        recover_question_mark: RecoverQuestionMark,
-    ) -> P<Ty> {
-        if let RecoverQuestionMark::No = recover_question_mark {
-            return ty;
-        }
+    pub(super) fn maybe_recover_from_question_mark(&mut self, ty: P<Ty>) -> P<Ty> {
         if self.token == token::Question {
             self.bump();
             self.struct_span_err(self.prev_token.span, "invalid `?` in type")
@@ -1272,13 +1307,9 @@ pub(super) fn maybe_recover_from_question_mark(
         }
     }
 
-    pub(super) fn maybe_recover_from_bad_type_plus(
-        &mut self,
-        allow_plus: AllowPlus,
-        ty: &Ty,
-    ) -> PResult<'a, ()> {
+    pub(super) fn maybe_recover_from_bad_type_plus(&mut self, ty: &Ty) -> PResult<'a, ()> {
         // Do not add `+` to expected tokens.
-        if matches!(allow_plus, AllowPlus::No) || !self.token.is_like_plus() {
+        if !self.token.is_like_plus() {
             return Ok(());
         }
 
@@ -1444,10 +1475,9 @@ fn inc_dec_standalone_suggest(
     pub(super) fn maybe_recover_from_bad_qpath<T: RecoverQPath>(
         &mut self,
         base: P<T>,
-        allow_recovery: bool,
     ) -> PResult<'a, P<T>> {
         // Do not add `::` to expected tokens.
-        if allow_recovery && self.token == token::ModSep {
+        if self.token == token::ModSep {
             if let Some(ty) = base.to_ty() {
                 return self.maybe_recover_from_bad_qpath_stage_2(ty.span, ty);
             }
@@ -1469,15 +1499,10 @@ pub(super) fn maybe_recover_from_bad_qpath_stage_2<T: RecoverQPath>(
         path.span = ty_span.to(self.prev_token.span);
 
         let ty_str = self.span_to_snippet(ty_span).unwrap_or_else(|_| pprust::ty_to_string(&ty));
-        self.struct_span_err(path.span, "missing angle brackets in associated item path")
-            .span_suggestion(
-                // This is a best-effort recovery.
-                path.span,
-                "try",
-                format!("<{}>::{}", ty_str, pprust::path_to_string(&path)),
-                Applicability::MaybeIncorrect,
-            )
-            .emit();
+        self.sess.emit_err(BadQPathStage2 {
+            span: path.span,
+            ty: format!("<{}>::{}", ty_str, pprust::path_to_string(&path)),
+        });
 
         let path_span = ty_span.shrink_to_hi(); // Use an empty path since `position == 0`.
         Ok(P(T::recovered(Some(QSelf { ty, path_span, position: 0 }), path)))
@@ -1486,13 +1511,10 @@ pub(super) fn maybe_recover_from_bad_qpath_stage_2<T: RecoverQPath>(
     pub fn maybe_consume_incorrect_semicolon(&mut self, items: &[P<Item>]) -> bool {
         if self.token.kind == TokenKind::Semi {
             self.bump();
-            let mut err = self.struct_span_err(self.prev_token.span, "expected item, found `;`");
-            err.span_suggestion_short(
-                self.prev_token.span,
-                "remove this semicolon",
-                String::new(),
-                Applicability::MachineApplicable,
-            );
+
+            let mut err =
+                IncorrectSemicolon { span: self.prev_token.span, opt_help: None, name: "" };
+
             if !items.is_empty() {
                 let previous_item = &items[items.len() - 1];
                 let previous_item_kind_name = match previous_item.kind {
@@ -1505,10 +1527,11 @@ pub fn maybe_consume_incorrect_semicolon(&mut self, items: &[P<Item>]) -> bool {
                     _ => None,
                 };
                 if let Some(name) = previous_item_kind_name {
-                    err.help(&format!("{name} declarations are not followed by a semicolon"));
+                    err.opt_help = Some(());
+                    err.name = name;
                 }
             }
-            err.emit();
+            self.sess.emit_err(err);
             true
         } else {
             false
@@ -1593,7 +1616,7 @@ pub(super) fn recover_incorrect_await_syntax(
             _ => ExprKind::Await(expr),
         };
         let expr = self.mk_expr(lo.to(sp), kind, attrs);
-        self.maybe_recover_from_bad_qpath(expr, true)
+        self.maybe_recover_from_bad_qpath(expr)
     }
 
     fn recover_await_macro(&mut self) -> PResult<'a, (Span, P<Expr>, bool)> {
@@ -1622,18 +1645,20 @@ fn recover_await_prefix(&mut self, await_sp: Span) -> PResult<'a, (Span, P<Expr>
     }
 
     fn error_on_incorrect_await(&self, lo: Span, hi: Span, expr: &Expr, is_question: bool) -> Span {
-        let expr_str =
-            self.span_to_snippet(expr.span).unwrap_or_else(|_| pprust::expr_to_string(&expr));
-        let suggestion = format!("{}.await{}", expr_str, if is_question { "?" } else { "" });
-        let sp = lo.to(hi);
-        let app = match expr.kind {
+        let span = lo.to(hi);
+        let applicability = match expr.kind {
             ExprKind::Try(_) => Applicability::MaybeIncorrect, // `await <expr>?`
             _ => Applicability::MachineApplicable,
         };
-        self.struct_span_err(sp, "incorrect use of `await`")
-            .span_suggestion(sp, "`await` is a postfix operation", suggestion, app)
-            .emit();
-        sp
+
+        self.sess.emit_err(IncorrectAwait {
+            span,
+            sugg_span: (span, applicability),
+            expr: self.span_to_snippet(expr.span).unwrap_or_else(|_| pprust::expr_to_string(&expr)),
+            question_mark: if is_question { "?" } else { "" },
+        });
+
+        span
     }
 
     /// If encountering `future.await()`, consumes and emits an error.
@@ -1644,16 +1669,10 @@ pub(super) fn recover_from_await_method_call(&mut self) {
             // future.await()
             let lo = self.token.span;
             self.bump(); // (
-            let sp = lo.to(self.token.span);
+            let span = lo.to(self.token.span);
             self.bump(); // )
-            self.struct_span_err(sp, "incorrect use of `await`")
-                .span_suggestion(
-                    sp,
-                    "`await` is not a method call, remove the parentheses",
-                    String::new(),
-                    Applicability::MachineApplicable,
-                )
-                .emit();
+
+            self.sess.emit_err(IncorrectUseOfAwait { span });
         }
     }
 
@@ -1925,14 +1944,10 @@ pub(super) fn recover_stmt_(
     pub(super) fn check_for_for_in_in_typo(&mut self, in_span: Span) {
         if self.eat_keyword(kw::In) {
             // a common typo: `for _ in in bar {}`
-            self.struct_span_err(self.prev_token.span, "expected iterable, found keyword `in`")
-                .span_suggestion_short(
-                    in_span.until(self.prev_token.span),
-                    "remove the duplicated `in`",
-                    String::new(),
-                    Applicability::MachineApplicable,
-                )
-                .emit();
+            self.sess.emit_err(InInTypo {
+                span: self.prev_token.span,
+                sugg_span: in_span.until(self.prev_token.span),
+            });
         }
     }
 
@@ -2457,10 +2472,9 @@ pub(super) fn incorrect_move_async_order_found(
     pub(crate) fn maybe_recover_colon_colon_in_pat_typo(
         &mut self,
         mut first_pat: P<Pat>,
-        ra: RecoverColon,
         expected: Expected,
     ) -> P<Pat> {
-        if RecoverColon::Yes != ra || token::Colon != self.token.kind {
+        if token::Colon != self.token.kind {
             return first_pat;
         }
         if !matches!(first_pat.kind, PatKind::Ident(_, _, None) | PatKind::Path(..))
@@ -2594,10 +2608,9 @@ pub(crate) fn maybe_recover_unexpected_block_label(&mut self) -> bool {
     pub(crate) fn maybe_recover_unexpected_comma(
         &mut self,
         lo: Span,
-        rc: RecoverComma,
         rt: CommaRecoveryMode,
     ) -> PResult<'a, ()> {
-        if rc == RecoverComma::No || self.token != token::Comma {
+        if self.token != token::Comma {
             return Ok(());
         }
 
index bb6d892138a3848f39b405fb84c61a70f3765d96..63c7decbb2fe65103185ef93646d8883de14792b 100644 (file)
@@ -1417,7 +1417,7 @@ fn parse_lit_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
         match self.parse_opt_lit() {
             Some(literal) => {
                 let expr = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Lit(literal), attrs);
-                self.maybe_recover_from_bad_qpath(expr, true)
+                self.maybe_recover_from_bad_qpath(expr)
             }
             None => self.try_macro_suggestion(),
         }
@@ -1444,7 +1444,7 @@ fn parse_tuple_parens_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
             ExprKind::Tup(es)
         };
         let expr = self.mk_expr(lo.to(self.prev_token.span), kind, attrs);
-        self.maybe_recover_from_bad_qpath(expr, true)
+        self.maybe_recover_from_bad_qpath(expr)
     }
 
     fn parse_array_or_repeat_expr(
@@ -1481,7 +1481,7 @@ fn parse_array_or_repeat_expr(
             }
         };
         let expr = self.mk_expr(lo.to(self.prev_token.span), kind, attrs);
-        self.maybe_recover_from_bad_qpath(expr, true)
+        self.maybe_recover_from_bad_qpath(expr)
     }
 
     fn parse_path_start_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
@@ -1519,7 +1519,7 @@ fn parse_path_start_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
         };
 
         let expr = self.mk_expr(lo.to(hi), kind, attrs);
-        self.maybe_recover_from_bad_qpath(expr, true)
+        self.maybe_recover_from_bad_qpath(expr)
     }
 
     /// Parse `'label: $expr`. The label is already parsed.
@@ -1604,7 +1604,7 @@ fn parse_return_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
         let lo = self.prev_token.span;
         let kind = ExprKind::Ret(self.parse_expr_opt()?);
         let expr = self.mk_expr(lo.to(self.prev_token.span), kind, attrs);
-        self.maybe_recover_from_bad_qpath(expr, true)
+        self.maybe_recover_from_bad_qpath(expr)
     }
 
     /// Parse `"do" "yeet" expr?`.
@@ -1619,7 +1619,7 @@ fn parse_yeet_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
         let span = lo.to(self.prev_token.span);
         self.sess.gated_spans.gate(sym::yeet_expr, span);
         let expr = self.mk_expr(span, kind, attrs);
-        self.maybe_recover_from_bad_qpath(expr, true)
+        self.maybe_recover_from_bad_qpath(expr)
     }
 
     /// Parse `"break" (('label (:? expr)?) | expr?)` with `"break"` token already eaten.
@@ -1679,7 +1679,7 @@ fn parse_break_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
             None
         };
         let expr = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Break(label, kind), attrs);
-        self.maybe_recover_from_bad_qpath(expr, true)
+        self.maybe_recover_from_bad_qpath(expr)
     }
 
     /// Parse `"yield" expr?`.
@@ -1689,7 +1689,7 @@ fn parse_yield_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
         let span = lo.to(self.prev_token.span);
         self.sess.gated_spans.gate(sym::generators, span);
         let expr = self.mk_expr(span, kind, attrs);
-        self.maybe_recover_from_bad_qpath(expr, true)
+        self.maybe_recover_from_bad_qpath(expr)
     }
 
     /// Returns a string literal if the next token is a string literal.
index 8019c5fb67cb9b46f255e6141e4b468d3b364c6e..2ad3f3ec19d572a4b80d4426e07eeac487b918a2 100644 (file)
@@ -100,8 +100,10 @@ fn parse_pat_allow_top_alt_inner(
         };
 
         // Parse the first pattern (`p_0`).
-        let first_pat = self.parse_pat_no_top_alt(expected)?;
-        self.maybe_recover_unexpected_comma(first_pat.span, rc, rt)?;
+        let mut first_pat = self.parse_pat_no_top_alt(expected)?;
+        if rc == RecoverComma::Yes {
+            self.maybe_recover_unexpected_comma(first_pat.span, rt)?;
+        }
 
         // If the next token is not a `|`,
         // this is not an or-pattern and we should exit here.
@@ -111,7 +113,9 @@ fn parse_pat_allow_top_alt_inner(
             // This complicated procedure is done purely for diagnostics UX.
 
             // Check if the user wrote `foo:bar` instead of `foo::bar`.
-            let first_pat = self.maybe_recover_colon_colon_in_pat_typo(first_pat, ra, expected);
+            if ra == RecoverColon::Yes {
+                first_pat = self.maybe_recover_colon_colon_in_pat_typo(first_pat, expected);
+            }
 
             if let Some(leading_vert_span) = leading_vert_span {
                 // If there was a leading vert, treat this as an or-pattern. This improves
@@ -139,7 +143,9 @@ fn parse_pat_allow_top_alt_inner(
                 err.span_label(lo, WHILE_PARSING_OR_MSG);
                 err
             })?;
-            self.maybe_recover_unexpected_comma(pat.span, rc, rt)?;
+            if rc == RecoverComma::Yes {
+                self.maybe_recover_unexpected_comma(pat.span, rt)?;
+            }
             pats.push(pat);
         }
         let or_pattern_span = lo.to(self.prev_token.span);
@@ -408,7 +414,7 @@ fn parse_pat_with_range_pat(
         };
 
         let pat = self.mk_pat(lo.to(self.prev_token.span), pat);
-        let pat = self.maybe_recover_from_bad_qpath(pat, true)?;
+        let pat = self.maybe_recover_from_bad_qpath(pat)?;
         let pat = self.recover_intersection_pat(pat)?;
 
         if !allow_range_pat {
index 27a6a48747408f959bb312f409cd951ea65c4e1a..7907ec44e98e9682554c741a9b3152c4e08a68d4 100644 (file)
@@ -180,7 +180,7 @@ fn parse_stmt_mac(&mut self, lo: Span, attrs: AttrVec, path: ast::Path) -> PResu
         } else {
             // Since none of the above applied, this is an expression statement macro.
             let e = self.mk_expr(lo.to(hi), ExprKind::MacCall(mac), AttrVec::new());
-            let e = self.maybe_recover_from_bad_qpath(e, true)?;
+            let e = self.maybe_recover_from_bad_qpath(e)?;
             let e = self.parse_dot_or_call_expr_with(e, lo, attrs.into())?;
             let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?;
             StmtKind::Expr(e)
index fb3f5eb3f9fe112b75b2b0c2fcc3b105441d5cf7..dee025cfd3c8a5659a617a403a0f977394e41ccb 100644 (file)
@@ -312,13 +312,18 @@ fn parse_ty_common(
         };
 
         let span = lo.to(self.prev_token.span);
-        let ty = self.mk_ty(span, kind);
+        let mut ty = self.mk_ty(span, kind);
 
         // Try to recover from use of `+` with incorrect priority.
-        self.maybe_report_ambiguous_plus(allow_plus, impl_dyn_multi, &ty);
-        self.maybe_recover_from_bad_type_plus(allow_plus, &ty)?;
-        let ty = self.maybe_recover_from_question_mark(ty, recover_question_mark);
-        self.maybe_recover_from_bad_qpath(ty, allow_qpath_recovery)
+        if matches!(allow_plus, AllowPlus::Yes) {
+            self.maybe_recover_from_bad_type_plus(&ty)?;
+        } else {
+            self.maybe_report_ambiguous_plus(impl_dyn_multi, &ty);
+        }
+        if let RecoverQuestionMark::Yes = recover_question_mark {
+            ty = self.maybe_recover_from_question_mark(ty);
+        }
+        if allow_qpath_recovery { self.maybe_recover_from_bad_qpath(ty) } else { Ok(ty) }
     }
 
     /// Parses either:
index e78d9a59982842b92879b36d5bc9928dd901970c..519fb7ea2640a5b19d874609a41343dcf7465558 100644 (file)
@@ -722,11 +722,7 @@ fn warn_dead_code(
                         traits_str,
                         is_are
                     );
-                    let multispan = ign_traits
-                        .iter()
-                        .map(|(_, impl_id)| self.tcx.def_span(*impl_id))
-                        .collect::<Vec<_>>();
-                    err.span_note(multispan, &msg);
+                    err.note(&msg);
                 }
                 err.emit();
             });
index 0ded6a421f57f30b20a2b948ee8c25db1dbba214..75376cdc592d36597c1d8b5e594d825d779c69cf 100644 (file)
@@ -148,32 +148,15 @@ fn def_id_represents_local_inlined_item(&self, def_id: DefId) -> bool {
                 hir::TraitItemKind::Fn(_, hir::TraitFn::Required(_))
                 | hir::TraitItemKind::Type(..) => false,
             },
-            Some(Node::ImplItem(impl_item)) => {
-                match impl_item.kind {
-                    hir::ImplItemKind::Const(..) => true,
-                    hir::ImplItemKind::Fn(..) => {
-                        let attrs = self.tcx.codegen_fn_attrs(def_id);
-                        let generics = self.tcx.generics_of(def_id);
-                        if generics.requires_monomorphization(self.tcx) || attrs.requests_inline() {
-                            true
-                        } else {
-                            let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
-                            let impl_did = self.tcx.hir().get_parent_item(hir_id);
-                            // Check the impl. If the generics on the self
-                            // type of the impl require inlining, this method
-                            // does too.
-                            match self.tcx.hir().expect_item(impl_did).kind {
-                                hir::ItemKind::Impl { .. } => {
-                                    let generics = self.tcx.generics_of(impl_did);
-                                    generics.requires_monomorphization(self.tcx)
-                                }
-                                _ => false,
-                            }
-                        }
-                    }
-                    hir::ImplItemKind::TyAlias(_) => false,
+            Some(Node::ImplItem(impl_item)) => match impl_item.kind {
+                hir::ImplItemKind::Const(..) => true,
+                hir::ImplItemKind::Fn(..) => {
+                    let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
+                    let impl_did = self.tcx.hir().get_parent_item(hir_id);
+                    method_might_be_inlined(self.tcx, impl_item, impl_did)
                 }
-            }
+                hir::ImplItemKind::TyAlias(_) => false,
+            },
             Some(_) => false,
             None => false, // This will happen for default methods.
         }
index 8e4b3269402e9b6a84dc40d144ab0825acba1792..e93bf1a475225adb2a8a15ef312f3b52214003cc 100644 (file)
@@ -713,7 +713,7 @@ fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Self {
         let len = BytePos::decode(decoder);
 
         let file_lo = decoder.file_index_to_file(file_lo_index);
-        let lo = file_lo.lines[line_lo - 1] + col_lo;
+        let lo = file_lo.lines(|lines| lines[line_lo - 1] + col_lo);
         let hi = lo + len;
 
         Span::new(lo, hi, ctxt, parent)
@@ -993,11 +993,6 @@ impl<'a, 'tcx, E> Encoder for CacheEncoder<'a, 'tcx, E>
 {
     type Error = E::Error;
 
-    #[inline]
-    fn emit_unit(&mut self) -> Result<(), Self::Error> {
-        Ok(())
-    }
-
     encoder_methods! {
         emit_usize(usize);
         emit_u128(u128);
index acf2990b6434883ba92509cb4bacc68e1f86a557..1fa085926767d3402186f0042dea533c6cc0e680 100644 (file)
@@ -69,7 +69,7 @@ fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHas
             external_src: _,
             start_pos,
             end_pos: _,
-            ref lines,
+            lines: _,
             ref multibyte_chars,
             ref non_narrow_chars,
             ref normalized_pos,
@@ -79,11 +79,15 @@ fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHas
 
         src_hash.hash_stable(hcx, hasher);
 
-        // We only hash the relative position within this source_file
-        lines.len().hash_stable(hcx, hasher);
-        for &line in lines.iter() {
-            stable_byte_pos(line, start_pos).hash_stable(hcx, hasher);
-        }
+        // We are always in `Lines` form by the time we reach here.
+        assert!(self.lines.borrow().is_lines());
+        self.lines(|lines| {
+            // We only hash the relative position within this source_file
+            lines.len().hash_stable(hcx, hasher);
+            for &line in lines.iter() {
+                stable_byte_pos(line, start_pos).hash_stable(hcx, hasher);
+            }
+        });
 
         // We only hash the relative position within this source_file
         multibyte_chars.len().hash_stable(hcx, hasher);
index c199cff2038729e3ce0aa59961e8fcfb1b9f78bc..b1fe418f687b4916547bd7110a3d77a599f72c15 100644 (file)
@@ -1839,9 +1839,18 @@ pub(crate) fn report_path_resolution_error(
                     )),
                 )
             } else if self.session.edition() == Edition::Edition2015 {
-                (format!("maybe a missing crate `{}`?", ident), None)
+                (
+                    format!("maybe a missing crate `{ident}`?"),
+                    Some((
+                        vec![],
+                        format!(
+                            "consider adding `extern crate {ident}` to use the `{ident}` crate"
+                        ),
+                        Applicability::MaybeIncorrect,
+                    )),
+                )
             } else {
-                (format!("could not find `{}` in the crate root", ident), None)
+                (format!("could not find `{ident}` in the crate root"), None)
             }
         } else if i > 0 {
             let parent = path[i - 1].ident.name;
@@ -1852,7 +1861,7 @@ pub(crate) fn report_path_resolution_error(
                     "the list of imported crates".to_owned()
                 }
                 kw::PathRoot | kw::Crate => "the crate root".to_owned(),
-                _ => format!("`{}`", parent),
+                _ => format!("`{parent}`"),
             };
 
             let mut msg = format!("could not find `{}` in {}", ident, parent);
index a8c8c674d2dd0ff4c0baa1fff96bc5b510a67a99..de83a3a5932c211a6f4f7238129b9a14803ae0c3 100644 (file)
@@ -475,6 +475,10 @@ fn throw_unresolved_import_error(
             }
 
             if let Some((suggestions, msg, applicability)) = err.suggestion {
+                if suggestions.is_empty() {
+                    diag.help(&msg);
+                    continue;
+                }
                 diag.multipart_suggestion(&msg, suggestions, applicability);
             }
         }
index 73d6566e3cd977655f2c1b5c07476aefe8aef1c3..288c89b0189c440a486356e9470244c828f2d433 100644 (file)
@@ -172,6 +172,23 @@ pub(crate) fn contains_params(&self) -> bool {
             AssocItemRibKind | ItemRibKind(_) | ForwardGenericParamBanRibKind => true,
         }
     }
+
+    /// This rib forbids referring to labels defined in upwards ribs.
+    fn is_label_barrier(self) -> bool {
+        match self {
+            NormalRibKind | MacroDefinition(..) => false,
+
+            AssocItemRibKind
+            | ClosureOrAsyncRibKind
+            | FnItemRibKind
+            | ItemRibKind(..)
+            | ConstantItemRibKind(..)
+            | ModuleRibKind(..)
+            | ForwardGenericParamBanRibKind
+            | ConstParamTyRibKind
+            | InlineAsmSymRibKind => true,
+        }
+    }
 }
 
 /// A single local scope.
@@ -732,7 +749,7 @@ fn visit_fn(&mut self, fn_kind: FnKind<'ast>, sp: Span, fn_id: NodeId) {
         // Create a value rib for the function.
         self.with_rib(ValueNS, rib_kind, |this| {
             // Create a label rib for the function.
-            this.with_label_rib(rib_kind, |this| {
+            this.with_label_rib(FnItemRibKind, |this| {
                 let async_node_id = fn_kind.header().and_then(|h| h.asyncness.opt_return_id());
 
                 if let FnKind::Fn(_, _, _, _, generics, _) = fn_kind {
@@ -1531,13 +1548,9 @@ fn record_lifetime_res(&mut self, id: NodeId, res: LifetimeRes) {
 
     /// Searches the current set of local scopes for labels. Returns the `NodeId` of the resolved
     /// label and reports an error if the label is not found or is unreachable.
-    fn resolve_label(&mut self, mut label: Ident) -> Option<NodeId> {
+    fn resolve_label(&mut self, mut label: Ident) -> Result<(NodeId, Span), ResolutionError<'a>> {
         let mut suggestion = None;
 
-        // Preserve the original span so that errors contain "in this macro invocation"
-        // information.
-        let original_span = label.span;
-
         for i in (0..self.label_ribs.len()).rev() {
             let rib = &self.label_ribs[i];
 
@@ -1553,18 +1566,13 @@ fn resolve_label(&mut self, mut label: Ident) -> Option<NodeId> {
             if let Some((ident, id)) = rib.bindings.get_key_value(&ident) {
                 let definition_span = ident.span;
                 return if self.is_label_valid_from_rib(i) {
-                    Some(*id)
+                    Ok((*id, definition_span))
                 } else {
-                    self.report_error(
-                        original_span,
-                        ResolutionError::UnreachableLabel {
-                            name: label.name,
-                            definition_span,
-                            suggestion,
-                        },
-                    );
-
-                    None
+                    Err(ResolutionError::UnreachableLabel {
+                        name: label.name,
+                        definition_span,
+                        suggestion,
+                    })
                 };
             }
 
@@ -1573,11 +1581,7 @@ fn resolve_label(&mut self, mut label: Ident) -> Option<NodeId> {
             suggestion = suggestion.or_else(|| self.suggestion_for_label_in_rib(i, label));
         }
 
-        self.report_error(
-            original_span,
-            ResolutionError::UndeclaredLabel { name: label.name, suggestion },
-        );
-        None
+        Err(ResolutionError::UndeclaredLabel { name: label.name, suggestion })
     }
 
     /// Determine whether or not a label from the `rib_index`th label rib is reachable.
@@ -1585,22 +1589,8 @@ fn is_label_valid_from_rib(&self, rib_index: usize) -> bool {
         let ribs = &self.label_ribs[rib_index + 1..];
 
         for rib in ribs {
-            match rib.kind {
-                NormalRibKind | MacroDefinition(..) => {
-                    // Nothing to do. Continue.
-                }
-
-                AssocItemRibKind
-                | ClosureOrAsyncRibKind
-                | FnItemRibKind
-                | ItemRibKind(..)
-                | ConstantItemRibKind(..)
-                | ModuleRibKind(..)
-                | ForwardGenericParamBanRibKind
-                | ConstParamTyRibKind
-                | InlineAsmSymRibKind => {
-                    return false;
-                }
+            if rib.kind.is_label_barrier() {
+                return false;
             }
         }
 
@@ -1895,6 +1885,8 @@ fn with_generic_param_rib<'c, F>(
         let mut function_value_rib = Rib::new(kind);
         let mut function_lifetime_rib = LifetimeRib::new(lifetime_kind);
         let mut seen_bindings = FxHashMap::default();
+        // Store all seen lifetimes names from outer scopes.
+        let mut seen_lifetimes = FxHashSet::default();
 
         // We also can't shadow bindings from the parent item
         if let AssocItemRibKind = kind {
@@ -1910,16 +1902,36 @@ fn with_generic_param_rib<'c, F>(
             add_bindings_for_ns(TypeNS);
         }
 
+        // Forbid shadowing lifetime bindings
+        for rib in self.lifetime_ribs.iter().rev() {
+            seen_lifetimes.extend(rib.bindings.iter().map(|(ident, _)| *ident));
+            if let LifetimeRibKind::Item = rib.kind {
+                break;
+            }
+        }
+
         for param in params {
             let ident = param.ident.normalize_to_macros_2_0();
             debug!("with_generic_param_rib: {}", param.id);
 
+            if let GenericParamKind::Lifetime = param.kind
+                && let Some(&original) = seen_lifetimes.get(&ident)
+            {
+                diagnostics::signal_lifetime_shadowing(self.r.session, original, param.ident);
+                // Record lifetime res, so lowering knows there is something fishy.
+                self.record_lifetime_res(param.id, LifetimeRes::Error);
+                continue;
+            }
+
             match seen_bindings.entry(ident) {
                 Entry::Occupied(entry) => {
                     let span = *entry.get();
                     let err = ResolutionError::NameAlreadyUsedInParameterList(ident.name, span);
-                    if !matches!(param.kind, GenericParamKind::Lifetime) {
-                        self.report_error(param.ident.span, err);
+                    self.report_error(param.ident.span, err);
+                    if let GenericParamKind::Lifetime = param.kind {
+                        // Record lifetime res, so lowering knows there is something fishy.
+                        self.record_lifetime_res(param.id, LifetimeRes::Error);
+                        continue;
                     }
                 }
                 Entry::Vacant(entry) => {
@@ -1936,6 +1948,8 @@ fn with_generic_param_rib<'c, F>(
                 )
                 .span_label(param.ident.span, "`'_` is a reserved lifetime name")
                 .emit();
+                // Record lifetime res, so lowering knows there is something fishy.
+                self.record_lifetime_res(param.id, LifetimeRes::Error);
                 continue;
             }
 
@@ -1949,6 +1963,8 @@ fn with_generic_param_rib<'c, F>(
                 )
                 .span_label(param.ident.span, "'static is a reserved lifetime name")
                 .emit();
+                // Record lifetime res, so lowering knows there is something fishy.
+                self.record_lifetime_res(param.id, LifetimeRes::Error);
                 continue;
             }
 
@@ -3114,6 +3130,11 @@ fn with_resolved_label(&mut self, label: Option<Label>, id: NodeId, f: impl FnOn
             if label.ident.as_str().as_bytes()[1] != b'_' {
                 self.diagnostic_metadata.unused_labels.insert(id, label.ident.span);
             }
+
+            if let Ok((_, orig_span)) = self.resolve_label(label.ident) {
+                diagnostics::signal_label_shadowing(self.r.session, orig_span, label.ident)
+            }
+
             self.with_label_rib(NormalRibKind, |this| {
                 let ident = label.ident.normalize_to_macro_rules();
                 this.label_ribs.last_mut().unwrap().bindings.insert(ident, id);
@@ -3219,10 +3240,15 @@ fn resolve_expr(&mut self, expr: &'ast Expr, parent: Option<&'ast Expr>) {
             }
 
             ExprKind::Break(Some(label), _) | ExprKind::Continue(Some(label)) => {
-                if let Some(node_id) = self.resolve_label(label.ident) {
-                    // Since this res is a label, it is never read.
-                    self.r.label_res_map.insert(expr.id, node_id);
-                    self.diagnostic_metadata.unused_labels.remove(&node_id);
+                match self.resolve_label(label.ident) {
+                    Ok((node_id, _)) => {
+                        // Since this res is a label, it is never read.
+                        self.r.label_res_map.insert(expr.id, node_id);
+                        self.diagnostic_metadata.unused_labels.remove(&node_id);
+                    }
+                    Err(error) => {
+                        self.report_error(label.ident.span, error);
+                    }
                 }
 
                 // visit `break` argument if any
index a6a04ac9ea6fc7da2681b608038edfcdc486fdf9..cb39eb5416ba27dbc2822d8529ffb2d32ef6b870 100644 (file)
@@ -13,7 +13,7 @@
 };
 use rustc_ast_lowering::ResolverAstLowering;
 use rustc_ast_pretty::pprust::path_segment_to_string;
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
 use rustc_errors::{
     pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
     MultiSpan,
 use rustc_hir as hir;
 use rustc_hir::def::Namespace::{self, *};
 use rustc_hir::def::{self, CtorKind, CtorOf, DefKind};
-use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_hir::PrimTy;
 use rustc_session::lint;
 use rustc_session::parse::feature_err;
+use rustc_session::Session;
 use rustc_span::edition::Edition;
 use rustc_span::hygiene::MacroKind;
 use rustc_span::lev_distance::find_best_match_for_name;
@@ -2036,6 +2037,34 @@ pub(crate) fn maybe_emit_forbidden_non_static_lifetime_error(
     }
 }
 
+/// Report lifetime/lifetime shadowing as an error.
+pub fn signal_lifetime_shadowing(sess: &Session, orig: Ident, shadower: Ident) {
+    let mut err = struct_span_err!(
+        sess,
+        shadower.span,
+        E0496,
+        "lifetime name `{}` shadows a lifetime name that is already in scope",
+        orig.name,
+    );
+    err.span_label(orig.span, "first declared here");
+    err.span_label(shadower.span, format!("lifetime `{}` already in scope", orig.name));
+    err.emit();
+}
+
+/// Shadowing involving a label is only a warning for historical reasons.
+//FIXME: make this a proper lint.
+pub fn signal_label_shadowing(sess: &Session, orig: Span, shadower: Ident) {
+    let name = shadower.name;
+    let shadower = shadower.span;
+    let mut err = sess.struct_span_warn(
+        shadower,
+        &format!("label name `{}` shadows a label name that is already in scope", name),
+    );
+    err.span_label(orig, "first declared here");
+    err.span_label(shadower, format!("label `{}` already in scope", name));
+    err.emit();
+}
+
 impl<'tcx> LifetimeContext<'_, 'tcx> {
     pub(crate) fn report_missing_lifetime_specifiers(
         &self,
@@ -2053,7 +2082,7 @@ pub(crate) fn report_missing_lifetime_specifiers(
 
     /// Returns whether to add `'static` lifetime to the suggested lifetime list.
     pub(crate) fn report_elision_failure(
-        &mut self,
+        &self,
         diag: &mut Diagnostic,
         params: &[ElisionFailureInfo],
     ) -> bool {
@@ -2158,10 +2187,27 @@ pub(crate) fn add_missing_lifetime_specifiers_label(
         &self,
         err: &mut Diagnostic,
         mut spans_with_counts: Vec<(Span, usize)>,
-        lifetime_names: &FxHashSet<Symbol>,
-        lifetime_spans: Vec<Span>,
-        params: &[ElisionFailureInfo],
+        in_scope_lifetimes: FxIndexSet<LocalDefId>,
+        params: Option<&[ElisionFailureInfo]>,
     ) {
+        let (mut lifetime_names, lifetime_spans): (FxHashSet<_>, Vec<_>) = in_scope_lifetimes
+            .iter()
+            .filter_map(|def_id| {
+                let name = self.tcx.item_name(def_id.to_def_id());
+                let span = self.tcx.def_ident_span(def_id.to_def_id())?;
+                Some((name, span))
+            })
+            .filter(|&(n, _)| n != kw::UnderscoreLifetime)
+            .unzip();
+
+        if let Some(params) = params {
+            // If there's no lifetime available, suggest `'static`.
+            if self.report_elision_failure(err, params) && lifetime_names.is_empty() {
+                lifetime_names.insert(kw::StaticLifetime);
+            }
+        }
+        let params = params.unwrap_or(&[]);
+
         let snippets: Vec<Option<String>> = spans_with_counts
             .iter()
             .map(|(span, _)| self.tcx.sess.source_map().span_to_snippet(*span).ok())
index 2fe65441ac90e8e6da53b35dd4a06157744e1627..11f80b314d7702171607eed088358b860c830bce 100644 (file)
@@ -8,22 +8,22 @@
 
 use crate::late::diagnostics::{ForLifetimeSpanType, MissingLifetimeSpot};
 use rustc_ast::walk_list;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefIdMap, LocalDefId};
 use rustc_hir::hir_id::ItemLocalId;
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{GenericArg, GenericParam, LifetimeName, Node, ParamName};
-use rustc_hir::{GenericParamKind, HirIdMap, HirIdSet};
+use rustc_hir::{GenericArg, GenericParam, LifetimeName, Node};
+use rustc_hir::{GenericParamKind, HirIdMap};
 use rustc_middle::hir::map::Map;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::resolve_lifetime::*;
-use rustc_middle::ty::{self, DefIdTree, GenericParamDefKind, TyCtxt};
+use rustc_middle::ty::{self, GenericParamDefKind, TyCtxt};
 use rustc_middle::{bug, span_bug};
 use rustc_span::def_id::DefId;
-use rustc_span::symbol::{kw, sym, Ident, Symbol};
+use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::Span;
 use std::borrow::Cow;
 use std::cell::Cell;
@@ -33,9 +33,9 @@
 use tracing::{debug, span, Level};
 
 trait RegionExt {
-    fn early(hir_map: Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (ParamName, Region);
+    fn early(hir_map: Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (LocalDefId, Region);
 
-    fn late(index: u32, hir_map: Map<'_>, param: &GenericParam<'_>) -> (ParamName, Region);
+    fn late(index: u32, hir_map: Map<'_>, param: &GenericParam<'_>) -> (LocalDefId, Region);
 
     fn late_anon(named_late_bound_vars: u32, index: &Cell<u32>) -> Region;
 
@@ -51,22 +51,22 @@ fn subst<'a, L>(self, params: L, map: &NamedRegionMap) -> Option<Region>
 }
 
 impl RegionExt for Region {
-    fn early(hir_map: Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (ParamName, Region) {
+    fn early(hir_map: Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (LocalDefId, Region) {
         let i = *index;
         *index += 1;
         let def_id = hir_map.local_def_id(param.hir_id);
         debug!("Region::early: index={} def_id={:?}", i, def_id);
-        (param.name.normalize_to_macros_2_0(), Region::EarlyBound(i, def_id.to_def_id()))
+        (def_id, Region::EarlyBound(i, def_id.to_def_id()))
     }
 
-    fn late(idx: u32, hir_map: Map<'_>, param: &GenericParam<'_>) -> (ParamName, Region) {
+    fn late(idx: u32, hir_map: Map<'_>, param: &GenericParam<'_>) -> (LocalDefId, Region) {
         let depth = ty::INNERMOST;
         let def_id = hir_map.local_def_id(param.hir_id);
         debug!(
             "Region::late: idx={:?}, param={:?} depth={:?} def_id={:?}",
             idx, param, depth, def_id,
         );
-        (param.name.normalize_to_macros_2_0(), Region::LateBound(depth, idx, def_id.to_def_id()))
+        (def_id, Region::LateBound(depth, idx, def_id.to_def_id()))
     }
 
     fn late_anon(named_late_bound_vars: u32, index: &Cell<u32>) -> Region {
@@ -134,11 +134,6 @@ struct NamedRegionMap {
     // `Region` describing how that region is bound
     defs: HirIdMap<Region>,
 
-    // the set of lifetime def ids that are late-bound; a region can
-    // be late-bound if (a) it does NOT appear in a where-clause and
-    // (b) it DOES appear in the arguments.
-    late_bound: HirIdSet,
-
     // Maps relevant hir items to the bound vars on them. These include:
     // - function defs
     // - function pointers
@@ -161,9 +156,6 @@ pub(crate) struct LifetimeContext<'a, 'tcx> {
     /// we eventually need lifetimes resolve for trait items.
     trait_definition_only: bool,
 
-    /// List of labels in the function/method currently under analysis.
-    labels_in_fn: Vec<Ident>,
-
     /// Cache for cross-crate per-definition object lifetime defaults.
     xcrate_object_lifetime_defaults: DefIdMap<Vec<ObjectLifetimeDefault>>,
 
@@ -181,7 +173,7 @@ enum Scope<'a> {
     Binder {
         /// We use an IndexMap here because we want these lifetimes in order
         /// for diagnostics.
-        lifetimes: FxIndexMap<hir::ParamName, Region>,
+        lifetimes: FxIndexMap<LocalDefId, Region>,
 
         /// if we extend this scope with another scope, what is the next index
         /// we should use for an early-bound region?
@@ -405,7 +397,7 @@ fn resolve_lifetimes_trait_definition(
     tcx: TyCtxt<'_>,
     local_def_id: LocalDefId,
 ) -> ResolveLifetimes {
-    convert_named_region_map(tcx, do_resolve(tcx, local_def_id, true, false))
+    convert_named_region_map(do_resolve(tcx, local_def_id, true, false))
 }
 
 /// Computes the `ResolveLifetimes` map that contains data for an entire `Item`.
@@ -413,7 +405,7 @@ fn resolve_lifetimes_trait_definition(
 /// `named_region_map`, `is_late_bound_map`, etc.
 #[tracing::instrument(level = "debug", skip(tcx))]
 fn resolve_lifetimes(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> ResolveLifetimes {
-    convert_named_region_map(tcx, do_resolve(tcx, local_def_id, false, false))
+    convert_named_region_map(do_resolve(tcx, local_def_id, false, false))
 }
 
 fn do_resolve(
@@ -425,7 +417,6 @@ fn do_resolve(
     let item = tcx.hir().expect_item(local_def_id);
     let mut named_region_map = NamedRegionMap {
         defs: Default::default(),
-        late_bound: Default::default(),
         late_bound_vars: Default::default(),
         scope_for_path: with_scope_for_path.then(|| Default::default()),
     };
@@ -434,7 +425,6 @@ fn do_resolve(
         map: &mut named_region_map,
         scope: ROOT_SCOPE,
         trait_definition_only,
-        labels_in_fn: vec![],
         xcrate_object_lifetime_defaults: Default::default(),
         missing_named_lifetime_spots: vec![],
     };
@@ -443,18 +433,13 @@ fn do_resolve(
     named_region_map
 }
 
-fn convert_named_region_map(tcx: TyCtxt<'_>, named_region_map: NamedRegionMap) -> ResolveLifetimes {
+fn convert_named_region_map(named_region_map: NamedRegionMap) -> ResolveLifetimes {
     let mut rl = ResolveLifetimes::default();
 
     for (hir_id, v) in named_region_map.defs {
         let map = rl.defs.entry(hir_id.owner).or_default();
         map.insert(hir_id.local_id, v);
     }
-    for hir_id in named_region_map.late_bound {
-        let map = rl.late_bound.entry(hir_id.owner).or_default();
-        let def_id = tcx.hir().local_def_id(hir_id);
-        map.insert(def_id);
-    }
     for (hir_id, v) in named_region_map.late_bound_vars {
         let map = rl.late_bound_vars.entry(hir_id.owner).or_default();
         map.insert(hir_id.local_id, v);
@@ -510,28 +495,6 @@ fn item_for(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> LocalDefId {
     item
 }
 
-fn is_late_bound_map<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    def_id: LocalDefId,
-) -> Option<(LocalDefId, &'tcx FxHashSet<LocalDefId>)> {
-    match tcx.def_kind(def_id) {
-        DefKind::AnonConst | DefKind::InlineConst => {
-            let mut def_id = tcx.local_parent(def_id);
-            // We search for the next outer anon const or fn here
-            // while skipping closures.
-            //
-            // Note that for `AnonConst` we still just recurse until we
-            // find a function body, but who cares :shrug:
-            while tcx.is_closure(def_id.to_def_id()) {
-                def_id = tcx.local_parent(def_id);
-            }
-
-            tcx.is_late_bound_map(def_id)
-        }
-        _ => resolve_lifetimes_for(tcx, def_id).late_bound.get(&def_id).map(|lt| (def_id, lt)),
-    }
-}
-
 /// In traits, there is an implicit `Self` type parameter which comes before the generics.
 /// We have to account for this when computing the index of the other generic parameters.
 /// This function returns whether there is such an implicit parameter defined on the given item.
@@ -558,10 +521,7 @@ fn get_lifetime_scopes_for_path(mut scope: &Scope<'_>) -> LifetimeScopeForPath {
     loop {
         match scope {
             Scope::Binder { lifetimes, s, .. } => {
-                available_lifetimes.extend(lifetimes.keys().filter_map(|p| match p {
-                    hir::ParamName::Plain(ident) => Some(ident.name),
-                    _ => None,
-                }));
+                available_lifetimes.extend(lifetimes.keys());
                 scope = s;
             }
             Scope::Body { s, .. } => {
@@ -641,14 +601,10 @@ fn visit_trait_item_ref(&mut self, ii: &'tcx hir::TraitItemRef) {
     }
 
     fn visit_nested_body(&mut self, body: hir::BodyId) {
-        // Each body has their own set of labels, save labels.
-        let saved = take(&mut self.labels_in_fn);
         let body = self.tcx.hir().body(body);
-        extract_labels(self, body);
-        self.with(Scope::Body { id: body.id(), s: self.scope }, |_, this| {
+        self.with(Scope::Body { id: body.id(), s: self.scope }, |this| {
             this.visit_body(body);
         });
-        self.labels_in_fn = saved;
     }
 
     fn visit_fn(
@@ -683,9 +639,7 @@ fn visit_fn(
                     scope_type: BinderScopeType::Normal,
                     allow_late_bound: true,
                 };
-                self.with(scope, move |_old_scope, this| {
-                    intravisit::walk_fn(this, fk, fd, b, s, hir_id)
-                });
+                self.with(scope, move |this| intravisit::walk_fn(this, fk, fd, b, s, hir_id));
             }
         }
     }
@@ -700,9 +654,9 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
             _ => {}
         }
         match item.kind {
-            hir::ItemKind::Fn(ref sig, ref generics, _) => {
+            hir::ItemKind::Fn(_, ref generics, _) => {
                 self.missing_named_lifetime_spots.push(generics.into());
-                self.visit_early_late(None, item.hir_id(), &sig.decl, generics, |this| {
+                self.visit_early_late(None, item.hir_id(), generics, |this| {
                     intravisit::walk_item(this, item);
                 });
                 self.missing_named_lifetime_spots.pop();
@@ -720,7 +674,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
             hir::ItemKind::Static(..) | hir::ItemKind::Const(..) => {
                 // No lifetime parameters, but implied 'static.
                 let scope = Scope::Elision { elide: Elide::Exact(Region::Static), s: ROOT_SCOPE };
-                self.with(scope, |_, this| intravisit::walk_item(this, item));
+                self.with(scope, |this| intravisit::walk_item(this, item));
             }
             hir::ItemKind::OpaqueTy(hir::OpaqueTy { .. }) => {
                 // Opaque types are visited when we visit the
@@ -744,13 +698,6 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
                                     self.map.defs.insert(hir::HirId { owner, local_id }, *region);
                                 });
                             }
-                            for (&owner, late_bound) in resolved_lifetimes.late_bound.iter() {
-                                late_bound.iter().for_each(|&id| {
-                                    let hir_id = self.tcx.local_def_id_to_hir_id(id);
-                                    debug_assert_eq!(owner, hir_id.owner);
-                                    self.map.late_bound.insert(hir_id);
-                                });
-                            }
                             for (&owner, late_bound_vars) in
                                 resolved_lifetimes.late_bound_vars.iter()
                             {
@@ -807,10 +754,9 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
                     s: ROOT_SCOPE,
                     allow_late_bound: false,
                 };
-                self.with(scope, |old_scope, this| {
-                    this.check_lifetime_params(old_scope, &generics.params);
+                self.with(scope, |this| {
                     let scope = Scope::TraitRefBoundary { s: this.scope };
-                    this.with(scope, |_, this| {
+                    this.with(scope, |this| {
                         intravisit::walk_item(this, item);
                     });
                 });
@@ -821,8 +767,8 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
 
     fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) {
         match item.kind {
-            hir::ForeignItemKind::Fn(ref decl, _, ref generics) => {
-                self.visit_early_late(None, item.hir_id(), decl, generics, |this| {
+            hir::ForeignItemKind::Fn(_, _, ref generics) => {
+                self.visit_early_late(None, item.hir_id(), generics, |this| {
                     intravisit::walk_foreign_item(this, item);
                 })
             }
@@ -852,7 +798,7 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
                 };
                 self.missing_named_lifetime_spots
                     .push(MissingLifetimeSpot::HigherRanked { span, span_type });
-                let (lifetimes, binders): (FxIndexMap<hir::ParamName, Region>, Vec<_>) = c
+                let (lifetimes, binders): (FxIndexMap<LocalDefId, Region>, Vec<_>) = c
                     .generic_params
                     .iter()
                     .filter(|param| matches!(param.kind, GenericParamKind::Lifetime { .. }))
@@ -873,10 +819,9 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
                     scope_type: BinderScopeType::Normal,
                     allow_late_bound: true,
                 };
-                self.with(scope, |old_scope, this| {
+                self.with(scope, |this| {
                     // a bare fn has no bounds, so everything
                     // contained within is scoped within its binder.
-                    this.check_lifetime_params(old_scope, &c.generic_params);
                     intravisit::walk_ty(this, ty);
                 });
                 self.missing_named_lifetime_spots.pop();
@@ -884,7 +829,7 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
             hir::TyKind::TraitObject(bounds, ref lifetime, _) => {
                 debug!(?bounds, ?lifetime, "TraitObject");
                 let scope = Scope::TraitRefBoundary { s: self.scope };
-                self.with(scope, |_, this| {
+                self.with(scope, |this| {
                     for bound in bounds {
                         this.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None);
                     }
@@ -910,7 +855,7 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
                         // cc #48468
                         self.resolve_elided_lifetimes(&[lifetime])
                     }
-                    LifetimeName::Param(_) | LifetimeName::Static => {
+                    LifetimeName::Param(..) | LifetimeName::Static => {
                         // If the user wrote an explicit name, use that.
                         self.visit_lifetime(lifetime);
                     }
@@ -923,7 +868,7 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
                     lifetime: self.map.defs.get(&lifetime_ref.hir_id).cloned(),
                     s: self.scope,
                 };
-                self.with(scope, |_, this| this.visit_ty(&mt.ty));
+                self.with(scope, |this| this.visit_ty(&mt.ty));
             }
             hir::TyKind::OpaqueDef(item_id, lifetimes) => {
                 // Resolve the lifetimes in the bounds to the lifetime defs in the generics.
@@ -944,9 +889,9 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
                         // Elided lifetimes are not allowed in non-return
                         // position impl Trait
                         let scope = Scope::TraitRefBoundary { s: self.scope };
-                        self.with(scope, |_, this| {
+                        self.with(scope, |this| {
                             let scope = Scope::Elision { elide: Elide::Forbid, s: this.scope };
-                            this.with(scope, |_, this| {
+                            this.with(scope, |this| {
                                 intravisit::walk_item(this, opaque_ty);
                             })
                         });
@@ -1028,17 +973,17 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
                 for param in generics.params {
                     match param.kind {
                         GenericParamKind::Lifetime { .. } => {
-                            let (name, reg) = Region::early(self.tcx.hir(), &mut index, &param);
+                            let (def_id, reg) = Region::early(self.tcx.hir(), &mut index, &param);
                             if let hir::ParamName::Plain(Ident {
                                 name: kw::UnderscoreLifetime,
                                 ..
-                            }) = name
+                            }) = param.name
                             {
                                 // Pick the elided lifetime "definition" if one exists
                                 // and use it to make an elision scope.
                                 elision = Some(reg);
                             } else {
-                                lifetimes.insert(name, reg);
+                                lifetimes.insert(def_id, reg);
                             }
                         }
                         GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
@@ -1052,7 +997,7 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
                 if let Some(elision_region) = elision {
                     let scope =
                         Scope::Elision { elide: Elide::Exact(elision_region), s: self.scope };
-                    self.with(scope, |_old_scope, this| {
+                    self.with(scope, |this| {
                         let scope = Scope::Binder {
                             hir_id: ty.hir_id,
                             lifetimes,
@@ -1062,10 +1007,10 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
                             scope_type: BinderScopeType::Normal,
                             allow_late_bound: false,
                         };
-                        this.with(scope, |_old_scope, this| {
+                        this.with(scope, |this| {
                             this.visit_generics(generics);
                             let scope = Scope::TraitRefBoundary { s: this.scope };
-                            this.with(scope, |_, this| {
+                            this.with(scope, |this| {
                                 for bound in bounds {
                                     this.visit_param_bound(bound);
                                 }
@@ -1082,9 +1027,9 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
                         scope_type: BinderScopeType::Normal,
                         allow_late_bound: false,
                     };
-                    self.with(scope, |_old_scope, this| {
+                    self.with(scope, |this| {
                         let scope = Scope::TraitRefBoundary { s: this.scope };
-                        this.with(scope, |_, this| {
+                        this.with(scope, |this| {
                             this.visit_generics(generics);
                             for bound in bounds {
                                 this.visit_param_bound(bound);
@@ -1100,13 +1045,12 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
     fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
         use self::hir::TraitItemKind::*;
         match trait_item.kind {
-            Fn(ref sig, _) => {
+            Fn(_, _) => {
                 self.missing_named_lifetime_spots.push((&trait_item.generics).into());
                 let tcx = self.tcx;
                 self.visit_early_late(
                     Some(tcx.hir().get_parent_item(trait_item.hir_id())),
                     trait_item.hir_id(),
-                    &sig.decl,
                     &trait_item.generics,
                     |this| intravisit::walk_trait_item(this, trait_item),
                 );
@@ -1141,10 +1085,9 @@ fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
                     scope_type: BinderScopeType::Normal,
                     allow_late_bound: false,
                 };
-                self.with(scope, |old_scope, this| {
-                    this.check_lifetime_params(old_scope, &generics.params);
+                self.with(scope, |this| {
                     let scope = Scope::TraitRefBoundary { s: this.scope };
-                    this.with(scope, |_, this| {
+                    this.with(scope, |this| {
                         this.visit_generics(generics);
                         for bound in bounds {
                             this.visit_param_bound(bound);
@@ -1169,13 +1112,12 @@ fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
     fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
         use self::hir::ImplItemKind::*;
         match impl_item.kind {
-            Fn(ref sig, _) => {
+            Fn(..) => {
                 self.missing_named_lifetime_spots.push((&impl_item.generics).into());
                 let tcx = self.tcx;
                 self.visit_early_late(
                     Some(tcx.hir().get_parent_item(impl_item.hir_id())),
                     impl_item.hir_id(),
-                    &sig.decl,
                     &impl_item.generics,
                     |this| intravisit::walk_impl_item(this, impl_item),
                 );
@@ -1187,7 +1129,7 @@ fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
                 let mut index = self.next_early_index();
                 let mut non_lifetime_count = 0;
                 debug!("visit_ty: index = {}", index);
-                let lifetimes: FxIndexMap<hir::ParamName, Region> = generics
+                let lifetimes: FxIndexMap<LocalDefId, Region> = generics
                     .params
                     .iter()
                     .filter_map(|param| match param.kind {
@@ -1210,10 +1152,9 @@ fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
                     scope_type: BinderScopeType::Normal,
                     allow_late_bound: true,
                 };
-                self.with(scope, |old_scope, this| {
-                    this.check_lifetime_params(old_scope, &generics.params);
+                self.with(scope, |this| {
                     let scope = Scope::TraitRefBoundary { s: this.scope };
-                    this.with(scope, |_, this| {
+                    this.with(scope, |this| {
                         this.visit_generics(generics);
                         this.visit_ty(ty);
                     })
@@ -1232,15 +1173,17 @@ fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
 
     #[tracing::instrument(level = "debug", skip(self))]
     fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
-        if lifetime_ref.is_elided() {
-            self.resolve_elided_lifetimes(&[lifetime_ref]);
-            return;
-        }
-        if lifetime_ref.is_static() {
-            self.insert_lifetime(lifetime_ref, Region::Static);
-            return;
+        match lifetime_ref.name {
+            hir::LifetimeName::ImplicitObjectLifetimeDefault
+            | hir::LifetimeName::Implicit
+            | hir::LifetimeName::Underscore => self.resolve_elided_lifetimes(&[lifetime_ref]),
+            hir::LifetimeName::Static => self.insert_lifetime(lifetime_ref, Region::Static),
+            hir::LifetimeName::Param(param_def_id, _) => {
+                self.resolve_lifetime_ref(param_def_id, lifetime_ref)
+            }
+            // If we've already reported an error, just ignore `lifetime_ref`.
+            hir::LifetimeName::Error => {}
         }
-        self.resolve_lifetime_ref(lifetime_ref);
     }
 
     fn visit_assoc_type_binding(&mut self, type_binding: &'tcx hir::TypeBinding<'_>) {
@@ -1300,7 +1243,7 @@ fn visit_fn_decl(&mut self, fd: &'tcx hir::FnDecl<'tcx>) {
 
     fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) {
         let scope = Scope::TraitRefBoundary { s: self.scope };
-        self.with(scope, |_, this| {
+        self.with(scope, |this| {
             for param in generics.params {
                 match param.kind {
                     GenericParamKind::Lifetime { .. } => {}
@@ -1325,7 +1268,7 @@ fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) {
                         ref bound_generic_params,
                         ..
                     }) => {
-                        let (lifetimes, binders): (FxIndexMap<hir::ParamName, Region>, Vec<_>) =
+                        let (lifetimes, binders): (FxIndexMap<LocalDefId, Region>, Vec<_>) =
                             bound_generic_params
                                 .iter()
                                 .filter(|param| {
@@ -1354,8 +1297,7 @@ fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) {
                             scope_type: BinderScopeType::Normal,
                             allow_late_bound: true,
                         };
-                        this.with(scope, |old_scope, this| {
-                            this.check_lifetime_params(old_scope, &bound_generic_params);
+                        this.with(scope, |this| {
                             this.visit_ty(&bounded_ty);
                             walk_list!(this, visit_param_bound, bounds);
                         })
@@ -1427,7 +1369,7 @@ fn visit_param_bound(&mut self, bound: &'tcx hir::GenericBound<'tcx>) {
                     scope_type,
                     allow_late_bound: true,
                 };
-                self.with(scope, |_, this| {
+                self.with(scope, |this| {
                     intravisit::walk_param_bound(this, bound);
                 });
             }
@@ -1448,7 +1390,7 @@ fn visit_poly_trait_ref(
         let (mut binders, scope_type) = self.poly_trait_ref_binder_info();
 
         let initial_bound_vars = binders.len() as u32;
-        let mut lifetimes: FxIndexMap<hir::ParamName, Region> = FxIndexMap::default();
+        let mut lifetimes: FxIndexMap<LocalDefId, Region> = FxIndexMap::default();
         let binders_iter = trait_ref
             .bound_generic_params
             .iter()
@@ -1479,8 +1421,7 @@ fn visit_poly_trait_ref(
             scope_type,
             allow_late_bound: true,
         };
-        self.with(scope, |old_scope, this| {
-            this.check_lifetime_params(old_scope, &trait_ref.bound_generic_params);
+        self.with(scope, |this| {
             walk_list!(this, visit_generic_param, trait_ref.bound_generic_params);
             this.visit_trait_ref(&trait_ref.trait_ref);
         });
@@ -1491,154 +1432,6 @@ fn visit_poly_trait_ref(
     }
 }
 
-#[derive(Copy, Clone, PartialEq)]
-enum ShadowKind {
-    Label,
-    Lifetime,
-}
-struct Original {
-    kind: ShadowKind,
-    span: Span,
-}
-struct Shadower {
-    kind: ShadowKind,
-    span: Span,
-}
-
-fn original_label(span: Span) -> Original {
-    Original { kind: ShadowKind::Label, span }
-}
-fn shadower_label(span: Span) -> Shadower {
-    Shadower { kind: ShadowKind::Label, span }
-}
-fn original_lifetime(span: Span) -> Original {
-    Original { kind: ShadowKind::Lifetime, span }
-}
-fn shadower_lifetime(param: &hir::GenericParam<'_>) -> Shadower {
-    Shadower { kind: ShadowKind::Lifetime, span: param.span }
-}
-
-impl ShadowKind {
-    fn desc(&self) -> &'static str {
-        match *self {
-            ShadowKind::Label => "label",
-            ShadowKind::Lifetime => "lifetime",
-        }
-    }
-}
-
-fn signal_shadowing_problem(tcx: TyCtxt<'_>, name: Symbol, orig: Original, shadower: Shadower) {
-    let mut err = if let (ShadowKind::Lifetime, ShadowKind::Lifetime) = (orig.kind, shadower.kind) {
-        // lifetime/lifetime shadowing is an error
-        struct_span_err!(
-            tcx.sess,
-            shadower.span,
-            E0496,
-            "{} name `{}` shadows a \
-             {} name that is already in scope",
-            shadower.kind.desc(),
-            name,
-            orig.kind.desc()
-        )
-        .forget_guarantee()
-    } else {
-        // shadowing involving a label is only a warning, due to issues with
-        // labels and lifetimes not being macro-hygienic.
-        tcx.sess.struct_span_warn(
-            shadower.span,
-            &format!(
-                "{} name `{}` shadows a \
-                 {} name that is already in scope",
-                shadower.kind.desc(),
-                name,
-                orig.kind.desc()
-            ),
-        )
-    };
-    err.span_label(orig.span, "first declared here");
-    err.span_label(shadower.span, format!("{} `{}` already in scope", orig.kind.desc(), name));
-    err.emit();
-}
-
-// Adds all labels in `b` to `ctxt.labels_in_fn`, signalling a warning
-// if one of the label shadows a lifetime or another label.
-fn extract_labels(ctxt: &mut LifetimeContext<'_, '_>, body: &hir::Body<'_>) {
-    struct GatherLabels<'a, 'tcx> {
-        tcx: TyCtxt<'tcx>,
-        scope: ScopeRef<'a>,
-        labels_in_fn: &'a mut Vec<Ident>,
-    }
-
-    let mut gather =
-        GatherLabels { tcx: ctxt.tcx, scope: ctxt.scope, labels_in_fn: &mut ctxt.labels_in_fn };
-    gather.visit_body(body);
-
-    impl<'v, 'a, 'tcx> Visitor<'v> for GatherLabels<'a, 'tcx> {
-        fn visit_expr(&mut self, ex: &hir::Expr<'_>) {
-            if let Some(label) = expression_label(ex) {
-                for prior_label in &self.labels_in_fn[..] {
-                    // FIXME (#24278): non-hygienic comparison
-                    if label.name == prior_label.name {
-                        signal_shadowing_problem(
-                            self.tcx,
-                            label.name,
-                            original_label(prior_label.span),
-                            shadower_label(label.span),
-                        );
-                    }
-                }
-
-                check_if_label_shadows_lifetime(self.tcx, self.scope, label);
-
-                self.labels_in_fn.push(label);
-            }
-            intravisit::walk_expr(self, ex)
-        }
-    }
-
-    fn expression_label(ex: &hir::Expr<'_>) -> Option<Ident> {
-        match ex.kind {
-            hir::ExprKind::Loop(_, Some(label), ..) => Some(label.ident),
-            hir::ExprKind::Block(_, Some(label)) => Some(label.ident),
-            _ => None,
-        }
-    }
-
-    fn check_if_label_shadows_lifetime(tcx: TyCtxt<'_>, mut scope: ScopeRef<'_>, label: Ident) {
-        loop {
-            match *scope {
-                Scope::Body { s, .. }
-                | Scope::Elision { s, .. }
-                | Scope::ObjectLifetimeDefault { s, .. }
-                | Scope::Supertrait { s, .. }
-                | Scope::TraitRefBoundary { s, .. } => {
-                    scope = s;
-                }
-
-                Scope::Root => {
-                    return;
-                }
-
-                Scope::Binder { ref lifetimes, s, .. } => {
-                    // FIXME (#24278): non-hygienic comparison
-                    if let Some(def) =
-                        lifetimes.get(&hir::ParamName::Plain(label.normalize_to_macros_2_0()))
-                    {
-                        signal_shadowing_problem(
-                            tcx,
-                            label.name,
-                            original_lifetime(tcx.def_span(def.id().unwrap().expect_local())),
-                            shadower_label(label.span),
-                        );
-                        return;
-                    }
-                    scope = s;
-                }
-            }
-        }
-    }
-}
-
 fn compute_object_lifetime_defaults<'tcx>(
     tcx: TyCtxt<'tcx>,
     item: &hir::Item<'_>,
@@ -1744,14 +1537,17 @@ fn add_bounds(set: &mut Set1<hir::LifetimeName>, bounds: &[hir::GenericBound<'_>
                             .iter()
                             .filter_map(|param| match param.kind {
                                 GenericParamKind::Lifetime { .. } => {
-                                    Some((param.hir_id, hir::LifetimeName::Param(param.name)))
+                                    let param_def_id = tcx.hir().local_def_id(param.hir_id);
+                                    Some((
+                                        param_def_id,
+                                        hir::LifetimeName::Param(param_def_id, param.name),
+                                    ))
                                 }
                                 _ => None,
                             })
                             .enumerate()
                             .find(|&(_, (_, lt_name))| lt_name == name)
-                            .map_or(Set1::Many, |(i, (id, _))| {
-                                let def_id = tcx.hir().local_def_id(id);
+                            .map_or(Set1::Many, |(i, (def_id, _))| {
                                 Set1::One(Region::EarlyBound(i as u32, def_id.to_def_id()))
                             })
                     }
@@ -1774,10 +1570,9 @@ fn add_bounds(set: &mut Set1<hir::LifetimeName>, bounds: &[hir::GenericBound<'_>
 impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
     fn with<F>(&mut self, wrap_scope: Scope<'_>, f: F)
     where
-        F: for<'b> FnOnce(ScopeRef<'_>, &mut LifetimeContext<'b, 'tcx>),
+        F: for<'b> FnOnce(&mut LifetimeContext<'b, 'tcx>),
     {
         let LifetimeContext { tcx, map, .. } = self;
-        let labels_in_fn = take(&mut self.labels_in_fn);
         let xcrate_object_lifetime_defaults = take(&mut self.xcrate_object_lifetime_defaults);
         let missing_named_lifetime_spots = take(&mut self.missing_named_lifetime_spots);
         let mut this = LifetimeContext {
@@ -1785,16 +1580,14 @@ fn with<F>(&mut self, wrap_scope: Scope<'_>, f: F)
             map,
             scope: &wrap_scope,
             trait_definition_only: self.trait_definition_only,
-            labels_in_fn,
             xcrate_object_lifetime_defaults,
             missing_named_lifetime_spots,
         };
         let span = tracing::debug_span!("scope", scope = ?TruncatedScopeDebug(&this.scope));
         {
             let _enter = span.enter();
-            f(self.scope, &mut this);
+            f(&mut this);
         }
-        self.labels_in_fn = this.labels_in_fn;
         self.xcrate_object_lifetime_defaults = this.xcrate_object_lifetime_defaults;
         self.missing_named_lifetime_spots = this.missing_named_lifetime_spots;
     }
@@ -1821,14 +1614,11 @@ fn visit_early_late<F>(
         &mut self,
         parent_id: Option<LocalDefId>,
         hir_id: hir::HirId,
-        decl: &'tcx hir::FnDecl<'tcx>,
         generics: &'tcx hir::Generics<'tcx>,
         walk: F,
     ) where
         F: for<'b, 'c> FnOnce(&'b mut LifetimeContext<'c, 'tcx>),
     {
-        insert_late_bound_lifetimes(self.map, decl, generics);
-
         // Find the start of nested early scopes, e.g., in methods.
         let mut next_early_index = 0;
         if let Some(parent_id) = parent_id {
@@ -1847,12 +1637,12 @@ fn visit_early_late<F>(
 
         let mut non_lifetime_count = 0;
         let mut named_late_bound_vars = 0;
-        let lifetimes: FxIndexMap<hir::ParamName, Region> = generics
+        let lifetimes: FxIndexMap<LocalDefId, Region> = generics
             .params
             .iter()
             .filter_map(|param| match param.kind {
                 GenericParamKind::Lifetime { .. } => {
-                    if self.map.late_bound.contains(&param.hir_id) {
+                    if self.tcx.is_late_bound(param.hir_id) {
                         let late_bound_idx = named_late_bound_vars;
                         named_late_bound_vars += 1;
                         Some(Region::late(late_bound_idx, self.tcx.hir(), param))
@@ -1873,7 +1663,7 @@ fn visit_early_late<F>(
             .iter()
             .filter(|param| {
                 matches!(param.kind, GenericParamKind::Lifetime { .. })
-                    && self.map.late_bound.contains(&param.hir_id)
+                    && self.tcx.is_late_bound(param.hir_id)
             })
             .enumerate()
             .map(|(late_bound_idx, param)| {
@@ -1891,10 +1681,7 @@ fn visit_early_late<F>(
             scope_type: BinderScopeType::Normal,
             allow_late_bound: true,
         };
-        self.with(scope, move |old_scope, this| {
-            this.check_lifetime_params(old_scope, &generics.params);
-            walk(this);
-        });
+        self.with(scope, walk);
     }
 
     fn next_early_index_helper(&self, only_opaque_type_parent: bool) -> u32 {
@@ -1933,14 +1720,12 @@ fn next_early_index_for_opaque_type(&self) -> u32 {
         self.next_early_index_helper(false)
     }
 
-    fn resolve_lifetime_ref(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
-        debug!("resolve_lifetime_ref(lifetime_ref={:?})", lifetime_ref);
-
-        // If we've already reported an error, just ignore `lifetime_ref`.
-        if let LifetimeName::Error = lifetime_ref.name {
-            return;
-        }
-
+    #[tracing::instrument(level = "debug", skip(self))]
+    fn resolve_lifetime_ref(
+        &mut self,
+        region_def_id: LocalDefId,
+        lifetime_ref: &'tcx hir::Lifetime,
+    ) {
         // Walk up the scope chain, tracking the number of fn scopes
         // that we pass through, until we find a lifetime with the
         // given name or we run out of scopes.
@@ -1960,14 +1745,8 @@ fn resolve_lifetime_ref(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
                 }
 
                 Scope::Binder { ref lifetimes, scope_type, s, .. } => {
-                    match lifetime_ref.name {
-                        LifetimeName::Param(param_name) => {
-                            if let Some(&def) = lifetimes.get(&param_name.normalize_to_macros_2_0())
-                            {
-                                break Some(def.shifted(late_depth));
-                            }
-                        }
-                        _ => bug!("expected LifetimeName::Param"),
+                    if let Some(&def) = lifetimes.get(&region_def_id) {
+                        break Some(def.shifted(late_depth));
                     }
                     match scope_type {
                         BinderScopeType::Normal => late_depth += 1,
@@ -2165,7 +1944,7 @@ fn visit_segment_args(
                 GenericArg::Type(ty) => {
                     if let Some(&lt) = object_lifetime_defaults.get(i) {
                         let scope = Scope::ObjectLifetimeDefault { lifetime: lt, s: self.scope };
-                        self.with(scope, |_, this| this.visit_ty(ty));
+                        self.with(scope, |this| this.visit_ty(ty));
                     } else {
                         self.visit_ty(ty);
                     }
@@ -2222,15 +2001,15 @@ fn visit_segment_args(
                     type_def_id,
                     binding.ident,
                 );
-                self.with(scope, |_, this| {
+                self.with(scope, |this| {
                     let scope = Scope::Supertrait {
                         lifetimes: lifetimes.unwrap_or_default(),
                         s: this.scope,
                     };
-                    this.with(scope, |_, this| this.visit_assoc_type_binding(binding));
+                    this.with(scope, |this| this.visit_assoc_type_binding(binding));
                 });
             } else {
-                self.with(scope, |_, this| this.visit_assoc_type_binding(binding));
+                self.with(scope, |this| this.visit_assoc_type_binding(binding));
             }
         }
     }
@@ -2346,7 +2125,7 @@ fn visit_fn_like_elision(
             elide: Elide::FreshLateAnon(named_late_bound_vars, Cell::new(0)),
             s: self.scope,
         };
-        self.with(arg_scope, |_, this| {
+        self.with(arg_scope, |this| {
             for input in inputs {
                 this.visit_ty(input);
             }
@@ -2466,7 +2245,7 @@ fn visit_ty(&mut self, ty: &'a hir::Ty<'a>) {
             visitor.visit_ty(&inputs[0]);
             if let Set1::One(lifetime) = visitor.lifetime {
                 let scope = Scope::Elision { elide: Elide::Exact(lifetime), s: self.scope };
-                self.with(scope, |_, this| this.visit_ty(output));
+                self.with(scope, |this| this.visit_ty(output));
                 return;
             }
         }
@@ -2517,7 +2296,7 @@ fn visit_ty(&mut self, ty: &'a hir::Ty<'a>) {
         debug!(?elide);
 
         let scope = Scope::Elision { elide, s: self.scope };
-        self.with(scope, |_, this| this.visit_ty(output));
+        self.with(scope, |this| this.visit_ty(output));
 
         struct GatherLifetimes<'a> {
             map: &'a NamedRegionMap,
@@ -2643,8 +2422,7 @@ fn resolve_elided_lifetimes(&mut self, lifetime_refs: &[&'tcx hir::Lifetime]) {
 
         let mut late_depth = 0;
         let mut scope = self.scope;
-        let mut lifetime_names = FxHashSet::default();
-        let mut lifetime_spans = vec![];
+        let mut in_scope_lifetimes = FxIndexSet::default();
         let error = loop {
             match *scope {
                 // Do not assign any resolution, it will be inferred.
@@ -2654,12 +2432,7 @@ fn resolve_elided_lifetimes(&mut self, lifetime_refs: &[&'tcx hir::Lifetime]) {
 
                 Scope::Binder { s, ref lifetimes, scope_type, .. } => {
                     // collect named lifetimes for suggestions
-                    for name in lifetimes.keys() {
-                        if let hir::ParamName::Plain(name) = name {
-                            lifetime_names.insert(name.name);
-                            lifetime_spans.push(name.span);
-                        }
-                    }
+                    in_scope_lifetimes.extend(lifetimes.keys().copied());
                     match scope_type {
                         BinderScopeType::Normal => late_depth += 1,
                         BinderScopeType::Concatenating => {}
@@ -2694,12 +2467,7 @@ fn resolve_elided_lifetimes(&mut self, lifetime_refs: &[&'tcx hir::Lifetime]) {
                         match scope {
                             Scope::Binder { ref lifetimes, s, .. } => {
                                 // Collect named lifetimes for suggestions.
-                                for name in lifetimes.keys() {
-                                    if let hir::ParamName::Plain(name) = name {
-                                        lifetime_names.insert(name.name);
-                                        lifetime_spans.push(name.span);
-                                    }
-                                }
+                                in_scope_lifetimes.extend(lifetimes.keys().copied());
                                 scope = s;
                             }
                             Scope::ObjectLifetimeDefault { ref s, .. }
@@ -2744,19 +2512,11 @@ fn resolve_elided_lifetimes(&mut self, lifetime_refs: &[&'tcx hir::Lifetime]) {
 
         let mut err = self.report_missing_lifetime_specifiers(spans.clone(), lifetime_refs.len());
 
-        if let Some(params) = error {
-            // If there's no lifetime available, suggest `'static`.
-            if self.report_elision_failure(&mut err, params) && lifetime_names.is_empty() {
-                lifetime_names.insert(kw::StaticLifetime);
-            }
-        }
-
         self.add_missing_lifetime_specifiers_label(
             &mut err,
             spans_with_counts,
-            &lifetime_names,
-            lifetime_spans,
-            error.unwrap_or(&[]),
+            in_scope_lifetimes,
+            error,
         );
         err.emit();
     }
@@ -2789,101 +2549,6 @@ fn resolve_object_lifetime_default(&mut self, lifetime_ref: &'tcx hir::Lifetime)
         self.insert_lifetime(lifetime_ref, lifetime.shifted(late_depth));
     }
 
-    fn check_lifetime_params(
-        &mut self,
-        old_scope: ScopeRef<'_>,
-        params: &'tcx [hir::GenericParam<'tcx>],
-    ) {
-        let lifetimes: Vec<_> = params
-            .iter()
-            .filter_map(|param| match param.kind {
-                GenericParamKind::Lifetime { .. } => {
-                    Some((param, param.name.normalize_to_macros_2_0()))
-                }
-                _ => None,
-            })
-            .collect();
-        for (i, (lifetime_i, lifetime_i_name)) in lifetimes.iter().enumerate() {
-            if let hir::ParamName::Plain(_) = lifetime_i_name {
-                let name = lifetime_i_name.ident().name;
-                if name == kw::UnderscoreLifetime || name == kw::StaticLifetime {
-                    self.tcx.sess.delay_span_bug(
-                        lifetime_i.span,
-                        &format!("invalid lifetime parameter name: `{}`", lifetime_i.name.ident()),
-                    );
-                }
-            }
-
-            // It is a hard error to shadow a lifetime within the same scope.
-            for (lifetime_j, lifetime_j_name) in lifetimes.iter().skip(i + 1) {
-                if lifetime_i_name == lifetime_j_name {
-                    struct_span_err!(
-                        self.tcx.sess,
-                        lifetime_j.span,
-                        E0263,
-                        "lifetime name `{}` declared twice in the same scope",
-                        lifetime_j.name.ident()
-                    )
-                    .span_label(lifetime_j.span, "declared twice")
-                    .span_label(lifetime_i.span, "previous declaration here")
-                    .emit();
-                }
-            }
-
-            // It is a soft error to shadow a lifetime within a parent scope.
-            self.check_lifetime_param_for_shadowing(old_scope, &lifetime_i);
-        }
-    }
-
-    fn check_lifetime_param_for_shadowing(
-        &self,
-        mut old_scope: ScopeRef<'_>,
-        param: &'tcx hir::GenericParam<'tcx>,
-    ) {
-        for label in &self.labels_in_fn {
-            // FIXME (#24278): non-hygienic comparison
-            if param.name.ident().name == label.name {
-                signal_shadowing_problem(
-                    self.tcx,
-                    label.name,
-                    original_label(label.span),
-                    shadower_lifetime(&param),
-                );
-                return;
-            }
-        }
-
-        loop {
-            match *old_scope {
-                Scope::Body { s, .. }
-                | Scope::Elision { s, .. }
-                | Scope::ObjectLifetimeDefault { s, .. }
-                | Scope::Supertrait { s, .. }
-                | Scope::TraitRefBoundary { s, .. } => {
-                    old_scope = s;
-                }
-
-                Scope::Root => {
-                    return;
-                }
-
-                Scope::Binder { ref lifetimes, s, .. } => {
-                    if let Some(&def) = lifetimes.get(&param.name.normalize_to_macros_2_0()) {
-                        signal_shadowing_problem(
-                            self.tcx,
-                            param.name.ident().name,
-                            original_lifetime(self.tcx.def_span(def.id().unwrap())),
-                            shadower_lifetime(&param),
-                        );
-                        return;
-                    }
-
-                    old_scope = s;
-                }
-            }
-        }
-    }
-
     #[tracing::instrument(level = "debug", skip(self))]
     fn insert_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime, def: Region) {
         debug!(
@@ -2903,7 +2568,7 @@ fn uninsert_lifetime_on_error(&mut self, lifetime_ref: &'tcx hir::Lifetime, bad_
 }
 
 /// Detects late-bound lifetimes and inserts them into
-/// `map.late_bound`.
+/// `late_bound`.
 ///
 /// A region declared on a fn is **late-bound** if:
 /// - it is constrained by an argument type;
@@ -2912,12 +2577,13 @@ fn uninsert_lifetime_on_error(&mut self, lifetime_ref: &'tcx hir::Lifetime, bad_
 /// "Constrained" basically means that it appears in any type but
 /// not amongst the inputs to a projection. In other words, `<&'a
 /// T as Trait<''b>>::Foo` does not constrain `'a` or `'b`.
-#[tracing::instrument(level = "debug", skip(map))]
-fn insert_late_bound_lifetimes(
-    map: &mut NamedRegionMap,
-    decl: &hir::FnDecl<'_>,
-    generics: &hir::Generics<'_>,
-) {
+fn is_late_bound_map(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<&FxHashSet<LocalDefId>> {
+    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+    let decl = tcx.hir().fn_decl_by_hir_id(hir_id)?;
+    let generics = tcx.hir().get_generics(def_id)?;
+
+    let mut late_bound = FxHashSet::default();
+
     let mut constrained_by_input = ConstrainedCollector::default();
     for arg_ty in decl.inputs {
         constrained_by_input.visit_ty(arg_ty);
@@ -2948,30 +2614,32 @@ fn insert_late_bound_lifetimes(
             hir::GenericParamKind::Type { .. } | hir::GenericParamKind::Const { .. } => continue,
         }
 
-        let lt_name = hir::LifetimeName::Param(param.name.normalize_to_macros_2_0());
+        let param_def_id = tcx.hir().local_def_id(param.hir_id);
+
         // appears in the where clauses? early-bound.
-        if appears_in_where_clause.regions.contains(&lt_name) {
+        if appears_in_where_clause.regions.contains(&param_def_id) {
             continue;
         }
 
         // does not appear in the inputs, but appears in the return type? early-bound.
-        if !constrained_by_input.regions.contains(&lt_name)
-            && appears_in_output.regions.contains(&lt_name)
+        if !constrained_by_input.regions.contains(&param_def_id)
+            && appears_in_output.regions.contains(&param_def_id)
         {
             continue;
         }
 
         debug!("lifetime {:?} with id {:?} is late-bound", param.name.ident(), param.hir_id);
 
-        let inserted = map.late_bound.insert(param.hir_id);
+        let inserted = late_bound.insert(param_def_id);
         assert!(inserted, "visited lifetime {:?} twice", param.hir_id);
     }
 
-    return;
+    debug!(?late_bound);
+    return Some(tcx.arena.alloc(late_bound));
 
     #[derive(Default)]
     struct ConstrainedCollector {
-        regions: FxHashSet<hir::LifetimeName>,
+        regions: FxHashSet<LocalDefId>,
     }
 
     impl<'v> Visitor<'v> for ConstrainedCollector {
@@ -3003,18 +2671,22 @@ fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
         }
 
         fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) {
-            self.regions.insert(lifetime_ref.name.normalize_to_macros_2_0());
+            if let hir::LifetimeName::Param(def_id, _) = lifetime_ref.name {
+                self.regions.insert(def_id);
+            }
         }
     }
 
     #[derive(Default)]
     struct AllCollector {
-        regions: FxHashSet<hir::LifetimeName>,
+        regions: FxHashSet<LocalDefId>,
     }
 
     impl<'v> Visitor<'v> for AllCollector {
         fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) {
-            self.regions.insert(lifetime_ref.name.normalize_to_macros_2_0());
+            if let hir::LifetimeName::Param(def_id, _) = lifetime_ref.name {
+                self.regions.insert(def_id);
+            }
         }
     }
 }
index 73c8a9d28bd5f4372d364ea95d657086a8b6ec4c..49c15d2c9ef1f7be31c42a28a41d95c70b921db1 100644 (file)
@@ -28,7 +28,7 @@
 use rustc_ast::{self as ast, NodeId, CRATE_NODE_ID};
 use rustc_ast::{AngleBracketedArg, Crate, Expr, ExprKind, GenericArg, GenericArgs, LitKind, Path};
 use rustc_ast_lowering::{LifetimeRes, ResolverAstLowering};
-use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_data_structures::intern::Interned;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed};
@@ -941,7 +941,7 @@ pub struct Resolver<'a> {
     visibilities: FxHashMap<LocalDefId, ty::Visibility>,
     has_pub_restricted: bool,
     used_imports: FxHashSet<NodeId>,
-    maybe_unused_trait_imports: FxHashSet<LocalDefId>,
+    maybe_unused_trait_imports: FxIndexSet<LocalDefId>,
     maybe_unused_extern_crates: Vec<(LocalDefId, Span)>,
 
     /// Privacy errors are delayed until the end in order to deduplicate them.
index 7e6375968aeb64b58fab58e84b148d185de5b4c0..2e2d3674560e8d380063b5d17acb8290ec53f9ba 100644 (file)
@@ -443,11 +443,22 @@ fn cfg_accessible(
                 PathResult::NonModule(partial_res) if partial_res.unresolved_segments() == 0 => {
                     return Ok(true);
                 }
+                PathResult::NonModule(..) |
+                // HACK(Urgau): This shouldn't be necessary
+                PathResult::Failed { is_error_from_last_segment: false, .. } => {
+                    self.session
+                        .struct_span_err(span, "not sure whether the path is accessible or not")
+                        .note("the type may have associated items, but we are currently not checking them")
+                        .emit();
+
+                    // If we get a partially resolved NonModule in one namespace, we should get the
+                    // same result in any other namespaces, so we can return early.
+                    return Ok(false);
+                }
                 PathResult::Indeterminate => indeterminate = true,
-                // FIXME: `resolve_path` is not ready to report partially resolved paths
-                // correctly, so we just report an error if the path was reported as unresolved.
-                // This needs to be fixed for `cfg_accessible` to be useful.
-                PathResult::NonModule(..) | PathResult::Failed { .. } => {}
+                // We can only be sure that a path doesn't exist after having tested all the
+                // posibilities, only at that time we can return false.
+                PathResult::Failed { .. } => {}
                 PathResult::Module(_) => panic!("unexpected path resolution"),
             }
         }
@@ -456,10 +467,6 @@ fn cfg_accessible(
             return Err(Indeterminate);
         }
 
-        self.session
-            .struct_span_err(span, "not sure whether the path is accessible or not")
-            .span_note(span, "`cfg_accessible` is not fully implemented")
-            .emit();
         Ok(false)
     }
 
index 761e988360a3ba641185f2a15c8bb418f335608d..c4541bbcac921e9ec34083e6fc1355b9e6c4ca13 100644 (file)
@@ -25,12 +25,11 @@ fn decode(d: &mut D) -> SmallVec<A> {
 
 impl<S: Encoder, T: Encodable<S>> Encodable<S> for LinkedList<T> {
     fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_seq(self.len(), |s| {
-            for (i, e) in self.iter().enumerate() {
-                s.emit_seq_elt(i, |s| e.encode(s))?;
-            }
-            Ok(())
-        })
+        s.emit_usize(self.len())?;
+        for e in self.iter() {
+            e.encode(s)?;
+        }
+        Ok(())
     }
 }
 
@@ -43,12 +42,11 @@ fn decode(d: &mut D) -> LinkedList<T> {
 
 impl<S: Encoder, T: Encodable<S>> Encodable<S> for VecDeque<T> {
     fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_seq(self.len(), |s| {
-            for (i, e) in self.iter().enumerate() {
-                s.emit_seq_elt(i, |s| e.encode(s))?;
-            }
-            Ok(())
-        })
+        s.emit_usize(self.len())?;
+        for e in self.iter() {
+            e.encode(s)?;
+        }
+        Ok(())
     }
 }
 
@@ -65,13 +63,12 @@ impl<S: Encoder, K, V> Encodable<S> for BTreeMap<K, V>
     V: Encodable<S>,
 {
     fn encode(&self, e: &mut S) -> Result<(), S::Error> {
-        e.emit_map(self.len(), |e| {
-            for (i, (key, val)) in self.iter().enumerate() {
-                e.emit_map_elt_key(i, |e| key.encode(e))?;
-                e.emit_map_elt_val(|e| val.encode(e))?;
-            }
-            Ok(())
-        })
+        e.emit_usize(self.len())?;
+        for (key, val) in self.iter() {
+            key.encode(e)?;
+            val.encode(e)?;
+        }
+        Ok(())
     }
 }
 
@@ -97,12 +94,11 @@ impl<S: Encoder, T> Encodable<S> for BTreeSet<T>
     T: Encodable<S> + PartialEq + Ord,
 {
     fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_seq(self.len(), |s| {
-            for (i, e) in self.iter().enumerate() {
-                s.emit_seq_elt(i, |s| e.encode(s))?;
-            }
-            Ok(())
-        })
+        s.emit_usize(self.len())?;
+        for e in self.iter() {
+            e.encode(s)?;
+        }
+        Ok(())
     }
 }
 
@@ -127,13 +123,12 @@ impl<E: Encoder, K, V, S> Encodable<E> for HashMap<K, V, S>
     S: BuildHasher,
 {
     fn encode(&self, e: &mut E) -> Result<(), E::Error> {
-        e.emit_map(self.len(), |e| {
-            for (i, (key, val)) in self.iter().enumerate() {
-                e.emit_map_elt_key(i, |e| key.encode(e))?;
-                e.emit_map_elt_val(|e| val.encode(e))?;
-            }
-            Ok(())
-        })
+        e.emit_usize(self.len())?;
+        for (key, val) in self.iter() {
+            key.encode(e)?;
+            val.encode(e)?;
+        }
+        Ok(())
     }
 }
 
@@ -162,12 +157,11 @@ impl<E: Encoder, T, S> Encodable<E> for HashSet<T, S>
     S: BuildHasher,
 {
     fn encode(&self, s: &mut E) -> Result<(), E::Error> {
-        s.emit_seq(self.len(), |s| {
-            for (i, e) in self.iter().enumerate() {
-                s.emit_seq_elt(i, |s| e.encode(s))?;
-            }
-            Ok(())
-        })
+        s.emit_usize(self.len())?;
+        for e in self.iter() {
+            e.encode(s)?;
+        }
+        Ok(())
     }
 }
 
@@ -194,13 +188,12 @@ impl<E: Encoder, K, V, S> Encodable<E> for indexmap::IndexMap<K, V, S>
     S: BuildHasher,
 {
     fn encode(&self, e: &mut E) -> Result<(), E::Error> {
-        e.emit_map(self.len(), |e| {
-            for (i, (key, val)) in self.iter().enumerate() {
-                e.emit_map_elt_key(i, |e| key.encode(e))?;
-                e.emit_map_elt_val(|e| val.encode(e))?;
-            }
-            Ok(())
-        })
+        e.emit_usize(self.len())?;
+        for (key, val) in self.iter() {
+            key.encode(e)?;
+            val.encode(e)?;
+        }
+        Ok(())
     }
 }
 
@@ -229,12 +222,11 @@ impl<E: Encoder, T, S> Encodable<E> for indexmap::IndexSet<T, S>
     S: BuildHasher,
 {
     fn encode(&self, s: &mut E) -> Result<(), E::Error> {
-        s.emit_seq(self.len(), |s| {
-            for (i, e) in self.iter().enumerate() {
-                s.emit_seq_elt(i, |s| e.encode(s))?;
-            }
-            Ok(())
-        })
+        s.emit_usize(self.len())?;
+        for e in self.iter() {
+            e.encode(s)?;
+        }
+        Ok(())
     }
 }
 
diff --git a/compiler/rustc_serialize/src/json.rs b/compiler/rustc_serialize/src/json.rs
deleted file mode 100644 (file)
index c915dd5..0000000
+++ /dev/null
@@ -1,2368 +0,0 @@
-// Rust JSON serialization library.
-// Copyright (c) 2011 Google Inc.
-
-#![forbid(non_camel_case_types)]
-#![allow(missing_docs)]
-
-//! JSON parsing and serialization
-//!
-//! # What is JSON?
-//!
-//! JSON (JavaScript Object Notation) is a way to write data in Javascript.
-//! Like XML, it allows to encode structured data in a text format that can be easily read by humans
-//! Its simple syntax and native compatibility with JavaScript have made it a widely used format.
-//!
-//! Data types that can be encoded are JavaScript types (see the `Json` enum for more details):
-//!
-//! * `Boolean`: equivalent to rust's `bool`
-//! * `Number`: equivalent to rust's `f64`
-//! * `String`: equivalent to rust's `String`
-//! * `Array`: equivalent to rust's `Vec<T>`, but also allowing objects of different types in the
-//!   same array
-//! * `Object`: equivalent to rust's `BTreeMap<String, json::Json>`
-//! * `Null`
-//!
-//! An object is a series of string keys mapping to values, in `"key": value` format.
-//! Arrays are enclosed in square brackets ([ ... ]) and objects in curly brackets ({ ... }).
-//! A simple JSON document encoding a person, their age, address and phone numbers could look like
-//!
-//! ```json
-//! {
-//!     "FirstName": "John",
-//!     "LastName": "Doe",
-//!     "Age": 43,
-//!     "Address": {
-//!         "Street": "Downing Street 10",
-//!         "City": "London",
-//!         "Country": "Great Britain"
-//!     },
-//!     "PhoneNumbers": [
-//!         "+44 1234567",
-//!         "+44 2345678"
-//!     ]
-//! }
-//! ```
-//!
-//! # Rust Type-based Encoding and Decoding
-//!
-//! To be able to encode a piece of data, it must implement the
-//! `serialize::Encodable` trait.  The `rustc_macros` crate provides an
-//! annotation to automatically generate the code for this trait: `#[derive(Encodable)]`.
-//!
-//! The JSON API provides an enum `json::Json` and a trait `ToJson` to encode objects.
-//! The `ToJson` trait provides a `to_json` method to convert an object into a `json::Json` value.
-//! A `json::Json` value can be encoded as a string or buffer using the functions described above.
-//! You can also use the `json::Encoder` object, which implements the `Encoder` trait.
-//!
-//! When using `ToJson` the `Encodable` trait implementation is not mandatory.
-//!
-//! # Examples of use
-//!
-//! ## Using Autoserialization
-//!
-//! Create a struct called `TestStruct` and serialize and deserialize it to and from JSON using the
-//! serialization API, using the derived serialization code.
-//!
-//! ```rust
-//! # #![feature(rustc_private)]
-//! use rustc_macros::{Encodable};
-//! use rustc_serialize::json;
-//!
-//! // Automatically generate `Encodable` trait implementations
-//! #[derive(Encodable)]
-//! pub struct TestStruct  {
-//!     data_int: u8,
-//!     data_str: String,
-//!     data_vector: Vec<u8>,
-//! }
-//!
-//! let object = TestStruct {
-//!     data_int: 1,
-//!     data_str: "homura".to_string(),
-//!     data_vector: vec![2,3,4,5],
-//! };
-//!
-//! // Serialize using `json::encode`
-//! let encoded = json::encode(&object).unwrap();
-//! ```
-//!
-//! ## Using the `ToJson` trait
-//!
-//! The examples above use the `ToJson` trait to generate the JSON string, which is required
-//! for custom mappings.
-//!
-//! ### Simple example of `ToJson` usage
-//!
-//! ```rust
-//! # #![feature(rustc_private)]
-//! use rustc_macros::Encodable;
-//! use rustc_serialize::json::{self, ToJson, Json};
-//!
-//! // A custom data structure
-//! struct ComplexNum {
-//!     a: f64,
-//!     b: f64,
-//! }
-//!
-//! // JSON value representation
-//! impl ToJson for ComplexNum {
-//!     fn to_json(&self) -> Json {
-//!         Json::String(format!("{}+{}i", self.a, self.b))
-//!     }
-//! }
-//!
-//! // Only generate `Encodable` trait implementation
-//! #[derive(Encodable)]
-//! pub struct ComplexNumRecord {
-//!     uid: u8,
-//!     dsc: String,
-//!     val: Json,
-//! }
-//!
-//! let num = ComplexNum { a: 0.0001, b: 12.539 };
-//! let data: String = json::encode(&ComplexNumRecord{
-//!     uid: 1,
-//!     dsc: "test".to_string(),
-//!     val: num.to_json(),
-//! }).unwrap();
-//! println!("data: {}", data);
-//! // data: {"uid":1,"dsc":"test","val":"0.0001+12.539i"};
-//! ```
-//!
-//! ### Verbose example of `ToJson` usage
-//!
-//! ```rust
-//! # #![feature(rustc_private)]
-//! use std::collections::BTreeMap;
-//! use rustc_serialize::json::{Json, ToJson};
-//!
-//! pub struct TestStruct {
-//!     data_int: u8,
-//!     data_str: String,
-//!     data_vector: Vec<u8>,
-//! }
-//!
-//! // Specify encoding method manually
-//! impl ToJson for TestStruct {
-//!     fn to_json(&self) -> Json {
-//!         let mut d = BTreeMap::new();
-//!         // All standard types implement `to_json()`, so use it
-//!         d.insert("data_int".to_string(), self.data_int.to_json());
-//!         d.insert("data_str".to_string(), self.data_str.to_json());
-//!         d.insert("data_vector".to_string(), self.data_vector.to_json());
-//!         Json::Object(d)
-//!     }
-//! }
-//!
-//! // Serialize using `ToJson`
-//! let input_data = TestStruct {
-//!     data_int: 1,
-//!     data_str: "madoka".to_string(),
-//!     data_vector: vec![2,3,4,5],
-//! };
-//! let json_obj: Json = input_data.to_json();
-//! let json_str: String = json_obj.to_string();
-//! ```
-
-use self::ErrorCode::*;
-use self::InternalStackElement::*;
-use self::JsonEvent::*;
-use self::ParserError::*;
-use self::ParserState::*;
-
-use std::borrow::Cow;
-use std::collections::{BTreeMap, HashMap};
-use std::mem::swap;
-use std::num::FpCategory as Fp;
-use std::ops::Index;
-use std::str::FromStr;
-use std::string;
-use std::{char, fmt, str};
-
-use crate::Encodable;
-
-/// Represents a json value
-#[derive(Clone, PartialEq, PartialOrd, Debug)]
-pub enum Json {
-    I64(i64),
-    U64(u64),
-    F64(f64),
-    String(string::String),
-    Boolean(bool),
-    Array(self::Array),
-    Object(self::Object),
-    Null,
-}
-
-pub type Array = Vec<Json>;
-pub type Object = BTreeMap<string::String, Json>;
-
-pub struct PrettyJson<'a> {
-    inner: &'a Json,
-}
-
-pub struct AsJson<'a, T> {
-    inner: &'a T,
-}
-pub struct AsPrettyJson<'a, T> {
-    inner: &'a T,
-    indent: Option<usize>,
-}
-
-/// The errors that can arise while parsing a JSON stream.
-#[derive(Clone, Copy, PartialEq, Debug)]
-pub enum ErrorCode {
-    InvalidSyntax,
-    InvalidNumber,
-    EOFWhileParsingObject,
-    EOFWhileParsingArray,
-    EOFWhileParsingValue,
-    EOFWhileParsingString,
-    KeyMustBeAString,
-    ExpectedColon,
-    TrailingCharacters,
-    TrailingComma,
-    InvalidEscape,
-    InvalidUnicodeCodePoint,
-    LoneLeadingSurrogateInHexEscape,
-    UnexpectedEndOfHexEscape,
-    UnrecognizedHex,
-    NotFourDigit,
-    NotUtf8,
-}
-
-#[derive(Clone, PartialEq, Debug)]
-pub enum ParserError {
-    /// msg, line, col
-    SyntaxError(ErrorCode, usize, usize),
-}
-
-// Builder and Parser have the same errors.
-pub type BuilderError = ParserError;
-
-#[derive(Copy, Clone, Debug)]
-pub enum EncoderError {
-    FmtError(fmt::Error),
-    BadHashmapKey,
-}
-
-/// Returns a readable error string for a given error code.
-pub fn error_str(error: ErrorCode) -> &'static str {
-    match error {
-        InvalidSyntax => "invalid syntax",
-        InvalidNumber => "invalid number",
-        EOFWhileParsingObject => "EOF While parsing object",
-        EOFWhileParsingArray => "EOF While parsing array",
-        EOFWhileParsingValue => "EOF While parsing value",
-        EOFWhileParsingString => "EOF While parsing string",
-        KeyMustBeAString => "key must be a string",
-        ExpectedColon => "expected `:`",
-        TrailingCharacters => "trailing characters",
-        TrailingComma => "trailing comma",
-        InvalidEscape => "invalid escape",
-        UnrecognizedHex => "invalid \\u{ esc}ape (unrecognized hex)",
-        NotFourDigit => "invalid \\u{ esc}ape (not four digits)",
-        NotUtf8 => "contents not utf-8",
-        InvalidUnicodeCodePoint => "invalid Unicode code point",
-        LoneLeadingSurrogateInHexEscape => "lone leading surrogate in hex escape",
-        UnexpectedEndOfHexEscape => "unexpected end of hex escape",
-    }
-}
-
-/// Shortcut function to encode a `T` into a JSON `String`
-pub fn encode<T: for<'r> crate::Encodable<Encoder<'r>>>(
-    object: &T,
-) -> Result<string::String, EncoderError> {
-    let mut s = String::new();
-    {
-        let mut encoder = Encoder::new(&mut s);
-        object.encode(&mut encoder)?;
-    }
-    Ok(s)
-}
-
-impl fmt::Display for ErrorCode {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        error_str(*self).fmt(f)
-    }
-}
-
-impl fmt::Display for ParserError {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        // FIXME this should be a nicer error
-        fmt::Debug::fmt(self, f)
-    }
-}
-
-impl fmt::Display for EncoderError {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        // FIXME this should be a nicer error
-        fmt::Debug::fmt(self, f)
-    }
-}
-
-impl std::error::Error for EncoderError {}
-
-impl From<fmt::Error> for EncoderError {
-    /// Converts a [`fmt::Error`] into `EncoderError`
-    ///
-    /// This conversion does not allocate memory.
-    fn from(err: fmt::Error) -> EncoderError {
-        EncoderError::FmtError(err)
-    }
-}
-
-pub type EncodeResult = Result<(), EncoderError>;
-
-fn escape_str(wr: &mut dyn fmt::Write, v: &str) -> EncodeResult {
-    wr.write_str("\"")?;
-
-    let mut start = 0;
-
-    for (i, byte) in v.bytes().enumerate() {
-        let escaped = match byte {
-            b'"' => "\\\"",
-            b'\\' => "\\\\",
-            b'\x00' => "\\u0000",
-            b'\x01' => "\\u0001",
-            b'\x02' => "\\u0002",
-            b'\x03' => "\\u0003",
-            b'\x04' => "\\u0004",
-            b'\x05' => "\\u0005",
-            b'\x06' => "\\u0006",
-            b'\x07' => "\\u0007",
-            b'\x08' => "\\b",
-            b'\t' => "\\t",
-            b'\n' => "\\n",
-            b'\x0b' => "\\u000b",
-            b'\x0c' => "\\f",
-            b'\r' => "\\r",
-            b'\x0e' => "\\u000e",
-            b'\x0f' => "\\u000f",
-            b'\x10' => "\\u0010",
-            b'\x11' => "\\u0011",
-            b'\x12' => "\\u0012",
-            b'\x13' => "\\u0013",
-            b'\x14' => "\\u0014",
-            b'\x15' => "\\u0015",
-            b'\x16' => "\\u0016",
-            b'\x17' => "\\u0017",
-            b'\x18' => "\\u0018",
-            b'\x19' => "\\u0019",
-            b'\x1a' => "\\u001a",
-            b'\x1b' => "\\u001b",
-            b'\x1c' => "\\u001c",
-            b'\x1d' => "\\u001d",
-            b'\x1e' => "\\u001e",
-            b'\x1f' => "\\u001f",
-            b'\x7f' => "\\u007f",
-            _ => {
-                continue;
-            }
-        };
-
-        if start < i {
-            wr.write_str(&v[start..i])?;
-        }
-
-        wr.write_str(escaped)?;
-
-        start = i + 1;
-    }
-
-    if start != v.len() {
-        wr.write_str(&v[start..])?;
-    }
-
-    wr.write_str("\"")?;
-    Ok(())
-}
-
-fn escape_char(writer: &mut dyn fmt::Write, v: char) -> EncodeResult {
-    escape_str(writer, v.encode_utf8(&mut [0; 4]))
-}
-
-fn spaces(wr: &mut dyn fmt::Write, mut n: usize) -> EncodeResult {
-    const BUF: &str = "                ";
-
-    while n >= BUF.len() {
-        wr.write_str(BUF)?;
-        n -= BUF.len();
-    }
-
-    if n > 0 {
-        wr.write_str(&BUF[..n])?;
-    }
-    Ok(())
-}
-
-fn fmt_number_or_null(v: f64) -> string::String {
-    match v.classify() {
-        Fp::Nan | Fp::Infinite => string::String::from("null"),
-        _ if v.fract() != 0f64 => v.to_string(),
-        _ => v.to_string() + ".0",
-    }
-}
-
-/// A structure for implementing serialization to JSON.
-pub struct Encoder<'a> {
-    writer: &'a mut (dyn fmt::Write + 'a),
-    is_emitting_map_key: bool,
-}
-
-impl<'a> Encoder<'a> {
-    /// Creates a new JSON encoder whose output will be written to the writer
-    /// specified.
-    pub fn new(writer: &'a mut dyn fmt::Write) -> Encoder<'a> {
-        Encoder { writer, is_emitting_map_key: false }
-    }
-}
-
-macro_rules! emit_enquoted_if_mapkey {
-    ($enc:ident,$e:expr) => {{
-        if $enc.is_emitting_map_key {
-            write!($enc.writer, "\"{}\"", $e)?;
-        } else {
-            write!($enc.writer, "{}", $e)?;
-        }
-        Ok(())
-    }};
-}
-
-impl<'a> crate::Encoder for Encoder<'a> {
-    type Error = EncoderError;
-
-    fn emit_unit(&mut self) -> EncodeResult {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        write!(self.writer, "null")?;
-        Ok(())
-    }
-
-    fn emit_usize(&mut self, v: usize) -> EncodeResult {
-        emit_enquoted_if_mapkey!(self, v)
-    }
-    fn emit_u128(&mut self, v: u128) -> EncodeResult {
-        emit_enquoted_if_mapkey!(self, v)
-    }
-    fn emit_u64(&mut self, v: u64) -> EncodeResult {
-        emit_enquoted_if_mapkey!(self, v)
-    }
-    fn emit_u32(&mut self, v: u32) -> EncodeResult {
-        emit_enquoted_if_mapkey!(self, v)
-    }
-    fn emit_u16(&mut self, v: u16) -> EncodeResult {
-        emit_enquoted_if_mapkey!(self, v)
-    }
-    fn emit_u8(&mut self, v: u8) -> EncodeResult {
-        emit_enquoted_if_mapkey!(self, v)
-    }
-
-    fn emit_isize(&mut self, v: isize) -> EncodeResult {
-        emit_enquoted_if_mapkey!(self, v)
-    }
-    fn emit_i128(&mut self, v: i128) -> EncodeResult {
-        emit_enquoted_if_mapkey!(self, v)
-    }
-    fn emit_i64(&mut self, v: i64) -> EncodeResult {
-        emit_enquoted_if_mapkey!(self, v)
-    }
-    fn emit_i32(&mut self, v: i32) -> EncodeResult {
-        emit_enquoted_if_mapkey!(self, v)
-    }
-    fn emit_i16(&mut self, v: i16) -> EncodeResult {
-        emit_enquoted_if_mapkey!(self, v)
-    }
-    fn emit_i8(&mut self, v: i8) -> EncodeResult {
-        emit_enquoted_if_mapkey!(self, v)
-    }
-
-    fn emit_bool(&mut self, v: bool) -> EncodeResult {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        if v {
-            write!(self.writer, "true")?;
-        } else {
-            write!(self.writer, "false")?;
-        }
-        Ok(())
-    }
-
-    fn emit_f64(&mut self, v: f64) -> EncodeResult {
-        emit_enquoted_if_mapkey!(self, fmt_number_or_null(v))
-    }
-    fn emit_f32(&mut self, v: f32) -> EncodeResult {
-        self.emit_f64(f64::from(v))
-    }
-
-    fn emit_char(&mut self, v: char) -> EncodeResult {
-        escape_char(self.writer, v)
-    }
-    fn emit_str(&mut self, v: &str) -> EncodeResult {
-        escape_str(self.writer, v)
-    }
-    fn emit_raw_bytes(&mut self, s: &[u8]) -> Result<(), Self::Error> {
-        for &c in s.iter() {
-            self.emit_u8(c)?;
-        }
-        Ok(())
-    }
-
-    fn emit_enum<F>(&mut self, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
-    {
-        f(self)
-    }
-
-    fn emit_enum_variant<F>(&mut self, name: &str, _id: usize, cnt: usize, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
-    {
-        // enums are encoded as strings or objects
-        // Bunny => "Bunny"
-        // Kangaroo(34,"William") => {"variant": "Kangaroo", "fields": [34,"William"]}
-        if cnt == 0 {
-            escape_str(self.writer, name)
-        } else {
-            if self.is_emitting_map_key {
-                return Err(EncoderError::BadHashmapKey);
-            }
-            write!(self.writer, "{{\"variant\":")?;
-            escape_str(self.writer, name)?;
-            write!(self.writer, ",\"fields\":[")?;
-            f(self)?;
-            write!(self.writer, "]}}")?;
-            Ok(())
-        }
-    }
-
-    fn emit_fieldless_enum_variant<const ID: usize>(
-        &mut self,
-        name: &str,
-    ) -> Result<(), Self::Error> {
-        escape_str(self.writer, name)
-    }
-
-    fn emit_enum_variant_arg<F>(&mut self, first: bool, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        if !first {
-            write!(self.writer, ",")?;
-        }
-        f(self)
-    }
-
-    fn emit_struct<F>(&mut self, _: bool, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        write!(self.writer, "{{")?;
-        f(self)?;
-        write!(self.writer, "}}")?;
-        Ok(())
-    }
-
-    fn emit_struct_field<F>(&mut self, name: &str, first: bool, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        if !first {
-            write!(self.writer, ",")?;
-        }
-        escape_str(self.writer, name)?;
-        write!(self.writer, ":")?;
-        f(self)
-    }
-
-    fn emit_tuple<F>(&mut self, len: usize, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        self.emit_seq(len, f)
-    }
-    fn emit_tuple_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        self.emit_seq_elt(idx, f)
-    }
-
-    fn emit_option<F>(&mut self, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        f(self)
-    }
-    fn emit_option_none(&mut self) -> EncodeResult {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        self.emit_unit()
-    }
-    fn emit_option_some<F>(&mut self, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        f(self)
-    }
-
-    fn emit_seq<F>(&mut self, _len: usize, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        write!(self.writer, "[")?;
-        f(self)?;
-        write!(self.writer, "]")?;
-        Ok(())
-    }
-
-    fn emit_seq_elt<F>(&mut self, idx: usize, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        if idx != 0 {
-            write!(self.writer, ",")?;
-        }
-        f(self)
-    }
-
-    fn emit_map<F>(&mut self, _len: usize, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        write!(self.writer, "{{")?;
-        f(self)?;
-        write!(self.writer, "}}")?;
-        Ok(())
-    }
-
-    fn emit_map_elt_key<F>(&mut self, idx: usize, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        if idx != 0 {
-            write!(self.writer, ",")?
-        }
-        self.is_emitting_map_key = true;
-        f(self)?;
-        self.is_emitting_map_key = false;
-        Ok(())
-    }
-
-    fn emit_map_elt_val<F>(&mut self, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        write!(self.writer, ":")?;
-        f(self)
-    }
-}
-
-/// Another encoder for JSON, but prints out human-readable JSON instead of
-/// compact data
-pub struct PrettyEncoder<'a> {
-    writer: &'a mut (dyn fmt::Write + 'a),
-    curr_indent: usize,
-    indent: usize,
-    is_emitting_map_key: bool,
-}
-
-impl<'a> PrettyEncoder<'a> {
-    /// Creates a new encoder whose output will be written to the specified writer
-    pub fn new(writer: &'a mut dyn fmt::Write) -> PrettyEncoder<'a> {
-        PrettyEncoder { writer, curr_indent: 0, indent: 2, is_emitting_map_key: false }
-    }
-
-    /// Sets the number of spaces to indent for each level.
-    /// This is safe to set during encoding.
-    pub fn set_indent(&mut self, indent: usize) {
-        // self.indent very well could be 0 so we need to use checked division.
-        let level = self.curr_indent.checked_div(self.indent).unwrap_or(0);
-        self.indent = indent;
-        self.curr_indent = level * self.indent;
-    }
-}
-
-impl<'a> crate::Encoder for PrettyEncoder<'a> {
-    type Error = EncoderError;
-
-    fn emit_unit(&mut self) -> EncodeResult {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        write!(self.writer, "null")?;
-        Ok(())
-    }
-
-    fn emit_usize(&mut self, v: usize) -> EncodeResult {
-        emit_enquoted_if_mapkey!(self, v)
-    }
-    fn emit_u128(&mut self, v: u128) -> EncodeResult {
-        emit_enquoted_if_mapkey!(self, v)
-    }
-    fn emit_u64(&mut self, v: u64) -> EncodeResult {
-        emit_enquoted_if_mapkey!(self, v)
-    }
-    fn emit_u32(&mut self, v: u32) -> EncodeResult {
-        emit_enquoted_if_mapkey!(self, v)
-    }
-    fn emit_u16(&mut self, v: u16) -> EncodeResult {
-        emit_enquoted_if_mapkey!(self, v)
-    }
-    fn emit_u8(&mut self, v: u8) -> EncodeResult {
-        emit_enquoted_if_mapkey!(self, v)
-    }
-
-    fn emit_isize(&mut self, v: isize) -> EncodeResult {
-        emit_enquoted_if_mapkey!(self, v)
-    }
-    fn emit_i128(&mut self, v: i128) -> EncodeResult {
-        emit_enquoted_if_mapkey!(self, v)
-    }
-    fn emit_i64(&mut self, v: i64) -> EncodeResult {
-        emit_enquoted_if_mapkey!(self, v)
-    }
-    fn emit_i32(&mut self, v: i32) -> EncodeResult {
-        emit_enquoted_if_mapkey!(self, v)
-    }
-    fn emit_i16(&mut self, v: i16) -> EncodeResult {
-        emit_enquoted_if_mapkey!(self, v)
-    }
-    fn emit_i8(&mut self, v: i8) -> EncodeResult {
-        emit_enquoted_if_mapkey!(self, v)
-    }
-
-    fn emit_bool(&mut self, v: bool) -> EncodeResult {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        if v {
-            write!(self.writer, "true")?;
-        } else {
-            write!(self.writer, "false")?;
-        }
-        Ok(())
-    }
-
-    fn emit_f64(&mut self, v: f64) -> EncodeResult {
-        emit_enquoted_if_mapkey!(self, fmt_number_or_null(v))
-    }
-    fn emit_f32(&mut self, v: f32) -> EncodeResult {
-        self.emit_f64(f64::from(v))
-    }
-
-    fn emit_char(&mut self, v: char) -> EncodeResult {
-        escape_char(self.writer, v)
-    }
-    fn emit_str(&mut self, v: &str) -> EncodeResult {
-        escape_str(self.writer, v)
-    }
-    fn emit_raw_bytes(&mut self, s: &[u8]) -> Result<(), Self::Error> {
-        for &c in s.iter() {
-            self.emit_u8(c)?;
-        }
-        Ok(())
-    }
-
-    fn emit_enum<F>(&mut self, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
-    {
-        f(self)
-    }
-
-    fn emit_enum_variant<F>(&mut self, name: &str, _id: usize, cnt: usize, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
-    {
-        if cnt == 0 {
-            escape_str(self.writer, name)
-        } else {
-            if self.is_emitting_map_key {
-                return Err(EncoderError::BadHashmapKey);
-            }
-            writeln!(self.writer, "{{")?;
-            self.curr_indent += self.indent;
-            spaces(self.writer, self.curr_indent)?;
-            write!(self.writer, "\"variant\": ")?;
-            escape_str(self.writer, name)?;
-            writeln!(self.writer, ",")?;
-            spaces(self.writer, self.curr_indent)?;
-            writeln!(self.writer, "\"fields\": [")?;
-            self.curr_indent += self.indent;
-            f(self)?;
-            self.curr_indent -= self.indent;
-            writeln!(self.writer)?;
-            spaces(self.writer, self.curr_indent)?;
-            self.curr_indent -= self.indent;
-            writeln!(self.writer, "]")?;
-            spaces(self.writer, self.curr_indent)?;
-            write!(self.writer, "}}")?;
-            Ok(())
-        }
-    }
-
-    fn emit_fieldless_enum_variant<const ID: usize>(
-        &mut self,
-        name: &str,
-    ) -> Result<(), Self::Error> {
-        escape_str(self.writer, name)
-    }
-
-    fn emit_enum_variant_arg<F>(&mut self, first: bool, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        if !first {
-            writeln!(self.writer, ",")?;
-        }
-        spaces(self.writer, self.curr_indent)?;
-        f(self)
-    }
-
-    fn emit_struct<F>(&mut self, no_fields: bool, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        if no_fields {
-            write!(self.writer, "{{}}")?;
-        } else {
-            write!(self.writer, "{{")?;
-            self.curr_indent += self.indent;
-            f(self)?;
-            self.curr_indent -= self.indent;
-            writeln!(self.writer)?;
-            spaces(self.writer, self.curr_indent)?;
-            write!(self.writer, "}}")?;
-        }
-        Ok(())
-    }
-
-    fn emit_struct_field<F>(&mut self, name: &str, first: bool, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        if first {
-            writeln!(self.writer)?;
-        } else {
-            writeln!(self.writer, ",")?;
-        }
-        spaces(self.writer, self.curr_indent)?;
-        escape_str(self.writer, name)?;
-        write!(self.writer, ": ")?;
-        f(self)
-    }
-
-    fn emit_tuple<F>(&mut self, len: usize, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        self.emit_seq(len, f)
-    }
-    fn emit_tuple_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        self.emit_seq_elt(idx, f)
-    }
-
-    fn emit_option<F>(&mut self, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        f(self)
-    }
-    fn emit_option_none(&mut self) -> EncodeResult {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        self.emit_unit()
-    }
-    fn emit_option_some<F>(&mut self, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        f(self)
-    }
-
-    fn emit_seq<F>(&mut self, len: usize, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        if len == 0 {
-            write!(self.writer, "[]")?;
-        } else {
-            write!(self.writer, "[")?;
-            self.curr_indent += self.indent;
-            f(self)?;
-            self.curr_indent -= self.indent;
-            writeln!(self.writer)?;
-            spaces(self.writer, self.curr_indent)?;
-            write!(self.writer, "]")?;
-        }
-        Ok(())
-    }
-
-    fn emit_seq_elt<F>(&mut self, idx: usize, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        if idx == 0 {
-            writeln!(self.writer)?;
-        } else {
-            writeln!(self.writer, ",")?;
-        }
-        spaces(self.writer, self.curr_indent)?;
-        f(self)
-    }
-
-    fn emit_map<F>(&mut self, len: usize, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        if len == 0 {
-            write!(self.writer, "{{}}")?;
-        } else {
-            write!(self.writer, "{{")?;
-            self.curr_indent += self.indent;
-            f(self)?;
-            self.curr_indent -= self.indent;
-            writeln!(self.writer)?;
-            spaces(self.writer, self.curr_indent)?;
-            write!(self.writer, "}}")?;
-        }
-        Ok(())
-    }
-
-    fn emit_map_elt_key<F>(&mut self, idx: usize, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        if idx == 0 {
-            writeln!(self.writer)?;
-        } else {
-            writeln!(self.writer, ",")?;
-        }
-        spaces(self.writer, self.curr_indent)?;
-        self.is_emitting_map_key = true;
-        f(self)?;
-        self.is_emitting_map_key = false;
-        Ok(())
-    }
-
-    fn emit_map_elt_val<F>(&mut self, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        write!(self.writer, ": ")?;
-        f(self)
-    }
-}
-
-impl<E: crate::Encoder> Encodable<E> for Json {
-    fn encode(&self, e: &mut E) -> Result<(), E::Error> {
-        match *self {
-            Json::I64(v) => v.encode(e),
-            Json::U64(v) => v.encode(e),
-            Json::F64(v) => v.encode(e),
-            Json::String(ref v) => v.encode(e),
-            Json::Boolean(v) => v.encode(e),
-            Json::Array(ref v) => v.encode(e),
-            Json::Object(ref v) => v.encode(e),
-            Json::Null => e.emit_unit(),
-        }
-    }
-}
-
-/// Creates an `AsJson` wrapper which can be used to print a value as JSON
-/// on-the-fly via `write!`
-pub fn as_json<T>(t: &T) -> AsJson<'_, T> {
-    AsJson { inner: t }
-}
-
-/// Creates an `AsPrettyJson` wrapper which can be used to print a value as JSON
-/// on-the-fly via `write!`
-pub fn as_pretty_json<T>(t: &T) -> AsPrettyJson<'_, T> {
-    AsPrettyJson { inner: t, indent: None }
-}
-
-impl Json {
-    /// Borrow this json object as a pretty object to generate a pretty
-    /// representation for it via `Display`.
-    pub fn pretty(&self) -> PrettyJson<'_> {
-        PrettyJson { inner: self }
-    }
-
-    /// If the Json value is an Object, returns the value associated with the provided key.
-    /// Otherwise, returns None.
-    pub fn find(&self, key: &str) -> Option<&Json> {
-        match *self {
-            Json::Object(ref map) => map.get(key),
-            _ => None,
-        }
-    }
-
-    /// If the Json value is an Object, deletes the value associated with the
-    /// provided key from the Object and returns it. Otherwise, returns None.
-    pub fn remove_key(&mut self, key: &str) -> Option<Json> {
-        match *self {
-            Json::Object(ref mut map) => map.remove(key),
-            _ => None,
-        }
-    }
-
-    /// Attempts to get a nested Json Object for each key in `keys`.
-    /// If any key is found not to exist, `find_path` will return `None`.
-    /// Otherwise, it will return the Json value associated with the final key.
-    pub fn find_path<'a>(&'a self, keys: &[&str]) -> Option<&'a Json> {
-        let mut target = self;
-        for key in keys {
-            target = target.find(*key)?;
-        }
-        Some(target)
-    }
-
-    /// If the Json value is an Object, performs a depth-first search until
-    /// a value associated with the provided key is found. If no value is found
-    /// or the Json value is not an Object, returns `None`.
-    pub fn search(&self, key: &str) -> Option<&Json> {
-        match *self {
-            Json::Object(ref map) => match map.get(key) {
-                Some(json_value) => Some(json_value),
-                None => {
-                    for v in map.values() {
-                        match v.search(key) {
-                            x if x.is_some() => return x,
-                            _ => (),
-                        }
-                    }
-                    None
-                }
-            },
-            _ => None,
-        }
-    }
-
-    /// Returns `true` if the Json value is an `Object`.
-    pub fn is_object(&self) -> bool {
-        self.as_object().is_some()
-    }
-
-    /// If the Json value is an `Object`, returns the associated `BTreeMap`;
-    /// returns `None` otherwise.
-    pub fn as_object(&self) -> Option<&Object> {
-        match *self {
-            Json::Object(ref map) => Some(map),
-            _ => None,
-        }
-    }
-
-    /// Returns `true` if the Json value is an `Array`.
-    pub fn is_array(&self) -> bool {
-        self.as_array().is_some()
-    }
-
-    /// If the Json value is an `Array`, returns the associated vector;
-    /// returns `None` otherwise.
-    pub fn as_array(&self) -> Option<&Array> {
-        match *self {
-            Json::Array(ref array) => Some(&*array),
-            _ => None,
-        }
-    }
-
-    /// Returns `true` if the Json value is a `String`.
-    pub fn is_string(&self) -> bool {
-        self.as_string().is_some()
-    }
-
-    /// If the Json value is a `String`, returns the associated `str`;
-    /// returns `None` otherwise.
-    pub fn as_string(&self) -> Option<&str> {
-        match *self {
-            Json::String(ref s) => Some(&s[..]),
-            _ => None,
-        }
-    }
-
-    /// Returns `true` if the Json value is a `Number`.
-    pub fn is_number(&self) -> bool {
-        matches!(*self, Json::I64(_) | Json::U64(_) | Json::F64(_))
-    }
-
-    /// Returns `true` if the Json value is an `i64`.
-    pub fn is_i64(&self) -> bool {
-        matches!(*self, Json::I64(_))
-    }
-
-    /// Returns `true` if the Json value is a `u64`.
-    pub fn is_u64(&self) -> bool {
-        matches!(*self, Json::U64(_))
-    }
-
-    /// Returns `true` if the Json value is a `f64`.
-    pub fn is_f64(&self) -> bool {
-        matches!(*self, Json::F64(_))
-    }
-
-    /// If the Json value is a number, returns or cast it to an `i64`;
-    /// returns `None` otherwise.
-    pub fn as_i64(&self) -> Option<i64> {
-        match *self {
-            Json::I64(n) => Some(n),
-            Json::U64(n) => Some(n as i64),
-            _ => None,
-        }
-    }
-
-    /// If the Json value is a number, returns or cast it to a `u64`;
-    /// returns `None` otherwise.
-    pub fn as_u64(&self) -> Option<u64> {
-        match *self {
-            Json::I64(n) => Some(n as u64),
-            Json::U64(n) => Some(n),
-            _ => None,
-        }
-    }
-
-    /// If the Json value is a number, returns or cast it to a `f64`;
-    /// returns `None` otherwise.
-    pub fn as_f64(&self) -> Option<f64> {
-        match *self {
-            Json::I64(n) => Some(n as f64),
-            Json::U64(n) => Some(n as f64),
-            Json::F64(n) => Some(n),
-            _ => None,
-        }
-    }
-
-    /// Returns `true` if the Json value is a `Boolean`.
-    pub fn is_boolean(&self) -> bool {
-        self.as_boolean().is_some()
-    }
-
-    /// If the Json value is a `Boolean`, returns the associated `bool`;
-    /// returns `None` otherwise.
-    pub fn as_boolean(&self) -> Option<bool> {
-        match *self {
-            Json::Boolean(b) => Some(b),
-            _ => None,
-        }
-    }
-
-    /// Returns `true` if the Json value is a `Null`.
-    pub fn is_null(&self) -> bool {
-        self.as_null().is_some()
-    }
-
-    /// If the Json value is a `Null`, returns `()`;
-    /// returns `None` otherwise.
-    pub fn as_null(&self) -> Option<()> {
-        match *self {
-            Json::Null => Some(()),
-            _ => None,
-        }
-    }
-}
-
-impl<'a> Index<&'a str> for Json {
-    type Output = Json;
-
-    fn index(&self, idx: &'a str) -> &Json {
-        self.find(idx).unwrap()
-    }
-}
-
-impl Index<usize> for Json {
-    type Output = Json;
-
-    fn index(&self, idx: usize) -> &Json {
-        match *self {
-            Json::Array(ref v) => &v[idx],
-            _ => panic!("can only index Json with usize if it is an array"),
-        }
-    }
-}
-
-/// The output of the streaming parser.
-#[derive(PartialEq, Clone, Debug)]
-pub enum JsonEvent {
-    ObjectStart,
-    ObjectEnd,
-    ArrayStart,
-    ArrayEnd,
-    BooleanValue(bool),
-    I64Value(i64),
-    U64Value(u64),
-    F64Value(f64),
-    StringValue(string::String),
-    NullValue,
-    Error(ParserError),
-}
-
-#[derive(PartialEq, Debug)]
-enum ParserState {
-    // Parse a value in an array, true means first element.
-    ParseArray(bool),
-    // Parse ',' or ']' after an element in an array.
-    ParseArrayComma,
-    // Parse a key:value in an object, true means first element.
-    ParseObject(bool),
-    // Parse ',' or ']' after an element in an object.
-    ParseObjectComma,
-    // Initial state.
-    ParseStart,
-    // Expecting the stream to end.
-    ParseBeforeFinish,
-    // Parsing can't continue.
-    ParseFinished,
-}
-
-/// A Stack represents the current position of the parser in the logical
-/// structure of the JSON stream.
-///
-/// An example is `foo.bar[3].x`.
-#[derive(Default)]
-pub struct Stack {
-    stack: Vec<InternalStackElement>,
-    str_buffer: Vec<u8>,
-}
-
-/// StackElements compose a Stack.
-///
-/// As an example, `StackElement::Key("foo")`, `StackElement::Key("bar")`,
-/// `StackElement::Index(3)`, and `StackElement::Key("x")` are the
-/// StackElements composing the stack that represents `foo.bar[3].x`.
-#[derive(PartialEq, Clone, Debug)]
-pub enum StackElement<'l> {
-    Index(u32),
-    Key(&'l str),
-}
-
-// Internally, Key elements are stored as indices in a buffer to avoid
-// allocating a string for every member of an object.
-#[derive(PartialEq, Clone, Debug)]
-enum InternalStackElement {
-    InternalIndex(u32),
-    InternalKey(u16, u16), // start, size
-}
-
-impl Stack {
-    pub fn new() -> Stack {
-        Self::default()
-    }
-
-    /// Returns The number of elements in the Stack.
-    pub fn len(&self) -> usize {
-        self.stack.len()
-    }
-
-    /// Returns `true` if the stack is empty.
-    pub fn is_empty(&self) -> bool {
-        self.stack.is_empty()
-    }
-
-    /// Provides access to the StackElement at a given index.
-    /// lower indices are at the bottom of the stack while higher indices are
-    /// at the top.
-    pub fn get(&self, idx: usize) -> StackElement<'_> {
-        match self.stack[idx] {
-            InternalIndex(i) => StackElement::Index(i),
-            InternalKey(start, size) => StackElement::Key(
-                str::from_utf8(&self.str_buffer[start as usize..start as usize + size as usize])
-                    .unwrap(),
-            ),
-        }
-    }
-
-    /// Compares this stack with an array of StackElement<'_>s.
-    pub fn is_equal_to(&self, rhs: &[StackElement<'_>]) -> bool {
-        if self.stack.len() != rhs.len() {
-            return false;
-        }
-        for (i, r) in rhs.iter().enumerate() {
-            if self.get(i) != *r {
-                return false;
-            }
-        }
-        true
-    }
-
-    /// Returns `true` if the bottom-most elements of this stack are the same as
-    /// the ones passed as parameter.
-    pub fn starts_with(&self, rhs: &[StackElement<'_>]) -> bool {
-        if self.stack.len() < rhs.len() {
-            return false;
-        }
-        for (i, r) in rhs.iter().enumerate() {
-            if self.get(i) != *r {
-                return false;
-            }
-        }
-        true
-    }
-
-    /// Returns `true` if the top-most elements of this stack are the same as
-    /// the ones passed as parameter.
-    pub fn ends_with(&self, rhs: &[StackElement<'_>]) -> bool {
-        if self.stack.len() < rhs.len() {
-            return false;
-        }
-        let offset = self.stack.len() - rhs.len();
-        for (i, r) in rhs.iter().enumerate() {
-            if self.get(i + offset) != *r {
-                return false;
-            }
-        }
-        true
-    }
-
-    /// Returns the top-most element (if any).
-    pub fn top(&self) -> Option<StackElement<'_>> {
-        match self.stack.last() {
-            None => None,
-            Some(&InternalIndex(i)) => Some(StackElement::Index(i)),
-            Some(&InternalKey(start, size)) => Some(StackElement::Key(
-                str::from_utf8(&self.str_buffer[start as usize..(start + size) as usize]).unwrap(),
-            )),
-        }
-    }
-
-    // Used by Parser to insert StackElement::Key elements at the top of the stack.
-    fn push_key(&mut self, key: string::String) {
-        self.stack.push(InternalKey(self.str_buffer.len() as u16, key.len() as u16));
-        self.str_buffer.extend(key.as_bytes());
-    }
-
-    // Used by Parser to insert StackElement::Index elements at the top of the stack.
-    fn push_index(&mut self, index: u32) {
-        self.stack.push(InternalIndex(index));
-    }
-
-    // Used by Parser to remove the top-most element of the stack.
-    fn pop(&mut self) {
-        assert!(!self.is_empty());
-        match *self.stack.last().unwrap() {
-            InternalKey(_, sz) => {
-                let new_size = self.str_buffer.len() - sz as usize;
-                self.str_buffer.truncate(new_size);
-            }
-            InternalIndex(_) => {}
-        }
-        self.stack.pop();
-    }
-
-    // Used by Parser to test whether the top-most element is an index.
-    fn last_is_index(&self) -> bool {
-        matches!(self.stack.last(), Some(InternalIndex(_)))
-    }
-
-    // Used by Parser to increment the index of the top-most element.
-    fn bump_index(&mut self) {
-        let len = self.stack.len();
-        let idx = match *self.stack.last().unwrap() {
-            InternalIndex(i) => i + 1,
-            _ => {
-                panic!();
-            }
-        };
-        self.stack[len - 1] = InternalIndex(idx);
-    }
-}
-
-/// A streaming JSON parser implemented as an iterator of JsonEvent, consuming
-/// an iterator of char.
-pub struct Parser<T> {
-    rdr: T,
-    ch: Option<char>,
-    line: usize,
-    col: usize,
-    // We maintain a stack representing where we are in the logical structure
-    // of the JSON stream.
-    stack: Stack,
-    // A state machine is kept to make it possible to interrupt and resume parsing.
-    state: ParserState,
-}
-
-impl<T: Iterator<Item = char>> Iterator for Parser<T> {
-    type Item = JsonEvent;
-
-    fn next(&mut self) -> Option<JsonEvent> {
-        if self.state == ParseFinished {
-            return None;
-        }
-
-        if self.state == ParseBeforeFinish {
-            self.parse_whitespace();
-            // Make sure there is no trailing characters.
-            if self.eof() {
-                self.state = ParseFinished;
-                return None;
-            } else {
-                return Some(self.error_event(TrailingCharacters));
-            }
-        }
-
-        Some(self.parse())
-    }
-}
-
-impl<T: Iterator<Item = char>> Parser<T> {
-    /// Creates the JSON parser.
-    pub fn new(rdr: T) -> Parser<T> {
-        let mut p = Parser {
-            rdr,
-            ch: Some('\x00'),
-            line: 1,
-            col: 0,
-            stack: Stack::new(),
-            state: ParseStart,
-        };
-        p.bump();
-        p
-    }
-
-    /// Provides access to the current position in the logical structure of the
-    /// JSON stream.
-    pub fn stack(&self) -> &Stack {
-        &self.stack
-    }
-
-    fn eof(&self) -> bool {
-        self.ch.is_none()
-    }
-    fn ch_or_null(&self) -> char {
-        self.ch.unwrap_or('\x00')
-    }
-    fn bump(&mut self) {
-        self.ch = self.rdr.next();
-
-        if self.ch_is('\n') {
-            self.line += 1;
-            self.col = 1;
-        } else {
-            self.col += 1;
-        }
-    }
-
-    fn next_char(&mut self) -> Option<char> {
-        self.bump();
-        self.ch
-    }
-    fn ch_is(&self, c: char) -> bool {
-        self.ch == Some(c)
-    }
-
-    fn error<U>(&self, reason: ErrorCode) -> Result<U, ParserError> {
-        Err(SyntaxError(reason, self.line, self.col))
-    }
-
-    fn parse_whitespace(&mut self) {
-        while self.ch_is(' ') || self.ch_is('\n') || self.ch_is('\t') || self.ch_is('\r') {
-            self.bump();
-        }
-    }
-
-    fn parse_number(&mut self) -> JsonEvent {
-        let neg = if self.ch_is('-') {
-            self.bump();
-            true
-        } else {
-            false
-        };
-
-        let res = match self.parse_u64() {
-            Ok(res) => res,
-            Err(e) => {
-                return Error(e);
-            }
-        };
-
-        if self.ch_is('.') || self.ch_is('e') || self.ch_is('E') {
-            let mut res = res as f64;
-
-            if self.ch_is('.') {
-                res = match self.parse_decimal(res) {
-                    Ok(res) => res,
-                    Err(e) => {
-                        return Error(e);
-                    }
-                };
-            }
-
-            if self.ch_is('e') || self.ch_is('E') {
-                res = match self.parse_exponent(res) {
-                    Ok(res) => res,
-                    Err(e) => {
-                        return Error(e);
-                    }
-                };
-            }
-
-            if neg {
-                res *= -1.0;
-            }
-
-            F64Value(res)
-        } else if neg {
-            let res = (res as i64).wrapping_neg();
-
-            // Make sure we didn't underflow.
-            if res > 0 {
-                Error(SyntaxError(InvalidNumber, self.line, self.col))
-            } else {
-                I64Value(res)
-            }
-        } else {
-            U64Value(res)
-        }
-    }
-
-    fn parse_u64(&mut self) -> Result<u64, ParserError> {
-        let mut accum = 0u64;
-        let last_accum = 0; // necessary to detect overflow.
-
-        match self.ch_or_null() {
-            '0' => {
-                self.bump();
-
-                // A leading '0' must be the only digit before the decimal point.
-                if let '0'..='9' = self.ch_or_null() {
-                    return self.error(InvalidNumber);
-                }
-            }
-            '1'..='9' => {
-                while !self.eof() {
-                    match self.ch_or_null() {
-                        c @ '0'..='9' => {
-                            accum = accum.wrapping_mul(10);
-                            accum = accum.wrapping_add((c as u64) - ('0' as u64));
-
-                            // Detect overflow by comparing to the last value.
-                            if accum <= last_accum {
-                                return self.error(InvalidNumber);
-                            }
-
-                            self.bump();
-                        }
-                        _ => break,
-                    }
-                }
-            }
-            _ => return self.error(InvalidNumber),
-        }
-
-        Ok(accum)
-    }
-
-    fn parse_decimal(&mut self, mut res: f64) -> Result<f64, ParserError> {
-        self.bump();
-
-        // Make sure a digit follows the decimal place.
-        match self.ch_or_null() {
-            '0'..='9' => (),
-            _ => return self.error(InvalidNumber),
-        }
-
-        let mut dec = 1.0;
-        while !self.eof() {
-            match self.ch_or_null() {
-                c @ '0'..='9' => {
-                    dec /= 10.0;
-                    res += (((c as isize) - ('0' as isize)) as f64) * dec;
-                    self.bump();
-                }
-                _ => break,
-            }
-        }
-
-        Ok(res)
-    }
-
-    fn parse_exponent(&mut self, mut res: f64) -> Result<f64, ParserError> {
-        self.bump();
-
-        let mut exp = 0;
-        let mut neg_exp = false;
-
-        if self.ch_is('+') {
-            self.bump();
-        } else if self.ch_is('-') {
-            self.bump();
-            neg_exp = true;
-        }
-
-        // Make sure a digit follows the exponent place.
-        match self.ch_or_null() {
-            '0'..='9' => (),
-            _ => return self.error(InvalidNumber),
-        }
-        while !self.eof() {
-            match self.ch_or_null() {
-                c @ '0'..='9' => {
-                    exp *= 10;
-                    exp += (c as usize) - ('0' as usize);
-
-                    self.bump();
-                }
-                _ => break,
-            }
-        }
-
-        let exp = 10_f64.powi(exp as i32);
-        if neg_exp {
-            res /= exp;
-        } else {
-            res *= exp;
-        }
-
-        Ok(res)
-    }
-
-    fn decode_hex_escape(&mut self) -> Result<u16, ParserError> {
-        let mut i = 0;
-        let mut n = 0;
-        while i < 4 && !self.eof() {
-            self.bump();
-            n = match self.ch_or_null() {
-                c @ '0'..='9' => n * 16 + ((c as u16) - ('0' as u16)),
-                'a' | 'A' => n * 16 + 10,
-                'b' | 'B' => n * 16 + 11,
-                'c' | 'C' => n * 16 + 12,
-                'd' | 'D' => n * 16 + 13,
-                'e' | 'E' => n * 16 + 14,
-                'f' | 'F' => n * 16 + 15,
-                _ => return self.error(InvalidEscape),
-            };
-
-            i += 1;
-        }
-
-        // Error out if we didn't parse 4 digits.
-        if i != 4 {
-            return self.error(InvalidEscape);
-        }
-
-        Ok(n)
-    }
-
-    fn parse_str(&mut self) -> Result<string::String, ParserError> {
-        let mut escape = false;
-        let mut res = string::String::new();
-
-        loop {
-            self.bump();
-            if self.eof() {
-                return self.error(EOFWhileParsingString);
-            }
-
-            if escape {
-                match self.ch_or_null() {
-                    '"' => res.push('"'),
-                    '\\' => res.push('\\'),
-                    '/' => res.push('/'),
-                    'b' => res.push('\x08'),
-                    'f' => res.push('\x0c'),
-                    'n' => res.push('\n'),
-                    'r' => res.push('\r'),
-                    't' => res.push('\t'),
-                    'u' => match self.decode_hex_escape()? {
-                        0xDC00..=0xDFFF => return self.error(LoneLeadingSurrogateInHexEscape),
-
-                        // Non-BMP characters are encoded as a sequence of
-                        // two hex escapes, representing UTF-16 surrogates.
-                        n1 @ 0xD800..=0xDBFF => {
-                            match (self.next_char(), self.next_char()) {
-                                (Some('\\'), Some('u')) => (),
-                                _ => return self.error(UnexpectedEndOfHexEscape),
-                            }
-
-                            let n2 = self.decode_hex_escape()?;
-                            if !(0xDC00..=0xDFFF).contains(&n2) {
-                                return self.error(LoneLeadingSurrogateInHexEscape);
-                            }
-                            let c =
-                                (u32::from(n1 - 0xD800) << 10 | u32::from(n2 - 0xDC00)) + 0x1_0000;
-                            res.push(char::from_u32(c).unwrap());
-                        }
-
-                        n => match char::from_u32(u32::from(n)) {
-                            Some(c) => res.push(c),
-                            None => return self.error(InvalidUnicodeCodePoint),
-                        },
-                    },
-                    _ => return self.error(InvalidEscape),
-                }
-                escape = false;
-            } else if self.ch_is('\\') {
-                escape = true;
-            } else {
-                match self.ch {
-                    Some('"') => {
-                        self.bump();
-                        return Ok(res);
-                    }
-                    Some(c) => res.push(c),
-                    None => unreachable!(),
-                }
-            }
-        }
-    }
-
-    // Invoked at each iteration, consumes the stream until it has enough
-    // information to return a JsonEvent.
-    // Manages an internal state so that parsing can be interrupted and resumed.
-    // Also keeps track of the position in the logical structure of the json
-    // stream isize the form of a stack that can be queried by the user using the
-    // stack() method.
-    fn parse(&mut self) -> JsonEvent {
-        loop {
-            // The only paths where the loop can spin a new iteration
-            // are in the cases ParseArrayComma and ParseObjectComma if ','
-            // is parsed. In these cases the state is set to (respectively)
-            // ParseArray(false) and ParseObject(false), which always return,
-            // so there is no risk of getting stuck in an infinite loop.
-            // All other paths return before the end of the loop's iteration.
-            self.parse_whitespace();
-
-            match self.state {
-                ParseStart => {
-                    return self.parse_start();
-                }
-                ParseArray(first) => {
-                    return self.parse_array(first);
-                }
-                ParseArrayComma => {
-                    if let Some(evt) = self.parse_array_comma_or_end() {
-                        return evt;
-                    }
-                }
-                ParseObject(first) => {
-                    return self.parse_object(first);
-                }
-                ParseObjectComma => {
-                    self.stack.pop();
-                    if self.ch_is(',') {
-                        self.state = ParseObject(false);
-                        self.bump();
-                    } else {
-                        return self.parse_object_end();
-                    }
-                }
-                _ => {
-                    return self.error_event(InvalidSyntax);
-                }
-            }
-        }
-    }
-
-    fn parse_start(&mut self) -> JsonEvent {
-        let val = self.parse_value();
-        self.state = match val {
-            Error(_) => ParseFinished,
-            ArrayStart => ParseArray(true),
-            ObjectStart => ParseObject(true),
-            _ => ParseBeforeFinish,
-        };
-        val
-    }
-
-    fn parse_array(&mut self, first: bool) -> JsonEvent {
-        if self.ch_is(']') {
-            if !first {
-                self.error_event(InvalidSyntax)
-            } else {
-                self.state = if self.stack.is_empty() {
-                    ParseBeforeFinish
-                } else if self.stack.last_is_index() {
-                    ParseArrayComma
-                } else {
-                    ParseObjectComma
-                };
-                self.bump();
-                ArrayEnd
-            }
-        } else {
-            if first {
-                self.stack.push_index(0);
-            }
-            let val = self.parse_value();
-            self.state = match val {
-                Error(_) => ParseFinished,
-                ArrayStart => ParseArray(true),
-                ObjectStart => ParseObject(true),
-                _ => ParseArrayComma,
-            };
-            val
-        }
-    }
-
-    fn parse_array_comma_or_end(&mut self) -> Option<JsonEvent> {
-        if self.ch_is(',') {
-            self.stack.bump_index();
-            self.state = ParseArray(false);
-            self.bump();
-            None
-        } else if self.ch_is(']') {
-            self.stack.pop();
-            self.state = if self.stack.is_empty() {
-                ParseBeforeFinish
-            } else if self.stack.last_is_index() {
-                ParseArrayComma
-            } else {
-                ParseObjectComma
-            };
-            self.bump();
-            Some(ArrayEnd)
-        } else if self.eof() {
-            Some(self.error_event(EOFWhileParsingArray))
-        } else {
-            Some(self.error_event(InvalidSyntax))
-        }
-    }
-
-    fn parse_object(&mut self, first: bool) -> JsonEvent {
-        if self.ch_is('}') {
-            if !first {
-                if self.stack.is_empty() {
-                    return self.error_event(TrailingComma);
-                } else {
-                    self.stack.pop();
-                }
-            }
-            self.state = if self.stack.is_empty() {
-                ParseBeforeFinish
-            } else if self.stack.last_is_index() {
-                ParseArrayComma
-            } else {
-                ParseObjectComma
-            };
-            self.bump();
-            return ObjectEnd;
-        }
-        if self.eof() {
-            return self.error_event(EOFWhileParsingObject);
-        }
-        if !self.ch_is('"') {
-            return self.error_event(KeyMustBeAString);
-        }
-        let s = match self.parse_str() {
-            Ok(s) => s,
-            Err(e) => {
-                self.state = ParseFinished;
-                return Error(e);
-            }
-        };
-        self.parse_whitespace();
-        if self.eof() {
-            return self.error_event(EOFWhileParsingObject);
-        } else if self.ch_or_null() != ':' {
-            return self.error_event(ExpectedColon);
-        }
-        self.stack.push_key(s);
-        self.bump();
-        self.parse_whitespace();
-
-        let val = self.parse_value();
-
-        self.state = match val {
-            Error(_) => ParseFinished,
-            ArrayStart => ParseArray(true),
-            ObjectStart => ParseObject(true),
-            _ => ParseObjectComma,
-        };
-        val
-    }
-
-    fn parse_object_end(&mut self) -> JsonEvent {
-        if self.ch_is('}') {
-            self.state = if self.stack.is_empty() {
-                ParseBeforeFinish
-            } else if self.stack.last_is_index() {
-                ParseArrayComma
-            } else {
-                ParseObjectComma
-            };
-            self.bump();
-            ObjectEnd
-        } else if self.eof() {
-            self.error_event(EOFWhileParsingObject)
-        } else {
-            self.error_event(InvalidSyntax)
-        }
-    }
-
-    fn parse_value(&mut self) -> JsonEvent {
-        if self.eof() {
-            return self.error_event(EOFWhileParsingValue);
-        }
-        match self.ch_or_null() {
-            'n' => self.parse_ident("ull", NullValue),
-            't' => self.parse_ident("rue", BooleanValue(true)),
-            'f' => self.parse_ident("alse", BooleanValue(false)),
-            '0'..='9' | '-' => self.parse_number(),
-            '"' => match self.parse_str() {
-                Ok(s) => StringValue(s),
-                Err(e) => Error(e),
-            },
-            '[' => {
-                self.bump();
-                ArrayStart
-            }
-            '{' => {
-                self.bump();
-                ObjectStart
-            }
-            _ => self.error_event(InvalidSyntax),
-        }
-    }
-
-    fn parse_ident(&mut self, ident: &str, value: JsonEvent) -> JsonEvent {
-        if ident.chars().all(|c| Some(c) == self.next_char()) {
-            self.bump();
-            value
-        } else {
-            Error(SyntaxError(InvalidSyntax, self.line, self.col))
-        }
-    }
-
-    fn error_event(&mut self, reason: ErrorCode) -> JsonEvent {
-        self.state = ParseFinished;
-        Error(SyntaxError(reason, self.line, self.col))
-    }
-}
-
-/// A Builder consumes a json::Parser to create a generic Json structure.
-pub struct Builder<T> {
-    parser: Parser<T>,
-    token: Option<JsonEvent>,
-}
-
-impl<T: Iterator<Item = char>> Builder<T> {
-    /// Creates a JSON Builder.
-    pub fn new(src: T) -> Builder<T> {
-        Builder { parser: Parser::new(src), token: None }
-    }
-
-    // Decode a Json value from a Parser.
-    pub fn build(&mut self) -> Result<Json, BuilderError> {
-        self.bump();
-        let result = self.build_value();
-        self.bump();
-        match self.token {
-            None => {}
-            Some(Error(ref e)) => {
-                return Err(e.clone());
-            }
-            ref tok => {
-                panic!("unexpected token {:?}", tok.clone());
-            }
-        }
-        result
-    }
-
-    fn bump(&mut self) {
-        self.token = self.parser.next();
-    }
-
-    fn build_value(&mut self) -> Result<Json, BuilderError> {
-        match self.token {
-            Some(NullValue) => Ok(Json::Null),
-            Some(I64Value(n)) => Ok(Json::I64(n)),
-            Some(U64Value(n)) => Ok(Json::U64(n)),
-            Some(F64Value(n)) => Ok(Json::F64(n)),
-            Some(BooleanValue(b)) => Ok(Json::Boolean(b)),
-            Some(StringValue(ref mut s)) => {
-                let mut temp = string::String::new();
-                swap(s, &mut temp);
-                Ok(Json::String(temp))
-            }
-            Some(Error(ref e)) => Err(e.clone()),
-            Some(ArrayStart) => self.build_array(),
-            Some(ObjectStart) => self.build_object(),
-            Some(ObjectEnd) => self.parser.error(InvalidSyntax),
-            Some(ArrayEnd) => self.parser.error(InvalidSyntax),
-            None => self.parser.error(EOFWhileParsingValue),
-        }
-    }
-
-    fn build_array(&mut self) -> Result<Json, BuilderError> {
-        self.bump();
-        let mut values = Vec::new();
-
-        loop {
-            if self.token == Some(ArrayEnd) {
-                return Ok(Json::Array(values.into_iter().collect()));
-            }
-            match self.build_value() {
-                Ok(v) => values.push(v),
-                Err(e) => return Err(e),
-            }
-            self.bump();
-        }
-    }
-
-    fn build_object(&mut self) -> Result<Json, BuilderError> {
-        self.bump();
-
-        let mut values = BTreeMap::new();
-
-        loop {
-            match self.token {
-                Some(ObjectEnd) => {
-                    return Ok(Json::Object(values));
-                }
-                Some(Error(ref e)) => {
-                    return Err(e.clone());
-                }
-                None => {
-                    break;
-                }
-                _ => {}
-            }
-            let key = match self.parser.stack().top() {
-                Some(StackElement::Key(k)) => k.to_owned(),
-                _ => {
-                    panic!("invalid state");
-                }
-            };
-            match self.build_value() {
-                Ok(value) => {
-                    values.insert(key, value);
-                }
-                Err(e) => {
-                    return Err(e);
-                }
-            }
-            self.bump();
-        }
-        self.parser.error(EOFWhileParsingObject)
-    }
-}
-
-/// Decodes a json value from a string
-pub fn from_str(s: &str) -> Result<Json, BuilderError> {
-    let mut builder = Builder::new(s.chars());
-    builder.build()
-}
-
-/// A trait for converting values to JSON
-pub trait ToJson {
-    /// Converts the value of `self` to an instance of JSON
-    fn to_json(&self) -> Json;
-}
-
-macro_rules! to_json_impl_i64 {
-    ($($t:ty), +) => (
-        $(impl ToJson for $t {
-            fn to_json(&self) -> Json {
-                Json::I64(*self as i64)
-            }
-        })+
-    )
-}
-
-to_json_impl_i64! { isize, i8, i16, i32, i64 }
-
-macro_rules! to_json_impl_u64 {
-    ($($t:ty), +) => (
-        $(impl ToJson for $t {
-            fn to_json(&self) -> Json {
-                Json::U64(*self as u64)
-            }
-        })+
-    )
-}
-
-to_json_impl_u64! { usize, u8, u16, u32, u64 }
-
-impl ToJson for Json {
-    fn to_json(&self) -> Json {
-        self.clone()
-    }
-}
-
-impl ToJson for f32 {
-    fn to_json(&self) -> Json {
-        f64::from(*self).to_json()
-    }
-}
-
-impl ToJson for f64 {
-    fn to_json(&self) -> Json {
-        match self.classify() {
-            Fp::Nan | Fp::Infinite => Json::Null,
-            _ => Json::F64(*self),
-        }
-    }
-}
-
-impl ToJson for () {
-    fn to_json(&self) -> Json {
-        Json::Null
-    }
-}
-
-impl ToJson for bool {
-    fn to_json(&self) -> Json {
-        Json::Boolean(*self)
-    }
-}
-
-impl ToJson for str {
-    fn to_json(&self) -> Json {
-        Json::String(self.to_string())
-    }
-}
-
-impl ToJson for string::String {
-    fn to_json(&self) -> Json {
-        Json::String((*self).clone())
-    }
-}
-
-impl<'a> ToJson for Cow<'a, str> {
-    fn to_json(&self) -> Json {
-        Json::String(self.to_string())
-    }
-}
-
-macro_rules! tuple_impl {
-    // use variables to indicate the arity of the tuple
-    ($($tyvar:ident),* ) => {
-        // the trailing commas are for the 1 tuple
-        impl<
-            $( $tyvar : ToJson ),*
-            > ToJson for ( $( $tyvar ),* , ) {
-
-            #[inline]
-            #[allow(non_snake_case)]
-            fn to_json(&self) -> Json {
-                match *self {
-                    ($(ref $tyvar),*,) => Json::Array(vec![$($tyvar.to_json()),*])
-                }
-            }
-        }
-    }
-}
-
-tuple_impl! {A}
-tuple_impl! {A, B}
-tuple_impl! {A, B, C}
-tuple_impl! {A, B, C, D}
-tuple_impl! {A, B, C, D, E}
-tuple_impl! {A, B, C, D, E, F}
-tuple_impl! {A, B, C, D, E, F, G}
-tuple_impl! {A, B, C, D, E, F, G, H}
-tuple_impl! {A, B, C, D, E, F, G, H, I}
-tuple_impl! {A, B, C, D, E, F, G, H, I, J}
-tuple_impl! {A, B, C, D, E, F, G, H, I, J, K}
-tuple_impl! {A, B, C, D, E, F, G, H, I, J, K, L}
-
-impl<A: ToJson> ToJson for [A] {
-    fn to_json(&self) -> Json {
-        Json::Array(self.iter().map(|elt| elt.to_json()).collect())
-    }
-}
-
-impl<A: ToJson> ToJson for Vec<A> {
-    fn to_json(&self) -> Json {
-        Json::Array(self.iter().map(|elt| elt.to_json()).collect())
-    }
-}
-
-impl<'a, A: ToJson> ToJson for Cow<'a, [A]>
-where
-    [A]: ToOwned,
-{
-    fn to_json(&self) -> Json {
-        Json::Array(self.iter().map(|elt| elt.to_json()).collect())
-    }
-}
-
-impl<T: ToString, A: ToJson> ToJson for BTreeMap<T, A> {
-    fn to_json(&self) -> Json {
-        let mut d = BTreeMap::new();
-        for (key, value) in self {
-            d.insert(key.to_string(), value.to_json());
-        }
-        Json::Object(d)
-    }
-}
-
-impl<A: ToJson> ToJson for HashMap<string::String, A> {
-    fn to_json(&self) -> Json {
-        let mut d = BTreeMap::new();
-        for (key, value) in self {
-            d.insert((*key).clone(), value.to_json());
-        }
-        Json::Object(d)
-    }
-}
-
-impl<A: ToJson> ToJson for Option<A> {
-    fn to_json(&self) -> Json {
-        match *self {
-            None => Json::Null,
-            Some(ref value) => value.to_json(),
-        }
-    }
-}
-
-struct FormatShim<'a, 'b> {
-    inner: &'a mut fmt::Formatter<'b>,
-}
-
-impl<'a, 'b> fmt::Write for FormatShim<'a, 'b> {
-    fn write_str(&mut self, s: &str) -> fmt::Result {
-        match self.inner.write_str(s) {
-            Ok(_) => Ok(()),
-            Err(_) => Err(fmt::Error),
-        }
-    }
-}
-
-impl fmt::Display for Json {
-    /// Encodes a json value into a string
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let mut shim = FormatShim { inner: f };
-        let mut encoder = Encoder::new(&mut shim);
-        match self.encode(&mut encoder) {
-            Ok(_) => Ok(()),
-            Err(_) => Err(fmt::Error),
-        }
-    }
-}
-
-impl<'a> fmt::Display for PrettyJson<'a> {
-    /// Encodes a json value into a string
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let mut shim = FormatShim { inner: f };
-        let mut encoder = PrettyEncoder::new(&mut shim);
-        match self.inner.encode(&mut encoder) {
-            Ok(_) => Ok(()),
-            Err(_) => Err(fmt::Error),
-        }
-    }
-}
-
-impl<'a, T: for<'r> Encodable<Encoder<'r>>> fmt::Display for AsJson<'a, T> {
-    /// Encodes a json value into a string
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let mut shim = FormatShim { inner: f };
-        let mut encoder = Encoder::new(&mut shim);
-        match self.inner.encode(&mut encoder) {
-            Ok(_) => Ok(()),
-            Err(_) => Err(fmt::Error),
-        }
-    }
-}
-
-impl<'a, T> AsPrettyJson<'a, T> {
-    /// Sets the indentation level for the emitted JSON
-    pub fn indent(mut self, indent: usize) -> AsPrettyJson<'a, T> {
-        self.indent = Some(indent);
-        self
-    }
-}
-
-impl<'a, T: for<'x> Encodable<PrettyEncoder<'x>>> fmt::Display for AsPrettyJson<'a, T> {
-    /// Encodes a json value into a string
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let mut shim = FormatShim { inner: f };
-        let mut encoder = PrettyEncoder::new(&mut shim);
-        if let Some(n) = self.indent {
-            encoder.set_indent(n);
-        }
-        match self.inner.encode(&mut encoder) {
-            Ok(_) => Ok(()),
-            Err(_) => Err(fmt::Error),
-        }
-    }
-}
-
-impl FromStr for Json {
-    type Err = BuilderError;
-    fn from_str(s: &str) -> Result<Json, BuilderError> {
-        from_str(s)
-    }
-}
-
-#[cfg(test)]
-mod tests;
diff --git a/compiler/rustc_serialize/src/json/tests.rs b/compiler/rustc_serialize/src/json/tests.rs
deleted file mode 100644 (file)
index 01678fb..0000000
+++ /dev/null
@@ -1,147 +0,0 @@
-// Benchmarks and tests that require private items
-
-extern crate test;
-use super::{from_str, Parser, Stack, StackElement};
-use std::string;
-use test::Bencher;
-
-#[test]
-fn test_stack() {
-    let mut stack = Stack::new();
-
-    assert!(stack.is_empty());
-    assert!(stack.is_empty());
-    assert!(!stack.last_is_index());
-
-    stack.push_index(0);
-    stack.bump_index();
-
-    assert!(stack.len() == 1);
-    assert!(stack.is_equal_to(&[StackElement::Index(1)]));
-    assert!(stack.starts_with(&[StackElement::Index(1)]));
-    assert!(stack.ends_with(&[StackElement::Index(1)]));
-    assert!(stack.last_is_index());
-    assert!(stack.get(0) == StackElement::Index(1));
-
-    stack.push_key("foo".to_string());
-
-    assert!(stack.len() == 2);
-    assert!(stack.is_equal_to(&[StackElement::Index(1), StackElement::Key("foo")]));
-    assert!(stack.starts_with(&[StackElement::Index(1), StackElement::Key("foo")]));
-    assert!(stack.starts_with(&[StackElement::Index(1)]));
-    assert!(stack.ends_with(&[StackElement::Index(1), StackElement::Key("foo")]));
-    assert!(stack.ends_with(&[StackElement::Key("foo")]));
-    assert!(!stack.last_is_index());
-    assert!(stack.get(0) == StackElement::Index(1));
-    assert!(stack.get(1) == StackElement::Key("foo"));
-
-    stack.push_key("bar".to_string());
-
-    assert!(stack.len() == 3);
-    assert!(stack.is_equal_to(&[
-        StackElement::Index(1),
-        StackElement::Key("foo"),
-        StackElement::Key("bar")
-    ]));
-    assert!(stack.starts_with(&[StackElement::Index(1)]));
-    assert!(stack.starts_with(&[StackElement::Index(1), StackElement::Key("foo")]));
-    assert!(stack.starts_with(&[
-        StackElement::Index(1),
-        StackElement::Key("foo"),
-        StackElement::Key("bar")
-    ]));
-    assert!(stack.ends_with(&[StackElement::Key("bar")]));
-    assert!(stack.ends_with(&[StackElement::Key("foo"), StackElement::Key("bar")]));
-    assert!(stack.ends_with(&[
-        StackElement::Index(1),
-        StackElement::Key("foo"),
-        StackElement::Key("bar")
-    ]));
-    assert!(!stack.last_is_index());
-    assert!(stack.get(0) == StackElement::Index(1));
-    assert!(stack.get(1) == StackElement::Key("foo"));
-    assert!(stack.get(2) == StackElement::Key("bar"));
-
-    stack.pop();
-
-    assert!(stack.len() == 2);
-    assert!(stack.is_equal_to(&[StackElement::Index(1), StackElement::Key("foo")]));
-    assert!(stack.starts_with(&[StackElement::Index(1), StackElement::Key("foo")]));
-    assert!(stack.starts_with(&[StackElement::Index(1)]));
-    assert!(stack.ends_with(&[StackElement::Index(1), StackElement::Key("foo")]));
-    assert!(stack.ends_with(&[StackElement::Key("foo")]));
-    assert!(!stack.last_is_index());
-    assert!(stack.get(0) == StackElement::Index(1));
-    assert!(stack.get(1) == StackElement::Key("foo"));
-}
-
-#[bench]
-fn bench_streaming_small(b: &mut Bencher) {
-    b.iter(|| {
-        let mut parser = Parser::new(
-            r#"{
-                "a": 1.0,
-                "b": [
-                    true,
-                    "foo\nbar",
-                    { "c": {"d": null} }
-                ]
-            }"#
-            .chars(),
-        );
-        loop {
-            match parser.next() {
-                None => return,
-                _ => {}
-            }
-        }
-    });
-}
-#[bench]
-fn bench_small(b: &mut Bencher) {
-    b.iter(|| {
-        let _ = from_str(
-            r#"{
-            "a": 1.0,
-            "b": [
-                true,
-                "foo\nbar",
-                { "c": {"d": null} }
-            ]
-        }"#,
-        );
-    });
-}
-
-fn big_json() -> string::String {
-    let mut src = "[\n".to_string();
-    for _ in 0..500 {
-        src.push_str(
-            r#"{ "a": true, "b": null, "c":3.1415, "d": "Hello world", "e": \
-                        [1,2,3]},"#,
-        );
-    }
-    src.push_str("{}]");
-    return src;
-}
-
-#[bench]
-fn bench_streaming_large(b: &mut Bencher) {
-    let src = big_json();
-    b.iter(|| {
-        let mut parser = Parser::new(src.chars());
-        loop {
-            match parser.next() {
-                None => return,
-                _ => {}
-            }
-        }
-    });
-}
-#[bench]
-fn bench_large(b: &mut Bencher) {
-    let src = big_json();
-    b.iter(|| {
-        let _ = from_str(&src);
-    });
-}
index bd257dc64646a2744e41fdbdacce2765b42a7b73..b3a0bcf0e1134f0b9e6a4e227a9c9821f2b31ef1 100644 (file)
@@ -25,7 +25,5 @@
 mod collection_impls;
 mod serialize;
 
-pub mod json;
-
 pub mod leb128;
 pub mod opaque;
index 5e5cbacbcff1a47c9551f9c6c76b99116f96b8c7..3bcb7cc3650549a2ff87fb90300d4a8123692325 100644 (file)
@@ -64,11 +64,6 @@ macro_rules! write_leb128 {
 impl serialize::Encoder for Encoder {
     type Error = !;
 
-    #[inline]
-    fn emit_unit(&mut self) -> EncodeResult {
-        Ok(())
-    }
-
     #[inline]
     fn emit_usize(&mut self, v: usize) -> EncodeResult {
         write_leb128!(self, v, usize, write_usize_leb128)
@@ -419,11 +414,6 @@ macro_rules! file_encoder_write_leb128 {
 impl serialize::Encoder for FileEncoder {
     type Error = io::Error;
 
-    #[inline]
-    fn emit_unit(&mut self) -> FileEncodeResult {
-        Ok(())
-    }
-
     #[inline]
     fn emit_usize(&mut self, v: usize) -> FileEncodeResult {
         file_encoder_write_leb128!(self, v, usize, write_usize_leb128)
index 36e575b2427af3d4ecb3d7710c5ae417bef5eef7..817a0c9dcb17b0196d81f0574f7b62b667d28db3 100644 (file)
@@ -15,7 +15,6 @@ pub trait Encoder {
     type Error;
 
     // Primitive types:
-    fn emit_unit(&mut self) -> Result<(), Self::Error>;
     fn emit_usize(&mut self, v: usize) -> Result<(), Self::Error>;
     fn emit_u128(&mut self, v: u128) -> Result<(), Self::Error>;
     fn emit_u64(&mut self, v: u64) -> Result<(), Self::Error>;
@@ -35,22 +34,8 @@ pub trait Encoder {
     fn emit_str(&mut self, v: &str) -> Result<(), Self::Error>;
     fn emit_raw_bytes(&mut self, s: &[u8]) -> Result<(), Self::Error>;
 
-    // Compound types:
-    #[inline]
-    fn emit_enum<F>(&mut self, f: F) -> Result<(), Self::Error>
-    where
-        F: FnOnce(&mut Self) -> Result<(), Self::Error>,
-    {
-        f(self)
-    }
-
-    fn emit_enum_variant<F>(
-        &mut self,
-        _v_name: &str,
-        v_id: usize,
-        _len: usize,
-        f: F,
-    ) -> Result<(), Self::Error>
+    // Convenience for the derive macro:
+    fn emit_enum_variant<F>(&mut self, v_id: usize, f: F) -> Result<(), Self::Error>
     where
         F: FnOnce(&mut Self) -> Result<(), Self::Error>,
     {
@@ -65,112 +50,9 @@ fn emit_enum_variant<F>(
     // optimization that would otherwise be necessary here, likely due to the
     // multiple levels of inlining and const-prop that are needed.
     #[inline]
-    fn emit_fieldless_enum_variant<const ID: usize>(
-        &mut self,
-        _v_name: &str,
-    ) -> Result<(), Self::Error> {
+    fn emit_fieldless_enum_variant<const ID: usize>(&mut self) -> Result<(), Self::Error> {
         self.emit_usize(ID)
     }
-
-    #[inline]
-    fn emit_enum_variant_arg<F>(&mut self, _first: bool, f: F) -> Result<(), Self::Error>
-    where
-        F: FnOnce(&mut Self) -> Result<(), Self::Error>,
-    {
-        f(self)
-    }
-
-    #[inline]
-    fn emit_struct<F>(&mut self, _no_fields: bool, f: F) -> Result<(), Self::Error>
-    where
-        F: FnOnce(&mut Self) -> Result<(), Self::Error>,
-    {
-        f(self)
-    }
-
-    #[inline]
-    fn emit_struct_field<F>(&mut self, _f_name: &str, _first: bool, f: F) -> Result<(), Self::Error>
-    where
-        F: FnOnce(&mut Self) -> Result<(), Self::Error>,
-    {
-        f(self)
-    }
-
-    #[inline]
-    fn emit_tuple<F>(&mut self, _len: usize, f: F) -> Result<(), Self::Error>
-    where
-        F: FnOnce(&mut Self) -> Result<(), Self::Error>,
-    {
-        f(self)
-    }
-
-    #[inline]
-    fn emit_tuple_arg<F>(&mut self, _idx: usize, f: F) -> Result<(), Self::Error>
-    where
-        F: FnOnce(&mut Self) -> Result<(), Self::Error>,
-    {
-        f(self)
-    }
-
-    // Specialized types:
-    fn emit_option<F>(&mut self, f: F) -> Result<(), Self::Error>
-    where
-        F: FnOnce(&mut Self) -> Result<(), Self::Error>,
-    {
-        self.emit_enum(f)
-    }
-
-    #[inline]
-    fn emit_option_none(&mut self) -> Result<(), Self::Error> {
-        self.emit_enum_variant("None", 0, 0, |_| Ok(()))
-    }
-
-    fn emit_option_some<F>(&mut self, f: F) -> Result<(), Self::Error>
-    where
-        F: FnOnce(&mut Self) -> Result<(), Self::Error>,
-    {
-        self.emit_enum_variant("Some", 1, 1, f)
-    }
-
-    fn emit_seq<F>(&mut self, len: usize, f: F) -> Result<(), Self::Error>
-    where
-        F: FnOnce(&mut Self) -> Result<(), Self::Error>,
-    {
-        self.emit_usize(len)?;
-        f(self)
-    }
-
-    #[inline]
-    fn emit_seq_elt<F>(&mut self, _idx: usize, f: F) -> Result<(), Self::Error>
-    where
-        F: FnOnce(&mut Self) -> Result<(), Self::Error>,
-    {
-        f(self)
-    }
-
-    fn emit_map<F>(&mut self, len: usize, f: F) -> Result<(), Self::Error>
-    where
-        F: FnOnce(&mut Self) -> Result<(), Self::Error>,
-    {
-        self.emit_usize(len)?;
-        f(self)
-    }
-
-    #[inline]
-    fn emit_map_elt_key<F>(&mut self, _idx: usize, f: F) -> Result<(), Self::Error>
-    where
-        F: FnOnce(&mut Self) -> Result<(), Self::Error>,
-    {
-        f(self)
-    }
-
-    #[inline]
-    fn emit_map_elt_val<F>(&mut self, f: F) -> Result<(), Self::Error>
-    where
-        F: FnOnce(&mut Self) -> Result<(), Self::Error>,
-    {
-        f(self)
-    }
 }
 
 // Note: all the methods in this trait are infallible, which may be surprising.
@@ -320,8 +202,8 @@ fn decode(d: &mut D) -> String {
 }
 
 impl<S: Encoder> Encodable<S> for () {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_unit()
+    fn encode(&self, _s: &mut S) -> Result<(), S::Error> {
+        Ok(())
     }
 }
 
@@ -330,8 +212,8 @@ fn decode(_: &mut D) -> () {}
 }
 
 impl<S: Encoder, T> Encodable<S> for PhantomData<T> {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_unit()
+    fn encode(&self, _s: &mut S) -> Result<(), S::Error> {
+        Ok(())
     }
 }
 
@@ -362,12 +244,11 @@ fn decode(d: &mut D) -> Rc<T> {
 
 impl<S: Encoder, T: Encodable<S>> Encodable<S> for [T] {
     default fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_seq(self.len(), |s| {
-            for (i, e) in self.iter().enumerate() {
-                s.emit_seq_elt(i, |s| e.encode(s))?
-            }
-            Ok(())
-        })
+        s.emit_usize(self.len())?;
+        for e in self.iter() {
+            e.encode(s)?
+        }
+        Ok(())
     }
 }
 
@@ -450,10 +331,10 @@ fn decode(d: &mut D) -> Cow<'static, str> {
 
 impl<S: Encoder, T: Encodable<S>> Encodable<S> for Option<T> {
     fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_option(|s| match *self {
-            None => s.emit_option_none(),
-            Some(ref v) => s.emit_option_some(|s| v.encode(s)),
-        })
+        match *self {
+            None => s.emit_enum_variant(0, |_| Ok(())),
+            Some(ref v) => s.emit_enum_variant(1, |s| v.encode(s)),
+        }
     }
 }
 
@@ -469,14 +350,10 @@ fn decode(d: &mut D) -> Option<T> {
 
 impl<S: Encoder, T1: Encodable<S>, T2: Encodable<S>> Encodable<S> for Result<T1, T2> {
     fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_enum(|s| match *self {
-            Ok(ref v) => {
-                s.emit_enum_variant("Ok", 0, 1, |s| s.emit_enum_variant_arg(true, |s| v.encode(s)))
-            }
-            Err(ref v) => {
-                s.emit_enum_variant("Err", 1, 1, |s| s.emit_enum_variant_arg(true, |s| v.encode(s)))
-            }
-        })
+        match *self {
+            Ok(ref v) => s.emit_enum_variant(0, |s| v.encode(s)),
+            Err(ref v) => s.emit_enum_variant(1, |s| v.encode(s)),
+        }
     }
 }
 
@@ -494,18 +371,6 @@ macro_rules! peel {
     ($name:ident, $($other:ident,)*) => (tuple! { $($other,)* })
 }
 
-/// Evaluates to the number of tokens passed to it.
-///
-/// Logarithmic counting: every one or two recursive expansions, the number of
-/// tokens to count is divided by two, instead of being reduced by one.
-/// Therefore, the recursion depth is the binary logarithm of the number of
-/// tokens to count, and the expanded tree is likewise very small.
-macro_rules! count {
-    ($one:tt)              => (1usize);
-    ($($pairs:tt $_p:tt)*) => (count!($($pairs)*) << 1usize);
-    ($odd:tt $($rest:tt)*) => (count!($($rest)*) | 1usize);
-}
-
 macro_rules! tuple {
     () => ();
     ( $($name:ident,)+ ) => (
@@ -518,12 +383,8 @@ impl<S: Encoder, $($name: Encodable<S>),+> Encodable<S> for ($($name,)+) {
             #[allow(non_snake_case)]
             fn encode(&self, s: &mut S) -> Result<(), S::Error> {
                 let ($(ref $name,)+) = *self;
-                let len: usize = count!($($name)+);
-                s.emit_tuple(len, |s| {
-                    let mut i = 0;
-                    $(s.emit_tuple_arg({ i+=1; i-1 }, |s| $name.encode(s))?;)+
-                    Ok(())
-                })
+                $($name.encode(s)?;)+
+                Ok(())
             }
         }
         peel! { $($name,)+ }
diff --git a/compiler/rustc_serialize/tests/json.rs b/compiler/rustc_serialize/tests/json.rs
deleted file mode 100644 (file)
index 944fe46..0000000
+++ /dev/null
@@ -1,978 +0,0 @@
-#![allow(rustc::internal)]
-
-use json::ErrorCode::*;
-use json::Json::*;
-use json::JsonEvent::*;
-use json::ParserError::*;
-use json::{from_str, Encoder, EncoderError, Json, JsonEvent, Parser, StackElement};
-use rustc_macros::Encodable;
-use rustc_serialize::json;
-use rustc_serialize::Encodable;
-
-use std::collections::BTreeMap;
-use std::io::prelude::*;
-use std::string;
-use Animal::*;
-
-#[derive(Eq, PartialEq, Debug)]
-struct OptionData {
-    opt: Option<usize>,
-}
-
-#[derive(PartialEq, Encodable, Debug)]
-enum Animal {
-    Dog,
-    Frog(string::String, isize),
-}
-
-#[derive(PartialEq, Encodable, Debug)]
-struct Inner {
-    a: (),
-    b: usize,
-    c: Vec<string::String>,
-}
-
-#[derive(PartialEq, Encodable, Debug)]
-struct Outer {
-    inner: Vec<Inner>,
-}
-
-fn mk_object(items: &[(string::String, Json)]) -> Json {
-    let mut d = BTreeMap::new();
-
-    for item in items {
-        match *item {
-            (ref key, ref value) => {
-                d.insert((*key).clone(), (*value).clone());
-            }
-        }
-    }
-
-    Object(d)
-}
-
-#[test]
-fn test_from_str_trait() {
-    let s = "null";
-    assert!(s.parse::<Json>().unwrap() == s.parse().unwrap());
-}
-
-#[test]
-fn test_write_null() {
-    assert_eq!(Null.to_string(), "null");
-    assert_eq!(Null.pretty().to_string(), "null");
-}
-
-#[test]
-fn test_write_i64() {
-    assert_eq!(U64(0).to_string(), "0");
-    assert_eq!(U64(0).pretty().to_string(), "0");
-
-    assert_eq!(U64(1234).to_string(), "1234");
-    assert_eq!(U64(1234).pretty().to_string(), "1234");
-
-    assert_eq!(I64(-5678).to_string(), "-5678");
-    assert_eq!(I64(-5678).pretty().to_string(), "-5678");
-
-    assert_eq!(U64(7650007200025252000).to_string(), "7650007200025252000");
-    assert_eq!(U64(7650007200025252000).pretty().to_string(), "7650007200025252000");
-}
-
-#[test]
-fn test_write_f64() {
-    assert_eq!(F64(3.0).to_string(), "3.0");
-    assert_eq!(F64(3.0).pretty().to_string(), "3.0");
-
-    assert_eq!(F64(3.1).to_string(), "3.1");
-    assert_eq!(F64(3.1).pretty().to_string(), "3.1");
-
-    assert_eq!(F64(-1.5).to_string(), "-1.5");
-    assert_eq!(F64(-1.5).pretty().to_string(), "-1.5");
-
-    assert_eq!(F64(0.5).to_string(), "0.5");
-    assert_eq!(F64(0.5).pretty().to_string(), "0.5");
-
-    assert_eq!(F64(f64::NAN).to_string(), "null");
-    assert_eq!(F64(f64::NAN).pretty().to_string(), "null");
-
-    assert_eq!(F64(f64::INFINITY).to_string(), "null");
-    assert_eq!(F64(f64::INFINITY).pretty().to_string(), "null");
-
-    assert_eq!(F64(f64::NEG_INFINITY).to_string(), "null");
-    assert_eq!(F64(f64::NEG_INFINITY).pretty().to_string(), "null");
-}
-
-#[test]
-fn test_write_str() {
-    assert_eq!(String("".to_string()).to_string(), "\"\"");
-    assert_eq!(String("".to_string()).pretty().to_string(), "\"\"");
-
-    assert_eq!(String("homura".to_string()).to_string(), "\"homura\"");
-    assert_eq!(String("madoka".to_string()).pretty().to_string(), "\"madoka\"");
-}
-
-#[test]
-fn test_write_bool() {
-    assert_eq!(Boolean(true).to_string(), "true");
-    assert_eq!(Boolean(true).pretty().to_string(), "true");
-
-    assert_eq!(Boolean(false).to_string(), "false");
-    assert_eq!(Boolean(false).pretty().to_string(), "false");
-}
-
-#[test]
-fn test_write_array() {
-    assert_eq!(Array(vec![]).to_string(), "[]");
-    assert_eq!(Array(vec![]).pretty().to_string(), "[]");
-
-    assert_eq!(Array(vec![Boolean(true)]).to_string(), "[true]");
-    assert_eq!(
-        Array(vec![Boolean(true)]).pretty().to_string(),
-        "\
-        [\n  \
-            true\n\
-        ]"
-    );
-
-    let long_test_array =
-        Array(vec![Boolean(false), Null, Array(vec![String("foo\nbar".to_string()), F64(3.5)])]);
-
-    assert_eq!(long_test_array.to_string(), "[false,null,[\"foo\\nbar\",3.5]]");
-    assert_eq!(
-        long_test_array.pretty().to_string(),
-        "\
-        [\n  \
-            false,\n  \
-            null,\n  \
-            [\n    \
-                \"foo\\nbar\",\n    \
-                3.5\n  \
-            ]\n\
-        ]"
-    );
-}
-
-#[test]
-fn test_write_object() {
-    assert_eq!(mk_object(&[]).to_string(), "{}");
-    assert_eq!(mk_object(&[]).pretty().to_string(), "{}");
-
-    assert_eq!(mk_object(&[("a".to_string(), Boolean(true))]).to_string(), "{\"a\":true}");
-    assert_eq!(
-        mk_object(&[("a".to_string(), Boolean(true))]).pretty().to_string(),
-        "\
-        {\n  \
-            \"a\": true\n\
-        }"
-    );
-
-    let complex_obj = mk_object(&[(
-        "b".to_string(),
-        Array(vec![
-            mk_object(&[("c".to_string(), String("\x0c\r".to_string()))]),
-            mk_object(&[("d".to_string(), String("".to_string()))]),
-        ]),
-    )]);
-
-    assert_eq!(
-        complex_obj.to_string(),
-        "{\
-            \"b\":[\
-                {\"c\":\"\\f\\r\"},\
-                {\"d\":\"\"}\
-            ]\
-        }"
-    );
-    assert_eq!(
-        complex_obj.pretty().to_string(),
-        "\
-        {\n  \
-            \"b\": [\n    \
-                {\n      \
-                    \"c\": \"\\f\\r\"\n    \
-                },\n    \
-                {\n      \
-                    \"d\": \"\"\n    \
-                }\n  \
-            ]\n\
-        }"
-    );
-
-    let a = mk_object(&[
-        ("a".to_string(), Boolean(true)),
-        (
-            "b".to_string(),
-            Array(vec![
-                mk_object(&[("c".to_string(), String("\x0c\r".to_string()))]),
-                mk_object(&[("d".to_string(), String("".to_string()))]),
-            ]),
-        ),
-    ]);
-
-    // We can't compare the strings directly because the object fields be
-    // printed in a different order.
-    assert_eq!(a.clone(), a.to_string().parse().unwrap());
-    assert_eq!(a.clone(), a.pretty().to_string().parse().unwrap());
-}
-
-#[test]
-fn test_write_enum() {
-    let animal = Dog;
-    assert_eq!(json::as_json(&animal).to_string(), "\"Dog\"");
-    assert_eq!(json::as_pretty_json(&animal).to_string(), "\"Dog\"");
-
-    let animal = Frog("Henry".to_string(), 349);
-    assert_eq!(
-        json::as_json(&animal).to_string(),
-        "{\"variant\":\"Frog\",\"fields\":[\"Henry\",349]}"
-    );
-    assert_eq!(
-        json::as_pretty_json(&animal).to_string(),
-        "{\n  \
-           \"variant\": \"Frog\",\n  \
-           \"fields\": [\n    \
-             \"Henry\",\n    \
-             349\n  \
-           ]\n\
-         }"
-    );
-}
-
-macro_rules! check_encoder_for_simple {
-    ($value:expr, $expected:expr) => {{
-        let s = json::as_json(&$value).to_string();
-        assert_eq!(s, $expected);
-
-        let s = json::as_pretty_json(&$value).to_string();
-        assert_eq!(s, $expected);
-    }};
-}
-
-#[test]
-fn test_write_some() {
-    check_encoder_for_simple!(Some("jodhpurs".to_string()), "\"jodhpurs\"");
-}
-
-#[test]
-fn test_write_none() {
-    check_encoder_for_simple!(None::<string::String>, "null");
-}
-
-#[test]
-fn test_write_char() {
-    check_encoder_for_simple!('a', "\"a\"");
-    check_encoder_for_simple!('\t', "\"\\t\"");
-    check_encoder_for_simple!('\u{0000}', "\"\\u0000\"");
-    check_encoder_for_simple!('\u{001b}', "\"\\u001b\"");
-    check_encoder_for_simple!('\u{007f}', "\"\\u007f\"");
-    check_encoder_for_simple!('\u{00a0}', "\"\u{00a0}\"");
-    check_encoder_for_simple!('\u{abcd}', "\"\u{abcd}\"");
-    check_encoder_for_simple!('\u{10ffff}', "\"\u{10ffff}\"");
-}
-
-#[test]
-fn test_trailing_characters() {
-    assert_eq!(from_str("nulla"), Err(SyntaxError(TrailingCharacters, 1, 5)));
-    assert_eq!(from_str("truea"), Err(SyntaxError(TrailingCharacters, 1, 5)));
-    assert_eq!(from_str("falsea"), Err(SyntaxError(TrailingCharacters, 1, 6)));
-    assert_eq!(from_str("1a"), Err(SyntaxError(TrailingCharacters, 1, 2)));
-    assert_eq!(from_str("[]a"), Err(SyntaxError(TrailingCharacters, 1, 3)));
-    assert_eq!(from_str("{}a"), Err(SyntaxError(TrailingCharacters, 1, 3)));
-}
-
-#[test]
-fn test_read_identifiers() {
-    assert_eq!(from_str("n"), Err(SyntaxError(InvalidSyntax, 1, 2)));
-    assert_eq!(from_str("nul"), Err(SyntaxError(InvalidSyntax, 1, 4)));
-    assert_eq!(from_str("t"), Err(SyntaxError(InvalidSyntax, 1, 2)));
-    assert_eq!(from_str("truz"), Err(SyntaxError(InvalidSyntax, 1, 4)));
-    assert_eq!(from_str("f"), Err(SyntaxError(InvalidSyntax, 1, 2)));
-    assert_eq!(from_str("faz"), Err(SyntaxError(InvalidSyntax, 1, 3)));
-
-    assert_eq!(from_str("null"), Ok(Null));
-    assert_eq!(from_str("true"), Ok(Boolean(true)));
-    assert_eq!(from_str("false"), Ok(Boolean(false)));
-    assert_eq!(from_str(" null "), Ok(Null));
-    assert_eq!(from_str(" true "), Ok(Boolean(true)));
-    assert_eq!(from_str(" false "), Ok(Boolean(false)));
-}
-
-#[test]
-fn test_read_number() {
-    assert_eq!(from_str("+"), Err(SyntaxError(InvalidSyntax, 1, 1)));
-    assert_eq!(from_str("."), Err(SyntaxError(InvalidSyntax, 1, 1)));
-    assert_eq!(from_str("NaN"), Err(SyntaxError(InvalidSyntax, 1, 1)));
-    assert_eq!(from_str("-"), Err(SyntaxError(InvalidNumber, 1, 2)));
-    assert_eq!(from_str("00"), Err(SyntaxError(InvalidNumber, 1, 2)));
-    assert_eq!(from_str("1."), Err(SyntaxError(InvalidNumber, 1, 3)));
-    assert_eq!(from_str("1e"), Err(SyntaxError(InvalidNumber, 1, 3)));
-    assert_eq!(from_str("1e+"), Err(SyntaxError(InvalidNumber, 1, 4)));
-
-    assert_eq!(from_str("18446744073709551616"), Err(SyntaxError(InvalidNumber, 1, 20)));
-    assert_eq!(from_str("-9223372036854775809"), Err(SyntaxError(InvalidNumber, 1, 21)));
-
-    assert_eq!(from_str("3"), Ok(U64(3)));
-    assert_eq!(from_str("3.1"), Ok(F64(3.1)));
-    assert_eq!(from_str("-1.2"), Ok(F64(-1.2)));
-    assert_eq!(from_str("0.4"), Ok(F64(0.4)));
-    assert_eq!(from_str("0.4e5"), Ok(F64(0.4e5)));
-    assert_eq!(from_str("0.4e+15"), Ok(F64(0.4e15)));
-    assert_eq!(from_str("0.4e-01"), Ok(F64(0.4e-01)));
-    assert_eq!(from_str(" 3 "), Ok(U64(3)));
-
-    assert_eq!(from_str("-9223372036854775808"), Ok(I64(i64::MIN)));
-    assert_eq!(from_str("9223372036854775807"), Ok(U64(i64::MAX as u64)));
-    assert_eq!(from_str("18446744073709551615"), Ok(U64(u64::MAX)));
-}
-
-#[test]
-fn test_read_str() {
-    assert_eq!(from_str("\""), Err(SyntaxError(EOFWhileParsingString, 1, 2)));
-    assert_eq!(from_str("\"lol"), Err(SyntaxError(EOFWhileParsingString, 1, 5)));
-
-    assert_eq!(from_str("\"\""), Ok(String("".to_string())));
-    assert_eq!(from_str("\"foo\""), Ok(String("foo".to_string())));
-    assert_eq!(from_str("\"\\\"\""), Ok(String("\"".to_string())));
-    assert_eq!(from_str("\"\\b\""), Ok(String("\x08".to_string())));
-    assert_eq!(from_str("\"\\n\""), Ok(String("\n".to_string())));
-    assert_eq!(from_str("\"\\r\""), Ok(String("\r".to_string())));
-    assert_eq!(from_str("\"\\t\""), Ok(String("\t".to_string())));
-    assert_eq!(from_str(" \"foo\" "), Ok(String("foo".to_string())));
-    assert_eq!(from_str("\"\\u12ab\""), Ok(String("\u{12ab}".to_string())));
-    assert_eq!(from_str("\"\\uAB12\""), Ok(String("\u{AB12}".to_string())));
-}
-
-#[test]
-fn test_read_array() {
-    assert_eq!(from_str("["), Err(SyntaxError(EOFWhileParsingValue, 1, 2)));
-    assert_eq!(from_str("[1"), Err(SyntaxError(EOFWhileParsingArray, 1, 3)));
-    assert_eq!(from_str("[1,"), Err(SyntaxError(EOFWhileParsingValue, 1, 4)));
-    assert_eq!(from_str("[1,]"), Err(SyntaxError(InvalidSyntax, 1, 4)));
-    assert_eq!(from_str("[6 7]"), Err(SyntaxError(InvalidSyntax, 1, 4)));
-
-    assert_eq!(from_str("[]"), Ok(Array(vec![])));
-    assert_eq!(from_str("[ ]"), Ok(Array(vec![])));
-    assert_eq!(from_str("[true]"), Ok(Array(vec![Boolean(true)])));
-    assert_eq!(from_str("[ false ]"), Ok(Array(vec![Boolean(false)])));
-    assert_eq!(from_str("[null]"), Ok(Array(vec![Null])));
-    assert_eq!(from_str("[3, 1]"), Ok(Array(vec![U64(3), U64(1)])));
-    assert_eq!(from_str("\n[3, 2]\n"), Ok(Array(vec![U64(3), U64(2)])));
-    assert_eq!(from_str("[2, [4, 1]]"), Ok(Array(vec![U64(2), Array(vec![U64(4), U64(1)])])));
-}
-
-#[test]
-fn test_read_object() {
-    assert_eq!(from_str("{"), Err(SyntaxError(EOFWhileParsingObject, 1, 2)));
-    assert_eq!(from_str("{ "), Err(SyntaxError(EOFWhileParsingObject, 1, 3)));
-    assert_eq!(from_str("{1"), Err(SyntaxError(KeyMustBeAString, 1, 2)));
-    assert_eq!(from_str("{ \"a\""), Err(SyntaxError(EOFWhileParsingObject, 1, 6)));
-    assert_eq!(from_str("{\"a\""), Err(SyntaxError(EOFWhileParsingObject, 1, 5)));
-    assert_eq!(from_str("{\"a\" "), Err(SyntaxError(EOFWhileParsingObject, 1, 6)));
-
-    assert_eq!(from_str("{\"a\" 1"), Err(SyntaxError(ExpectedColon, 1, 6)));
-    assert_eq!(from_str("{\"a\":"), Err(SyntaxError(EOFWhileParsingValue, 1, 6)));
-    assert_eq!(from_str("{\"a\":1"), Err(SyntaxError(EOFWhileParsingObject, 1, 7)));
-    assert_eq!(from_str("{\"a\":1 1"), Err(SyntaxError(InvalidSyntax, 1, 8)));
-    assert_eq!(from_str("{\"a\":1,"), Err(SyntaxError(EOFWhileParsingObject, 1, 8)));
-
-    assert_eq!(from_str("{}").unwrap(), mk_object(&[]));
-    assert_eq!(from_str("{\"a\": 3}").unwrap(), mk_object(&[("a".to_string(), U64(3))]));
-
-    assert_eq!(
-        from_str("{ \"a\": null, \"b\" : true }").unwrap(),
-        mk_object(&[("a".to_string(), Null), ("b".to_string(), Boolean(true))])
-    );
-    assert_eq!(
-        from_str("\n{ \"a\": null, \"b\" : true }\n").unwrap(),
-        mk_object(&[("a".to_string(), Null), ("b".to_string(), Boolean(true))])
-    );
-    assert_eq!(
-        from_str("{\"a\" : 1.0 ,\"b\": [ true ]}").unwrap(),
-        mk_object(&[("a".to_string(), F64(1.0)), ("b".to_string(), Array(vec![Boolean(true)]))])
-    );
-    assert_eq!(
-        from_str(
-            "{\
-                        \"a\": 1.0, \
-                        \"b\": [\
-                            true,\
-                            \"foo\\nbar\", \
-                            { \"c\": {\"d\": null} } \
-                        ]\
-                    }"
-        )
-        .unwrap(),
-        mk_object(&[
-            ("a".to_string(), F64(1.0)),
-            (
-                "b".to_string(),
-                Array(vec![
-                    Boolean(true),
-                    String("foo\nbar".to_string()),
-                    mk_object(&[("c".to_string(), mk_object(&[("d".to_string(), Null)]))])
-                ])
-            )
-        ])
-    );
-}
-
-#[test]
-fn test_multiline_errors() {
-    assert_eq!(from_str("{\n  \"foo\":\n \"bar\""), Err(SyntaxError(EOFWhileParsingObject, 3, 8)));
-}
-
-#[test]
-fn test_find() {
-    let json_value = from_str("{\"dog\" : \"cat\"}").unwrap();
-    let found_str = json_value.find("dog");
-    assert!(found_str.unwrap().as_string().unwrap() == "cat");
-}
-
-#[test]
-fn test_find_path() {
-    let json_value = from_str("{\"dog\":{\"cat\": {\"mouse\" : \"cheese\"}}}").unwrap();
-    let found_str = json_value.find_path(&["dog", "cat", "mouse"]);
-    assert!(found_str.unwrap().as_string().unwrap() == "cheese");
-}
-
-#[test]
-fn test_search() {
-    let json_value = from_str("{\"dog\":{\"cat\": {\"mouse\" : \"cheese\"}}}").unwrap();
-    let found_str = json_value.search("mouse").and_then(|j| j.as_string());
-    assert!(found_str.unwrap() == "cheese");
-}
-
-#[test]
-fn test_index() {
-    let json_value = from_str("{\"animals\":[\"dog\",\"cat\",\"mouse\"]}").unwrap();
-    let ref array = json_value["animals"];
-    assert_eq!(array[0].as_string().unwrap(), "dog");
-    assert_eq!(array[1].as_string().unwrap(), "cat");
-    assert_eq!(array[2].as_string().unwrap(), "mouse");
-}
-
-#[test]
-fn test_is_object() {
-    let json_value = from_str("{}").unwrap();
-    assert!(json_value.is_object());
-}
-
-#[test]
-fn test_as_object() {
-    let json_value = from_str("{}").unwrap();
-    let json_object = json_value.as_object();
-    assert!(json_object.is_some());
-}
-
-#[test]
-fn test_is_array() {
-    let json_value = from_str("[1, 2, 3]").unwrap();
-    assert!(json_value.is_array());
-}
-
-#[test]
-fn test_as_array() {
-    let json_value = from_str("[1, 2, 3]").unwrap();
-    let json_array = json_value.as_array();
-    let expected_length = 3;
-    assert!(json_array.is_some() && json_array.unwrap().len() == expected_length);
-}
-
-#[test]
-fn test_is_string() {
-    let json_value = from_str("\"dog\"").unwrap();
-    assert!(json_value.is_string());
-}
-
-#[test]
-fn test_as_string() {
-    let json_value = from_str("\"dog\"").unwrap();
-    let json_str = json_value.as_string();
-    let expected_str = "dog";
-    assert_eq!(json_str, Some(expected_str));
-}
-
-#[test]
-fn test_is_number() {
-    let json_value = from_str("12").unwrap();
-    assert!(json_value.is_number());
-}
-
-#[test]
-fn test_is_i64() {
-    let json_value = from_str("-12").unwrap();
-    assert!(json_value.is_i64());
-
-    let json_value = from_str("12").unwrap();
-    assert!(!json_value.is_i64());
-
-    let json_value = from_str("12.0").unwrap();
-    assert!(!json_value.is_i64());
-}
-
-#[test]
-fn test_is_u64() {
-    let json_value = from_str("12").unwrap();
-    assert!(json_value.is_u64());
-
-    let json_value = from_str("-12").unwrap();
-    assert!(!json_value.is_u64());
-
-    let json_value = from_str("12.0").unwrap();
-    assert!(!json_value.is_u64());
-}
-
-#[test]
-fn test_is_f64() {
-    let json_value = from_str("12").unwrap();
-    assert!(!json_value.is_f64());
-
-    let json_value = from_str("-12").unwrap();
-    assert!(!json_value.is_f64());
-
-    let json_value = from_str("12.0").unwrap();
-    assert!(json_value.is_f64());
-
-    let json_value = from_str("-12.0").unwrap();
-    assert!(json_value.is_f64());
-}
-
-#[test]
-fn test_as_i64() {
-    let json_value = from_str("-12").unwrap();
-    let json_num = json_value.as_i64();
-    assert_eq!(json_num, Some(-12));
-}
-
-#[test]
-fn test_as_u64() {
-    let json_value = from_str("12").unwrap();
-    let json_num = json_value.as_u64();
-    assert_eq!(json_num, Some(12));
-}
-
-#[test]
-fn test_as_f64() {
-    let json_value = from_str("12.0").unwrap();
-    let json_num = json_value.as_f64();
-    assert_eq!(json_num, Some(12f64));
-}
-
-#[test]
-fn test_is_boolean() {
-    let json_value = from_str("false").unwrap();
-    assert!(json_value.is_boolean());
-}
-
-#[test]
-fn test_as_boolean() {
-    let json_value = from_str("false").unwrap();
-    let json_bool = json_value.as_boolean();
-    let expected_bool = false;
-    assert!(json_bool.is_some() && json_bool.unwrap() == expected_bool);
-}
-
-#[test]
-fn test_is_null() {
-    let json_value = from_str("null").unwrap();
-    assert!(json_value.is_null());
-}
-
-#[test]
-fn test_as_null() {
-    let json_value = from_str("null").unwrap();
-    let json_null = json_value.as_null();
-    let expected_null = ();
-    assert!(json_null.is_some() && json_null.unwrap() == expected_null);
-}
-
-#[test]
-fn test_encode_hashmap_with_numeric_key() {
-    use std::collections::HashMap;
-    use std::str::from_utf8;
-    let mut hm: HashMap<usize, bool> = HashMap::new();
-    hm.insert(1, true);
-    let mut mem_buf = Vec::new();
-    write!(&mut mem_buf, "{}", json::as_pretty_json(&hm)).unwrap();
-    let json_str = from_utf8(&mem_buf[..]).unwrap();
-    match from_str(json_str) {
-        Err(_) => panic!("Unable to parse json_str: {:?}", json_str),
-        _ => {} // it parsed and we are good to go
-    }
-}
-
-#[test]
-fn test_prettyencode_hashmap_with_numeric_key() {
-    use std::collections::HashMap;
-    use std::str::from_utf8;
-    let mut hm: HashMap<usize, bool> = HashMap::new();
-    hm.insert(1, true);
-    let mut mem_buf = Vec::new();
-    write!(&mut mem_buf, "{}", json::as_pretty_json(&hm)).unwrap();
-    let json_str = from_utf8(&mem_buf[..]).unwrap();
-    match from_str(json_str) {
-        Err(_) => panic!("Unable to parse json_str: {:?}", json_str),
-        _ => {} // it parsed and we are good to go
-    }
-}
-
-#[test]
-fn test_prettyencoder_indent_level_param() {
-    use std::collections::BTreeMap;
-    use std::str::from_utf8;
-
-    let mut tree = BTreeMap::new();
-
-    tree.insert("hello".to_string(), String("guten tag".to_string()));
-    tree.insert("goodbye".to_string(), String("sayonara".to_string()));
-
-    let json = Array(
-        // The following layout below should look a lot like
-        // the pretty-printed JSON (indent * x)
-        vec![
-            // 0x
-            String("greetings".to_string()), // 1x
-            Object(tree),                    // 1x + 2x + 2x + 1x
-        ], // 0x
-           // End JSON array (7 lines)
-    );
-
-    // Helper function for counting indents
-    fn indents(source: &str) -> usize {
-        let trimmed = source.trim_start_matches(' ');
-        source.len() - trimmed.len()
-    }
-
-    // Test up to 4 spaces of indents (more?)
-    for i in 0..4 {
-        let mut writer = Vec::new();
-        write!(&mut writer, "{}", json::as_pretty_json(&json).indent(i)).unwrap();
-
-        let printed = from_utf8(&writer[..]).unwrap();
-
-        // Check for indents at each line
-        let lines: Vec<&str> = printed.lines().collect();
-        assert_eq!(lines.len(), 7); // JSON should be 7 lines
-
-        assert_eq!(indents(lines[0]), 0 * i); // [
-        assert_eq!(indents(lines[1]), 1 * i); //   "greetings",
-        assert_eq!(indents(lines[2]), 1 * i); //   {
-        assert_eq!(indents(lines[3]), 2 * i); //     "hello": "guten tag",
-        assert_eq!(indents(lines[4]), 2 * i); //     "goodbye": "sayonara"
-        assert_eq!(indents(lines[5]), 1 * i); //   },
-        assert_eq!(indents(lines[6]), 0 * i); // ]
-
-        // Finally, test that the pretty-printed JSON is valid
-        from_str(printed).ok().expect("Pretty-printed JSON is invalid!");
-    }
-}
-
-#[test]
-fn test_hashmap_with_enum_key() {
-    use std::collections::HashMap;
-    #[derive(Encodable, Eq, Hash, PartialEq, Debug)]
-    enum Enum {
-        Foo,
-        #[allow(dead_code)]
-        Bar,
-    }
-    let mut map = HashMap::new();
-    map.insert(Enum::Foo, 0);
-    let result = json::encode(&map).unwrap();
-    assert_eq!(&result[..], r#"{"Foo":0}"#);
-}
-
-fn assert_stream_equal(src: &str, expected: Vec<(JsonEvent, Vec<StackElement<'_>>)>) {
-    let mut parser = Parser::new(src.chars());
-    let mut i = 0;
-    loop {
-        let evt = match parser.next() {
-            Some(e) => e,
-            None => {
-                break;
-            }
-        };
-        let (ref expected_evt, ref expected_stack) = expected[i];
-        if !parser.stack().is_equal_to(expected_stack) {
-            panic!("Parser stack is not equal to {:?}", expected_stack);
-        }
-        assert_eq!(&evt, expected_evt);
-        i += 1;
-    }
-}
-#[test]
-fn test_streaming_parser() {
-    assert_stream_equal(
-        r#"{ "foo":"bar", "array" : [0, 1, 2, 3, 4, 5], "idents":[null,true,false]}"#,
-        vec![
-            (ObjectStart, vec![]),
-            (StringValue("bar".to_string()), vec![StackElement::Key("foo")]),
-            (ArrayStart, vec![StackElement::Key("array")]),
-            (U64Value(0), vec![StackElement::Key("array"), StackElement::Index(0)]),
-            (U64Value(1), vec![StackElement::Key("array"), StackElement::Index(1)]),
-            (U64Value(2), vec![StackElement::Key("array"), StackElement::Index(2)]),
-            (U64Value(3), vec![StackElement::Key("array"), StackElement::Index(3)]),
-            (U64Value(4), vec![StackElement::Key("array"), StackElement::Index(4)]),
-            (U64Value(5), vec![StackElement::Key("array"), StackElement::Index(5)]),
-            (ArrayEnd, vec![StackElement::Key("array")]),
-            (ArrayStart, vec![StackElement::Key("idents")]),
-            (NullValue, vec![StackElement::Key("idents"), StackElement::Index(0)]),
-            (BooleanValue(true), vec![StackElement::Key("idents"), StackElement::Index(1)]),
-            (BooleanValue(false), vec![StackElement::Key("idents"), StackElement::Index(2)]),
-            (ArrayEnd, vec![StackElement::Key("idents")]),
-            (ObjectEnd, vec![]),
-        ],
-    );
-}
-fn last_event(src: &str) -> JsonEvent {
-    let mut parser = Parser::new(src.chars());
-    let mut evt = NullValue;
-    loop {
-        evt = match parser.next() {
-            Some(e) => e,
-            None => return evt,
-        }
-    }
-}
-
-#[test]
-fn test_read_object_streaming() {
-    assert_eq!(last_event("{ "), Error(SyntaxError(EOFWhileParsingObject, 1, 3)));
-    assert_eq!(last_event("{1"), Error(SyntaxError(KeyMustBeAString, 1, 2)));
-    assert_eq!(last_event("{ \"a\""), Error(SyntaxError(EOFWhileParsingObject, 1, 6)));
-    assert_eq!(last_event("{\"a\""), Error(SyntaxError(EOFWhileParsingObject, 1, 5)));
-    assert_eq!(last_event("{\"a\" "), Error(SyntaxError(EOFWhileParsingObject, 1, 6)));
-
-    assert_eq!(last_event("{\"a\" 1"), Error(SyntaxError(ExpectedColon, 1, 6)));
-    assert_eq!(last_event("{\"a\":"), Error(SyntaxError(EOFWhileParsingValue, 1, 6)));
-    assert_eq!(last_event("{\"a\":1"), Error(SyntaxError(EOFWhileParsingObject, 1, 7)));
-    assert_eq!(last_event("{\"a\":1 1"), Error(SyntaxError(InvalidSyntax, 1, 8)));
-    assert_eq!(last_event("{\"a\":1,"), Error(SyntaxError(EOFWhileParsingObject, 1, 8)));
-    assert_eq!(last_event("{\"a\":1,}"), Error(SyntaxError(TrailingComma, 1, 8)));
-
-    assert_stream_equal("{}", vec![(ObjectStart, vec![]), (ObjectEnd, vec![])]);
-    assert_stream_equal(
-        "{\"a\": 3}",
-        vec![
-            (ObjectStart, vec![]),
-            (U64Value(3), vec![StackElement::Key("a")]),
-            (ObjectEnd, vec![]),
-        ],
-    );
-    assert_stream_equal(
-        "{ \"a\": null, \"b\" : true }",
-        vec![
-            (ObjectStart, vec![]),
-            (NullValue, vec![StackElement::Key("a")]),
-            (BooleanValue(true), vec![StackElement::Key("b")]),
-            (ObjectEnd, vec![]),
-        ],
-    );
-    assert_stream_equal(
-        "{\"a\" : 1.0 ,\"b\": [ true ]}",
-        vec![
-            (ObjectStart, vec![]),
-            (F64Value(1.0), vec![StackElement::Key("a")]),
-            (ArrayStart, vec![StackElement::Key("b")]),
-            (BooleanValue(true), vec![StackElement::Key("b"), StackElement::Index(0)]),
-            (ArrayEnd, vec![StackElement::Key("b")]),
-            (ObjectEnd, vec![]),
-        ],
-    );
-    assert_stream_equal(
-        r#"{
-            "a": 1.0,
-            "b": [
-                true,
-                "foo\nbar",
-                { "c": {"d": null} }
-            ]
-        }"#,
-        vec![
-            (ObjectStart, vec![]),
-            (F64Value(1.0), vec![StackElement::Key("a")]),
-            (ArrayStart, vec![StackElement::Key("b")]),
-            (BooleanValue(true), vec![StackElement::Key("b"), StackElement::Index(0)]),
-            (
-                StringValue("foo\nbar".to_string()),
-                vec![StackElement::Key("b"), StackElement::Index(1)],
-            ),
-            (ObjectStart, vec![StackElement::Key("b"), StackElement::Index(2)]),
-            (
-                ObjectStart,
-                vec![StackElement::Key("b"), StackElement::Index(2), StackElement::Key("c")],
-            ),
-            (
-                NullValue,
-                vec![
-                    StackElement::Key("b"),
-                    StackElement::Index(2),
-                    StackElement::Key("c"),
-                    StackElement::Key("d"),
-                ],
-            ),
-            (
-                ObjectEnd,
-                vec![StackElement::Key("b"), StackElement::Index(2), StackElement::Key("c")],
-            ),
-            (ObjectEnd, vec![StackElement::Key("b"), StackElement::Index(2)]),
-            (ArrayEnd, vec![StackElement::Key("b")]),
-            (ObjectEnd, vec![]),
-        ],
-    );
-}
-#[test]
-fn test_read_array_streaming() {
-    assert_stream_equal("[]", vec![(ArrayStart, vec![]), (ArrayEnd, vec![])]);
-    assert_stream_equal("[ ]", vec![(ArrayStart, vec![]), (ArrayEnd, vec![])]);
-    assert_stream_equal(
-        "[true]",
-        vec![
-            (ArrayStart, vec![]),
-            (BooleanValue(true), vec![StackElement::Index(0)]),
-            (ArrayEnd, vec![]),
-        ],
-    );
-    assert_stream_equal(
-        "[ false ]",
-        vec![
-            (ArrayStart, vec![]),
-            (BooleanValue(false), vec![StackElement::Index(0)]),
-            (ArrayEnd, vec![]),
-        ],
-    );
-    assert_stream_equal(
-        "[null]",
-        vec![(ArrayStart, vec![]), (NullValue, vec![StackElement::Index(0)]), (ArrayEnd, vec![])],
-    );
-    assert_stream_equal(
-        "[3, 1]",
-        vec![
-            (ArrayStart, vec![]),
-            (U64Value(3), vec![StackElement::Index(0)]),
-            (U64Value(1), vec![StackElement::Index(1)]),
-            (ArrayEnd, vec![]),
-        ],
-    );
-    assert_stream_equal(
-        "\n[3, 2]\n",
-        vec![
-            (ArrayStart, vec![]),
-            (U64Value(3), vec![StackElement::Index(0)]),
-            (U64Value(2), vec![StackElement::Index(1)]),
-            (ArrayEnd, vec![]),
-        ],
-    );
-    assert_stream_equal(
-        "[2, [4, 1]]",
-        vec![
-            (ArrayStart, vec![]),
-            (U64Value(2), vec![StackElement::Index(0)]),
-            (ArrayStart, vec![StackElement::Index(1)]),
-            (U64Value(4), vec![StackElement::Index(1), StackElement::Index(0)]),
-            (U64Value(1), vec![StackElement::Index(1), StackElement::Index(1)]),
-            (ArrayEnd, vec![StackElement::Index(1)]),
-            (ArrayEnd, vec![]),
-        ],
-    );
-
-    assert_eq!(last_event("["), Error(SyntaxError(EOFWhileParsingValue, 1, 2)));
-
-    assert_eq!(from_str("["), Err(SyntaxError(EOFWhileParsingValue, 1, 2)));
-    assert_eq!(from_str("[1"), Err(SyntaxError(EOFWhileParsingArray, 1, 3)));
-    assert_eq!(from_str("[1,"), Err(SyntaxError(EOFWhileParsingValue, 1, 4)));
-    assert_eq!(from_str("[1,]"), Err(SyntaxError(InvalidSyntax, 1, 4)));
-    assert_eq!(from_str("[6 7]"), Err(SyntaxError(InvalidSyntax, 1, 4)));
-}
-#[test]
-fn test_trailing_characters_streaming() {
-    assert_eq!(last_event("nulla"), Error(SyntaxError(TrailingCharacters, 1, 5)));
-    assert_eq!(last_event("truea"), Error(SyntaxError(TrailingCharacters, 1, 5)));
-    assert_eq!(last_event("falsea"), Error(SyntaxError(TrailingCharacters, 1, 6)));
-    assert_eq!(last_event("1a"), Error(SyntaxError(TrailingCharacters, 1, 2)));
-    assert_eq!(last_event("[]a"), Error(SyntaxError(TrailingCharacters, 1, 3)));
-    assert_eq!(last_event("{}a"), Error(SyntaxError(TrailingCharacters, 1, 3)));
-}
-#[test]
-fn test_read_identifiers_streaming() {
-    assert_eq!(Parser::new("null".chars()).next(), Some(NullValue));
-    assert_eq!(Parser::new("true".chars()).next(), Some(BooleanValue(true)));
-    assert_eq!(Parser::new("false".chars()).next(), Some(BooleanValue(false)));
-
-    assert_eq!(last_event("n"), Error(SyntaxError(InvalidSyntax, 1, 2)));
-    assert_eq!(last_event("nul"), Error(SyntaxError(InvalidSyntax, 1, 4)));
-    assert_eq!(last_event("t"), Error(SyntaxError(InvalidSyntax, 1, 2)));
-    assert_eq!(last_event("truz"), Error(SyntaxError(InvalidSyntax, 1, 4)));
-    assert_eq!(last_event("f"), Error(SyntaxError(InvalidSyntax, 1, 2)));
-    assert_eq!(last_event("faz"), Error(SyntaxError(InvalidSyntax, 1, 3)));
-}
-
-#[test]
-fn test_to_json() {
-    use json::ToJson;
-    use std::collections::{BTreeMap, HashMap};
-
-    let array2 = Array(vec![U64(1), U64(2)]);
-    let array3 = Array(vec![U64(1), U64(2), U64(3)]);
-    let object = {
-        let mut tree_map = BTreeMap::new();
-        tree_map.insert("a".to_string(), U64(1));
-        tree_map.insert("b".to_string(), U64(2));
-        Object(tree_map)
-    };
-
-    assert_eq!(array2.to_json(), array2);
-    assert_eq!(object.to_json(), object);
-    assert_eq!(3_isize.to_json(), I64(3));
-    assert_eq!(4_i8.to_json(), I64(4));
-    assert_eq!(5_i16.to_json(), I64(5));
-    assert_eq!(6_i32.to_json(), I64(6));
-    assert_eq!(7_i64.to_json(), I64(7));
-    assert_eq!(8_usize.to_json(), U64(8));
-    assert_eq!(9_u8.to_json(), U64(9));
-    assert_eq!(10_u16.to_json(), U64(10));
-    assert_eq!(11_u32.to_json(), U64(11));
-    assert_eq!(12_u64.to_json(), U64(12));
-    assert_eq!(13.0_f32.to_json(), F64(13.0_f64));
-    assert_eq!(14.0_f64.to_json(), F64(14.0_f64));
-    assert_eq!(().to_json(), Null);
-    assert_eq!(f32::INFINITY.to_json(), Null);
-    assert_eq!(f64::NAN.to_json(), Null);
-    assert_eq!(true.to_json(), Boolean(true));
-    assert_eq!(false.to_json(), Boolean(false));
-    assert_eq!("abc".to_json(), String("abc".to_string()));
-    assert_eq!("abc".to_string().to_json(), String("abc".to_string()));
-    assert_eq!((1_usize, 2_usize).to_json(), array2);
-    assert_eq!((1_usize, 2_usize, 3_usize).to_json(), array3);
-    assert_eq!([1_usize, 2_usize].to_json(), array2);
-    assert_eq!((&[1_usize, 2_usize, 3_usize]).to_json(), array3);
-    assert_eq!((vec![1_usize, 2_usize]).to_json(), array2);
-    assert_eq!(vec![1_usize, 2_usize, 3_usize].to_json(), array3);
-    let mut tree_map = BTreeMap::new();
-    tree_map.insert("a".to_string(), 1 as usize);
-    tree_map.insert("b".to_string(), 2);
-    assert_eq!(tree_map.to_json(), object);
-    let mut hash_map = HashMap::new();
-    hash_map.insert("a".to_string(), 1 as usize);
-    hash_map.insert("b".to_string(), 2);
-    assert_eq!(hash_map.to_json(), object);
-    assert_eq!(Some(15).to_json(), I64(15));
-    assert_eq!(Some(15 as usize).to_json(), U64(15));
-    assert_eq!(None::<isize>.to_json(), Null);
-}
-
-#[test]
-fn test_encode_hashmap_with_arbitrary_key() {
-    use std::collections::HashMap;
-    #[derive(PartialEq, Eq, Hash, Encodable)]
-    struct ArbitraryType(usize);
-    let mut hm: HashMap<ArbitraryType, bool> = HashMap::new();
-    hm.insert(ArbitraryType(1), true);
-    let mut mem_buf = string::String::new();
-    let mut encoder = Encoder::new(&mut mem_buf);
-    let result = hm.encode(&mut encoder);
-    match result.unwrap_err() {
-        EncoderError::BadHashmapKey => (),
-        _ => panic!("expected bad hash map key"),
-    }
-}
index 66198dff2ae3df518f64c290f6a16e368905035f..ae32fd2dee9220e0e6c0615432d8cd152f3604b9 100644 (file)
@@ -1207,10 +1207,6 @@ pub(crate) fn parse_branch_protection(
     assert_incr_state: Option<String> = (None, parse_opt_string, [UNTRACKED],
         "assert that the incremental cache is in given state: \
          either `loaded` or `not-loaded`."),
-    ast_json: bool = (false, parse_bool, [UNTRACKED],
-        "print the AST as JSON and halt (default: no)"),
-    ast_json_noexpand: bool = (false, parse_bool, [UNTRACKED],
-        "print the pre-expansion AST as JSON and halt (default: no)"),
     binary_dep_depinfo: bool = (false, parse_bool, [TRACKED],
         "include artifacts (sysroot, crate dependencies) used during compilation in dep-info \
         (default: no)"),
index 3976c0622218762721f6ae350816929eb5b3dbf4..2bd0880a7c4254fa036f728a39260aae8049e718 100644 (file)
@@ -307,11 +307,8 @@ pub fn is_top_level_module(self) -> bool {
 
 impl<E: Encoder> Encodable<E> for DefId {
     default fn encode(&self, s: &mut E) -> Result<(), E::Error> {
-        s.emit_struct(false, |s| {
-            s.emit_struct_field("krate", true, |s| self.krate.encode(s))?;
-
-            s.emit_struct_field("index", false, |s| self.index.encode(s))
-        })
+        self.krate.encode(s)?;
+        self.index.encode(s)
     }
 }
 
index adf5a744048083b62558190ec46b4668aeb6b554..01fe9aea89bc2084ff274a7d359c13bd042fa586 100644 (file)
@@ -196,24 +196,23 @@ fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
 // an added assert statement
 impl<S: Encoder> Encodable<S> for RealFileName {
     fn encode(&self, encoder: &mut S) -> Result<(), S::Error> {
-        encoder.emit_enum(|encoder| match *self {
-            RealFileName::LocalPath(ref local_path) => {
-                encoder.emit_enum_variant("LocalPath", 0, 1, |encoder| {
-                    encoder.emit_enum_variant_arg(true, |encoder| local_path.encode(encoder))?;
-                    Ok(())
+        match *self {
+            RealFileName::LocalPath(ref local_path) => encoder.emit_enum_variant(0, |encoder| {
+                Ok({
+                    local_path.encode(encoder)?;
                 })
-            }
+            }),
 
             RealFileName::Remapped { ref local_path, ref virtual_name } => encoder
-                .emit_enum_variant("Remapped", 1, 2, |encoder| {
+                .emit_enum_variant(1, |encoder| {
                     // For privacy and build reproducibility, we must not embed host-dependant path in artifacts
                     // if they have been remapped by --remap-path-prefix
                     assert!(local_path.is_none());
-                    encoder.emit_enum_variant_arg(true, |encoder| local_path.encode(encoder))?;
-                    encoder.emit_enum_variant_arg(false, |encoder| virtual_name.encode(encoder))?;
+                    local_path.encode(encoder)?;
+                    virtual_name.encode(encoder)?;
                     Ok(())
                 }),
-        })
+        }
     }
 }
 
@@ -950,10 +949,8 @@ fn default() -> Self {
 impl<E: Encoder> Encodable<E> for Span {
     default fn encode(&self, s: &mut E) -> Result<(), E::Error> {
         let span = self.data();
-        s.emit_struct(false, |s| {
-            s.emit_struct_field("lo", true, |s| span.lo.encode(s))?;
-            s.emit_struct_field("hi", false, |s| span.hi.encode(s))
-        })
+        span.lo.encode(s)?;
+        span.hi.encode(s)
     }
 }
 impl<D: Decoder> Decodable<D> for Span {
@@ -1222,6 +1219,52 @@ pub fn new(src: Arc<[u8]>, visualizer_type: DebuggerVisualizerType) -> Self {
     }
 }
 
+#[derive(Clone)]
+pub enum SourceFileLines {
+    /// The source file lines, in decoded (random-access) form.
+    Lines(Vec<BytePos>),
+
+    /// The source file lines, in undecoded difference list form.
+    Diffs(SourceFileDiffs),
+}
+
+impl SourceFileLines {
+    pub fn is_lines(&self) -> bool {
+        matches!(self, SourceFileLines::Lines(_))
+    }
+}
+
+/// The source file lines in difference list form. This matches the form
+/// used within metadata, which saves space by exploiting the fact that the
+/// lines list is sorted and individual lines are usually not that long.
+///
+/// We read it directly from metadata and only decode it into `Lines` form
+/// when necessary. This is a significant performance win, especially for
+/// small crates where very little of `std`'s metadata is used.
+#[derive(Clone)]
+pub struct SourceFileDiffs {
+    /// Position of the first line. Note that this is always encoded as a
+    /// `BytePos` because it is often much larger than any of the
+    /// differences.
+    line_start: BytePos,
+
+    /// Always 1, 2, or 4. Always as small as possible, while being big
+    /// enough to hold the length of the longest line in the source file.
+    /// The 1 case is by far the most common.
+    bytes_per_diff: usize,
+
+    /// The number of diffs encoded in `raw_diffs`. Always one less than
+    /// the number of lines in the source file.
+    num_diffs: usize,
+
+    /// The diffs in "raw" form. Each segment of `bytes_per_diff` length
+    /// encodes one little-endian diff. Note that they aren't LEB128
+    /// encoded. This makes for much faster decoding. Besides, the
+    /// bytes_per_diff==1 case is by far the most common, and LEB128
+    /// encoding has no effect on that case.
+    raw_diffs: Vec<u8>,
+}
+
 /// A single source in the [`SourceMap`].
 #[derive(Clone)]
 pub struct SourceFile {
@@ -1241,7 +1284,7 @@ pub struct SourceFile {
     /// The end position of this source in the `SourceMap`.
     pub end_pos: BytePos,
     /// Locations of lines beginnings in the source code.
-    pub lines: Vec<BytePos>,
+    pub lines: Lock<SourceFileLines>,
     /// Locations of multi-byte characters in the source code.
     pub multibyte_chars: Vec<MultiByteChar>,
     /// Width of characters that are not narrow in the source code.
@@ -1256,77 +1299,77 @@ pub struct SourceFile {
 
 impl<S: Encoder> Encodable<S> for SourceFile {
     fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_struct(false, |s| {
-            s.emit_struct_field("name", true, |s| self.name.encode(s))?;
-            s.emit_struct_field("src_hash", false, |s| self.src_hash.encode(s))?;
-            s.emit_struct_field("start_pos", false, |s| self.start_pos.encode(s))?;
-            s.emit_struct_field("end_pos", false, |s| self.end_pos.encode(s))?;
-            s.emit_struct_field("lines", false, |s| {
-                let lines = &self.lines[..];
-                // Store the length.
-                s.emit_u32(lines.len() as u32)?;
-
-                if !lines.is_empty() {
-                    // In order to preserve some space, we exploit the fact that
-                    // the lines list is sorted and individual lines are
-                    // probably not that long. Because of that we can store lines
-                    // as a difference list, using as little space as possible
-                    // for the differences. But note that the first line is
-                    // always encoded as a `BytePos` because its position is
-                    // often much larger than any of the differences.
-                    let max_line_length = if lines.len() == 1 {
-                        0
-                    } else {
-                        lines
-                            .array_windows()
-                            .map(|&[fst, snd]| snd - fst)
-                            .map(|bp| bp.to_usize())
-                            .max()
-                            .unwrap()
-                    };
-
-                    let bytes_per_diff: u8 = match max_line_length {
-                        0..=0xFF => 1,
-                        0x100..=0xFFFF => 2,
-                        _ => 4,
-                    };
-
-                    // Encode the number of bytes used per diff.
-                    bytes_per_diff.encode(s)?;
-
-                    // Encode the first element.
-                    lines[0].encode(s)?;
-
-                    let diff_iter = lines.array_windows().map(|&[fst, snd]| snd - fst);
-
-                    match bytes_per_diff {
-                        1 => {
-                            for diff in diff_iter {
-                                (diff.0 as u8).encode(s)?
-                            }
+        self.name.encode(s)?;
+        self.src_hash.encode(s)?;
+        self.start_pos.encode(s)?;
+        self.end_pos.encode(s)?;
+
+        // We are always in `Lines` form by the time we reach here.
+        assert!(self.lines.borrow().is_lines());
+        self.lines(|lines| {
+            // Store the length.
+            s.emit_u32(lines.len() as u32)?;
+
+            // Compute and store the difference list.
+            if lines.len() != 0 {
+                let max_line_length = if lines.len() == 1 {
+                    0
+                } else {
+                    lines
+                        .array_windows()
+                        .map(|&[fst, snd]| snd - fst)
+                        .map(|bp| bp.to_usize())
+                        .max()
+                        .unwrap()
+                };
+
+                let bytes_per_diff: usize = match max_line_length {
+                    0..=0xFF => 1,
+                    0x100..=0xFFFF => 2,
+                    _ => 4,
+                };
+
+                // Encode the number of bytes used per diff.
+                s.emit_u8(bytes_per_diff as u8)?;
+
+                // Encode the first element.
+                lines[0].encode(s)?;
+
+                // Encode the difference list.
+                let diff_iter = lines.array_windows().map(|&[fst, snd]| snd - fst);
+                let num_diffs = lines.len() - 1;
+                let mut raw_diffs;
+                match bytes_per_diff {
+                    1 => {
+                        raw_diffs = Vec::with_capacity(num_diffs);
+                        for diff in diff_iter {
+                            raw_diffs.push(diff.0 as u8);
                         }
-                        2 => {
-                            for diff in diff_iter {
-                                (diff.0 as u16).encode(s)?
-                            }
+                    }
+                    2 => {
+                        raw_diffs = Vec::with_capacity(bytes_per_diff * num_diffs);
+                        for diff in diff_iter {
+                            raw_diffs.extend_from_slice(&(diff.0 as u16).to_le_bytes());
                         }
-                        4 => {
-                            for diff in diff_iter {
-                                diff.0.encode(s)?
-                            }
+                    }
+                    4 => {
+                        raw_diffs = Vec::with_capacity(bytes_per_diff * num_diffs);
+                        for diff in diff_iter {
+                            raw_diffs.extend_from_slice(&(diff.0 as u32).to_le_bytes());
                         }
-                        _ => unreachable!(),
                     }
+                    _ => unreachable!(),
                 }
+                s.emit_raw_bytes(&raw_diffs)?;
+            }
+            Ok(())
+        })?;
 
-                Ok(())
-            })?;
-            s.emit_struct_field("multibyte_chars", false, |s| self.multibyte_chars.encode(s))?;
-            s.emit_struct_field("non_narrow_chars", false, |s| self.non_narrow_chars.encode(s))?;
-            s.emit_struct_field("name_hash", false, |s| self.name_hash.encode(s))?;
-            s.emit_struct_field("normalized_pos", false, |s| self.normalized_pos.encode(s))?;
-            s.emit_struct_field("cnum", false, |s| self.cnum.encode(s))
-        })
+        self.multibyte_chars.encode(s)?;
+        self.non_narrow_chars.encode(s)?;
+        self.name_hash.encode(s)?;
+        self.normalized_pos.encode(s)?;
+        self.cnum.encode(s)
     }
 }
 
@@ -1336,36 +1379,27 @@ fn decode(d: &mut D) -> SourceFile {
         let src_hash: SourceFileHash = Decodable::decode(d);
         let start_pos: BytePos = Decodable::decode(d);
         let end_pos: BytePos = Decodable::decode(d);
-        let lines: Vec<BytePos> = {
+        let lines = {
             let num_lines: u32 = Decodable::decode(d);
-            let mut lines = Vec::with_capacity(num_lines as usize);
-
             if num_lines > 0 {
                 // Read the number of bytes used per diff.
-                let bytes_per_diff: u8 = Decodable::decode(d);
+                let bytes_per_diff = d.read_u8() as usize;
 
                 // Read the first element.
-                let mut line_start: BytePos = Decodable::decode(d);
-                lines.push(line_start);
-
-                match bytes_per_diff {
-                    1 => lines.extend((1..num_lines).map(|_| {
-                        line_start = line_start + BytePos(d.read_u8() as u32);
-                        line_start
-                    })),
-                    2 => lines.extend((1..num_lines).map(|_| {
-                        line_start = line_start + BytePos(d.read_u16() as u32);
-                        line_start
-                    })),
-                    4 => lines.extend((1..num_lines).map(|_| {
-                        line_start = line_start + BytePos(d.read_u32());
-                        line_start
-                    })),
-                    _ => unreachable!(),
-                }
+                let line_start: BytePos = Decodable::decode(d);
+
+                // Read the difference list.
+                let num_diffs = num_lines as usize - 1;
+                let raw_diffs = d.read_raw_bytes(bytes_per_diff * num_diffs).to_vec();
+                SourceFileLines::Diffs(SourceFileDiffs {
+                    line_start,
+                    bytes_per_diff,
+                    num_diffs,
+                    raw_diffs,
+                })
+            } else {
+                SourceFileLines::Lines(vec![])
             }
-
-            lines
         };
         let multibyte_chars: Vec<MultiByteChar> = Decodable::decode(d);
         let non_narrow_chars: Vec<NonNarrowChar> = Decodable::decode(d);
@@ -1381,7 +1415,7 @@ fn decode(d: &mut D) -> SourceFile {
             // Unused - the metadata decoder will construct
             // a new SourceFile, filling in `external_src` properly
             external_src: Lock::new(ExternalSource::Unneeded),
-            lines,
+            lines: Lock::new(lines),
             multibyte_chars,
             non_narrow_chars,
             normalized_pos,
@@ -1426,7 +1460,7 @@ pub fn new(
             external_src: Lock::new(ExternalSource::Unneeded),
             start_pos,
             end_pos: Pos::from_usize(end_pos),
-            lines,
+            lines: Lock::new(SourceFileLines::Lines(lines)),
             multibyte_chars,
             non_narrow_chars,
             normalized_pos,
@@ -1435,10 +1469,68 @@ pub fn new(
         }
     }
 
+    pub fn lines<F, R>(&self, f: F) -> R
+    where
+        F: FnOnce(&[BytePos]) -> R,
+    {
+        let mut guard = self.lines.borrow_mut();
+        match &*guard {
+            SourceFileLines::Lines(lines) => f(lines),
+            SourceFileLines::Diffs(SourceFileDiffs {
+                mut line_start,
+                bytes_per_diff,
+                num_diffs,
+                raw_diffs,
+            }) => {
+                // Convert from "diffs" form to "lines" form.
+                let num_lines = num_diffs + 1;
+                let mut lines = Vec::with_capacity(num_lines);
+                lines.push(line_start);
+
+                assert_eq!(*num_diffs, raw_diffs.len() / bytes_per_diff);
+                match bytes_per_diff {
+                    1 => {
+                        lines.extend(raw_diffs.into_iter().map(|&diff| {
+                            line_start = line_start + BytePos(diff as u32);
+                            line_start
+                        }));
+                    }
+                    2 => {
+                        lines.extend((0..*num_diffs).map(|i| {
+                            let pos = bytes_per_diff * i;
+                            let bytes = [raw_diffs[pos], raw_diffs[pos + 1]];
+                            let diff = u16::from_le_bytes(bytes);
+                            line_start = line_start + BytePos(diff as u32);
+                            line_start
+                        }));
+                    }
+                    4 => {
+                        lines.extend((0..*num_diffs).map(|i| {
+                            let pos = bytes_per_diff * i;
+                            let bytes = [
+                                raw_diffs[pos],
+                                raw_diffs[pos + 1],
+                                raw_diffs[pos + 2],
+                                raw_diffs[pos + 3],
+                            ];
+                            let diff = u32::from_le_bytes(bytes);
+                            line_start = line_start + BytePos(diff);
+                            line_start
+                        }));
+                    }
+                    _ => unreachable!(),
+                }
+                let res = f(&lines);
+                *guard = SourceFileLines::Lines(lines);
+                res
+            }
+        }
+    }
+
     /// Returns the `BytePos` of the beginning of the current line.
     pub fn line_begin_pos(&self, pos: BytePos) -> BytePos {
         let line_index = self.lookup_line(pos).unwrap();
-        self.lines[line_index]
+        self.lines(|lines| lines[line_index])
     }
 
     /// Add externally loaded source.
@@ -1495,8 +1587,8 @@ fn get_until_newline(src: &str, begin: usize) -> &str {
         }
 
         let begin = {
-            let line = self.lines.get(line_number)?;
-            let begin: BytePos = *line - self.start_pos;
+            let line = self.lines(|lines| lines.get(line_number).copied())?;
+            let begin: BytePos = line - self.start_pos;
             begin.to_usize()
         };
 
@@ -1518,7 +1610,7 @@ pub fn is_imported(&self) -> bool {
     }
 
     pub fn count_lines(&self) -> usize {
-        self.lines.len()
+        self.lines(|lines| lines.len())
     }
 
     /// Finds the line containing the given position. The return value is the
@@ -1526,11 +1618,11 @@ pub fn count_lines(&self) -> usize {
     /// number. If the source_file is empty or the position is located before the
     /// first line, `None` is returned.
     pub fn lookup_line(&self, pos: BytePos) -> Option<usize> {
-        match self.lines.binary_search(&pos) {
+        self.lines(|lines| match lines.binary_search(&pos) {
             Ok(idx) => Some(idx),
             Err(0) => None,
             Err(idx) => Some(idx - 1),
-        }
+        })
     }
 
     pub fn line_bounds(&self, line_index: usize) -> Range<BytePos> {
@@ -1538,12 +1630,14 @@ pub fn line_bounds(&self, line_index: usize) -> Range<BytePos> {
             return self.start_pos..self.end_pos;
         }
 
-        assert!(line_index < self.lines.len());
-        if line_index == (self.lines.len() - 1) {
-            self.lines[line_index]..self.end_pos
-        } else {
-            self.lines[line_index]..self.lines[line_index + 1]
-        }
+        self.lines(|lines| {
+            assert!(line_index < lines.len());
+            if line_index == (lines.len() - 1) {
+                lines[line_index]..self.end_pos
+            } else {
+                lines[line_index]..lines[line_index + 1]
+            }
+        })
     }
 
     /// Returns whether or not the file contains the given `SourceMap` byte
@@ -1605,7 +1699,7 @@ pub fn lookup_file_pos(&self, pos: BytePos) -> (usize, CharPos) {
         match self.lookup_line(pos) {
             Some(a) => {
                 let line = a + 1; // Line numbers start at 1
-                let linebpos = self.lines[a];
+                let linebpos = self.lines(|lines| lines[a]);
                 let linechpos = self.bytepos_to_file_charpos(linebpos);
                 let col = chpos - linechpos;
                 debug!("byte pos {:?} is on the line at byte pos {:?}", pos, linebpos);
@@ -1624,7 +1718,7 @@ pub fn lookup_file_pos_with_col_display(&self, pos: BytePos) -> (usize, CharPos,
         let (line, col_or_chpos) = self.lookup_file_pos(pos);
         if line > 0 {
             let col = col_or_chpos;
-            let linebpos = self.lines[line - 1];
+            let linebpos = self.lines(|lines| lines[line - 1]);
             let col_display = {
                 let start_width_idx = self
                     .non_narrow_chars
index d60b4d3d021e840de82b8d61dbaaace52426511d..95ea7029617014715e25efe520be80e6ae7aa9fc 100644 (file)
@@ -331,7 +331,7 @@ pub fn new_imported_source_file(
         name_hash: u128,
         source_len: usize,
         cnum: CrateNum,
-        mut file_local_lines: Vec<BytePos>,
+        file_local_lines: Lock<SourceFileLines>,
         mut file_local_multibyte_chars: Vec<MultiByteChar>,
         mut file_local_non_narrow_chars: Vec<NonNarrowChar>,
         mut file_local_normalized_pos: Vec<NormalizedPos>,
@@ -355,8 +355,15 @@ pub fn new_imported_source_file(
         // form rather than pre-computing the offset into a local variable. The
         // compiler backend can optimize away the repeated computations in a
         // way that won't trigger overflow checks.
-        for pos in &mut file_local_lines {
-            *pos = (*pos - original_start_pos) + start_pos;
+        match &mut *file_local_lines.borrow_mut() {
+            SourceFileLines::Lines(lines) => {
+                for pos in lines {
+                    *pos = (*pos - original_start_pos) + start_pos;
+                }
+            }
+            SourceFileLines::Diffs(SourceFileDiffs { line_start, .. }) => {
+                *line_start = (*line_start - original_start_pos) + start_pos;
+            }
         }
         for mbc in &mut file_local_multibyte_chars {
             mbc.pos = (mbc.pos - original_start_pos) + start_pos;
index 16162f1cc898a5284ab49b7af4772888cbb3a7c6..5f301962061d8923cb9b17ed24d5643e6c62e595 100644 (file)
         generator_state,
         generators,
         generic_arg_infer,
+        generic_assert,
         generic_associated_types,
         generic_associated_types_extended,
         generic_const_exprs,
         rustc_allow_const_fn_unstable,
         rustc_allow_incoherent_impl,
         rustc_attrs,
+        rustc_box,
         rustc_builtin_macro,
         rustc_capture_analysis,
         rustc_clean,
index 11edcacc0d43ba95917ffadae0dc14d44b3cfebd..5b3915c33387bb18689b48f31f59ff4d8353d117 100644 (file)
@@ -5,7 +5,7 @@ fn test_lookup_line() {
     let source = "abcdefghijklm\nabcdefghij\n...".to_owned();
     let sf =
         SourceFile::new(FileName::Anon(0), source, BytePos(3), SourceFileHashAlgorithm::Sha256);
-    assert_eq!(sf.lines.as_slice(), &[BytePos(3), BytePos(17), BytePos(28)]);
+    sf.lines(|lines| assert_eq!(lines, &[BytePos(3), BytePos(17), BytePos(28)]));
 
     assert_eq!(sf.lookup_line(BytePos(0)), None);
     assert_eq!(sf.lookup_line(BytePos(3)), Some(0));
index 925813e6bb42762ff5887618910312df4e15a215..162376af45f15bc8c0353dc02053c78cfd443f68 100644 (file)
@@ -6,6 +6,7 @@ edition = "2021"
 [dependencies]
 bitflags = "1.2.1"
 tracing = "0.1"
+serde_json = "1.0.59"
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_macros = { path = "../rustc_macros" }
 rustc_serialize = { path = "../rustc_serialize" }
index a771369c80789448c90f8c7cc726fd2721528382..0850e6834590300d8f4a7d19d98644e08af83c3e 100644 (file)
@@ -1,6 +1,7 @@
 pub use Integer::*;
 pub use Primitive::*;
 
+use crate::json::{Json, ToJson};
 use crate::spec::Target;
 
 use std::convert::{TryFrom, TryInto};
@@ -13,7 +14,6 @@
 use rustc_data_structures::intern::Interned;
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_macros::HashStable_Generic;
-use rustc_serialize::json::{Json, ToJson};
 
 pub mod call;
 
@@ -166,7 +166,8 @@ pub fn parse(target: &Target) -> Result<TargetDataLayout, String> {
             ));
         }
 
-        if dl.pointer_size.bits() != target.pointer_width.into() {
+        let target_pointer_width: u64 = target.pointer_width.into();
+        if dl.pointer_size.bits() != target_pointer_width {
             return Err(format!(
                 "inconsistent target specification: \"data-layout\" claims \
                  pointers are {}-bit, while \"target-pointer-width\" is `{}`",
@@ -574,7 +575,7 @@ pub fn restrict_for_offset(self, offset: Size) -> Align {
 }
 
 /// A pair of alignments, ABI-mandated and preferred.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Encodable, Decodable)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
 #[derive(HashStable_Generic)]
 pub struct AbiAndPrefAlign {
     pub abi: Align,
diff --git a/compiler/rustc_target/src/json.rs b/compiler/rustc_target/src/json.rs
new file mode 100644 (file)
index 0000000..b5d9263
--- /dev/null
@@ -0,0 +1,91 @@
+use std::borrow::Cow;
+use std::collections::BTreeMap;
+
+pub use serde_json::Value as Json;
+use serde_json::{Map, Number};
+
+pub trait ToJson {
+    fn to_json(&self) -> Json;
+}
+
+impl ToJson for Json {
+    fn to_json(&self) -> Json {
+        self.clone()
+    }
+}
+
+macro_rules! to_json_impl_num {
+    ($($t:ty), +) => (
+        $(impl ToJson for $t {
+            fn to_json(&self) -> Json {
+                Json::Number(Number::from(*self))
+            }
+        })+
+    )
+}
+
+to_json_impl_num! { isize, i8, i16, i32, i64, usize, u8, u16, u32, u64 }
+
+impl ToJson for bool {
+    fn to_json(&self) -> Json {
+        Json::Bool(*self)
+    }
+}
+
+impl ToJson for str {
+    fn to_json(&self) -> Json {
+        Json::String(self.to_owned())
+    }
+}
+
+impl ToJson for String {
+    fn to_json(&self) -> Json {
+        Json::String(self.to_owned())
+    }
+}
+
+impl<'a> ToJson for Cow<'a, str> {
+    fn to_json(&self) -> Json {
+        Json::String(self.to_string())
+    }
+}
+
+impl<A: ToJson> ToJson for [A] {
+    fn to_json(&self) -> Json {
+        Json::Array(self.iter().map(|elt| elt.to_json()).collect())
+    }
+}
+
+impl<A: ToJson> ToJson for Vec<A> {
+    fn to_json(&self) -> Json {
+        Json::Array(self.iter().map(|elt| elt.to_json()).collect())
+    }
+}
+
+impl<'a, A: ToJson> ToJson for Cow<'a, [A]>
+where
+    [A]: ToOwned,
+{
+    fn to_json(&self) -> Json {
+        Json::Array(self.iter().map(|elt| elt.to_json()).collect())
+    }
+}
+
+impl<T: ToString, A: ToJson> ToJson for BTreeMap<T, A> {
+    fn to_json(&self) -> Json {
+        let mut d = Map::new();
+        for (key, value) in self {
+            d.insert(key.to_string(), value.to_json());
+        }
+        Json::Object(d)
+    }
+}
+
+impl<A: ToJson> ToJson for Option<A> {
+    fn to_json(&self) -> Json {
+        match *self {
+            None => Json::Null,
+            Some(ref value) => value.to_json(),
+        }
+    }
+}
index 4dc6af15001ecf5279d5f0b31903d2b5c4316309..e9627e33ff17079a159f34f37e18cc90d215ea57 100644 (file)
@@ -28,6 +28,7 @@
 
 pub mod abi;
 pub mod asm;
+pub mod json;
 pub mod spec;
 
 #[cfg(test)]
index 51f392a64b11b0d79167160a63faa2bcbd6c4684..52ac3622eca8d867136b99f025eeb44e332c7265 100644 (file)
@@ -40,8 +40,8 @@
 //! but not gcc's. As a result rustc cannot link with C++ static libraries (#36710)
 //! when linking in self-contained mode.
 
+use crate::json::{Json, ToJson};
 use crate::spec::LinkOutputKind;
-use rustc_serialize::json::{Json, ToJson};
 use std::borrow::Cow;
 use std::collections::BTreeMap;
 use std::str::FromStr;
index 07d5edc0a84f9acdcf71788afd1c8015805412cc..0f5db8982e84365582108381ef5bc315f769058f 100644 (file)
 //! to the list specified by the target, rather than replace.
 
 use crate::abi::Endian;
+use crate::json::{Json, ToJson};
 use crate::spec::abi::{lookup as lookup_abi, Abi};
 use crate::spec::crt_objects::{CrtObjects, CrtObjectsFallback};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_serialize::json::{Json, ToJson};
 use rustc_span::symbol::{sym, Symbol};
+use serde_json::Value;
 use std::borrow::Cow;
 use std::collections::BTreeMap;
 use std::convert::TryFrom;
@@ -211,7 +212,7 @@ fn to_json(&self) -> Json {
     }
 }
 
-#[derive(Clone, Copy, Debug, PartialEq, Hash, Encodable, Decodable)]
+#[derive(Clone, Copy, Debug, PartialEq, Hash)]
 pub enum RelroLevel {
     Full,
     Partial,
@@ -255,7 +256,7 @@ fn to_json(&self) -> Json {
     }
 }
 
-#[derive(Clone, Copy, Debug, PartialEq, Hash, Encodable, Decodable)]
+#[derive(Clone, Copy, Debug, PartialEq, Hash)]
 pub enum MergeFunctions {
     Disabled,
     Trampolines,
@@ -548,7 +549,7 @@ fn from_json(json: &Json) -> Result<Self, String> {
         let object = json.as_object().ok_or_else(|| "expected a JSON object")?;
         let kind = object
             .get("kind")
-            .and_then(|o| o.as_string())
+            .and_then(|o| o.as_str())
             .ok_or_else(|| "expected `kind` to be a string")?;
         match kind {
             "none" => Ok(StackProbeType::None),
@@ -592,11 +593,11 @@ fn to_json(&self) -> Json {
             StackProbeType::Call => {
                 [(String::from("kind"), "call".to_json())].into_iter().collect()
             }
-            StackProbeType::InlineOrCall { min_llvm_version_for_inline } => [
+            StackProbeType::InlineOrCall { min_llvm_version_for_inline: (maj, min, patch) } => [
                 (String::from("kind"), "inline-or-call".to_json()),
                 (
                     String::from("min-llvm-version-for-inline"),
-                    min_llvm_version_for_inline.to_json(),
+                    Json::Array(vec![maj.to_json(), min.to_json(), patch.to_json()]),
                 ),
             ]
             .into_iter()
@@ -1683,7 +1684,7 @@ pub fn max_atomic_width(&self) -> u64 {
     }
 
     /// Loads a target descriptor from a JSON object.
-    pub fn from_json(mut obj: Json) -> Result<(Target, TargetWarnings), String> {
+    pub fn from_json(obj: Json) -> Result<(Target, TargetWarnings), String> {
         // While ugly, this code must remain this way to retain
         // compatibility with existing JSON fields and the internal
         // expected naming of the Target and TargetOptions structs.
@@ -1691,9 +1692,14 @@ pub fn from_json(mut obj: Json) -> Result<(Target, TargetWarnings), String> {
         // are round-tripped through this code to catch cases where
         // the JSON parser is not updated to match the structs.
 
+        let mut obj = match obj {
+            Value::Object(obj) => obj,
+            _ => return Err("Expected JSON object for target")?,
+        };
+
         let mut get_req_field = |name: &str| {
-            obj.remove_key(name)
-                .and_then(|j| Json::as_string(&j).map(str::to_string))
+            obj.remove(name)
+                .and_then(|j| j.as_str().map(str::to_string))
                 .ok_or_else(|| format!("Field {} in target specification is required", name))
         };
 
@@ -1712,31 +1718,31 @@ pub fn from_json(mut obj: Json) -> Result<(Target, TargetWarnings), String> {
         macro_rules! key {
             ($key_name:ident) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                if let Some(s) = obj.remove_key(&name).and_then(|j| Json::as_string(&j).map(str::to_string).map(Cow::from)) {
+                if let Some(s) = obj.remove(&name).and_then(|s| s.as_str().map(str::to_string).map(Cow::from)) {
                     base.$key_name = s;
                 }
             } );
             ($key_name:ident = $json_name:expr) => ( {
                 let name = $json_name;
-                if let Some(s) = obj.remove_key(&name).and_then(|j| Json::as_string(&j).map(str::to_string).map(Cow::from)) {
+                if let Some(s) = obj.remove(name).and_then(|s| s.as_str().map(str::to_string).map(Cow::from)) {
                     base.$key_name = s;
                 }
             } );
             ($key_name:ident, bool) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                if let Some(s) = obj.remove_key(&name).and_then(|j| Json::as_boolean(&j)) {
+                if let Some(s) = obj.remove(&name).and_then(|b| b.as_bool()) {
                     base.$key_name = s;
                 }
             } );
             ($key_name:ident, u64) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                if let Some(s) = obj.remove_key(&name).and_then(|j| Json::as_u64(&j)) {
+                if let Some(s) = obj.remove(&name).and_then(|j| Json::as_u64(&j)) {
                     base.$key_name = s;
                 }
             } );
             ($key_name:ident, Option<u32>) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                if let Some(s) = obj.remove_key(&name).and_then(|j| Json::as_u64(&j)) {
+                if let Some(s) = obj.remove(&name).and_then(|b| b.as_u64()) {
                     if s < 1 || s > 5 {
                         return Err("Not a valid DWARF version number".into());
                     }
@@ -1745,13 +1751,13 @@ macro_rules! key {
             } );
             ($key_name:ident, Option<u64>) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                if let Some(s) = obj.remove_key(&name).and_then(|j| Json::as_u64(&j)) {
+                if let Some(s) = obj.remove(&name).and_then(|b| b.as_u64()) {
                     base.$key_name = Some(s);
                 }
             } );
             ($key_name:ident, MergeFunctions) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                obj.remove_key(&name[..]).and_then(|o| o.as_string().and_then(|s| {
+                obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
                     match s.parse::<MergeFunctions>() {
                         Ok(mergefunc) => base.$key_name = mergefunc,
                         _ => return Some(Err(format!("'{}' is not a valid value for \
@@ -1764,7 +1770,7 @@ macro_rules! key {
             } );
             ($key_name:ident, RelocModel) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                obj.remove_key(&name[..]).and_then(|o| o.as_string().and_then(|s| {
+                obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
                     match s.parse::<RelocModel>() {
                         Ok(relocation_model) => base.$key_name = relocation_model,
                         _ => return Some(Err(format!("'{}' is not a valid relocation model. \
@@ -1776,7 +1782,7 @@ macro_rules! key {
             } );
             ($key_name:ident, CodeModel) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                obj.remove_key(&name[..]).and_then(|o| o.as_string().and_then(|s| {
+                obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
                     match s.parse::<CodeModel>() {
                         Ok(code_model) => base.$key_name = Some(code_model),
                         _ => return Some(Err(format!("'{}' is not a valid code model. \
@@ -1788,7 +1794,7 @@ macro_rules! key {
             } );
             ($key_name:ident, TlsModel) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                obj.remove_key(&name[..]).and_then(|o| o.as_string().and_then(|s| {
+                obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
                     match s.parse::<TlsModel>() {
                         Ok(tls_model) => base.$key_name = tls_model,
                         _ => return Some(Err(format!("'{}' is not a valid TLS model. \
@@ -1800,7 +1806,7 @@ macro_rules! key {
             } );
             ($key_name:ident, PanicStrategy) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                obj.remove_key(&name[..]).and_then(|o| o.as_string().and_then(|s| {
+                obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
                     match s {
                         "unwind" => base.$key_name = PanicStrategy::Unwind,
                         "abort" => base.$key_name = PanicStrategy::Abort,
@@ -1813,7 +1819,7 @@ macro_rules! key {
             } );
             ($key_name:ident, RelroLevel) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                obj.remove_key(&name[..]).and_then(|o| o.as_string().and_then(|s| {
+                obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
                     match s.parse::<RelroLevel>() {
                         Ok(level) => base.$key_name = level,
                         _ => return Some(Err(format!("'{}' is not a valid value for \
@@ -1825,7 +1831,7 @@ macro_rules! key {
             } );
             ($key_name:ident, SplitDebuginfo) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                obj.remove_key(&name[..]).and_then(|o| o.as_string().and_then(|s| {
+                obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
                     match s.parse::<SplitDebuginfo>() {
                         Ok(level) => base.$key_name = level,
                         _ => return Some(Err(format!("'{}' is not a valid value for \
@@ -1837,10 +1843,10 @@ macro_rules! key {
             } );
             ($key_name:ident, list) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                if let Some(j) = obj.remove_key(&name){
-                    if let Some(v) = Json::as_array(&j) {
+                if let Some(j) = obj.remove(&name) {
+                    if let Some(v) = j.as_array() {
                         base.$key_name = v.iter()
-                            .map(|a| a.as_string().unwrap().to_string().into())
+                            .map(|a| a.as_str().unwrap().to_string().into())
                             .collect();
                     } else {
                         incorrect_type.push(name)
@@ -1849,10 +1855,10 @@ macro_rules! key {
             } );
             ($key_name:ident, opt_list) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                if let Some(j) = obj.remove_key(&name) {
-                    if let Some(v) = Json::as_array(&j) {
+                if let Some(j) = obj.remove(&name) {
+                    if let Some(v) = j.as_array() {
                         base.$key_name = Some(v.iter()
-                            .map(|a| a.as_string().unwrap().to_string().into())
+                            .map(|a| a.as_str().unwrap().to_string().into())
                             .collect());
                     } else {
                         incorrect_type.push(name)
@@ -1861,15 +1867,15 @@ macro_rules! key {
             } );
             ($key_name:ident, optional) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                if let Some(o) = obj.remove_key(&name[..]) {
+                if let Some(o) = obj.remove(&name) {
                     base.$key_name = o
-                        .as_string()
+                        .as_str()
                         .map(|s| s.to_string().into());
                 }
             } );
             ($key_name:ident, LldFlavor) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                obj.remove_key(&name[..]).and_then(|o| o.as_string().and_then(|s| {
+                obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
                     if let Some(flavor) = LldFlavor::from_str(&s) {
                         base.$key_name = flavor;
                     } else {
@@ -1883,7 +1889,7 @@ macro_rules! key {
             } );
             ($key_name:ident, LinkerFlavor) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                obj.remove_key(&name[..]).and_then(|o| o.as_string().and_then(|s| {
+                obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
                     match LinkerFlavor::from_str(s) {
                         Some(linker_flavor) => base.$key_name = linker_flavor,
                         _ => return Some(Err(format!("'{}' is not a valid value for linker-flavor. \
@@ -1894,7 +1900,7 @@ macro_rules! key {
             } );
             ($key_name:ident, StackProbeType) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                obj.remove_key(&name[..]).and_then(|o| match StackProbeType::from_json(&o) {
+                obj.remove(&name).and_then(|o| match StackProbeType::from_json(&o) {
                     Ok(v) => {
                         base.$key_name = v;
                         Some(Ok(()))
@@ -1906,10 +1912,10 @@ macro_rules! key {
             } );
             ($key_name:ident, SanitizerSet) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                if let Some(o) = obj.remove_key(&name[..]) {
+                if let Some(o) = obj.remove(&name) {
                     if let Some(a) = o.as_array() {
                         for s in a {
-                            base.$key_name |= match s.as_string() {
+                            base.$key_name |= match s.as_str() {
                                 Some("address") => SanitizerSet::ADDRESS,
                                 Some("cfi") => SanitizerSet::CFI,
                                 Some("leak") => SanitizerSet::LEAK,
@@ -1930,7 +1936,7 @@ macro_rules! key {
 
             ($key_name:ident, crt_objects_fallback) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                obj.remove_key(&name[..]).and_then(|o| o.as_string().and_then(|s| {
+                obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
                     match s.parse::<CrtObjectsFallback>() {
                         Ok(fallback) => base.$key_name = Some(fallback),
                         _ => return Some(Err(format!("'{}' is not a valid CRT objects fallback. \
@@ -1941,7 +1947,7 @@ macro_rules! key {
             } );
             ($key_name:ident, link_objects) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                if let Some(val) = obj.remove_key(&name[..]) {
+                if let Some(val) = obj.remove(&name) {
                     let obj = val.as_object().ok_or_else(|| format!("{}: expected a \
                         JSON object with fields per CRT object kind.", name))?;
                     let mut args = CrtObjects::new();
@@ -1956,7 +1962,7 @@ macro_rules! key {
                             format!("{}.{}: expected a JSON array", name, k)
                         )?.iter().enumerate()
                             .map(|(i,s)| {
-                                let s = s.as_string().ok_or_else(||
+                                let s = s.as_str().ok_or_else(||
                                     format!("{}.{}[{}]: expected a JSON string", name, k, i))?;
                                 Ok(s.to_string().into())
                             })
@@ -1969,7 +1975,7 @@ macro_rules! key {
             } );
             ($key_name:ident, link_args) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                if let Some(val) = obj.remove_key(&name[..]) {
+                if let Some(val) = obj.remove(&name) {
                     let obj = val.as_object().ok_or_else(|| format!("{}: expected a \
                         JSON object with fields per linker-flavor.", name))?;
                     let mut args = LinkArgs::new();
@@ -1983,7 +1989,7 @@ macro_rules! key {
                             format!("{}.{}: expected a JSON array", name, k)
                         )?.iter().enumerate()
                             .map(|(i,s)| {
-                                let s = s.as_string().ok_or_else(||
+                                let s = s.as_str().ok_or_else(||
                                     format!("{}.{}[{}]: expected a JSON string", name, k, i))?;
                                 Ok(s.to_string().into())
                             })
@@ -1996,10 +2002,10 @@ macro_rules! key {
             } );
             ($key_name:ident, env) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                if let Some(o) = obj.remove_key(&name[..]) {
+                if let Some(o) = obj.remove(&name) {
                     if let Some(a) = o.as_array() {
                         for o in a {
-                            if let Some(s) = o.as_string() {
+                            if let Some(s) = o.as_str() {
                                 let p = s.split('=').collect::<Vec<_>>();
                                 if p.len() == 2 {
                                     let k = p[0].to_string();
@@ -2015,7 +2021,7 @@ macro_rules! key {
             } );
             ($key_name:ident, Option<Abi>) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                obj.remove_key(&name[..]).and_then(|o| o.as_string().and_then(|s| {
+                obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
                     match lookup_abi(s) {
                         Some(abi) => base.$key_name = Some(abi),
                         _ => return Some(Err(format!("'{}' is not a valid value for abi", s))),
@@ -2024,28 +2030,28 @@ macro_rules! key {
                 })).unwrap_or(Ok(()))
             } );
             ($key_name:ident, TargetFamilies) => ( {
-                if let Some(value) = obj.remove_key("target-family") {
-                    if let Some(v) = Json::as_array(&value) {
+                if let Some(value) = obj.remove("target-family") {
+                    if let Some(v) = value.as_array() {
                         base.$key_name = v.iter()
-                            .map(|a| a.as_string().unwrap().to_string().into())
+                            .map(|a| a.as_str().unwrap().to_string().into())
                             .collect();
-                    } else if let Some(v) = Json::as_string(&value) {
+                    } else if let Some(v) = value.as_str() {
                         base.$key_name = vec![v.to_string().into()].into();
                     }
                 }
             } );
         }
 
-        if let Some(j) = obj.remove_key("target-endian") {
-            if let Some(s) = Json::as_string(&j) {
+        if let Some(j) = obj.remove("target-endian") {
+            if let Some(s) = j.as_str() {
                 base.endian = s.parse()?;
             } else {
                 incorrect_type.push("target-endian".into())
             }
         }
 
-        if let Some(fp) = obj.remove_key("frame-pointer") {
-            if let Some(s) = Json::as_string(&fp) {
+        if let Some(fp) = obj.remove("frame-pointer") {
+            if let Some(s) = fp.as_str() {
                 base.frame_pointer = s
                     .parse()
                     .map_err(|()| format!("'{}' is not a valid value for frame-pointer", s))?;
@@ -2157,8 +2163,8 @@ macro_rules! key {
             // This can cause unfortunate ICEs later down the line.
             return Err("may not set is_builtin for targets not built-in".into());
         }
-        // Each field should have been read using `Json::remove_key` so any keys remaining are unused.
-        let remaining_keys = obj.as_object().ok_or("Expected JSON object for target")?.keys();
+        // Each field should have been read using `Json::remove` so any keys remaining are unused.
+        let remaining_keys = obj.keys();
         Ok((
             base,
             TargetWarnings { unused_fields: remaining_keys.cloned().collect(), incorrect_type },
@@ -2190,13 +2196,12 @@ pub fn search(
         target_triple: &TargetTriple,
         sysroot: &Path,
     ) -> Result<(Target, TargetWarnings), String> {
-        use rustc_serialize::json;
         use std::env;
         use std::fs;
 
         fn load_file(path: &Path) -> Result<(Target, TargetWarnings), String> {
             let contents = fs::read_to_string(path).map_err(|e| e.to_string())?;
-            let obj = json::from_str(&contents).map_err(|e| e.to_string())?;
+            let obj = serde_json::from_str(&contents).map_err(|e| e.to_string())?;
             Target::from_json(obj)
         }
 
@@ -2249,7 +2254,7 @@ fn load_file(path: &Path) -> Result<(Target, TargetWarnings), String> {
 
 impl ToJson for Target {
     fn to_json(&self) -> Json {
-        let mut d = BTreeMap::new();
+        let mut d = serde_json::Map::new();
         let default: TargetOptions = Default::default();
 
         macro_rules! target_val {
index 3a737b3355a68825bbf59d431f6198119d803497..76375170db63da637c0a41b8533aedc82d8b3703 100644 (file)
@@ -1,10 +1,8 @@
 use crate::spec::Target;
-use rustc_serialize::json::Json;
-use std::str::FromStr;
 
 #[test]
 fn report_unused_fields() {
-    let json = Json::from_str(
+    let json = serde_json::from_str(
         r#"
     {
         "arch": "powerpc64",
@@ -23,7 +21,7 @@ fn report_unused_fields() {
 
 #[test]
 fn report_incorrect_json_type() {
-    let json = Json::from_str(
+    let json = serde_json::from_str(
         r#"
     {
         "arch": "powerpc64",
@@ -42,7 +40,7 @@ fn report_incorrect_json_type() {
 
 #[test]
 fn no_warnings_for_valid_target() {
-    let json = Json::from_str(
+    let json = serde_json::from_str(
         r#"
     {
         "arch": "powerpc64",
index a51e6e58f67a984349ca44d61e313df2cdef3d83..d0f20022bfbad6cacd7603e721c16ffe85debd2e 100644 (file)
@@ -21,7 +21,9 @@
 use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node};
 use rustc_middle::hir::map;
 use rustc_middle::ty::{
-    self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree,
+    self,
+    subst::{GenericArgKind, SubstsRef},
+    suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree,
     GeneratorDiagnosticData, GeneratorInteriorTypeCause, Infer, InferTy, ToPredicate, Ty, TyCtxt,
     TypeFoldable,
 };
@@ -458,6 +460,16 @@ fn suggest_restricting_param_bound(
             _ => (false, None),
         };
 
+        let generic_args_have_impl_trait = |args: SubstsRef<'tcx>| -> bool {
+            args.iter().any(|arg| match arg.unpack() {
+                GenericArgKind::Type(ty) => match ty.kind() {
+                    ty::Param(param) => param.name.as_str().starts_with("impl"),
+                    _ => false,
+                },
+                _ => false,
+            })
+        };
+
         // FIXME: Add check for trait bound that is already present, particularly `?Sized` so we
         //        don't suggest `T: Sized + ?Sized`.
         let mut hir_id = body_id;
@@ -588,7 +600,9 @@ fn suggest_restricting_param_bound(
                         | hir::ItemKind::TraitAlias(generics, _)
                         | hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. }),
                     ..
-                }) if !param_ty => {
+                }) if !param_ty
+                    && !generic_args_have_impl_trait(trait_pred.skip_binder().trait_ref.substs) =>
+                {
                     // Missing generic type parameter bound.
                     let param_name = self_ty.to_string();
                     let constraint = trait_pred.print_modifiers_and_trait_path().to_string();
index b83b0bf1ca52eea50331e7aa1f89d254b47c7c5c..f04f527ccb7af8f3062ab4a2f4361c8876afea16 100644 (file)
@@ -20,7 +20,7 @@ pub fn can_type_implement_copy<'tcx>(
     tcx: TyCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     self_type: Ty<'tcx>,
-    cause: ObligationCause<'tcx>,
+    parent_cause: ObligationCause<'tcx>,
 ) -> Result<(), CopyImplementationError<'tcx>> {
     // FIXME: (@jroesch) float this code up
     tcx.infer_ctxt().enter(|infcx| {
@@ -59,7 +59,7 @@ pub fn can_type_implement_copy<'tcx>(
                     .ty(tcx, traits::InternalSubsts::identity_for_item(tcx, adt.did()))
                     .has_param_types_or_consts()
                 {
-                    cause.clone()
+                    parent_cause.clone()
                 } else {
                     ObligationCause::dummy_with_span(span)
                 };
index a71621a4d52c0b90572d4adab0626af53008cb8e..641b915f373625ab9d52685eaa4328cb792e0538 100644 (file)
@@ -145,15 +145,28 @@ fn push_candidate(&mut self, candidate: ProjectionCandidate<'tcx>) -> bool {
     }
 }
 
-/// Takes the place of a
+/// States returned from `poly_project_and_unify_type`. Takes the place
+/// of the old return type, which was:
+/// ```ignore (not-rust)
 /// Result<
 ///     Result<Option<Vec<PredicateObligation<'tcx>>>, InProgress>,
 ///     MismatchedProjectionTypes<'tcx>,
 /// >
+/// ```
 pub(super) enum ProjectAndUnifyResult<'tcx> {
+    /// The projection bound holds subject to the given obligations. If the
+    /// projection cannot be normalized because the required trait bound does
+    /// not hold, this is returned, with `obligations` being a predicate that
+    /// cannot be proven.
     Holds(Vec<PredicateObligation<'tcx>>),
+    /// The projection cannot be normalized due to ambiguity. Resolving some
+    /// inference variables in the projection may fix this.
     FailedNormalization,
+    /// The project cannot be normalized because `poly_project_and_unify_type`
+    /// is called recursively while normalizing the same projection.
     Recursive,
+    // the projection can be normalized, but is not equal to the expected type.
+    // Returns the type error that arose from the mismatch.
     MismatchedProjectionTypes(MismatchedProjectionTypes<'tcx>),
 }
 
@@ -163,19 +176,6 @@ pub(super) enum ProjectAndUnifyResult<'tcx> {
 /// ```
 /// If successful, this may result in additional obligations. Also returns
 /// the projection cache key used to track these additional obligations.
-///
-/// ## Returns
-///
-/// - `Err(_)`: the projection can be normalized, but is not equal to the
-///   expected type.
-/// - `Ok(Err(InProgress))`: this is called recursively while normalizing
-///   the same projection.
-/// - `Ok(Ok(None))`: The projection cannot be normalized due to ambiguity
-///   (resolving some inference variables in the projection may fix this).
-/// - `Ok(Ok(Some(obligations)))`: The projection bound holds subject to
-///    the given obligations. If the projection cannot be normalized because
-///    the required trait bound doesn't hold this returned with `obligations`
-///    being a predicate that cannot be proven.
 #[instrument(level = "debug", skip(selcx))]
 pub(super) fn poly_project_and_unify_type<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
index 0379b16334cdc6f1ef64aa02d2889effa2ebe550..2ce2a44d3db76bd3703eea9c11483961ad2eb43d 100644 (file)
@@ -81,10 +81,17 @@ pub fn trait_obligations<'a, 'tcx>(
     body_id: hir::HirId,
     trait_ref: &ty::TraitRef<'tcx>,
     span: Span,
-    item: Option<&'tcx hir::Item<'tcx>>,
+    item: &'tcx hir::Item<'tcx>,
 ) -> Vec<traits::PredicateObligation<'tcx>> {
-    let mut wf =
-        WfPredicates { infcx, param_env, body_id, span, out: vec![], recursion_depth: 0, item };
+    let mut wf = WfPredicates {
+        infcx,
+        param_env,
+        body_id,
+        span,
+        out: vec![],
+        recursion_depth: 0,
+        item: Some(item),
+    };
     wf.compute_trait_ref(trait_ref, Elaborate::All);
     debug!(obligations = ?wf.out);
     wf.normalize()
index 650c3519b562e8cf4bc1045bd0925481019e082d..22b5b475b2cacf9ee53e2906dceaef6f886edd9e 100644 (file)
@@ -716,118 +716,116 @@ impl<I: Interner, E: TyEncoder> Encodable<E> for TyKind<I>
     I::AllocId: Encodable<E>,
 {
     fn encode(&self, e: &mut E) -> Result<(), <E as rustc_serialize::Encoder>::Error> {
-        rustc_serialize::Encoder::emit_enum(e, |e| {
-            let disc = discriminant(self);
-            match self {
-                Bool => e.emit_enum_variant("Bool", disc, 0, |_| Ok(())),
-                Char => e.emit_enum_variant("Char", disc, 0, |_| Ok(())),
-                Int(i) => e.emit_enum_variant("Int", disc, 1, |e| {
-                    e.emit_enum_variant_arg(true, |e| i.encode(e))?;
-                    Ok(())
-                }),
-                Uint(u) => e.emit_enum_variant("Uint", disc, 1, |e| {
-                    e.emit_enum_variant_arg(true, |e| u.encode(e))?;
-                    Ok(())
-                }),
-                Float(f) => e.emit_enum_variant("Float", disc, 1, |e| {
-                    e.emit_enum_variant_arg(true, |e| f.encode(e))?;
-                    Ok(())
-                }),
-                Adt(adt, substs) => e.emit_enum_variant("Adt", disc, 2, |e| {
-                    e.emit_enum_variant_arg(true, |e| adt.encode(e))?;
-                    e.emit_enum_variant_arg(false, |e| substs.encode(e))?;
-                    Ok(())
-                }),
-                Foreign(def_id) => e.emit_enum_variant("Foreign", disc, 1, |e| {
-                    e.emit_enum_variant_arg(true, |e| def_id.encode(e))?;
-                    Ok(())
-                }),
-                Str => e.emit_enum_variant("Str", disc, 0, |_| Ok(())),
-                Array(t, c) => e.emit_enum_variant("Array", disc, 2, |e| {
-                    e.emit_enum_variant_arg(true, |e| t.encode(e))?;
-                    e.emit_enum_variant_arg(false, |e| c.encode(e))?;
-                    Ok(())
-                }),
-                Slice(t) => e.emit_enum_variant("Slice", disc, 1, |e| {
-                    e.emit_enum_variant_arg(true, |e| t.encode(e))?;
-                    Ok(())
-                }),
-                RawPtr(tam) => e.emit_enum_variant("RawPtr", disc, 1, |e| {
-                    e.emit_enum_variant_arg(true, |e| tam.encode(e))?;
-                    Ok(())
-                }),
-                Ref(r, t, m) => e.emit_enum_variant("Ref", disc, 3, |e| {
-                    e.emit_enum_variant_arg(true, |e| r.encode(e))?;
-                    e.emit_enum_variant_arg(false, |e| t.encode(e))?;
-                    e.emit_enum_variant_arg(false, |e| m.encode(e))?;
-                    Ok(())
-                }),
-                FnDef(def_id, substs) => e.emit_enum_variant("FnDef", disc, 2, |e| {
-                    e.emit_enum_variant_arg(true, |e| def_id.encode(e))?;
-                    e.emit_enum_variant_arg(false, |e| substs.encode(e))?;
-                    Ok(())
-                }),
-                FnPtr(polyfnsig) => e.emit_enum_variant("FnPtr", disc, 1, |e| {
-                    e.emit_enum_variant_arg(true, |e| polyfnsig.encode(e))?;
-                    Ok(())
-                }),
-                Dynamic(l, r) => e.emit_enum_variant("Dynamic", disc, 2, |e| {
-                    e.emit_enum_variant_arg(true, |e| l.encode(e))?;
-                    e.emit_enum_variant_arg(false, |e| r.encode(e))?;
-                    Ok(())
-                }),
-                Closure(def_id, substs) => e.emit_enum_variant("Closure", disc, 2, |e| {
-                    e.emit_enum_variant_arg(true, |e| def_id.encode(e))?;
-                    e.emit_enum_variant_arg(false, |e| substs.encode(e))?;
-                    Ok(())
-                }),
-                Generator(def_id, substs, m) => e.emit_enum_variant("Generator", disc, 3, |e| {
-                    e.emit_enum_variant_arg(true, |e| def_id.encode(e))?;
-                    e.emit_enum_variant_arg(false, |e| substs.encode(e))?;
-                    e.emit_enum_variant_arg(false, |e| m.encode(e))?;
-                    Ok(())
-                }),
-                GeneratorWitness(b) => e.emit_enum_variant("GeneratorWitness", disc, 1, |e| {
-                    e.emit_enum_variant_arg(true, |e| b.encode(e))?;
-                    Ok(())
-                }),
-                Never => e.emit_enum_variant("Never", disc, 0, |_| Ok(())),
-                Tuple(substs) => e.emit_enum_variant("Tuple", disc, 1, |e| {
-                    e.emit_enum_variant_arg(true, |e| substs.encode(e))?;
-                    Ok(())
-                }),
-                Projection(p) => e.emit_enum_variant("Projection", disc, 1, |e| {
-                    e.emit_enum_variant_arg(true, |e| p.encode(e))?;
-                    Ok(())
-                }),
-                Opaque(def_id, substs) => e.emit_enum_variant("Opaque", disc, 2, |e| {
-                    e.emit_enum_variant_arg(true, |e| def_id.encode(e))?;
-                    e.emit_enum_variant_arg(false, |e| substs.encode(e))?;
-                    Ok(())
-                }),
-                Param(p) => e.emit_enum_variant("Param", disc, 1, |e| {
-                    e.emit_enum_variant_arg(true, |e| p.encode(e))?;
-                    Ok(())
-                }),
-                Bound(d, b) => e.emit_enum_variant("Bound", disc, 2, |e| {
-                    e.emit_enum_variant_arg(true, |e| d.encode(e))?;
-                    e.emit_enum_variant_arg(false, |e| b.encode(e))?;
-                    Ok(())
-                }),
-                Placeholder(p) => e.emit_enum_variant("Placeholder", disc, 1, |e| {
-                    e.emit_enum_variant_arg(true, |e| p.encode(e))?;
-                    Ok(())
-                }),
-                Infer(i) => e.emit_enum_variant("Infer", disc, 1, |e| {
-                    e.emit_enum_variant_arg(true, |e| i.encode(e))?;
-                    Ok(())
-                }),
-                Error(d) => e.emit_enum_variant("Error", disc, 1, |e| {
-                    e.emit_enum_variant_arg(true, |e| d.encode(e))?;
-                    Ok(())
-                }),
-            }
-        })
+        let disc = discriminant(self);
+        match self {
+            Bool => e.emit_enum_variant(disc, |_| Ok(())),
+            Char => e.emit_enum_variant(disc, |_| Ok(())),
+            Int(i) => e.emit_enum_variant(disc, |e| {
+                i.encode(e)?;
+                Ok(())
+            }),
+            Uint(u) => e.emit_enum_variant(disc, |e| {
+                u.encode(e)?;
+                Ok(())
+            }),
+            Float(f) => e.emit_enum_variant(disc, |e| {
+                f.encode(e)?;
+                Ok(())
+            }),
+            Adt(adt, substs) => e.emit_enum_variant(disc, |e| {
+                adt.encode(e)?;
+                substs.encode(e)?;
+                Ok(())
+            }),
+            Foreign(def_id) => e.emit_enum_variant(disc, |e| {
+                def_id.encode(e)?;
+                Ok(())
+            }),
+            Str => e.emit_enum_variant(disc, |_| Ok(())),
+            Array(t, c) => e.emit_enum_variant(disc, |e| {
+                t.encode(e)?;
+                c.encode(e)?;
+                Ok(())
+            }),
+            Slice(t) => e.emit_enum_variant(disc, |e| {
+                t.encode(e)?;
+                Ok(())
+            }),
+            RawPtr(tam) => e.emit_enum_variant(disc, |e| {
+                tam.encode(e)?;
+                Ok(())
+            }),
+            Ref(r, t, m) => e.emit_enum_variant(disc, |e| {
+                r.encode(e)?;
+                t.encode(e)?;
+                m.encode(e)?;
+                Ok(())
+            }),
+            FnDef(def_id, substs) => e.emit_enum_variant(disc, |e| {
+                def_id.encode(e)?;
+                substs.encode(e)?;
+                Ok(())
+            }),
+            FnPtr(polyfnsig) => e.emit_enum_variant(disc, |e| {
+                polyfnsig.encode(e)?;
+                Ok(())
+            }),
+            Dynamic(l, r) => e.emit_enum_variant(disc, |e| {
+                l.encode(e)?;
+                r.encode(e)?;
+                Ok(())
+            }),
+            Closure(def_id, substs) => e.emit_enum_variant(disc, |e| {
+                def_id.encode(e)?;
+                substs.encode(e)?;
+                Ok(())
+            }),
+            Generator(def_id, substs, m) => e.emit_enum_variant(disc, |e| {
+                def_id.encode(e)?;
+                substs.encode(e)?;
+                m.encode(e)?;
+                Ok(())
+            }),
+            GeneratorWitness(b) => e.emit_enum_variant(disc, |e| {
+                b.encode(e)?;
+                Ok(())
+            }),
+            Never => e.emit_enum_variant(disc, |_| Ok(())),
+            Tuple(substs) => e.emit_enum_variant(disc, |e| {
+                substs.encode(e)?;
+                Ok(())
+            }),
+            Projection(p) => e.emit_enum_variant(disc, |e| {
+                p.encode(e)?;
+                Ok(())
+            }),
+            Opaque(def_id, substs) => e.emit_enum_variant(disc, |e| {
+                def_id.encode(e)?;
+                substs.encode(e)?;
+                Ok(())
+            }),
+            Param(p) => e.emit_enum_variant(disc, |e| {
+                p.encode(e)?;
+                Ok(())
+            }),
+            Bound(d, b) => e.emit_enum_variant(disc, |e| {
+                d.encode(e)?;
+                b.encode(e)?;
+                Ok(())
+            }),
+            Placeholder(p) => e.emit_enum_variant(disc, |e| {
+                p.encode(e)?;
+                Ok(())
+            }),
+            Infer(i) => e.emit_enum_variant(disc, |e| {
+                i.encode(e)?;
+                Ok(())
+            }),
+            Error(d) => e.emit_enum_variant(disc, |e| {
+                d.encode(e)?;
+                Ok(())
+            }),
+        }
     }
 }
 
index 96d083bb94f3c9353d7d55e85a3ae0e317d03989..bcff2ae51290932fb4df6995be917329f25e6bd7 100644 (file)
@@ -16,7 +16,7 @@
 use rustc_ast::TraitObjectSyntax;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::{
-    struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, FatalError,
+    struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, FatalError, MultiSpan,
 };
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
@@ -30,7 +30,7 @@
 use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECTS};
 use rustc_span::edition::Edition;
 use rustc_span::lev_distance::find_best_match_for_name;
-use rustc_span::symbol::{Ident, Symbol};
+use rustc_span::symbol::{kw, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
 use rustc_target::spec::abi;
 use rustc_trait_selection::traits;
@@ -653,7 +653,7 @@ pub(crate) fn create_substs_for_associated_item(
             span, item_def_id, item_segment
         );
         if tcx.generics_of(item_def_id).params.is_empty() {
-            self.prohibit_generics(slice::from_ref(item_segment));
+            self.prohibit_generics(slice::from_ref(item_segment).iter(), |_| {});
 
             parent_substs
         } else {
@@ -681,7 +681,7 @@ pub fn instantiate_mono_trait_ref(
         trait_ref: &hir::TraitRef<'_>,
         self_ty: Ty<'tcx>,
     ) -> ty::TraitRef<'tcx> {
-        self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1);
+        self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1.iter(), |_| {});
 
         self.ast_path_to_mono_trait_ref(
             trait_ref.path.span,
@@ -784,7 +784,7 @@ pub(crate) fn instantiate_poly_trait_ref(
         let args = trait_segment.args();
         let infer_args = trait_segment.infer_args;
 
-        self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1);
+        self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1.iter(), |_| {});
         self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, false);
 
         self.instantiate_poly_trait_ref_inner(
@@ -1776,12 +1776,17 @@ pub fn associated_path_to_ty(
         hir_ref_id: hir::HirId,
         span: Span,
         qself_ty: Ty<'tcx>,
-        qself_res: Res,
+        qself: &hir::Ty<'_>,
         assoc_segment: &hir::PathSegment<'_>,
         permit_variants: bool,
     ) -> Result<(Ty<'tcx>, DefKind, DefId), ErrorGuaranteed> {
         let tcx = self.tcx();
         let assoc_ident = assoc_segment.ident;
+        let qself_res = if let hir::TyKind::Path(hir::QPath::Resolved(_, ref path)) = qself.kind {
+            path.res
+        } else {
+            Res::Err
+        };
 
         debug!("associated_path_to_ty: {:?}::{}", qself_ty, assoc_ident);
 
@@ -1796,7 +1801,87 @@ pub fn associated_path_to_ty(
                 if let Some(variant_def) = variant_def {
                     if permit_variants {
                         tcx.check_stability(variant_def.def_id, Some(hir_ref_id), span, None);
-                        self.prohibit_generics(slice::from_ref(assoc_segment));
+                        self.prohibit_generics(slice::from_ref(assoc_segment).iter(), |err| {
+                            err.note("enum variants can't have type parameters");
+                            let type_name = tcx.item_name(adt_def.did());
+                            let msg = format!(
+                                "you might have meant to specity type parameters on enum \
+                                 `{type_name}`"
+                            );
+                            let Some(args) = assoc_segment.args else { return; };
+                            // Get the span of the generics args *including* the leading `::`.
+                            let args_span = assoc_segment.ident.span.shrink_to_hi().to(args.span_ext);
+                            if tcx.generics_of(adt_def.did()).count() == 0 {
+                                // FIXME(estebank): we could also verify that the arguments being
+                                // work for the `enum`, instead of just looking if it takes *any*.
+                                err.span_suggestion_verbose(
+                                    args_span,
+                                    &format!("{type_name} doesn't have generic parameters"),
+                                    String::new(),
+                                    Applicability::MachineApplicable,
+                                );
+                                return;
+                            }
+                            let Ok(snippet) = tcx.sess.source_map().span_to_snippet(args_span) else {
+                                err.note(&msg);
+                                return;
+                            };
+                            let (qself_sugg_span, is_self) = if let hir::TyKind::Path(
+                                hir::QPath::Resolved(_, ref path)
+                            ) = qself.kind {
+                                // If the path segment already has type params, we want to overwrite
+                                // them.
+                                match &path.segments[..] {
+                                    // `segment` is the previous to last element on the path,
+                                    // which would normally be the `enum` itself, while the last
+                                    // `_` `PathSegment` corresponds to the variant.
+                                    [.., hir::PathSegment {
+                                        ident,
+                                        args,
+                                        res: Some(Res::Def(DefKind::Enum, _)),
+                                        ..
+                                    }, _] => (
+                                        // We need to include the `::` in `Type::Variant::<Args>`
+                                        // to point the span to `::<Args>`, not just `<Args>`.
+                                        ident.span.shrink_to_hi().to(args.map_or(
+                                            ident.span.shrink_to_hi(),
+                                            |a| a.span_ext)),
+                                        false,
+                                    ),
+                                    [segment] => (
+                                        // We need to include the `::` in `Type::Variant::<Args>`
+                                        // to point the span to `::<Args>`, not just `<Args>`.
+                                        segment.ident.span.shrink_to_hi().to(segment.args.map_or(
+                                            segment.ident.span.shrink_to_hi(),
+                                            |a| a.span_ext)),
+                                        kw::SelfUpper == segment.ident.name,
+                                    ),
+                                    _ => {
+                                        err.note(&msg);
+                                        return;
+                                    }
+                                }
+                            } else {
+                                err.note(&msg);
+                                return;
+                            };
+                            let suggestion = vec![
+                                if is_self {
+                                    // Account for people writing `Self::Variant::<Args>`, where
+                                    // `Self` is the enum, and suggest replacing `Self` with the
+                                    // appropriate type: `Type::<Args>::Variant`.
+                                    (qself.span, format!("{type_name}{snippet}"))
+                                } else {
+                                    (qself_sugg_span, snippet)
+                                },
+                                (args_span, String::new()),
+                            ];
+                            err.multipart_suggestion_verbose(
+                                &msg,
+                                suggestion,
+                                Applicability::MaybeIncorrect,
+                            );
+                        });
                         return Ok((qself_ty, DefKind::Variant, variant_def.def_id));
                     } else {
                         variant_resolution = Some(variant_def.def_id);
@@ -2017,69 +2102,112 @@ fn qpath_to_ty(
         self.normalize_ty(span, tcx.mk_projection(item_def_id, item_substs))
     }
 
-    pub fn prohibit_generics<'a, T: IntoIterator<Item = &'a hir::PathSegment<'a>>>(
+    pub fn prohibit_generics<'a>(
         &self,
-        segments: T,
+        segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone,
+        extend: impl Fn(&mut DiagnosticBuilder<'tcx, ErrorGuaranteed>),
     ) -> bool {
-        let mut has_err = false;
-        for segment in segments {
-            let (mut err_for_lt, mut err_for_ty, mut err_for_ct) = (false, false, false);
-            for arg in segment.args().args {
-                let (span, kind) = match arg {
-                    hir::GenericArg::Lifetime(lt) => {
-                        if err_for_lt {
-                            continue;
-                        }
-                        err_for_lt = true;
-                        has_err = true;
-                        (lt.span, "lifetime")
-                    }
-                    hir::GenericArg::Type(ty) => {
-                        if err_for_ty {
-                            continue;
-                        }
-                        err_for_ty = true;
-                        has_err = true;
-                        (ty.span, "type")
-                    }
-                    hir::GenericArg::Const(ct) => {
-                        if err_for_ct {
-                            continue;
-                        }
-                        err_for_ct = true;
-                        has_err = true;
-                        (ct.span, "const")
-                    }
-                    hir::GenericArg::Infer(inf) => {
-                        if err_for_ty {
-                            continue;
-                        }
-                        has_err = true;
-                        err_for_ty = true;
-                        (inf.span, "generic")
+        let args = segments.clone().flat_map(|segment| segment.args().args);
+        let types_and_spans: Vec<_> = segments
+            .clone()
+            .flat_map(|segment| {
+                segment.res.and_then(|res| {
+                    if segment.args().args.is_empty() {
+                        None
+                    } else {
+                        Some((
+                            match res {
+                                Res::PrimTy(ty) => format!("{} `{}`", res.descr(), ty.name()),
+                                Res::Def(_, def_id)
+                                if let Some(name) = self.tcx().opt_item_name(def_id) => {
+                                    format!("{} `{name}`", res.descr())
+                                }
+                                Res::Err => "this type".to_string(),
+                                _ => res.descr().to_string(),
+                            },
+                            segment.ident.span,
+                        ))
                     }
-                };
-                let mut err = struct_span_err!(
-                    self.tcx().sess,
-                    span,
-                    E0109,
-                    "{} arguments are not allowed for this type",
-                    kind,
-                );
-                err.span_label(span, format!("{} argument not allowed", kind));
-                err.emit();
-                if err_for_lt && err_for_ty && err_for_ct {
-                    break;
-                }
+                })
+            })
+            .collect();
+        let this_type = match &types_and_spans[..] {
+            [.., _, (last, _)] => format!(
+                "{} and {last}",
+                types_and_spans[..types_and_spans.len() - 1]
+                    .iter()
+                    .map(|(x, _)| x.as_str())
+                    .intersperse(&", ")
+                    .collect::<String>()
+            ),
+            [(only, _)] => only.to_string(),
+            [] => "this type".to_string(),
+        };
+
+        let (lt, ty, ct, inf) =
+            args.clone().fold((false, false, false, false), |(lt, ty, ct, inf), arg| match arg {
+                hir::GenericArg::Lifetime(_) => (true, ty, ct, inf),
+                hir::GenericArg::Type(_) => (lt, true, ct, inf),
+                hir::GenericArg::Const(_) => (lt, ty, true, inf),
+                hir::GenericArg::Infer(_) => (lt, ty, ct, true),
+            });
+        let mut emitted = false;
+        if lt || ty || ct || inf {
+            let arg_spans: Vec<Span> = args.map(|arg| arg.span()).collect();
+
+            let mut kinds = Vec::with_capacity(4);
+            if lt {
+                kinds.push("lifetime");
+            }
+            if ty {
+                kinds.push("type");
+            }
+            if ct {
+                kinds.push("const");
             }
+            if inf {
+                kinds.push("generic");
+            }
+            let (kind, s) = match kinds[..] {
+                [.., _, last] => (
+                    format!(
+                        "{} and {last}",
+                        kinds[..kinds.len() - 1]
+                            .iter()
+                            .map(|&x| x)
+                            .intersperse(", ")
+                            .collect::<String>()
+                    ),
+                    "s",
+                ),
+                [only] => (format!("{only}"), ""),
+                [] => unreachable!(),
+            };
+            let last_span = *arg_spans.last().unwrap();
+            let span: MultiSpan = arg_spans.into();
+            let mut err = struct_span_err!(
+                self.tcx().sess,
+                span,
+                E0109,
+                "{kind} arguments are not allowed on {this_type}",
+            );
+            err.span_label(last_span, format!("{kind} argument{s} not allowed"));
+            for (_, span) in types_and_spans {
+                err.span_label(span, "not allowed on this");
+            }
+            extend(&mut err);
+            err.emit();
+            emitted = true;
+        }
 
+        for segment in segments {
             // Only emit the first error to avoid overloading the user with error messages.
             if let [binding, ..] = segment.args().bindings {
-                has_err = true;
                 Self::prohibit_assoc_ty_binding(self.tcx(), binding.span);
+                return true;
             }
         }
-        has_err
+        emitted
     }
 
     // FIXME(eddyb, varkor) handle type paths here too, not just value ones.
@@ -2229,7 +2357,9 @@ pub fn res_to_ty(
                 // Check for desugared `impl Trait`.
                 assert!(ty::is_impl_trait_defn(tcx, did).is_none());
                 let item_segment = path.segments.split_last().unwrap();
-                self.prohibit_generics(item_segment.1);
+                self.prohibit_generics(item_segment.1.iter(), |err| {
+                    err.note("`impl Trait` types can't have type parameters");
+                });
                 let substs = self.ast_path_substs_for_ty(span, did, item_segment.0);
                 self.normalize_ty(span, tcx.mk_opaque(did, substs))
             }
@@ -2242,7 +2372,7 @@ pub fn res_to_ty(
                 did,
             ) => {
                 assert_eq!(opt_self_ty, None);
-                self.prohibit_generics(path.segments.split_last().unwrap().1);
+                self.prohibit_generics(path.segments.split_last().unwrap().1.iter(), |_| {});
                 self.ast_path_to_ty(span, did, path.segments.last().unwrap())
             }
             Res::Def(kind @ DefKind::Variant, def_id) if permit_variants => {
@@ -2254,18 +2384,26 @@ pub fn res_to_ty(
                     self.def_ids_for_value_path_segments(path.segments, None, kind, def_id);
                 let generic_segs: FxHashSet<_> =
                     path_segs.iter().map(|PathSeg(_, index)| index).collect();
-                self.prohibit_generics(path.segments.iter().enumerate().filter_map(
-                    |(index, seg)| {
+                self.prohibit_generics(
+                    path.segments.iter().enumerate().filter_map(|(index, seg)| {
                         if !generic_segs.contains(&index) { Some(seg) } else { None }
+                    }),
+                    |err| {
+                        err.note("enum variants can't have type parameters");
                     },
-                ));
+                );
 
                 let PathSeg(def_id, index) = path_segs.last().unwrap();
                 self.ast_path_to_ty(span, *def_id, &path.segments[*index])
             }
             Res::Def(DefKind::TyParam, def_id) => {
                 assert_eq!(opt_self_ty, None);
-                self.prohibit_generics(path.segments);
+                self.prohibit_generics(path.segments.iter(), |err| {
+                    if let Some(span) = tcx.def_ident_span(def_id) {
+                        let name = tcx.item_name(def_id);
+                        err.span_note(span, &format!("type parameter `{name}` defined here"));
+                    }
+                });
 
                 let def_id = def_id.expect_local();
                 let item_def_id = tcx.hir().ty_param_owner(def_id);
@@ -2276,15 +2414,81 @@ pub fn res_to_ty(
             Res::SelfTy { trait_: Some(_), alias_to: None } => {
                 // `Self` in trait or type alias.
                 assert_eq!(opt_self_ty, None);
-                self.prohibit_generics(path.segments);
+                self.prohibit_generics(path.segments.iter(), |err| {
+                    if let [hir::PathSegment { args: Some(args), ident, .. }] = &path.segments[..] {
+                        err.span_suggestion_verbose(
+                            ident.span.shrink_to_hi().to(args.span_ext),
+                            "the `Self` type doesn't accept type parameters",
+                            String::new(),
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                });
                 tcx.types.self_param
             }
             Res::SelfTy { trait_: _, alias_to: Some((def_id, forbid_generic)) } => {
                 // `Self` in impl (we know the concrete type).
                 assert_eq!(opt_self_ty, None);
-                self.prohibit_generics(path.segments);
                 // Try to evaluate any array length constants.
                 let ty = tcx.at(span).type_of(def_id);
+                let span_of_impl = tcx.span_of_impl(def_id);
+                self.prohibit_generics(path.segments.iter(), |err| {
+                    let def_id = match *ty.kind() {
+                        ty::Adt(self_def, _) => self_def.did(),
+                        _ => return,
+                    };
+
+                    let type_name = tcx.item_name(def_id);
+                    let span_of_ty = tcx.def_ident_span(def_id);
+                    let generics = tcx.generics_of(def_id).count();
+
+                    let msg = format!("`Self` is of type `{ty}`");
+                    if let (Ok(i_sp), Some(t_sp)) = (span_of_impl, span_of_ty) {
+                        let i_sp = tcx.sess.source_map().guess_head_span(i_sp);
+                        let mut span: MultiSpan = vec![t_sp].into();
+                        span.push_span_label(
+                            i_sp,
+                            &format!("`Self` is on type `{type_name}` in this `impl`"),
+                        );
+                        let mut postfix = "";
+                        if generics == 0 {
+                            postfix = ", which doesn't have generic parameters";
+                        }
+                        span.push_span_label(
+                            t_sp,
+                            &format!("`Self` corresponds to this type{postfix}"),
+                        );
+                        err.span_note(span, &msg);
+                    } else {
+                        err.note(&msg);
+                    }
+                    for segment in path.segments {
+                        if let Some(args) = segment.args && segment.ident.name == kw::SelfUpper {
+                            if generics == 0 {
+                                // FIXME(estebank): we could also verify that the arguments being
+                                // work for the `enum`, instead of just looking if it takes *any*.
+                                err.span_suggestion_verbose(
+                                    segment.ident.span.shrink_to_hi().to(args.span_ext),
+                                    "the `Self` type doesn't accept type parameters",
+                                    String::new(),
+                                    Applicability::MachineApplicable,
+                                );
+                                return;
+                            } else {
+                                err.span_suggestion_verbose(
+                                    segment.ident.span,
+                                    format!(
+                                        "the `Self` type doesn't accept type parameters, use the \
+                                        concrete type's name `{type_name}` instead if you want to \
+                                        specify its type parameters"
+                                    ),
+                                    type_name.to_string(),
+                                    Applicability::MaybeIncorrect,
+                                );
+                            }
+                        }
+                    }
+                });
                 // HACK(min_const_generics): Forbid generic `Self` types
                 // here as we can't easily do that during nameres.
                 //
@@ -2324,7 +2528,7 @@ pub fn res_to_ty(
             }
             Res::Def(DefKind::AssocTy, def_id) => {
                 debug_assert!(path.segments.len() >= 2);
-                self.prohibit_generics(&path.segments[..path.segments.len() - 2]);
+                self.prohibit_generics(path.segments[..path.segments.len() - 2].iter(), |_| {});
                 self.qpath_to_ty(
                     span,
                     opt_self_ty,
@@ -2335,7 +2539,19 @@ pub fn res_to_ty(
             }
             Res::PrimTy(prim_ty) => {
                 assert_eq!(opt_self_ty, None);
-                self.prohibit_generics(path.segments);
+                self.prohibit_generics(path.segments.iter(), |err| {
+                    let name = prim_ty.name_str();
+                    for segment in path.segments {
+                        if let Some(args) = segment.args {
+                            err.span_suggestion_verbose(
+                                segment.ident.span.shrink_to_hi().to(args.span_ext),
+                                &format!("primitive type `{name}` doesn't have generic parameters"),
+                                String::new(),
+                                Applicability::MaybeIncorrect,
+                            );
+                        }
+                    }
+                });
                 match prim_ty {
                     hir::PrimTy::Bool => tcx.types.bool,
                     hir::PrimTy::Char => tcx.types.char,
@@ -2426,13 +2642,7 @@ fn ast_ty_to_ty_inner(&self, ast_ty: &hir::Ty<'_>, borrowed: bool, in_path: bool
             hir::TyKind::Path(hir::QPath::TypeRelative(ref qself, ref segment)) => {
                 debug!(?qself, ?segment);
                 let ty = self.ast_ty_to_ty_inner(qself, false, true);
-
-                let res = if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = qself.kind {
-                    path.res
-                } else {
-                    Res::Err
-                };
-                self.associated_path_to_ty(ast_ty.hir_id, ast_ty.span, ty, res, segment, false)
+                self.associated_path_to_ty(ast_ty.hir_id, ast_ty.span, ty, qself, segment, false)
                     .map(|(ty, _, _)| ty)
                     .unwrap_or_else(|_| tcx.ty_error())
             }
index 7499e5efdeeab86670bfd177b2dd221f0f83dcb8..de5367ca27c3a65af21bab6cdc8b198881c27712 100644 (file)
@@ -8,10 +8,11 @@
 use rustc_attr as attr;
 use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan};
 use rustc_hir as hir;
+use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::lang_items::LangItem;
-use rustc_hir::{def::Res, ItemKind, Node, PathSegment};
+use rustc_hir::{ItemKind, Node, PathSegment};
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
 use rustc_infer::traits::Obligation;
@@ -29,7 +30,6 @@
 use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
 use rustc_ty_utils::representability::{self, Representability};
 
-use rustc_hir::def::DefKind;
 use std::iter;
 use std::ops::ControlFlow;
 
@@ -93,7 +93,6 @@ pub(super) fn check_fn<'a, 'tcx>(
     fcx.return_type_pre_known = return_type_pre_known;
 
     let tcx = fcx.tcx;
-    let sess = tcx.sess;
     let hir = tcx.hir();
 
     let declared_ret_ty = fn_sig.output();
@@ -259,85 +258,123 @@ pub(super) fn check_fn<'a, 'tcx>(
     if let Some(panic_impl_did) = tcx.lang_items().panic_impl()
         && panic_impl_did == hir.local_def_id(fn_id).to_def_id()
     {
-        if let Some(panic_info_did) = tcx.lang_items().panic_info() {
-            if *declared_ret_ty.kind() != ty::Never {
-                sess.span_err(decl.output.span(), "return type should be `!`");
-            }
-
-            let inputs = fn_sig.inputs();
-            let span = hir.span(fn_id);
-            if inputs.len() == 1 {
-                let arg_is_panic_info = match *inputs[0].kind() {
-                    ty::Ref(region, ty, mutbl) => match *ty.kind() {
-                        ty::Adt(ref adt, _) => {
-                            adt.did() == panic_info_did
-                                && mutbl == hir::Mutability::Not
-                                && !region.is_static()
-                        }
-                        _ => false,
-                    },
-                    _ => false,
-                };
-
-                if !arg_is_panic_info {
-                    sess.span_err(decl.inputs[0].span, "argument should be `&PanicInfo`");
-                }
-
-                if let Node::Item(item) = hir.get(fn_id)
-                    && let ItemKind::Fn(_, ref generics, _) = item.kind
-                    && !generics.params.is_empty()
-                {
-                            sess.span_err(span, "should have no type parameters");
-                        }
-            } else {
-                let span = sess.source_map().guess_head_span(span);
-                sess.span_err(span, "function should have one argument");
-            }
-        } else {
-            sess.err("language item required, but not found: `panic_info`");
-        }
+        check_panic_info_fn(tcx, panic_impl_did.expect_local(), fn_sig, decl, declared_ret_ty);
     }
 
     // Check that a function marked as `#[alloc_error_handler]` has signature `fn(Layout) -> !`
     if let Some(alloc_error_handler_did) = tcx.lang_items().oom()
         && alloc_error_handler_did == hir.local_def_id(fn_id).to_def_id()
     {
-        if let Some(alloc_layout_did) = tcx.lang_items().alloc_layout() {
-            if *declared_ret_ty.kind() != ty::Never {
-                sess.span_err(decl.output.span(), "return type should be `!`");
-            }
+        check_alloc_error_fn(tcx, alloc_error_handler_did.expect_local(), fn_sig, decl, declared_ret_ty);
+    }
 
-            let inputs = fn_sig.inputs();
-            let span = hir.span(fn_id);
-            if inputs.len() == 1 {
-                let arg_is_alloc_layout = match inputs[0].kind() {
-                    ty::Adt(ref adt, _) => adt.did() == alloc_layout_did,
-                    _ => false,
-                };
+    (fcx, gen_ty)
+}
 
-                if !arg_is_alloc_layout {
-                    sess.span_err(decl.inputs[0].span, "argument should be `Layout`");
-                }
+fn check_panic_info_fn(
+    tcx: TyCtxt<'_>,
+    fn_id: LocalDefId,
+    fn_sig: ty::FnSig<'_>,
+    decl: &hir::FnDecl<'_>,
+    declared_ret_ty: Ty<'_>,
+) {
+    let Some(panic_info_did) = tcx.lang_items().panic_info() else {
+        tcx.sess.err("language item required, but not found: `panic_info`");
+        return;
+    };
 
-                if let Node::Item(item) = hir.get(fn_id)
-                    && let ItemKind::Fn(_, ref generics, _) = item.kind
-                    && !generics.params.is_empty()
-                {
-                            sess.span_err(
-                                span,
-                        "`#[alloc_error_handler]` function should have no type parameters",
-                            );
-                        }
-            } else {
-                let span = sess.source_map().guess_head_span(span);
-                sess.span_err(span, "function should have one argument");
+    if *declared_ret_ty.kind() != ty::Never {
+        tcx.sess.span_err(decl.output.span(), "return type should be `!`");
+    }
+
+    let span = tcx.def_span(fn_id);
+    let inputs = fn_sig.inputs();
+    if inputs.len() != 1 {
+        let span = tcx.sess.source_map().guess_head_span(span);
+        tcx.sess.span_err(span, "function should have one argument");
+        return;
+    }
+
+    let arg_is_panic_info = match *inputs[0].kind() {
+        ty::Ref(region, ty, mutbl) => match *ty.kind() {
+            ty::Adt(ref adt, _) => {
+                adt.did() == panic_info_did && mutbl == hir::Mutability::Not && !region.is_static()
             }
-        } else {
-            sess.err("language item required, but not found: `alloc_layout`");
-        }
+            _ => false,
+        },
+        _ => false,
+    };
+
+    if !arg_is_panic_info {
+        tcx.sess.span_err(decl.inputs[0].span, "argument should be `&PanicInfo`");
     }
 
-    (fcx, gen_ty)
+    let DefKind::Fn = tcx.def_kind(fn_id) else {
+        let span = tcx.def_span(fn_id);
+        tcx.sess.span_err(span, "should be a function");
+        return;
+    };
+
+    let generic_counts = tcx.generics_of(fn_id).own_counts();
+    if generic_counts.types != 0 {
+        let span = tcx.def_span(fn_id);
+        tcx.sess.span_err(span, "should have no type parameters");
+    }
+    if generic_counts.consts != 0 {
+        let span = tcx.def_span(fn_id);
+        tcx.sess.span_err(span, "should have no const parameters");
+    }
+}
+
+fn check_alloc_error_fn(
+    tcx: TyCtxt<'_>,
+    fn_id: LocalDefId,
+    fn_sig: ty::FnSig<'_>,
+    decl: &hir::FnDecl<'_>,
+    declared_ret_ty: Ty<'_>,
+) {
+    let Some(alloc_layout_did) = tcx.lang_items().alloc_layout() else {
+        tcx.sess.err("language item required, but not found: `alloc_layout`");
+        return;
+    };
+
+    if *declared_ret_ty.kind() != ty::Never {
+        tcx.sess.span_err(decl.output.span(), "return type should be `!`");
+    }
+
+    let inputs = fn_sig.inputs();
+    if inputs.len() != 1 {
+        let span = tcx.def_span(fn_id);
+        let span = tcx.sess.source_map().guess_head_span(span);
+        tcx.sess.span_err(span, "function should have one argument");
+        return;
+    }
+
+    let arg_is_alloc_layout = match inputs[0].kind() {
+        ty::Adt(ref adt, _) => adt.did() == alloc_layout_did,
+        _ => false,
+    };
+
+    if !arg_is_alloc_layout {
+        tcx.sess.span_err(decl.inputs[0].span, "argument should be `Layout`");
+    }
+
+    let DefKind::Fn = tcx.def_kind(fn_id) else {
+        let span = tcx.def_span(fn_id);
+        tcx.sess.span_err(span, "`#[alloc_error_handler]` should be a function");
+        return;
+    };
+
+    let generic_counts = tcx.generics_of(fn_id).own_counts();
+    if generic_counts.types != 0 {
+        let span = tcx.def_span(fn_id);
+        tcx.sess.span_err(span, "`#[alloc_error_handler]` function should have no type parameters");
+    }
+    if generic_counts.consts != 0 {
+        let span = tcx.def_span(fn_id);
+        tcx.sess
+            .span_err(span, "`#[alloc_error_handler]` function should have no const parameters");
+    }
 }
 
 fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) {
index 1af50191cb006f55c7b630908b15166b8bf8f9bb..d6a8659d54b58dd0a52f2531a5853682c84f6eb2 100644 (file)
@@ -1500,7 +1500,8 @@ pub(crate) fn coerce_inner<'a>(
                             coercion_error.clone(),
                             fcx,
                             parent_id,
-                            expression.map(|expr| (expr, blk_id)),
+                            expression,
+                            Some(blk_id),
                         );
                         if !fcx.tcx.features().unsized_locals {
                             unsized_return = self.is_return_ty_unsized(fcx, blk_id);
@@ -1514,6 +1515,7 @@ pub(crate) fn coerce_inner<'a>(
                             coercion_error.clone(),
                             fcx,
                             id,
+                            expression,
                             None,
                         );
                         if !fcx.tcx.features().unsized_locals {
@@ -1564,21 +1566,28 @@ fn report_return_mismatched_types<'a>(
         ty_err: TypeError<'tcx>,
         fcx: &FnCtxt<'a, 'tcx>,
         id: hir::HirId,
-        expression: Option<(&'tcx hir::Expr<'tcx>, hir::HirId)>,
+        expression: Option<&'tcx hir::Expr<'tcx>>,
+        blk_id: Option<hir::HirId>,
     ) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
         let mut err = fcx.report_mismatched_types(cause, expected, found, ty_err);
 
         let mut pointing_at_return_type = false;
         let mut fn_output = None;
 
+        let parent_id = fcx.tcx.hir().get_parent_node(id);
+        let parent = fcx.tcx.hir().get(parent_id);
+        if let Some(expr) = expression
+            && let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(_, _, body_id, ..), .. }) = parent
+            && !matches!(fcx.tcx.hir().get(body_id.hir_id), hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Block(..), .. }))
+        {
+            fcx.suggest_missing_semicolon(&mut err, expr, expected, true);
+        }
         // Verify that this is a tail expression of a function, otherwise the
         // label pointing out the cause for the type coercion will be wrong
         // as prior return coercions would not be relevant (#57664).
-        let parent_id = fcx.tcx.hir().get_parent_node(id);
-        let fn_decl = if let Some((expr, blk_id)) = expression {
+        let fn_decl = if let (Some(expr), Some(blk_id)) = (expression, blk_id) {
             pointing_at_return_type =
                 fcx.suggest_mismatched_types_on_tail(&mut err, expr, expected, found, blk_id);
-            let parent = fcx.tcx.hir().get(parent_id);
             if let (Some(cond_expr), true, false) = (
                 fcx.tcx.hir().get_if_cause(expr.hir_id),
                 expected.is_unit(),
@@ -1607,7 +1616,7 @@ fn report_return_mismatched_types<'a>(
         };
 
         if let Some((fn_decl, can_suggest)) = fn_decl {
-            if expression.is_none() {
+            if blk_id.is_none() {
                 pointing_at_return_type |= fcx.suggest_missing_return_type(
                     &mut err,
                     &fn_decl,
@@ -1625,8 +1634,8 @@ fn report_return_mismatched_types<'a>(
         let parent_id = fcx.tcx.hir().get_parent_item(id);
         let parent_item = fcx.tcx.hir().get_by_def_id(parent_id);
 
-        if let (Some((expr, _)), Some((fn_decl, _, _))) =
-            (expression, fcx.get_node_fn_decl(parent_item))
+        if let (Some(expr), Some(_), Some((fn_decl, _, _))) =
+            (expression, blk_id, fcx.get_node_fn_decl(parent_item))
         {
             fcx.suggest_missing_break_or_return_expr(
                 &mut err,
index 277bc1cf0f06514abfdf23df83dc4f9d49f81275..4d17307ddb968bd72993d422bdea2dbfba07be3f 100644 (file)
@@ -660,8 +660,24 @@ fn compare_number_of_generics<'tcx>(
                     _ => None,
                 })
                 .collect();
-            let spans = impl_item.generics.spans();
-            let span = spans.primary_span();
+            let spans = if impl_item.generics.params.is_empty() {
+                vec![impl_item.generics.span]
+            } else {
+                impl_item
+                    .generics
+                    .params
+                    .iter()
+                    .filter(|p| {
+                        matches!(
+                            p.kind,
+                            hir::GenericParamKind::Type { .. }
+                                | hir::GenericParamKind::Const { .. }
+                        )
+                    })
+                    .map(|p| p.span)
+                    .collect::<Vec<Span>>()
+            };
+            let span = spans.first().copied();
 
             let mut err = tcx.sess.struct_span_err_with_code(
                 spans,
index ac2dc6522adc206223c634e37ca2d5f31f6373b3..c28c041e78dff9c9709211b3f784363cfd417f2f 100644 (file)
@@ -1228,6 +1228,7 @@ pub fn instantiate_value_path(
                     None
                 }
             }),
+            |_| {},
         );
 
         if let Res::Local(hid) = res {
index 34cc02f180b40b74d13068971a2733f44555a2b7..83afbfa54b1dda8dbe272df87ffb2045d8901990 100644 (file)
@@ -1564,13 +1564,8 @@ fn finish_resolving_struct_path(
             QPath::TypeRelative(ref qself, ref segment) => {
                 let ty = self.to_ty(qself);
 
-                let res = if let hir::TyKind::Path(QPath::Resolved(_, ref path)) = qself.kind {
-                    path.res
-                } else {
-                    Res::Err
-                };
                 let result = <dyn AstConv<'_>>::associated_path_to_ty(
-                    self, hir_id, path_span, ty, res, segment, true,
+                    self, hir_id, path_span, ty, qself, segment, true,
                 );
                 let ty = result.map(|(ty, _, _)| ty).unwrap_or_else(|_| self.tcx().ty_error());
                 let result = result.map(|(_, kind, def_id)| (kind, def_id));
index bd58a6754481a53e7ae6168ab4439ee4f2b2c5d9..76add2fb9c2859588531f53b16ef61706007fa43 100644 (file)
@@ -46,12 +46,7 @@ pub fn suggest_mismatched_types_on_tail(
         blk_id: hir::HirId,
     ) -> bool {
         let expr = expr.peel_drop_temps();
-        // If the expression is from an external macro, then do not suggest
-        // adding a semicolon, because there's nowhere to put it.
-        // See issue #81943.
-        if expr.can_have_side_effects() && !in_external_macro(self.tcx.sess, expr.span) {
-            self.suggest_missing_semicolon(err, expr, expected);
-        }
+        self.suggest_missing_semicolon(err, expr, expected, false);
         let mut pointing_at_return_type = false;
         if let Some((fn_decl, can_suggest)) = self.get_fn_decl(blk_id) {
             let fn_id = self.tcx.hir().get_return_block(blk_id).unwrap();
@@ -473,11 +468,15 @@ pub(in super::super) fn suggest_calling_boxed_future_when_appropriate(
     /// This routine checks if the return expression in a block would make sense on its own as a
     /// statement and the return type has been left as default or has been specified as `()`. If so,
     /// it suggests adding a semicolon.
-    fn suggest_missing_semicolon(
+    ///
+    /// If the expression is the expression of a closure without block (`|| expr`), a
+    /// block is needed to be added too (`|| { expr; }`). This is denoted by `needs_block`.
+    pub fn suggest_missing_semicolon(
         &self,
         err: &mut Diagnostic,
         expression: &'tcx hir::Expr<'tcx>,
         expected: Ty<'tcx>,
+        needs_block: bool,
     ) {
         if expected.is_unit() {
             // `BlockTailExpression` only relevant if the tail expr would be
@@ -489,14 +488,29 @@ fn suggest_missing_semicolon(
                 | ExprKind::If(..)
                 | ExprKind::Match(..)
                 | ExprKind::Block(..)
-                    if expression.can_have_side_effects() =>
+                    if expression.can_have_side_effects()
+                        // If the expression is from an external macro, then do not suggest
+                        // adding a semicolon, because there's nowhere to put it.
+                        // See issue #81943.
+                        && !in_external_macro(self.tcx.sess, expression.span) =>
                 {
-                    err.span_suggestion(
-                        expression.span.shrink_to_hi(),
-                        "consider using a semicolon here",
-                        ";".to_string(),
-                        Applicability::MachineApplicable,
-                    );
+                    if needs_block {
+                        err.multipart_suggestion(
+                            "consider using a semicolon here",
+                            vec![
+                                (expression.span.shrink_to_lo(), "{ ".to_owned()),
+                                (expression.span.shrink_to_hi(), "; }".to_owned()),
+                            ],
+                            Applicability::MachineApplicable,
+                        );
+                    } else {
+                        err.span_suggestion(
+                            expression.span.shrink_to_hi(),
+                            "consider using a semicolon here",
+                            ";".to_string(),
+                            Applicability::MachineApplicable,
+                        );
+                    }
                 }
                 _ => (),
             }
index 4e54d554c6ec23a510856618cd708efb3292e86c..0e198907c8d5092ed1a44e476cb0494621353581 100644 (file)
@@ -978,45 +978,9 @@ trait bound{s}",
                     label_span_not_found(&mut err);
                 }
 
-                if let SelfSource::MethodCall(expr) = source
-                    && let Some((fields, substs)) = self.get_field_candidates(span, actual)
-                {
-                    let call_expr =
-                        self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
-                    for candidate_field in fields.iter() {
-                        if let Some(field_path) = self.check_for_nested_field_satisfying(
-                            span,
-                            &|_, field_ty| {
-                                self.lookup_probe(
-                                    span,
-                                    item_name,
-                                    field_ty,
-                                    call_expr,
-                                    ProbeScope::AllTraits,
-                                )
-                                .is_ok()
-                            },
-                            candidate_field,
-                            substs,
-                            vec![],
-                            self.tcx.parent_module(expr.hir_id).to_def_id(),
-                        ) {
-                            let field_path_str = field_path
-                                .iter()
-                                .map(|id| id.name.to_ident_string())
-                                .collect::<Vec<String>>()
-                                .join(".");
-                            debug!("field_path_str: {:?}", field_path_str);
+                self.check_for_field_method(&mut err, source, span, actual, item_name);
 
-                            err.span_suggestion_verbose(
-                                item_name.span.shrink_to_lo(),
-                                "one of the expressions' fields has a method of the same name",
-                                format!("{field_path_str}."),
-                                Applicability::MaybeIncorrect,
-                            );
-                        }
-                    }
-                }
+                self.check_for_unwrap_self(&mut err, source, span, actual, item_name);
 
                 bound_spans.sort();
                 bound_spans.dedup();
@@ -1343,6 +1307,145 @@ fn suggest_constraining_numerical_ty(
         false
     }
 
+    fn check_for_field_method(
+        &self,
+        err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
+        source: SelfSource<'tcx>,
+        span: Span,
+        actual: Ty<'tcx>,
+        item_name: Ident,
+    ) {
+        if let SelfSource::MethodCall(expr) = source
+            && let Some((fields, substs)) = self.get_field_candidates(span, actual)
+        {
+            let call_expr = self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
+            for candidate_field in fields.iter() {
+                if let Some(field_path) = self.check_for_nested_field_satisfying(
+                    span,
+                    &|_, field_ty| {
+                        self.lookup_probe(
+                            span,
+                            item_name,
+                            field_ty,
+                            call_expr,
+                            ProbeScope::AllTraits,
+                        )
+                        .is_ok()
+                    },
+                    candidate_field,
+                    substs,
+                    vec![],
+                    self.tcx.parent_module(expr.hir_id).to_def_id(),
+                ) {
+                    let field_path_str = field_path
+                        .iter()
+                        .map(|id| id.name.to_ident_string())
+                        .collect::<Vec<String>>()
+                        .join(".");
+                    debug!("field_path_str: {:?}", field_path_str);
+
+                    err.span_suggestion_verbose(
+                        item_name.span.shrink_to_lo(),
+                        "one of the expressions' fields has a method of the same name",
+                        format!("{field_path_str}."),
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+            }
+        }
+    }
+
+    fn check_for_unwrap_self(
+        &self,
+        err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
+        source: SelfSource<'tcx>,
+        span: Span,
+        actual: Ty<'tcx>,
+        item_name: Ident,
+    ) {
+        let tcx = self.tcx;
+        let SelfSource::MethodCall(expr) = source else { return; };
+        let call_expr = tcx.hir().expect_expr(tcx.hir().get_parent_node(expr.hir_id));
+
+        let ty::Adt(kind, substs) = actual.kind() else { return; };
+        if !kind.is_enum() {
+            return;
+        }
+
+        let matching_variants: Vec<_> = kind
+            .variants()
+            .iter()
+            .flat_map(|variant| {
+                let [field] = &variant.fields[..] else { return None; };
+                let field_ty = field.ty(tcx, substs);
+
+                // Skip `_`, since that'll just lead to ambiguity.
+                if self.resolve_vars_if_possible(field_ty).is_ty_var() {
+                    return None;
+                }
+
+                self.lookup_probe(span, item_name, field_ty, call_expr, ProbeScope::AllTraits)
+                    .ok()
+                    .map(|pick| (variant, field, pick))
+            })
+            .collect();
+
+        let ret_ty_matches = |diagnostic_item| {
+            if let Some(ret_ty) = self
+                .ret_coercion
+                .as_ref()
+                .map(|c| self.resolve_vars_if_possible(c.borrow().expected_ty()))
+                && let ty::Adt(kind, _) = ret_ty.kind()
+                && tcx.get_diagnostic_item(diagnostic_item) == Some(kind.did())
+            {
+                true
+            } else {
+                false
+            }
+        };
+
+        match &matching_variants[..] {
+            [(_, field, pick)] => {
+                let self_ty = field.ty(tcx, substs);
+                err.span_note(
+                    tcx.def_span(pick.item.def_id),
+                    &format!("the method `{item_name}` exists on the type `{self_ty}`"),
+                );
+                let (article, kind, variant, question) =
+                    if Some(kind.did()) == tcx.get_diagnostic_item(sym::Result) {
+                        ("a", "Result", "Err", ret_ty_matches(sym::Result))
+                    } else if Some(kind.did()) == tcx.get_diagnostic_item(sym::Option) {
+                        ("an", "Option", "None", ret_ty_matches(sym::Option))
+                    } else {
+                        return;
+                    };
+                if question {
+                    err.span_suggestion_verbose(
+                        expr.span.shrink_to_hi(),
+                        format!(
+                            "use the `?` operator to extract the `{self_ty}` value, propagating \
+                            {article} `{kind}::{variant}` value to the caller"
+                        ),
+                        "?".to_owned(),
+                        Applicability::MachineApplicable,
+                    );
+                } else {
+                    err.span_suggestion_verbose(
+                        expr.span.shrink_to_hi(),
+                        format!(
+                            "consider using `{kind}::expect` to unwrap the `{self_ty}` value, \
+                             panicking if the value is {article} `{kind}::{variant}`"
+                        ),
+                        ".expect(\"REASON\")".to_owned(),
+                        Applicability::HasPlaceholders,
+                    );
+                }
+            }
+            // FIXME(compiler-errors): Support suggestions for other matching enum variants
+            _ => {}
+        }
+    }
+
     pub(crate) fn note_unmet_impls_on_type(
         &self,
         err: &mut Diagnostic,
@@ -1662,13 +1765,7 @@ fn suggest_traits_to_import(
                 (self.tcx.mk_mut_ref(self.tcx.lifetimes.re_erased, rcvr_ty), "&mut "),
                 (self.tcx.mk_imm_ref(self.tcx.lifetimes.re_erased, rcvr_ty), "&"),
             ] {
-                match self.lookup_probe(
-                    span,
-                    item_name,
-                    *rcvr_ty,
-                    rcvr,
-                    crate::check::method::probe::ProbeScope::AllTraits,
-                ) {
+                match self.lookup_probe(span, item_name, *rcvr_ty, rcvr, ProbeScope::AllTraits) {
                     Ok(pick) => {
                         // If the method is defined for the receiver we have, it likely wasn't `use`d.
                         // We point at the method, but we just skip the rest of the check for arbitrary
@@ -1700,13 +1797,15 @@ fn suggest_traits_to_import(
                     (self.tcx.mk_diagnostic_item(*rcvr_ty, sym::Arc), "Arc::new"),
                     (self.tcx.mk_diagnostic_item(*rcvr_ty, sym::Rc), "Rc::new"),
                 ] {
-                    if let Some(new_rcvr_t) = *rcvr_ty && let Ok(pick) = self.lookup_probe(
-                        span,
-                        item_name,
-                        new_rcvr_t,
-                        rcvr,
-                        crate::check::method::probe::ProbeScope::AllTraits,
-                    ) {
+                    if let Some(new_rcvr_t) = *rcvr_ty
+                        && let Ok(pick) = self.lookup_probe(
+                            span,
+                            item_name,
+                            new_rcvr_t,
+                            rcvr,
+                            ProbeScope::AllTraits,
+                        )
+                    {
                         debug!("try_alt_rcvr: pick candidate {:?}", pick);
                         let did = Some(pick.item.container.id());
                         // We don't want to suggest a container type when the missing
index a6c7573b787c6496a4f8fd597ce64042a58a66ed..20ef97c085f1884296fda4be45551b6cc97c46ba 100644 (file)
@@ -1228,7 +1228,7 @@ fn check_impl<'tcx>(
                     fcx.body_id,
                     &trait_ref,
                     ast_trait_ref.path.span,
-                    Some(item),
+                    item,
                 );
                 debug!(?obligations);
                 for obligation in obligations {
index 00f0d1e6f02a9744bd014ce2ab7e243789138e41..f28184c74d35548518765421a2f957972b580137 100644 (file)
@@ -16,48 +16,32 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
         used_trait_imports.extend(imports.iter());
     }
 
-    for id in tcx.hir().items() {
-        if matches!(tcx.def_kind(id.def_id), DefKind::Use) {
-            if tcx.visibility(id.def_id).is_public() {
-                continue;
-            }
-            let item = tcx.hir().item(id);
-            if item.span.is_dummy() {
-                continue;
-            }
-            if let hir::ItemKind::Use(path, _) = item.kind {
-                check_import(tcx, &mut used_trait_imports, item.item_id(), path.span);
-            }
+    for &id in tcx.maybe_unused_trait_imports(()) {
+        debug_assert_eq!(tcx.def_kind(id), DefKind::Use);
+        if tcx.visibility(id).is_public() {
+            continue;
+        }
+        if used_trait_imports.contains(&id) {
+            continue;
         }
+        let item = tcx.hir().expect_item(id);
+        if item.span.is_dummy() {
+            continue;
+        }
+        let hir::ItemKind::Use(path, _) = item.kind else { unreachable!() };
+        tcx.struct_span_lint_hir(lint::builtin::UNUSED_IMPORTS, item.hir_id(), path.span, |lint| {
+            let msg = if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(path.span) {
+                format!("unused import: `{}`", snippet)
+            } else {
+                "unused import".to_owned()
+            };
+            lint.build(&msg).emit();
+        });
     }
 
     unused_crates_lint(tcx);
 }
 
-fn check_import<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    used_trait_imports: &mut FxHashSet<LocalDefId>,
-    item_id: hir::ItemId,
-    span: Span,
-) {
-    if !tcx.maybe_unused_trait_import(item_id.def_id) {
-        return;
-    }
-
-    if used_trait_imports.contains(&item_id.def_id) {
-        return;
-    }
-
-    tcx.struct_span_lint_hir(lint::builtin::UNUSED_IMPORTS, item_id.hir_id(), span, |lint| {
-        let msg = if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(span) {
-            format!("unused import: `{}`", snippet)
-        } else {
-            "unused import".to_owned()
-        };
-        lint.build(&msg).emit();
-    });
-}
-
 fn unused_crates_lint(tcx: TyCtxt<'_>) {
     let lint = lint::builtin::UNUSED_EXTERN_CRATES;
 
index d08d9938708c914cfab09270c0519c4ef99f970a..9f4e6a46d73220596ce13b2108f80868a101805b 100644 (file)
@@ -2,7 +2,7 @@
 //! up data structures required by type-checking/codegen.
 
 use crate::errors::{CopyImplOnNonAdt, CopyImplOnTypeWithDtor, DropImplOnWrongItem};
-use rustc_errors::struct_span_err;
+use rustc_errors::{struct_span_err, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::lang_items::LangItem;
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::{RegionckMode, TyCtxtInferExt};
 use rustc_middle::ty::adjustment::CoerceUnsizedInfo;
-use rustc_middle::ty::TypeFoldable;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeFoldable};
 use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
 use rustc_trait_selection::traits::misc::{can_type_implement_copy, CopyImplementationError};
 use rustc_trait_selection::traits::predicate_for_trait_def;
 use rustc_trait_selection::traits::{self, ObligationCause, TraitEngine, TraitEngineExt};
+use std::collections::BTreeMap;
 
 pub fn check_trait(tcx: TyCtxt<'_>, trait_def_id: DefId) {
     let lang_items = tcx.lang_items();
@@ -91,8 +91,26 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
                 E0204,
                 "the trait `Copy` may not be implemented for this type"
             );
+
+            // We'll try to suggest constraining type parameters to fulfill the requirements of
+            // their `Copy` implementation.
+            let mut generics = None;
+            if let ty::Adt(def, _substs) = self_type.kind() {
+                let self_def_id = def.did();
+                if let Some(local) = self_def_id.as_local() {
+                    let self_item = tcx.hir().expect_item(local);
+                    generics = self_item.kind.generics();
+                }
+            }
+            let mut errors: BTreeMap<_, Vec<_>> = Default::default();
+            let mut bounds = vec![];
+
             for (field, ty) in fields {
                 let field_span = tcx.def_span(field.did);
+                let field_ty_span = match tcx.hir().get_if_local(field.did) {
+                    Some(hir::Node::Field(field_def)) => field_def.ty.span,
+                    _ => field_span,
+                };
                 err.span_label(field_span, "this field does not implement `Copy`");
                 // Spin up a new FulfillmentContext, so we can get the _precise_ reason
                 // why this field does not implement Copy. This is useful because sometimes
@@ -105,7 +123,7 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
                         param_env,
                         ty,
                         tcx.lang_items().copy_trait().unwrap(),
-                        traits::ObligationCause::dummy_with_span(field_span),
+                        traits::ObligationCause::dummy_with_span(field_ty_span),
                     );
                     for error in fulfill_cx.select_all_or_error(&infcx) {
                         let error_predicate = error.obligation.predicate;
@@ -115,17 +133,46 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
                         // FIXME: This error could be more descriptive, especially if the error_predicate
                         // contains a foreign type or if it's a deeply nested type...
                         if error_predicate != error.root_obligation.predicate {
-                            err.span_note(
-                                error.obligation.cause.span,
-                                &format!(
-                                    "the `Copy` impl for `{}` requires that `{}`",
-                                    ty, error_predicate
-                                ),
-                            );
+                            errors
+                                .entry((ty.to_string(), error_predicate.to_string()))
+                                .or_default()
+                                .push(error.obligation.cause.span);
+                        }
+                        if let ty::PredicateKind::Trait(ty::TraitPredicate {
+                            trait_ref,
+                            polarity: ty::ImplPolarity::Positive,
+                            ..
+                        }) = error_predicate.kind().skip_binder()
+                        {
+                            let ty = trait_ref.self_ty();
+                            if let ty::Param(_) = ty.kind() {
+                                bounds.push((
+                                    format!("{ty}"),
+                                    trait_ref.print_only_trait_path().to_string(),
+                                    Some(trait_ref.def_id),
+                                ));
+                            }
                         }
                     }
                 });
             }
+            for ((ty, error_predicate), spans) in errors {
+                let span: MultiSpan = spans.into();
+                err.span_note(
+                    span,
+                    &format!("the `Copy` impl for `{}` requires that `{}`", ty, error_predicate),
+                );
+            }
+            if let Some(generics) = generics {
+                suggest_constraining_type_params(
+                    tcx,
+                    generics,
+                    &mut err,
+                    bounds.iter().map(|(param, constraint, def_id)| {
+                        (param.as_str(), constraint.as_str(), *def_id)
+                    }),
+                );
+            }
             err.emit();
         }
         Err(CopyImplementationError::NotAnAdt) => {
index 3f1b4828d1af36089e11fa39965c09f6fc0a132f..3903448a00731b25feaa35ef0e42d2cbba2601b4 100644 (file)
@@ -57,7 +57,7 @@ fn enforce_trait_manually_implementable(
             E0322,
             "explicit impls for the `Pointee` trait are not permitted"
         )
-        .span_label(span, "impl of 'Pointee' not allowed")
+        .span_label(span, "impl of `Pointee` not allowed")
         .emit();
         return;
     }
@@ -70,7 +70,7 @@ fn enforce_trait_manually_implementable(
             E0322,
             "explicit impls for the `DiscriminantKind` trait are not permitted"
         )
-        .span_label(span, "impl of 'DiscriminantKind' not allowed")
+        .span_label(span, "impl of `DiscriminantKind` not allowed")
         .emit();
         return;
     }
@@ -83,7 +83,7 @@ fn enforce_trait_manually_implementable(
             E0322,
             "explicit impls for the `Sized` trait are not permitted"
         )
-        .span_label(span, "impl of 'Sized' not allowed")
+        .span_label(span, "impl of `Sized` not allowed")
         .emit();
         return;
     }
index 4322440d6856bf53af3d710f687b25d314028c4a..838980e08aa0459687fe5baa6372dafde0f2a88a 100644 (file)
@@ -1364,7 +1364,6 @@ fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) {
 
     fn has_late_bound_regions<'tcx>(
         tcx: TyCtxt<'tcx>,
-        def_id: LocalDefId,
         generics: &'tcx hir::Generics<'tcx>,
         decl: &'tcx hir::FnDecl<'tcx>,
     ) -> Option<Span> {
@@ -1373,14 +1372,9 @@ fn has_late_bound_regions<'tcx>(
             outer_index: ty::INNERMOST,
             has_late_bound_regions: None,
         };
-        let late_bound_map = tcx.is_late_bound_map(def_id);
-        let is_late_bound = |id| {
-            let id = tcx.hir().local_def_id(id);
-            late_bound_map.map_or(false, |(_, set)| set.contains(&id))
-        };
         for param in generics.params {
             if let GenericParamKind::Lifetime { .. } = param.kind {
-                if is_late_bound(param.hir_id) {
+                if tcx.is_late_bound(param.hir_id) {
                     return Some(param.span);
                 }
             }
@@ -1392,25 +1386,25 @@ fn has_late_bound_regions<'tcx>(
     match node {
         Node::TraitItem(item) => match item.kind {
             hir::TraitItemKind::Fn(ref sig, _) => {
-                has_late_bound_regions(tcx, item.def_id, &item.generics, sig.decl)
+                has_late_bound_regions(tcx, &item.generics, sig.decl)
             }
             _ => None,
         },
         Node::ImplItem(item) => match item.kind {
             hir::ImplItemKind::Fn(ref sig, _) => {
-                has_late_bound_regions(tcx, item.def_id, &item.generics, sig.decl)
+                has_late_bound_regions(tcx, &item.generics, sig.decl)
             }
             _ => None,
         },
         Node::ForeignItem(item) => match item.kind {
             hir::ForeignItemKind::Fn(fn_decl, _, ref generics) => {
-                has_late_bound_regions(tcx, item.def_id, generics, fn_decl)
+                has_late_bound_regions(tcx, generics, fn_decl)
             }
             _ => None,
         },
         Node::Item(item) => match item.kind {
             hir::ItemKind::Fn(ref sig, .., ref generics, _) => {
-                has_late_bound_regions(tcx, item.def_id, generics, sig.decl)
+                has_late_bound_regions(tcx, generics, sig.decl)
             }
             _ => None,
         },
@@ -1594,41 +1588,20 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
         _ => None,
     };
 
-    let mut opt_self = None;
-    let mut allow_defaults = false;
-
     let no_generics = hir::Generics::empty();
-    let ast_generics = match node {
-        Node::TraitItem(item) => &item.generics,
-
-        Node::ImplItem(item) => &item.generics,
-
+    let ast_generics = node.generics().unwrap_or(&no_generics);
+    let (opt_self, allow_defaults) = match node {
         Node::Item(item) => {
             match item.kind {
-                ItemKind::Fn(.., ref generics, _)
-                | ItemKind::Impl(hir::Impl { ref generics, .. }) => generics,
-
-                ItemKind::TyAlias(_, ref generics)
-                | ItemKind::Enum(_, ref generics)
-                | ItemKind::Struct(_, ref generics)
-                | ItemKind::OpaqueTy(hir::OpaqueTy { ref generics, .. })
-                | ItemKind::Union(_, ref generics) => {
-                    allow_defaults = true;
-                    generics
-                }
-
-                ItemKind::Trait(_, _, ref generics, ..)
-                | ItemKind::TraitAlias(ref generics, ..) => {
+                ItemKind::Trait(..) | ItemKind::TraitAlias(..) => {
                     // Add in the self type parameter.
                     //
                     // Something of a hack: use the node id for the trait, also as
                     // the node id for the Self type parameter.
-                    let param_id = item.def_id;
-
-                    opt_self = Some(ty::GenericParamDef {
+                    let opt_self = Some(ty::GenericParamDef {
                         index: 0,
                         name: kw::SelfUpper,
-                        def_id: param_id.to_def_id(),
+                        def_id,
                         pure_wrt_drop: false,
                         kind: ty::GenericParamDefKind::Type {
                             has_default: false,
@@ -1637,21 +1610,17 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
                         },
                     });
 
-                    allow_defaults = true;
-                    generics
+                    (opt_self, true)
                 }
-
-                _ => &no_generics,
+                ItemKind::TyAlias(..)
+                | ItemKind::Enum(..)
+                | ItemKind::Struct(..)
+                | ItemKind::OpaqueTy(..)
+                | ItemKind::Union(..) => (None, true),
+                _ => (None, false),
             }
         }
-
-        Node::ForeignItem(item) => match item.kind {
-            ForeignItemKind::Static(..) => &no_generics,
-            ForeignItemKind::Fn(_, _, ref generics) => generics,
-            ForeignItemKind::Type => &no_generics,
-        },
-
-        _ => &no_generics,
+        _ => (None, false),
     };
 
     let has_self = opt_self.is_some();
@@ -1671,7 +1640,7 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
         params.push(opt_self);
     }
 
-    let early_lifetimes = early_bound_lifetimes_from_generics(tcx, hir_id.owner, ast_generics);
+    let early_lifetimes = early_bound_lifetimes_from_generics(tcx, ast_generics);
     params.extend(early_lifetimes.enumerate().map(|(i, param)| ty::GenericParamDef {
         name: param.name.ident().name,
         index: own_start + i as u32,
@@ -2054,23 +2023,10 @@ fn impl_polarity(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ImplPolarity {
 /// `resolve_lifetime::early_bound_lifetimes`.
 fn early_bound_lifetimes_from_generics<'a, 'tcx: 'a>(
     tcx: TyCtxt<'tcx>,
-    def_id: LocalDefId,
     generics: &'a hir::Generics<'a>,
 ) -> impl Iterator<Item = &'a hir::GenericParam<'a>> + Captures<'tcx> {
-    let late_bound_map = if generics.params.is_empty() {
-        // This function may be called on `def_id == CRATE_DEF_ID`,
-        // which makes `is_late_bound_map` ICE.  Don't even try if there
-        // is no generic parameter.
-        None
-    } else {
-        tcx.is_late_bound_map(def_id)
-    };
-    let is_late_bound = move |hir_id| {
-        let id = tcx.hir().local_def_id(hir_id);
-        late_bound_map.map_or(false, |(_, set)| set.contains(&id))
-    };
     generics.params.iter().filter(move |param| match param.kind {
-        GenericParamKind::Lifetime { .. } => !is_late_bound(param.hir_id),
+        GenericParamKind::Lifetime { .. } => !tcx.is_late_bound(param.hir_id),
         _ => false,
     })
 }
@@ -2255,7 +2211,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
     // have to be careful to only iterate over early-bound regions.
     let mut index = parent_count
         + has_own_self as u32
-        + early_bound_lifetimes_from_generics(tcx, hir_id.owner, ast_generics).count() as u32;
+        + early_bound_lifetimes_from_generics(tcx, ast_generics).count() as u32;
 
     // Collect the predicates that were written inline by the user on each
     // type parameter (e.g., `<T: Foo>`).
index 4b6f80ce57a83eced8d248eeef0fe4cee04d1968..7e3fefe4502d2c1bc580377c4441cb70f8601502 100644 (file)
@@ -161,38 +161,23 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<
             // We've encountered an `AnonConst` in some path, so we need to
             // figure out which generic parameter it corresponds to and return
             // the relevant type.
-            let filtered = path.segments.iter().find_map(|seg| {
-                seg.args?
-                    .args
+            let Some((arg_index, segment)) = path.segments.iter().find_map(|seg| {
+                let args = seg.args?;
+                args.args
+                .iter()
+                .filter(|arg| arg.is_ty_or_const())
+                .position(|arg| arg.id() == hir_id)
+                .map(|index| (index, seg)).or_else(|| args.bindings
                     .iter()
-                    .filter(|arg| arg.is_ty_or_const())
-                    .position(|arg| arg.id() == hir_id)
-                    .map(|index| (index, seg))
-            });
-
-            // FIXME(associated_const_generics): can we blend this with iteration above?
-            let (arg_index, segment) = match filtered {
-                None => {
-                    let binding_filtered = path.segments.iter().find_map(|seg| {
-                        seg.args?
-                            .bindings
-                            .iter()
-                            .filter_map(TypeBinding::opt_const)
-                            .position(|ct| ct.hir_id == hir_id)
-                            .map(|idx| (idx, seg))
-                    });
-                    match binding_filtered {
-                        Some(inner) => inner,
-                        None => {
-                            tcx.sess.delay_span_bug(
-                                tcx.def_span(def_id),
-                                "no arg matching AnonConst in path",
-                            );
-                            return None;
-                        }
-                    }
-                }
-                Some(inner) => inner,
+                    .filter_map(TypeBinding::opt_const)
+                    .position(|ct| ct.hir_id == hir_id)
+                    .map(|idx| (idx, seg)))
+            }) else {
+                tcx.sess.delay_span_bug(
+                    tcx.def_span(def_id),
+                    "no arg matching AnonConst in path",
+                );
+                return None;
             };
 
             // Try to use the segment resolution if it is valid, otherwise we
index f1dc3cbbac459f72305b4ebe5d09d318d5536289..bc3a3db9fdadb3e7ce35a12f4d6c71f7fd39f738 100644 (file)
@@ -514,7 +514,9 @@ fn suggest_adding_lifetime_args(&self, err: &mut Diagnostic) {
                             param_names
                                 .iter()
                                 .take(num_params_to_take)
-                                .map(|p| p.as_str())
+                                .map(|def_id| {
+                                    self.tcx.item_name(def_id.to_def_id()).to_ident_string()
+                                })
                                 .collect::<Vec<_>>()
                                 .join(", ")
                         } else {
index a810e8c0e12d6e02cb8b7b99b39eb587faf6f615..b3284050f0530fff17fc550bf2d4677e71668f6c 100644 (file)
@@ -324,6 +324,12 @@ changelog-seen = 2
 # a Nix toolchain on non-NixOS distributions.
 #patch-binaries-for-nix = false
 
+# Collect information and statistics about the current build and writes it to
+# disk. Enabling this or not has no impact on the resulting build output. The
+# schema of the file generated by the build metrics feature is unstable, and
+# this is not intended to be used during local development.
+#metrics = false
+
 # =============================================================================
 # General install configuration options
 # =============================================================================
index cb4e438f8bea22cbd34455f8aed2791f2bc5e856..7a79fb77dea554307d289c1b0d02e33e6af47b5e 100644 (file)
@@ -67,14 +67,13 @@ pub trait ToOwned {
     /// Basic usage:
     ///
     /// ```
-    /// # #![feature(toowned_clone_into)]
     /// let mut s: String = String::new();
     /// "hello".clone_into(&mut s);
     ///
     /// let mut v: Vec<i32> = Vec::new();
     /// [1, 2][..].clone_into(&mut v);
     /// ```
-    #[unstable(feature = "toowned_clone_into", reason = "recently added", issue = "41263")]
+    #[stable(feature = "toowned_clone_into", since = "1.63.0")]
     fn clone_into(&self, target: &mut Self::Owned) {
         *target = self.to_owned();
     }
index c07536f0d0ce1c997a3d415d8886fec4237ec1cd..cc395759b207859abb78254bb611a3f7d49a3bb8 100644 (file)
 //! definition is just using `T*` can lead to undefined behavior, as
 //! described in [rust-lang/unsafe-code-guidelines#198][ucg#198].
 //!
+//! # Considerations for unsafe code
+//!
+//! **Warning: This section is not normative and is subject to change, possibly
+//! being relaxed in the future! It is a simplified summary of the rules
+//! currently implemented in the compiler.**
+//!
+//! The aliasing rules for `Box<T>` are the same as for `&mut T`. `Box<T>`
+//! asserts uniqueness over its content. Using raw pointers derived from a box
+//! after that box has been mutated through, moved or borrowed as `&mut T`
+//! is not allowed. For more guidance on working with box from unsafe code, see
+//! [rust-lang/unsafe-code-guidelines#326][ucg#326].
+//!
+//!
 //! [ucg#198]: https://github.com/rust-lang/unsafe-code-guidelines/issues/198
+//! [ucg#326]: https://github.com/rust-lang/unsafe-code-guidelines/issues/326
 //! [dereferencing]: core::ops::Deref
 //! [`Box::<T>::from_raw(value)`]: Box::from_raw
 //! [`Global`]: crate::alloc::Global
@@ -192,7 +206,25 @@ impl<T> Box<T> {
     /// ```
     /// let five = Box::new(5);
     /// ```
-    #[cfg(not(no_global_oom_handling))]
+    #[cfg(all(not(no_global_oom_handling), not(bootstrap)))]
+    #[inline(always)]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[must_use]
+    pub fn new(x: T) -> Self {
+        #[rustc_box]
+        Box::new(x)
+    }
+
+    /// Allocates memory on the heap and then places `x` into it.
+    ///
+    /// This doesn't actually allocate if `T` is zero-sized.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let five = Box::new(5);
+    /// ```
+    #[cfg(all(not(no_global_oom_handling), bootstrap))]
     #[inline(always)]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[must_use]
@@ -252,14 +284,21 @@ pub fn new_zeroed() -> Box<mem::MaybeUninit<T>> {
         Self::new_zeroed_in(Global)
     }
 
-    /// Constructs a new `Pin<Box<T>>`. If `T` does not implement `Unpin`, then
+    /// Constructs a new `Pin<Box<T>>`. If `T` does not implement [`Unpin`], then
     /// `x` will be pinned in memory and unable to be moved.
+    ///
+    /// Constructing and pinning of the `Box` can also be done in two steps: `Box::pin(x)`
+    /// does the same as <code>[Box::into_pin]\([Box::new]\(x))</code>. Consider using
+    /// [`into_pin`](Box::into_pin) if you already have a `Box<T>`, or if you want to
+    /// construct a (pinned) `Box` in a different way than with [`Box::new`].
     #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "pin", since = "1.33.0")]
     #[must_use]
     #[inline(always)]
     pub fn pin(x: T) -> Pin<Box<T>> {
-        (box x).into()
+        (#[cfg_attr(not(bootstrap), rustc_box)]
+        Box::new(x))
+        .into()
     }
 
     /// Allocates memory on the heap then places `x` into it,
@@ -539,8 +578,13 @@ pub const fn try_new_zeroed_in(alloc: A) -> Result<Box<mem::MaybeUninit<T>, A>,
         unsafe { Ok(Box::from_raw_in(ptr.as_ptr(), alloc)) }
     }
 
-    /// Constructs a new `Pin<Box<T, A>>`. If `T` does not implement `Unpin`, then
+    /// Constructs a new `Pin<Box<T, A>>`. If `T` does not implement [`Unpin`], then
     /// `x` will be pinned in memory and unable to be moved.
+    ///
+    /// Constructing and pinning of the `Box` can also be done in two steps: `Box::pin_in(x, alloc)`
+    /// does the same as <code>[Box::into_pin]\([Box::new_in]\(x, alloc))</code>. Consider using
+    /// [`into_pin`](Box::into_pin) if you already have a `Box<T, A>`, or if you want to
+    /// construct a (pinned) `Box` in a different way than with [`Box::new_in`].
     #[cfg(not(no_global_oom_handling))]
     #[unstable(feature = "allocator_api", issue = "32838")]
     #[rustc_const_unstable(feature = "const_box", issue = "92521")]
@@ -1156,19 +1200,44 @@ pub const fn leak<'a>(b: Self) -> &'a mut T
         unsafe { &mut *mem::ManuallyDrop::new(b).0.as_ptr() }
     }
 
-    /// Converts a `Box<T>` into a `Pin<Box<T>>`
+    /// Converts a `Box<T>` into a `Pin<Box<T>>`. If `T` does not implement [`Unpin`], then
+    /// `*boxed` will be pinned in memory and unable to be moved.
     ///
     /// This conversion does not allocate on the heap and happens in place.
     ///
     /// This is also available via [`From`].
-    #[unstable(feature = "box_into_pin", issue = "62370")]
+    ///
+    /// Constructing and pinning a `Box` with <code>Box::into_pin([Box::new]\(x))</code>
+    /// can also be written more concisely using <code>[Box::pin]\(x)</code>.
+    /// This `into_pin` method is useful if you already have a `Box<T>`, or you are
+    /// constructing a (pinned) `Box` in a different way than with [`Box::new`].
+    ///
+    /// # Notes
+    ///
+    /// It's not recommended that crates add an impl like `From<Box<T>> for Pin<T>`,
+    /// as it'll introduce an ambiguity when calling `Pin::from`.
+    /// A demonstration of such a poor impl is shown below.
+    ///
+    /// ```compile_fail
+    /// # use std::pin::Pin;
+    /// struct Foo; // A type defined in this crate.
+    /// impl From<Box<()>> for Pin<Foo> {
+    ///     fn from(_: Box<()>) -> Pin<Foo> {
+    ///         Pin::new(Foo)
+    ///     }
+    /// }
+    ///
+    /// let foo = Box::new(());
+    /// let bar = Pin::from(foo);
+    /// ```
+    #[stable(feature = "box_into_pin", since = "1.63.0")]
     #[rustc_const_unstable(feature = "const_box", issue = "92521")]
     pub const fn into_pin(boxed: Self) -> Pin<Self>
     where
         A: 'static,
     {
         // It's not possible to move or replace the insides of a `Pin<Box<T>>`
-        // when `T: !Unpin`,  so it's safe to pin it directly without any
+        // when `T: !Unpin`, so it's safe to pin it directly without any
         // additional requirements.
         unsafe { Pin::new_unchecked(boxed) }
     }
@@ -1186,7 +1255,8 @@ fn drop(&mut self) {
 impl<T: Default> Default for Box<T> {
     /// Creates a `Box<T>`, with the `Default` value for T.
     fn default() -> Self {
-        box T::default()
+        #[cfg_attr(not(bootstrap), rustc_box)]
+        Box::new(T::default())
     }
 }
 
@@ -1404,9 +1474,17 @@ impl<T: ?Sized, A: Allocator> const From<Box<T, A>> for Pin<Box<T, A>>
 where
     A: 'static,
 {
-    /// Converts a `Box<T>` into a `Pin<Box<T>>`
+    /// Converts a `Box<T>` into a `Pin<Box<T>>`. If `T` does not implement [`Unpin`], then
+    /// `*boxed` will be pinned in memory and unable to be moved.
     ///
     /// This conversion does not allocate on the heap and happens in place.
+    ///
+    /// This is also available via [`Box::into_pin`].
+    ///
+    /// Constructing and pinning a `Box` with <code><Pin<Box\<T>>>::from([Box::new]\(x))</code>
+    /// can also be written more concisely using <code>[Box::pin]\(x)</code>.
+    /// This `From` implementation is useful if you already have a `Box<T>`, or you are
+    /// constructing a (pinned) `Box` in a different way than with [`Box::new`].
     fn from(boxed: Box<T, A>) -> Self {
         Box::into_pin(boxed)
     }
@@ -1550,7 +1628,8 @@ fn from(s: Box<str, A>) -> Self {
     /// println!("{boxed:?}");
     /// ```
     fn from(array: [T; N]) -> Box<[T]> {
-        box array
+        #[cfg_attr(not(bootstrap), rustc_box)]
+        Box::new(array)
     }
 }
 
index 390030fa2b21cbd82db95c7d721a539df5818fd4..807c035fdbd0db099ca3ecc0ff943bb4463b2233 100644 (file)
@@ -138,7 +138,11 @@ fn data(&self) -> *mut u8 {
     }
 }
 
-/// A pointer to type-erased data, guaranteed to have a header `H` before the pointed-to location.
+/// A pointer to type-erased data, guaranteed to either be:
+/// 1. `NonNull::dangling()`, in the case where both the pointee (`T`) and
+///    metadata (`H`) are ZSTs.
+/// 2. A pointer to a valid `T` that has a header `H` directly before the
+///    pointed-to location.
 struct WithHeader<H>(NonNull<u8>, PhantomData<H>);
 
 impl<H> WithHeader<H> {
@@ -156,16 +160,27 @@ fn new<T>(header: H, value: T) -> WithHeader<H> {
         };
 
         unsafe {
-            let ptr = alloc::alloc(layout);
-
-            if ptr.is_null() {
-                alloc::handle_alloc_error(layout);
-            }
-            //  Safety:
-            //  -   The size is at least `aligned_header_size`.
-            let ptr = ptr.add(value_offset) as *mut _;
-
-            let ptr = NonNull::new_unchecked(ptr);
+            // Note: It's UB to pass a layout with a zero size to `alloc::alloc`, so
+            // we use `layout.dangling()` for this case, which should have a valid
+            // alignment for both `T` and `H`.
+            let ptr = if layout.size() == 0 {
+                // Some paranoia checking, mostly so that the ThinBox tests are
+                // more able to catch issues.
+                debug_assert!(
+                    value_offset == 0 && mem::size_of::<T>() == 0 && mem::size_of::<H>() == 0
+                );
+                layout.dangling()
+            } else {
+                let ptr = alloc::alloc(layout);
+                if ptr.is_null() {
+                    alloc::handle_alloc_error(layout);
+                }
+                // Safety:
+                // - The size is at least `aligned_header_size`.
+                let ptr = ptr.add(value_offset) as *mut _;
+
+                NonNull::new_unchecked(ptr)
+            };
 
             let result = WithHeader(ptr, PhantomData);
             ptr::write(result.header(), header);
@@ -175,18 +190,28 @@ fn new<T>(header: H, value: T) -> WithHeader<H> {
         }
     }
 
-    //  Safety:
-    //  -   Assumes that `value` can be dereferenced.
+    // Safety:
+    // - Assumes that either `value` can be dereferenced, or is the
+    //   `NonNull::dangling()` we use when both `T` and `H` are ZSTs.
     unsafe fn drop<T: ?Sized>(&self, value: *mut T) {
         unsafe {
+            let value_layout = Layout::for_value_raw(value);
             // SAFETY: Layout must have been computable if we're in drop
-            let (layout, value_offset) =
-                Self::alloc_layout(Layout::for_value_raw(value)).unwrap_unchecked();
+            let (layout, value_offset) = Self::alloc_layout(value_layout).unwrap_unchecked();
 
-            ptr::drop_in_place::<T>(value);
             // We only drop the value because the Pointee trait requires that the metadata is copy
-            // aka trivially droppable
-            alloc::dealloc(self.0.as_ptr().sub(value_offset), layout);
+            // aka trivially droppable.
+            ptr::drop_in_place::<T>(value);
+
+            // Note: Don't deallocate if the layout size is zero, because the pointer
+            // didn't come from the allocator.
+            if layout.size() != 0 {
+                alloc::dealloc(self.0.as_ptr().sub(value_offset), layout);
+            } else {
+                debug_assert!(
+                    value_offset == 0 && mem::size_of::<H>() == 0 && value_layout.size() == 0
+                );
+            }
         }
     }
 
@@ -198,7 +223,9 @@ fn header(&self) -> *mut H {
         //    needed to align the header. Subtracting the header size from the aligned data pointer
         //    will always result in an aligned header pointer, it just may not point to the
         //    beginning of the allocation.
-        unsafe { self.0.as_ptr().sub(Self::header_size()) as *mut H }
+        let hp = unsafe { self.0.as_ptr().sub(Self::header_size()) as *mut H };
+        debug_assert!(hp.is_aligned());
+        hp
     }
 
     fn value(&self) -> *mut u8 {
index c3c1d0c92a86be67d291e2cc05d73f2003620b2f..839088eac21eadf84207b3727f413458210aaa8b 100644 (file)
 /// item's ordering relative to any other item, as determined by the [`Ord`]
 /// trait, changes while it is in the heap. This is normally only possible
 /// through [`Cell`], [`RefCell`], global state, I/O, or unsafe code. The
-/// behavior resulting from such a logic error is not specified (it
-/// could include panics, incorrect results, aborts, memory leaks, or
-/// non-termination) but will not be undefined behavior.
+/// behavior resulting from such a logic error is not specified, but will
+/// be encapsulated to the `BinaryHeap` that observed the logic error and not
+/// result in undefined behavior. This could include panics, incorrect results,
+/// aborts, memory leaks, and non-termination.
 ///
 /// # Examples
 ///
index 264c217c9ef235faa2e96b2b5e485f868a84f3d7..6027991a0ed2fbb9b1e518ba7e937e6fde87ddae 100644 (file)
@@ -64,9 +64,9 @@
 /// It is a logic error for a key to be modified in such a way that the key's ordering relative to
 /// 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.
-/// The behavior resulting from such a logic error is not specified (it could include panics,
-/// incorrect results, aborts, memory leaks, or non-termination) but will not be undefined
-/// behavior.
+/// The behavior resulting from such a logic error is not specified, but will be encapsulated to the
+/// `BTreeMap` that observed the logic error and not result in undefined behavior. This could
+/// include panics, incorrect results, aborts, memory leaks, and non-termination.
 ///
 /// Iterators obtained from functions such as [`BTreeMap::iter`], [`BTreeMap::values`], or
 /// [`BTreeMap::keys`] produce their items in order by key, and take worst-case logarithmic and
index d6733425288d4d50091f07f8c62991f38f26d516..caa629cf4e65e412e4ec9461343b083cf4032f73 100644 (file)
@@ -23,9 +23,9 @@
 /// It is a logic error for an item to be modified in such a way that the item's ordering relative
 /// to any other item, as determined by the [`Ord`] trait, changes while it is in the set. This is
 /// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code.
-/// The behavior resulting from such a logic error is not specified (it could include panics,
-/// incorrect results, aborts, memory leaks, or non-termination) but will not be undefined
-/// behavior.
+/// The behavior resulting from such a logic error is not specified, but will be encapsulated to the
+/// `BTreeSet` that observed the logic error and not result in undefined behavior. This could
+/// include panics, incorrect results, aborts, memory leaks, and non-termination.
 ///
 /// Iterators returned by [`BTreeSet::iter`] produce their items in order, and take worst-case
 /// logarithmic and amortized constant time per item returned.
@@ -770,10 +770,14 @@ pub fn pop_last(&mut self) -> Option<T>
 
     /// Adds a value to the set.
     ///
-    /// If the set did not have an equal element present, `true` is returned.
+    /// Returns whether the value was newly inserted. That is:
     ///
-    /// If the set did have an equal element present, `false` is returned, and
-    /// the entry is not updated. See the [module-level documentation] for more.
+    /// - If the set did not previously contain an equal value, `true` is
+    ///   returned.
+    /// - If the set already contained an equal value, `false` is returned, and
+    ///   the entry is not updated.
+    ///
+    /// See the [module-level documentation] for more.
     ///
     /// [module-level documentation]: index.html#insert-and-complex-keys
     ///
index fd21b3671182bbea095da16d49005a94dcd32e5d..dbfe58056a53e0cedcb7e33a4e5af3c304b601ea 100644 (file)
 #![feature(ptr_sub_ptr)]
 #![feature(receiver_trait)]
 #![feature(set_ptr_value)]
+#![feature(slice_from_ptr_range)]
 #![feature(slice_group_by)]
 #![feature(slice_ptr_get)]
 #![feature(slice_ptr_len)]
 #![feature(allocator_internals)]
 #![feature(allow_internal_unstable)]
 #![feature(associated_type_bounds)]
-#![feature(box_syntax)]
+#![cfg_attr(bootstrap, feature(box_syntax))]
 #![feature(cfg_sanitize)]
 #![feature(const_deref)]
 #![feature(const_mut_refs)]
 #![feature(nll)] // Not necessary, but here to test the `nll` feature.
 #![feature(rustc_allow_const_fn_unstable)]
 #![feature(rustc_attrs)]
+#![feature(pointer_is_aligned)]
 #![feature(slice_internals)]
 #![feature(staged_api)]
+#![feature(stmt_expr_attributes)]
 #![cfg_attr(test, feature(test))]
 #![feature(unboxed_closures)]
 #![feature(unsized_fn_params)]
index d9346daa109c110a3d96996ffc7b4dc333987deb..37898b6655faa259bd2bc544cd658e673dd698f2 100644 (file)
 /// be mindful of side effects.
 ///
 /// [`Vec`]: crate::vec::Vec
-#[cfg(all(not(no_global_oom_handling), not(test)))]
+#[cfg(all(not(no_global_oom_handling), not(test), not(bootstrap)))]
+#[macro_export]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_diagnostic_item = "vec_macro"]
+#[allow_internal_unstable(rustc_attrs, liballoc_internals)]
+macro_rules! vec {
+    () => (
+        $crate::__rust_force_expr!($crate::vec::Vec::new())
+    );
+    ($elem:expr; $n:expr) => (
+        $crate::__rust_force_expr!($crate::vec::from_elem($elem, $n))
+    );
+    ($($x:expr),+ $(,)?) => (
+        $crate::__rust_force_expr!(<[_]>::into_vec(
+            #[rustc_box]
+            $crate::boxed::Box::new([$($x),+])
+        ))
+    );
+}
+
+/// Creates a `Vec` containing the arguments (bootstrap version).
+#[cfg(all(not(no_global_oom_handling), not(test), bootstrap))]
 #[macro_export]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_diagnostic_item = "vec_macro"]
@@ -65,7 +86,7 @@ macro_rules! vec {
         $crate::vec::from_elem($elem, $n)
     );
     ($($x:expr),*) => (
-        $crate::slice::into_vec(box [$($x),*])
+        $crate::slice::into_vec($crate::boxed::Box::new([$($x),*]))
     );
     ($($x:expr,)*) => (vec![$($x),*])
 }
index 199b3c9d0290c22abdd80a6aac327a539d67885e..4a9cecd9b4e1a3f3cf1297d1dbdbdf8f96962c9a 100644 (file)
 pub use core::slice::SliceIndex;
 #[stable(feature = "from_ref", since = "1.28.0")]
 pub use core::slice::{from_mut, from_ref};
+#[unstable(feature = "slice_from_ptr_range", issue = "89792")]
+pub use core::slice::{from_mut_ptr_range, from_ptr_range};
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::slice::{from_raw_parts, from_raw_parts_mut};
 #[stable(feature = "rust1", since = "1.0.0")]
index d5ed3fd18c3b87f43b7191785e814e5a3abe509f..55d51e0a3c4cf282e9916ef1a7417f0391997e93 100644 (file)
@@ -1393,11 +1393,11 @@ impl<T: Clone> Arc<T> {
     /// referred to as clone-on-write.
     ///
     /// However, if there are no other `Arc` pointers to this allocation, but some [`Weak`]
-    /// pointers, then the [`Weak`] pointers will be disassociated and the inner value will not
+    /// pointers, then the [`Weak`] pointers will be dissociated and the inner value will not
     /// be cloned.
     ///
     /// See also [`get_mut`], which will fail rather than cloning the inner value
-    /// or diassociating [`Weak`] pointers.
+    /// or dissociating [`Weak`] pointers.
     ///
     /// [`clone`]: Clone::clone
     /// [`get_mut`]: Arc::get_mut
@@ -1420,7 +1420,7 @@ impl<T: Clone> Arc<T> {
     /// assert_eq!(*other_data, 12);
     /// ```
     ///
-    /// [`Weak`] pointers will be disassociated:
+    /// [`Weak`] pointers will be dissociated:
     ///
     /// ```
     /// use std::sync::Arc;
index d222fcb445f584eec0bdefcc9f05e7d83daf3178..1c0cb6636a134582dc71f078d88e41ba4654a736 100644 (file)
@@ -1107,7 +1107,8 @@ pub fn as_mut_slice(&mut self) -> &mut [T] {
         self
     }
 
-    /// Returns a raw pointer to the vector's buffer.
+    /// Returns a raw pointer to the vector's buffer, or a dangling raw pointer
+    /// valid for zero sized reads if the vector didn't allocate.
     ///
     /// The caller must ensure that the vector outlives the pointer this
     /// function returns, or else it will end up pointing to garbage.
@@ -1144,7 +1145,8 @@ pub fn as_ptr(&self) -> *const T {
         ptr
     }
 
-    /// Returns an unsafe mutable pointer to the vector's buffer.
+    /// Returns an unsafe mutable pointer to the vector's buffer, or a dangling
+    /// raw pointer valid for zero sized reads if the vector didn't allocate.
     ///
     /// The caller must ensure that the vector outlives the pointer this
     /// function returns, or else it will end up pointing to garbage.
@@ -2470,7 +2472,7 @@ unsafe fn spec_extend_from_within(&mut self, src: Range<usize>) {
             // SAFETY:
             // - Both pointers are created from unique slice references (`&mut [_]`)
             //   so they are valid and do not overlap.
-            // - Elements are :Copy so it's OK to to copy them, without doing
+            // - Elements are :Copy so it's OK to copy them, without doing
             //   anything with the original values
             // - `count` is equal to the len of `source`, so source is valid for
             //   `count` reads
@@ -2493,6 +2495,7 @@ unsafe fn spec_extend_from_within(&mut self, src: Range<usize>) {
 impl<T, A: Allocator> ops::Deref for Vec<T, A> {
     type Target = [T];
 
+    #[inline]
     fn deref(&self) -> &[T] {
         unsafe { slice::from_raw_parts(self.as_ptr(), self.len) }
     }
@@ -2500,6 +2503,7 @@ fn deref(&self) -> &[T] {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T, A: Allocator> ops::DerefMut for Vec<T, A> {
+    #[inline]
     fn deref_mut(&mut self) -> &mut [T] {
         unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) }
     }
@@ -2983,12 +2987,15 @@ fn from(s: &mut [T]) -> Vec<T> {
     /// ```
     #[cfg(not(test))]
     fn from(s: [T; N]) -> Vec<T> {
-        <[T]>::into_vec(box s)
+        <[T]>::into_vec(
+            #[cfg_attr(not(bootstrap), rustc_box)]
+            Box::new(s),
+        )
     }
 
     #[cfg(test)]
     fn from(s: [T; N]) -> Vec<T> {
-        crate::slice::into_vec(box s)
+        crate::slice::into_vec(Box::new(s))
     }
 }
 
index 601a87aa4ac899af12c2419fef3d1c2a67b0d106..ffc7944ec7e1b7176e13f7c3ff5d6e9228a9feac 100644 (file)
@@ -42,6 +42,9 @@
 #![feature(panic_update_hook)]
 #![feature(slice_flatten)]
 #![feature(thin_box)]
+#![feature(bench_black_box)]
+#![feature(strict_provenance)]
+#![feature(once_cell)]
 
 use std::collections::hash_map::DefaultHasher;
 use std::hash::{Hash, Hasher};
index 51d2e9324bf2e9e2772582d13737be8b59a76062..70d1db8b45766c373bbf82eeb053020646cf8a36 100644 (file)
@@ -1,3 +1,4 @@
+use core::fmt::Debug;
 use core::mem::size_of;
 use std::boxed::ThinBox;
 
@@ -24,3 +25,231 @@ trait Tr {}
     assert!(is_thin::<[i32]>());
     assert!(is_thin::<i32>());
 }
+
+#[track_caller]
+fn verify_aligned<T>(ptr: *const T) {
+    // Use `black_box` to attempt to obscure the fact that we're calling this
+    // function on pointers that come from box/references, which the compiler
+    // would otherwise realize is impossible (because it would mean we've
+    // already executed UB).
+    //
+    // That is, we'd *like* it to be possible for the asserts in this function
+    // to detect brokenness in the ThinBox impl.
+    //
+    // It would probably be better if we instead had these as debug_asserts
+    // inside `ThinBox`, prior to the point where we do the UB. Anyway, in
+    // practice these checks are mostly just smoke-detectors for an extremely
+    // broken `ThinBox` impl, since it's an extremely subtle piece of code.
+    let ptr = core::hint::black_box(ptr);
+    let align = core::mem::align_of::<T>();
+    assert!(
+        (ptr.addr() & (align - 1)) == 0 && !ptr.is_null(),
+        "misaligned ThinBox data; valid pointers to `{}` should be aligned to {align}: {ptr:p}",
+        core::any::type_name::<T>(),
+    );
+}
+
+#[track_caller]
+fn check_thin_sized<T: Debug + PartialEq + Clone>(make: impl FnOnce() -> T) {
+    let value = make();
+    let boxed = ThinBox::new(value.clone());
+    let val = &*boxed;
+    verify_aligned(val as *const T);
+    assert_eq!(val, &value);
+}
+
+#[track_caller]
+fn check_thin_dyn<T: Debug + PartialEq + Clone>(make: impl FnOnce() -> T) {
+    let value = make();
+    let wanted_debug = format!("{value:?}");
+    let boxed: ThinBox<dyn Debug> = ThinBox::new_unsize(value.clone());
+    let val = &*boxed;
+    // wide reference -> wide pointer -> thin pointer
+    verify_aligned(val as *const dyn Debug as *const T);
+    let got_debug = format!("{val:?}");
+    assert_eq!(wanted_debug, got_debug);
+}
+
+macro_rules! define_test {
+    (
+        @test_name: $testname:ident;
+
+        $(#[$m:meta])*
+        struct $Type:ident($inner:ty);
+
+        $($test_stmts:tt)*
+    ) => {
+        #[test]
+        fn $testname() {
+            use core::sync::atomic::{AtomicIsize, Ordering};
+            // Define the type, and implement new/clone/drop in such a way that
+            // the number of live instances will be counted.
+            $(#[$m])*
+            #[derive(Debug, PartialEq)]
+            struct $Type {
+                _priv: $inner,
+            }
+
+            impl Clone for $Type {
+                fn clone(&self) -> Self {
+                    verify_aligned(self);
+                    Self::new(self._priv.clone())
+                }
+            }
+
+            impl Drop for $Type {
+                fn drop(&mut self) {
+                    verify_aligned(self);
+                    Self::modify_live(-1);
+                }
+            }
+
+            impl $Type {
+                fn new(i: $inner) -> Self {
+                    Self::modify_live(1);
+                    Self { _priv: i }
+                }
+
+                fn modify_live(n: isize) -> isize {
+                    static COUNTER: AtomicIsize = AtomicIsize::new(0);
+                    COUNTER.fetch_add(n, Ordering::Relaxed) + n
+                }
+
+                fn live_objects() -> isize {
+                    Self::modify_live(0)
+                }
+            }
+            // Run the test statements
+            let _: () = { $($test_stmts)* };
+            // Check that we didn't leak anything, or call drop too many times.
+            assert_eq!(
+                $Type::live_objects(), 0,
+                "Wrong number of drops of {}, `initializations - drops` should be 0.",
+                stringify!($Type),
+            );
+        }
+    };
+}
+
+define_test! {
+    @test_name: align1zst;
+    struct Align1Zst(());
+
+    check_thin_sized(|| Align1Zst::new(()));
+    check_thin_dyn(|| Align1Zst::new(()));
+}
+
+define_test! {
+    @test_name: align1small;
+    struct Align1Small(u8);
+
+    check_thin_sized(|| Align1Small::new(50));
+    check_thin_dyn(|| Align1Small::new(50));
+}
+
+define_test! {
+    @test_name: align1_size_not_pow2;
+    struct Align64NotPow2Size([u8; 79]);
+
+    check_thin_sized(|| Align64NotPow2Size::new([100; 79]));
+    check_thin_dyn(|| Align64NotPow2Size::new([100; 79]));
+}
+
+define_test! {
+    @test_name: align1big;
+    struct Align1Big([u8; 256]);
+
+    check_thin_sized(|| Align1Big::new([5u8; 256]));
+    check_thin_dyn(|| Align1Big::new([5u8; 256]));
+}
+
+// Note: `#[repr(align(2))]` is worth testing because
+// - can have pointers which are misaligned, unlike align(1)
+// - is still expected to have an alignment less than the alignment of a vtable.
+define_test! {
+    @test_name: align2zst;
+    #[repr(align(2))]
+    struct Align2Zst(());
+
+    check_thin_sized(|| Align2Zst::new(()));
+    check_thin_dyn(|| Align2Zst::new(()));
+}
+
+define_test! {
+    @test_name: align2small;
+    #[repr(align(2))]
+    struct Align2Small(u8);
+
+    check_thin_sized(|| Align2Small::new(60));
+    check_thin_dyn(|| Align2Small::new(60));
+}
+
+define_test! {
+    @test_name: align2full;
+    #[repr(align(2))]
+    struct Align2Full([u8; 2]);
+    check_thin_sized(|| Align2Full::new([3u8; 2]));
+    check_thin_dyn(|| Align2Full::new([3u8; 2]));
+}
+
+define_test! {
+    @test_name: align2_size_not_pow2;
+    #[repr(align(2))]
+    struct Align2NotPower2Size([u8; 6]);
+
+    check_thin_sized(|| Align2NotPower2Size::new([3; 6]));
+    check_thin_dyn(|| Align2NotPower2Size::new([3; 6]));
+}
+
+define_test! {
+    @test_name: align2big;
+    #[repr(align(2))]
+    struct Align2Big([u8; 256]);
+
+    check_thin_sized(|| Align2Big::new([5u8; 256]));
+    check_thin_dyn(|| Align2Big::new([5u8; 256]));
+}
+
+define_test! {
+    @test_name: align64zst;
+    #[repr(align(64))]
+    struct Align64Zst(());
+
+    check_thin_sized(|| Align64Zst::new(()));
+    check_thin_dyn(|| Align64Zst::new(()));
+}
+
+define_test! {
+    @test_name: align64small;
+    #[repr(align(64))]
+    struct Align64Small(u8);
+
+    check_thin_sized(|| Align64Small::new(50));
+    check_thin_dyn(|| Align64Small::new(50));
+}
+
+define_test! {
+    @test_name: align64med;
+    #[repr(align(64))]
+    struct Align64Med([u8; 64]);
+    check_thin_sized(|| Align64Med::new([10; 64]));
+    check_thin_dyn(|| Align64Med::new([10; 64]));
+}
+
+define_test! {
+    @test_name: align64_size_not_pow2;
+    #[repr(align(64))]
+    struct Align64NotPow2Size([u8; 192]);
+
+    check_thin_sized(|| Align64NotPow2Size::new([10; 192]));
+    check_thin_dyn(|| Align64NotPow2Size::new([10; 192]));
+}
+
+define_test! {
+    @test_name: align64big;
+    #[repr(align(64))]
+    struct Align64Big([u8; 256]);
+
+    check_thin_sized(|| Align64Big::new([10; 256]));
+    check_thin_dyn(|| Align64Big::new([10; 256]));
+}
index 9df66263459b155eacffef46c40a9ec271da5dd7..ff726ff7559d892b2ac436f155ef85a50571e899 100644 (file)
@@ -109,6 +109,17 @@ fn write_str_macro_debug(bh: &mut Bencher) {
     });
 }
 
+#[bench]
+fn write_str_macro_debug_ascii(bh: &mut Bencher) {
+    bh.iter(|| {
+        let mut mem = String::new();
+        let wr = &mut mem as &mut dyn fmt::Write;
+        for _ in 0..1000 {
+            write!(wr, "{:?}", "Hello, World!").unwrap();
+        }
+    });
+}
+
 #[bench]
 fn write_u128_max(bh: &mut Bencher) {
     bh.iter(|| {
index fba1a5a751c5920c4da3f431d2695ed7745ed71f..2ea4458bf6427b250a3094502aa74eaa3a171949 100644 (file)
@@ -92,7 +92,7 @@
 
 /// Converts a reference to `T` into a reference to an array of length 1 (without copying).
 #[stable(feature = "array_from_ref", since = "1.53.0")]
-#[rustc_const_unstable(feature = "const_array_from_ref", issue = "90206")]
+#[rustc_const_stable(feature = "const_array_from_ref_shared", since = "1.63.0")]
 pub const fn from_ref<T>(s: &T) -> &[T; 1] {
     // SAFETY: Converting `&T` to `&[T; 1]` is sound.
     unsafe { &*(s as *const T).cast::<[T; 1]>() }
index dde9bc383d23c27cc45886a35b6c42cd39c19b36..63655ae8a240b70790d0478cdc857c92e617c47d 100644 (file)
@@ -2233,35 +2233,41 @@ fn fmt(&self, f: &mut Formatter<'_>) -> Result {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized> Pointer for *const T {
     fn fmt(&self, f: &mut Formatter<'_>) -> Result {
-        /// Since the formatting will be identical for all pointer types, use a non-monomorphized
-        /// implementation for the actual formatting to reduce the amount of codegen work needed
-        fn inner(ptr: *const (), f: &mut Formatter<'_>) -> Result {
-            let old_width = f.width;
-            let old_flags = f.flags;
-
-            // The alternate flag is already treated by LowerHex as being special-
-            // it denotes whether to prefix with 0x. We use it to work out whether
-            // or not to zero extend, and then unconditionally set it to get the
-            // prefix.
-            if f.alternate() {
-                f.flags |= 1 << (FlagV1::SignAwareZeroPad as u32);
-
-                if f.width.is_none() {
-                    f.width = Some((usize::BITS / 4) as usize + 2);
-                }
-            }
-            f.flags |= 1 << (FlagV1::Alternate as u32);
+        // Cast is needed here because `.addr()` requires `T: Sized`.
+        pointer_fmt_inner((*self as *const ()).addr(), f)
+    }
+}
 
-            let ret = LowerHex::fmt(&(ptr.addr()), f);
+/// Since the formatting will be identical for all pointer types, use a non-monomorphized
+/// implementation for the actual formatting to reduce the amount of codegen work needed.
+///
+/// This uses `ptr_addr: usize` and not `ptr: *const ()` to be able to use this for
+/// `fn(...) -> ...` without using [problematic] "Oxford Casts".
+///
+/// [problematic]: https://github.com/rust-lang/rust/issues/95489
+pub(crate) fn pointer_fmt_inner(ptr_addr: usize, f: &mut Formatter<'_>) -> Result {
+    let old_width = f.width;
+    let old_flags = f.flags;
 
-            f.width = old_width;
-            f.flags = old_flags;
+    // The alternate flag is already treated by LowerHex as being special-
+    // it denotes whether to prefix with 0x. We use it to work out whether
+    // or not to zero extend, and then unconditionally set it to get the
+    // prefix.
+    if f.alternate() {
+        f.flags |= 1 << (FlagV1::SignAwareZeroPad as u32);
 
-            ret
+        if f.width.is_none() {
+            f.width = Some((usize::BITS / 4) as usize + 2);
         }
-
-        inner(*self as *const (), f)
     }
+    f.flags |= 1 << (FlagV1::Alternate as u32);
+
+    let ret = LowerHex::fmt(&ptr_addr, f);
+
+    f.width = old_width;
+    f.flags = old_flags;
+
+    ret
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
index 678d00c68c5c35322b76a18e468cd2bfdbadbb29..0b76790c0097e05ca2d136b4503b3b0022349ed1 100644 (file)
@@ -2287,6 +2287,7 @@ pub(crate) fn is_nonoverlapping<T>(src: *const T, dst: *const T, count: usize) -
 /// // Now the box is fine
 /// assert_eq!(*v, 42);
 /// ```
+#[doc(alias = "memset")]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")]
 #[inline]
index df0e7431f1f5f47df924255723869bc25cece707..a888ced49b3769cb16cd8e9589a0d5db321fa9f9 100644 (file)
@@ -126,7 +126,6 @@ impl FromStr for $t {
             /// ```txt
             /// Float  ::= Sign? ( 'inf' | 'infinity' | 'nan' | Number )
             /// Number ::= ( Digit+ |
-            ///              '.' Digit* |
             ///              Digit+ '.' Digit* |
             ///              Digit* '.' Digit+ ) Exp?
             /// Exp    ::= 'e' Sign? Digit+
index 6b1e63e0cfaae8de34a3609dea1029d0911af504..5b04ae7b07e69ecdc63ea76a6ac37dea5579659f 100644 (file)
@@ -1878,24 +1878,14 @@ fn hash<HH: hash::Hasher>(&self, state: &mut HH) {
         #[stable(feature = "fnptr_impls", since = "1.4.0")]
         impl<Ret, $($Arg),*> fmt::Pointer for $FnTy {
             fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-                // HACK: The intermediate cast as usize is required for AVR
-                // so that the address space of the source function pointer
-                // is preserved in the final function pointer.
-                //
-                // https://github.com/avr-rust/rust/issues/143
-                fmt::Pointer::fmt(&(*self as usize as *const ()), f)
+                fmt::pointer_fmt_inner(*self as usize, f)
             }
         }
 
         #[stable(feature = "fnptr_impls", since = "1.4.0")]
         impl<Ret, $($Arg),*> fmt::Debug for $FnTy {
             fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-                // HACK: The intermediate cast as usize is required for AVR
-                // so that the address space of the source function pointer
-                // is preserved in the final function pointer.
-                //
-                // https://github.com/avr-rust/rust/issues/143
-                fmt::Pointer::fmt(&(*self as usize as *const ()), f)
+                fmt::pointer_fmt_inner(*self as usize, f)
             }
         }
     }
index 37cf2ef4bfbb5f5d0c34fe9d52d1a41d47433963..1fbf592c2325b4285e6daa9baab07b584dfd019c 100644 (file)
@@ -1412,6 +1412,7 @@ pub unsafe fn drop_in_place(self) {
     /// See [`ptr::write_bytes`] for safety concerns and examples.
     ///
     /// [`ptr::write_bytes`]: crate::ptr::write_bytes()
+    #[doc(alias = "memset")]
     #[stable(feature = "pointer_methods", since = "1.26.0")]
     #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")]
     #[inline(always)]
@@ -1621,6 +1622,122 @@ pub const fn len(self) -> usize {
         metadata(self)
     }
 
+    /// Returns `true` if the raw slice has a length of 0.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(slice_ptr_len)]
+    ///
+    /// let mut a = [1, 2, 3];
+    /// let ptr = &mut a as *mut [_];
+    /// assert!(!ptr.is_empty());
+    /// ```
+    #[inline(always)]
+    #[unstable(feature = "slice_ptr_len", issue = "71146")]
+    #[rustc_const_unstable(feature = "const_slice_ptr_len", issue = "71146")]
+    pub const fn is_empty(self) -> bool {
+        self.len() == 0
+    }
+
+    /// Divides one mutable raw slice into two at an index.
+    ///
+    /// The first will contain all indices from `[0, mid)` (excluding
+    /// the index `mid` itself) and the second will contain all
+    /// indices from `[mid, len)` (excluding the index `len` itself).
+    ///
+    /// # Panics
+    ///
+    /// Panics if `mid > len`.
+    ///
+    /// # Safety
+    ///
+    /// `mid` must be [in-bounds] of the underlying [allocated object].
+    /// Which means `self` must be dereferenceable and span a single allocation
+    /// that is at least `mid * size_of::<T>()` bytes long. Not upholding these
+    /// requirements is *[undefined behavior]* even if the resulting pointers are not used.
+    ///
+    /// Since `len` being in-bounds it is not a safety invariant of `*mut [T]` the
+    /// safety requirements of this method are the same as for [`split_at_mut_unchecked`].
+    /// The explicit bounds check is only as useful as `len` is correct.
+    ///
+    /// [`split_at_mut_unchecked`]: #method.split_at_mut_unchecked
+    /// [in-bounds]: #method.add
+    /// [allocated object]: crate::ptr#allocated-object
+    /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(raw_slice_split)]
+    /// #![feature(slice_ptr_get)]
+    ///
+    /// let mut v = [1, 0, 3, 0, 5, 6];
+    /// let ptr = &mut v as *mut [_];
+    /// unsafe {
+    ///     let (left, right) = ptr.split_at_mut(2);
+    ///     assert_eq!(&*left, [1, 0]);
+    ///     assert_eq!(&*right, [3, 0, 5, 6]);
+    /// }
+    /// ```
+    #[inline(always)]
+    #[track_caller]
+    #[unstable(feature = "raw_slice_split", issue = "95595")]
+    pub unsafe fn split_at_mut(self, mid: usize) -> (*mut [T], *mut [T]) {
+        assert!(mid <= self.len());
+        // SAFETY: The assert above is only a safety-net as long as `self.len()` is correct
+        // The actual safety requirements of this function are the same as for `split_at_mut_unchecked`
+        unsafe { self.split_at_mut_unchecked(mid) }
+    }
+
+    /// Divides one mutable raw slice into two at an index, without doing bounds checking.
+    ///
+    /// The first will contain all indices from `[0, mid)` (excluding
+    /// the index `mid` itself) and the second will contain all
+    /// indices from `[mid, len)` (excluding the index `len` itself).
+    ///
+    /// # Safety
+    ///
+    /// `mid` must be [in-bounds] of the underlying [allocated object].
+    /// Which means `self` must be dereferenceable and span a single allocation
+    /// that is at least `mid * size_of::<T>()` bytes long. Not upholding these
+    /// requirements is *[undefined behavior]* even if the resulting pointers are not used.
+    ///
+    /// [in-bounds]: #method.add
+    /// [out-of-bounds index]: #method.add
+    /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(raw_slice_split)]
+    ///
+    /// let mut v = [1, 0, 3, 0, 5, 6];
+    /// // scoped to restrict the lifetime of the borrows
+    /// unsafe {
+    ///     let ptr = &mut v as *mut [_];
+    ///     let (left, right) = ptr.split_at_mut_unchecked(2);
+    ///     assert_eq!(&*left, [1, 0]);
+    ///     assert_eq!(&*right, [3, 0, 5, 6]);
+    ///     (&mut *left)[1] = 2;
+    ///     (&mut *right)[1] = 4;
+    /// }
+    /// assert_eq!(v, [1, 2, 3, 4, 5, 6]);
+    /// ```
+    #[inline(always)]
+    #[unstable(feature = "raw_slice_split", issue = "95595")]
+    pub unsafe fn split_at_mut_unchecked(self, mid: usize) -> (*mut [T], *mut [T]) {
+        let len = self.len();
+        let ptr = self.as_mut_ptr();
+
+        // SAFETY: Caller must pass a valid pointer and an index that is in-bounds.
+        let tail = unsafe { ptr.add(mid) };
+        (
+            crate::ptr::slice_from_raw_parts_mut(ptr, mid),
+            crate::ptr::slice_from_raw_parts_mut(tail, len - mid),
+        )
+    }
+
     /// Returns a raw pointer to the slice's buffer.
     ///
     /// This is equivalent to casting `self` to `*mut T`, but more type-safe.
@@ -1644,9 +1761,10 @@ pub const fn as_mut_ptr(self) -> *mut T {
     /// Returns a raw pointer to an element or subslice, without doing bounds
     /// checking.
     ///
-    /// Calling this method with an out-of-bounds index or when `self` is not dereferenceable
+    /// Calling this method with an [out-of-bounds index] or when `self` is not dereferenceable
     /// is *[undefined behavior]* even if the resulting pointer is not used.
     ///
+    /// [out-of-bounds index]: #method.add
     /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
     ///
     /// # Examples
index f5a90cb3d7ac9fcb5e27daf0ea54a455cc206000..77fd1ec2b8ea2594022102112e24773d715b2bdf 100644 (file)
@@ -3083,7 +3083,6 @@ pub fn fill(&mut self, value: T)
     /// buf.fill_with(Default::default);
     /// assert_eq!(buf, vec![0; 10]);
     /// ```
-    #[doc(alias = "memset")]
     #[stable(feature = "slice_fill_with", since = "1.51.0")]
     pub fn fill_with<F>(&mut self, mut f: F)
     where
index 6bc60b04b5c64eeaae0b4a7a1c19eb74627bb7b6..bf79214f4235847eab427b6e66a36ad18429918a 100644 (file)
 
 /// Converts a reference to T into a slice of length 1 (without copying).
 #[stable(feature = "from_ref", since = "1.28.0")]
-#[rustc_const_unstable(feature = "const_slice_from_ref", issue = "90206")]
+#[rustc_const_stable(feature = "const_slice_from_ref_shared", since = "1.63.0")]
 #[must_use]
 pub const fn from_ref<T>(s: &T) -> &[T] {
     array::from_ref(s)
@@ -213,7 +213,8 @@ pub const fn from_mut<T>(s: &mut T) -> &mut [T] {
 ///
 /// [valid]: ptr#safety
 #[unstable(feature = "slice_from_ptr_range", issue = "89792")]
-pub unsafe fn from_ptr_range<'a, T>(range: Range<*const T>) -> &'a [T] {
+#[rustc_const_unstable(feature = "const_slice_from_ptr_range", issue = "89792")]
+pub const unsafe fn from_ptr_range<'a, T>(range: Range<*const T>) -> &'a [T] {
     // SAFETY: the caller must uphold the safety contract for `from_ptr_range`.
     unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) }
 }
@@ -263,7 +264,8 @@ pub unsafe fn from_ptr_range<'a, T>(range: Range<*const T>) -> &'a [T] {
 ///
 /// [valid]: ptr#safety
 #[unstable(feature = "slice_from_ptr_range", issue = "89792")]
-pub unsafe fn from_mut_ptr_range<'a, T>(range: Range<*mut T>) -> &'a mut [T] {
+#[rustc_const_unstable(feature = "const_slice_from_mut_ptr_range", issue = "89792")]
+pub const unsafe fn from_mut_ptr_range<'a, T>(range: Range<*mut T>) -> &'a mut [T] {
     // SAFETY: the caller must uphold the safety contract for `from_mut_ptr_range`.
     unsafe { from_raw_parts_mut(range.start, range.end.sub_ptr(range.start)) }
 }
index c42850d2324134acf5f4baa5c5a7f27c0f86e25e..7c37f5f099c7f602711d80815df229fbdeed9cf6 100755 (executable)
@@ -170,7 +170,7 @@ def main():
     normal1 = compress_normal(normal1)
 
     print("""\
-// NOTE: The following code was generated by "src/libcore/unicode/printable.py",
+// NOTE: The following code was generated by "library/core/src/unicode/printable.py",
 //       do not edit directly!
 
 fn check(x: u16, singletonuppers: &[(u8, u8)], singletonlowers: &[u8], normal: &[u8]) -> bool {
@@ -211,7 +211,14 @@ fn check(x: u16, singletonuppers: &[(u8, u8)], singletonlowers: &[u8], normal: &
 pub(crate) fn is_printable(x: char) -> bool {
     let x = x as u32;
     let lower = x as u16;
-    if x < 0x10000 {
+
+    if x < 32 {
+        // ASCII fast path
+        false
+    } else if x < 127 {
+        // ASCII fast path
+        true
+    } else if x < 0x10000 {
         check(lower, SINGLETONS0U, SINGLETONS0L, NORMAL0)
     } else if x < 0x20000 {
         check(lower, SINGLETONS1U, SINGLETONS1L, NORMAL1)
index 1502b3160bc22b104a3552ebc6646f0b9966a3ba..31cf88a41497e01fc6d8e8cd0a6891f08fb66aaf 100644 (file)
@@ -1,4 +1,4 @@
-// NOTE: The following code was generated by "src/libcore/unicode/printable.py",
+// NOTE: The following code was generated by "library/core/src/unicode/printable.py",
 //       do not edit directly!
 
 fn check(x: u16, singletonuppers: &[(u8, u8)], singletonlowers: &[u8], normal: &[u8]) -> bool {
@@ -39,7 +39,14 @@ fn check(x: u16, singletonuppers: &[(u8, u8)], singletonlowers: &[u8], normal: &
 pub(crate) fn is_printable(x: char) -> bool {
     let x = x as u32;
     let lower = x as u16;
-    if x < 0x10000 {
+
+    if x < 32 {
+        // ASCII fast path
+        false
+    } else if x < 127 {
+        // ASCII fast path
+        true
+    } else if x < 0x10000 {
         check(lower, SINGLETONS0U, SINGLETONS0L, NORMAL0)
     } else if x < 0x20000 {
         check(lower, SINGLETONS1U, SINGLETONS1L, NORMAL1)
index 7e9d7d27101802b66e40d1ba1a8e9f10019aa7fc..9505ec31609f5a7ffcf6a07a157c71e129e3a58d 100644 (file)
@@ -84,6 +84,7 @@
 #![feature(const_option)]
 #![feature(const_option_ext)]
 #![feature(const_result)]
+#![feature(const_intrinsic_copy)]
 #![feature(integer_atomics)]
 #![feature(int_roundings)]
 #![feature(slice_group_by)]
index c5242ad04de84b44282e86599dc2800c8fc8375d..40b2b49bdbd7d96c6dcbc6a144acf7d77abe1945 100644 (file)
@@ -1,4 +1,5 @@
 use core::cell::RefCell;
+use core::mem::{self, MaybeUninit};
 use core::num::NonZeroUsize;
 use core::ptr;
 use core::ptr::*;
@@ -781,3 +782,42 @@ pub fn set_tag(&mut self, data: usize) {
         }
     }
 }
+
+#[test]
+fn test_const_copy() {
+    const {
+        let ptr1 = &1;
+        let mut ptr2 = &666;
+
+        // Copy ptr1 to ptr2, bytewise.
+        unsafe {
+            ptr::copy(
+                &ptr1 as *const _ as *const MaybeUninit<u8>,
+                &mut ptr2 as *mut _ as *mut MaybeUninit<u8>,
+                mem::size_of::<&i32>(),
+            );
+        }
+
+        // Make sure they still work.
+        assert!(*ptr1 == 1);
+        assert!(*ptr2 == 1);
+    };
+
+    const {
+        let ptr1 = &1;
+        let mut ptr2 = &666;
+
+        // Copy ptr1 to ptr2, bytewise.
+        unsafe {
+            ptr::copy_nonoverlapping(
+                &ptr1 as *const _ as *const MaybeUninit<u8>,
+                &mut ptr2 as *mut _ as *mut MaybeUninit<u8>,
+                mem::size_of::<&i32>(),
+            );
+        }
+
+        // Make sure they still work.
+        assert!(*ptr1 == 1);
+        assert!(*ptr2 == 1);
+    };
+}
index fb05a02dc4571e4cf1ba9215fd8cb93a6a5cc0b9..48030f8d82dcaa3671ec67631991774c36ed5098 100644 (file)
@@ -18,6 +18,7 @@ unsafe impl Sync for Buffer {}
 unsafe impl Send for Buffer {}
 
 impl Default for Buffer {
+    #[inline]
     fn default() -> Self {
         Self::from(vec![])
     }
@@ -25,26 +26,31 @@ fn default() -> Self {
 
 impl Deref for Buffer {
     type Target = [u8];
+    #[inline]
     fn deref(&self) -> &[u8] {
         unsafe { slice::from_raw_parts(self.data as *const u8, self.len) }
     }
 }
 
 impl DerefMut for Buffer {
+    #[inline]
     fn deref_mut(&mut self) -> &mut [u8] {
         unsafe { slice::from_raw_parts_mut(self.data, self.len) }
     }
 }
 
 impl Buffer {
+    #[inline]
     pub(super) fn new() -> Self {
         Self::default()
     }
 
+    #[inline]
     pub(super) fn clear(&mut self) {
         self.len = 0;
     }
 
+    #[inline]
     pub(super) fn take(&mut self) -> Self {
         mem::take(self)
     }
@@ -53,6 +59,7 @@ pub(super) fn take(&mut self) -> Self {
     // because in the case of small arrays, codegen can be more efficient
     // (avoiding a memmove call). With extend_from_slice, LLVM at least
     // currently is not able to make that optimization.
+    #[inline]
     pub(super) fn extend_from_array<const N: usize>(&mut self, xs: &[u8; N]) {
         if xs.len() > (self.capacity - self.len) {
             let b = self.take();
@@ -64,6 +71,7 @@ pub(super) fn take(&mut self) -> Self {
         }
     }
 
+    #[inline]
     pub(super) fn extend_from_slice(&mut self, xs: &[u8]) {
         if xs.len() > (self.capacity - self.len) {
             let b = self.take();
@@ -75,6 +83,7 @@ pub(super) fn extend_from_slice(&mut self, xs: &[u8]) {
         }
     }
 
+    #[inline]
     pub(super) fn push(&mut self, v: u8) {
         // The code here is taken from Vec::push, and we know that reserve()
         // will panic if we're exceeding isize::MAX bytes and so there's no need
@@ -91,22 +100,26 @@ pub(super) fn push(&mut self, v: u8) {
 }
 
 impl Write for Buffer {
+    #[inline]
     fn write(&mut self, xs: &[u8]) -> io::Result<usize> {
         self.extend_from_slice(xs);
         Ok(xs.len())
     }
 
+    #[inline]
     fn write_all(&mut self, xs: &[u8]) -> io::Result<()> {
         self.extend_from_slice(xs);
         Ok(())
     }
 
+    #[inline]
     fn flush(&mut self) -> io::Result<()> {
         Ok(())
     }
 }
 
 impl Drop for Buffer {
+    #[inline]
     fn drop(&mut self) {
         let b = self.take();
         (b.drop)(b);
index 6f7c6305afc14ec91e1be195cd68c6f4dc3a1735..f1c5eaad868e99d495224fd2cee4111f4e9c17b6 100644 (file)
@@ -703,12 +703,11 @@ pub enum Delimiter {
     /// `[ ... ]`
     #[stable(feature = "proc_macro_lib2", since = "1.29.0")]
     Bracket,
-    /// `/*«*/ ... /*»*/`
+    /// `Ø ... Ø`
     /// An invisible delimiter, that may, for example, appear around tokens coming from a
     /// "macro variable" `$var`. It is important to preserve operator priorities in cases like
     /// `$var * 3` where `$var` is `1 + 2`.
-    /// Invisible delimiters are not directly writable in normal Rust code except as comments.
-    /// Therefore, they might not survive a roundtrip of a token stream through a string.
+    /// Invisible delimiters might not survive roundtrip of a token stream through a string.
     #[stable(feature = "proc_macro_lib2", since = "1.29.0")]
     None,
 }
index 95506fc1eb9c84404e9eb4ba9409d7315a21f62f..229e546e085493c9043360f88e381f8aa3c6b9a2 100644 (file)
@@ -16,7 +16,7 @@ panic_unwind = { path = "../panic_unwind", optional = true }
 panic_abort = { path = "../panic_abort" }
 core = { path = "../core" }
 libc = { version = "0.2.126", default-features = false, features = ['rustc-dep-of-std'] }
-compiler_builtins = { version = "0.1.71" }
+compiler_builtins = { version = "0.1.73" }
 profiler_builtins = { path = "../profiler_builtins", optional = true }
 unwind = { path = "../unwind" }
 hashbrown = { version = "0.12", default-features = false, features = ['rustc-dep-of-std'] }
index 969f5dde4f05d915c7c70943b47000df0c10624b..11ccdd9ea1cc5e90ca76964e0322e9a965cc4c6a 100644 (file)
@@ -54,7 +54,8 @@
 /// the [`Eq`] trait, changes while it is in the map. This is normally only
 /// possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code.
 /// The behavior resulting from such a logic error is not specified, but will
-/// not result in undefined behavior. This could include panics, incorrect results,
+/// be encapsulated to the `HashMap` that observed the logic error and not
+/// result in undefined behavior. This could include panics, incorrect results,
 /// aborts, memory leaks, and non-termination.
 ///
 /// The hash table implementation is a Rust port of Google's [SwissTable].
@@ -895,6 +896,119 @@ pub fn get_key_value<Q: ?Sized>(&self, k: &Q) -> Option<(&K, &V)>
         self.base.get_key_value(k)
     }
 
+    /// Attempts to get mutable references to `N` values in the map at once.
+    ///
+    /// Returns an array of length `N` with the results of each query. For soundness, at most one
+    /// mutable reference will be returned to any value. `None` will be returned if any of the
+    /// keys are duplicates or missing.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(map_many_mut)]
+    /// use std::collections::HashMap;
+    ///
+    /// let mut libraries = HashMap::new();
+    /// libraries.insert("Bodleian Library".to_string(), 1602);
+    /// libraries.insert("Athenæum".to_string(), 1807);
+    /// libraries.insert("Herzogin-Anna-Amalia-Bibliothek".to_string(), 1691);
+    /// libraries.insert("Library of Congress".to_string(), 1800);
+    ///
+    /// let got = libraries.get_many_mut([
+    ///     "Athenæum",
+    ///     "Library of Congress",
+    /// ]);
+    /// assert_eq!(
+    ///     got,
+    ///     Some([
+    ///         &mut 1807,
+    ///         &mut 1800,
+    ///     ]),
+    /// );
+    ///
+    /// // Missing keys result in None
+    /// let got = libraries.get_many_mut([
+    ///     "Athenæum",
+    ///     "New York Public Library",
+    /// ]);
+    /// assert_eq!(got, None);
+    ///
+    /// // Duplicate keys result in None
+    /// let got = libraries.get_many_mut([
+    ///     "Athenæum",
+    ///     "Athenæum",
+    /// ]);
+    /// assert_eq!(got, None);
+    /// ```
+    #[inline]
+    #[unstable(feature = "map_many_mut", issue = "97601")]
+    pub fn get_many_mut<Q: ?Sized, const N: usize>(&mut self, ks: [&Q; N]) -> Option<[&'_ mut V; N]>
+    where
+        K: Borrow<Q>,
+        Q: Hash + Eq,
+    {
+        self.base.get_many_mut(ks)
+    }
+
+    /// Attempts to get mutable references to `N` values in the map at once, without validating that
+    /// the values are unique.
+    ///
+    /// Returns an array of length `N` with the results of each query. `None` will be returned if
+    /// any of the keys are missing.
+    ///
+    /// For a safe alternative see [`get_many_mut`](Self::get_many_mut).
+    ///
+    /// # Safety
+    ///
+    /// Calling this method with overlapping keys is *[undefined behavior]* even if the resulting
+    /// references are not used.
+    ///
+    /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(map_many_mut)]
+    /// use std::collections::HashMap;
+    ///
+    /// let mut libraries = HashMap::new();
+    /// libraries.insert("Bodleian Library".to_string(), 1602);
+    /// libraries.insert("Athenæum".to_string(), 1807);
+    /// libraries.insert("Herzogin-Anna-Amalia-Bibliothek".to_string(), 1691);
+    /// libraries.insert("Library of Congress".to_string(), 1800);
+    ///
+    /// let got = libraries.get_many_mut([
+    ///     "Athenæum",
+    ///     "Library of Congress",
+    /// ]);
+    /// assert_eq!(
+    ///     got,
+    ///     Some([
+    ///         &mut 1807,
+    ///         &mut 1800,
+    ///     ]),
+    /// );
+    ///
+    /// // Missing keys result in None
+    /// let got = libraries.get_many_mut([
+    ///     "Athenæum",
+    ///     "New York Public Library",
+    /// ]);
+    /// assert_eq!(got, None);
+    /// ```
+    #[inline]
+    #[unstable(feature = "map_many_mut", issue = "97601")]
+    pub unsafe fn get_many_unchecked_mut<Q: ?Sized, const N: usize>(
+        &mut self,
+        ks: [&Q; N],
+    ) -> Option<[&'_ mut V; N]>
+    where
+        K: Borrow<Q>,
+        Q: Hash + Eq,
+    {
+        self.base.get_many_unchecked_mut(ks)
+    }
+
     /// Returns `true` if the map contains a value for the specified key.
     ///
     /// The key may be any borrowed form of the map's key type, but
index 4ac0e081c2e2d2bbcac2c1ca92a8726207d6e428..19428fe9a2339c315b461b0f7b176fa14072b505 100644 (file)
 /// In other words, if two keys are equal, their hashes must be equal.
 ///
 ///
-/// It is a logic error for an item to be modified in such a way that the
-/// item's hash, as determined by the [`Hash`] trait, or its equality, as
-/// determined by the [`Eq`] trait, changes while it is in the set. This is
-/// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or
-/// unsafe code. The behavior resulting from such a logic error is not
-/// specified (it could include panics, incorrect results, aborts, memory
-/// leaks, or non-termination) but will not be undefined behavior.
+/// It is a logic error for a key to be modified in such a way that the key's
+/// hash, as determined by the [`Hash`] trait, or its equality, as determined by
+/// the [`Eq`] trait, changes while it is in the map. This is normally only
+/// possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code.
+/// The behavior resulting from such a logic error is not specified, but will
+/// be encapsulated to the `HashSet` that observed the logic error and not
+/// result in undefined behavior. This could include panics, incorrect results,
+/// aborts, memory leaks, and non-termination.
 ///
 /// # Examples
 ///
@@ -857,9 +858,10 @@ pub fn is_superset(&self, other: &HashSet<T, S>) -> bool {
 
     /// Adds a value to the set.
     ///
-    /// If the set did not have this value present, `true` is returned.
+    /// Returns whether the value was newly inserted. That is:
     ///
-    /// If the set did have this value present, `false` is returned.
+    /// - If the set did not previously contain this value, `true` is returned.
+    /// - If the set already contained this value, `false` is returned.
     ///
     /// # Examples
     ///
index 431a1efc8d1f64d4e7f3d56e9f3b31e3a0728295..55bd2c59406df9a3ac8db1fd5bedfe029f933162 100644 (file)
@@ -1620,7 +1620,7 @@ pub fn remove_file<P: AsRef<Path>>(path: P) -> io::Result<()> {
 /// # Platform-specific behavior
 ///
 /// This function currently corresponds to the `stat` function on Unix
-/// and the `GetFileAttributesEx` function on Windows.
+/// and the `GetFileInformationByHandle` function on Windows.
 /// Note that, this [may change in the future][changes].
 ///
 /// [changes]: io#platform-specific-behavior
@@ -1654,7 +1654,7 @@ pub fn metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
 /// # Platform-specific behavior
 ///
 /// This function currently corresponds to the `lstat` function on Unix
-/// and the `GetFileAttributesEx` function on Windows.
+/// and the `GetFileInformationByHandle` function on Windows.
 /// Note that, this [may change in the future][changes].
 ///
 /// [changes]: io#platform-specific-behavior
index 519f050d2fcbeda9e77d6226d94cab30eeb9cacf..71ea5f1a1f01e0c54afe682dffb9cdead333e345 100644 (file)
 #![feature(map_try_insert)]
 #![feature(new_uninit)]
 #![feature(thin_box)]
-#![feature(toowned_clone_into)]
 #![feature(try_reserve_kind)]
 #![feature(vec_into_raw_parts)]
 #![feature(slice_concat_trait)]
index f95b0ddd589ac4b311c4a7d4abfe96c186c80dd0..9197f0d6e6c8c3a2f737096cc9f7fff29ef625fb 100644 (file)
@@ -1,7 +1,8 @@
 use crate::ops::{Deref, DerefMut};
 
 #[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
-#[repr(align(64))]
+#[cfg_attr(target_arch = "aarch64", repr(align(128)))]
+#[cfg_attr(not(target_arch = "aarch64"), repr(align(64)))]
 pub(super) struct CacheAligned<T>(pub T);
 
 impl<T> Deref for CacheAligned<T> {
index f60835300059614db23aab9ef959584b2262e043..46f45b1977173e1a0ceecd829552a7a3712e32e3 100644 (file)
@@ -70,9 +70,13 @@ pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
         mutex.lock();
         res == 0
     }
+}
 
-    pub unsafe fn destroy(&self) {
-        let _ = abi::sem_destroy(self.sem1);
-        let _ = abi::sem_destroy(self.sem2);
+impl Drop for Condvar {
+    fn drop(&mut self) {
+        unsafe {
+            let _ = abi::sem_destroy(self.sem1);
+            let _ = abi::sem_destroy(self.sem2);
+        }
     }
 }
index 97b4c49896f63f1aaa783071d44004019a4c2c44..ef44bf411fba5c0bdf3845f1d8eabdd93489de52 100644 (file)
@@ -215,7 +215,4 @@ pub unsafe fn try_lock(&self) -> bool {
         }
         guard.locked
     }
-
-    #[inline]
-    pub unsafe fn destroy(&self) {}
 }
index 690bb155e1a27fea59e59253d524975d007817e1..d43fa08a17150418700c6e481463dafba6c77880 100644 (file)
@@ -84,12 +84,6 @@ pub unsafe fn write_unlock(&self) {
         // FIXME: should only wake up one of these some of the time
         self.cond.notify_all();
     }
-
-    #[inline]
-    pub unsafe fn destroy(&self) {
-        self.lock.destroy();
-        self.cond.destroy();
-    }
 }
 
 impl State {
index ed26c52802748309f771d2c515d741ee6aa6d5fa..008cd8fb1e3926f3dbe5c65bde43afda92ddc31c 100644 (file)
@@ -117,8 +117,6 @@ pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
         unsafe { mutex.lock() };
         success
     }
-
-    pub unsafe fn destroy(&self) {}
 }
 
 mod waiter_queue {
index 5ee231882bb589e8faf273d9ddab311e8b239045..2ba8454ff9245a6836b16843e3ace40e472ffcd9 100644 (file)
@@ -64,8 +64,10 @@ pub unsafe fn try_lock(&self) -> bool {
             }
         }
     }
+}
 
-    pub unsafe fn destroy(&self) {
+impl Drop for Mutex {
+    fn drop(&mut self) {
         if let Some(mtx) = self.mtx.get().map(|x| x.0) {
             expect_success_aborting(unsafe { abi::del_mtx(mtx) }, &"del_mtx");
         }
index c9736880b0880819b1a3d0a624de48ef60526324..36534e0eff3fd91595f559ac011de1077a50f53d 100644 (file)
@@ -1,4 +1,5 @@
 use crate::sys::locks::Mutex;
+use crate::sys_common::lazy_box::{LazyBox, LazyInit};
 use crate::time::Duration;
 
 use super::waitqueue::{SpinMutex, WaitQueue, WaitVariable};
@@ -7,16 +8,19 @@ pub struct Condvar {
     inner: SpinMutex<WaitVariable<()>>,
 }
 
-pub type MovableCondvar = Box<Condvar>;
+pub(crate) type MovableCondvar = LazyBox<Condvar>;
+
+impl LazyInit for Condvar {
+    fn init() -> Box<Self> {
+        Box::new(Self::new())
+    }
+}
 
 impl Condvar {
     pub const fn new() -> Condvar {
         Condvar { inner: SpinMutex::new(WaitVariable::new(())) }
     }
 
-    #[inline]
-    pub unsafe fn init(&mut self) {}
-
     #[inline]
     pub unsafe fn notify_one(&self) {
         let _ = WaitQueue::notify_one(self.inner.lock());
@@ -38,7 +42,4 @@ pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
         unsafe { mutex.lock() };
         success
     }
-
-    #[inline]
-    pub unsafe fn destroy(&self) {}
 }
index 98a390c4c2bcabe06cae174626f442ecb4324ee3..513cd77fd2aad17fff00752d6eba65d12b654929 100644 (file)
@@ -1,11 +1,18 @@
 use super::waitqueue::{try_lock_or_false, SpinMutex, WaitQueue, WaitVariable};
+use crate::sys_common::lazy_box::{LazyBox, LazyInit};
 
 pub struct Mutex {
     inner: SpinMutex<WaitVariable<bool>>,
 }
 
 // not movable: see UnsafeList implementation
-pub type MovableMutex = Box<Mutex>;
+pub(crate) type MovableMutex = LazyBox<Mutex>;
+
+impl LazyInit for Mutex {
+    fn init() -> Box<Self> {
+        Box::new(Self::new())
+    }
+}
 
 // Implementation according to “Operating Systems: Three Easy Pieces”, chapter 28
 impl Mutex {
@@ -52,7 +59,4 @@ pub unsafe fn try_lock(&self) -> bool {
             true
         }
     }
-
-    #[inline]
-    pub unsafe fn destroy(&self) {}
 }
index 47be4c006ec7ec4e1e294d77a6d6b53fabcb7f2b..a97fb9ab026f02d57cc3f347ac5d62ac891d4c96 100644 (file)
@@ -2,6 +2,7 @@
 mod tests;
 
 use crate::num::NonZeroUsize;
+use crate::sys_common::lazy_box::{LazyBox, LazyInit};
 
 use super::waitqueue::{
     try_lock_or_false, NotifiedTcs, SpinMutex, SpinMutexGuard, WaitQueue, WaitVariable,
@@ -13,7 +14,13 @@ pub struct RwLock {
     writer: SpinMutex<WaitVariable<bool>>,
 }
 
-pub type MovableRwLock = Box<RwLock>;
+pub(crate) type MovableRwLock = LazyBox<RwLock>;
+
+impl LazyInit for RwLock {
+    fn init() -> Box<Self> {
+        Box::new(Self::new())
+    }
+}
 
 // Check at compile time that RwLock size matches C definition (see test_c_rwlock_initializer below)
 //
@@ -168,9 +175,6 @@ unsafe fn unlock(&self) {
             unsafe { self.__read_unlock(rguard, wguard) };
         }
     }
-
-    #[inline]
-    pub unsafe fn destroy(&self) {}
 }
 
 // The following functions are needed by libunwind. These symbols are named
index df16cc680ad848d8e9d57fc9c2eacf3af41b8f40..433abc895f5d5c5f7b9ecba4f513ae7a74bb4cca 100644 (file)
@@ -82,9 +82,11 @@ pub unsafe fn write_unlock(&self) {
         let rwl = self.raw();
         expect_success_aborting(unsafe { abi::rwl_unl_rwl(rwl) }, &"rwl_unl_rwl");
     }
+}
 
+impl Drop for RwLock {
     #[inline]
-    pub unsafe fn destroy(&self) {
+    fn drop(&mut self) {
         if let Some(rwl) = self.rwl.get().map(|x| x.0) {
             expect_success_aborting(unsafe { abi::rwl_del_rwl(rwl) }, &"rwl_del_rwl");
         }
index 7a63af1ad7cf7dfa45bc95efbd20ae62545f78f0..a9a1a32c5afb09b41c434739d8de6bdcba73e194 100644 (file)
@@ -24,9 +24,6 @@ pub const fn new() -> Self {
     #[inline]
     pub unsafe fn init(&mut self) {}
 
-    #[inline]
-    pub unsafe fn destroy(&self) {}
-
     #[inline]
     pub unsafe fn try_lock(&self) -> bool {
         self.futex.compare_exchange(0, 1, Acquire, Relaxed).is_ok()
@@ -118,12 +115,6 @@ pub const fn new() -> Self {
         Self { futex: AtomicU32::new(0) }
     }
 
-    #[inline]
-    pub unsafe fn init(&mut self) {}
-
-    #[inline]
-    pub unsafe fn destroy(&self) {}
-
     // All the memory orderings here are `Relaxed`,
     // because synchronization is done by unlocking and locking the mutex.
 
index 5ff1aba79747a44ac3b42cbb7cb98c5fed9876d7..1f902f50587d2193e8021d507edb01990e52800c 100644 (file)
@@ -63,9 +63,6 @@ pub const fn new() -> Self {
         Self { state: AtomicU32::new(0), writer_notify: AtomicU32::new(0) }
     }
 
-    #[inline]
-    pub unsafe fn destroy(&self) {}
-
     #[inline]
     pub unsafe fn try_read(&self) -> bool {
         self.state
index 04c5c489fc9b94bb44fc97a40e265e88416bdb28..03400efa3c9aaf43d539d10d7fbea8bbadc95897 100644 (file)
@@ -9,14 +9,14 @@
     ))] {
         mod futex;
         mod futex_rwlock;
-        pub use futex::{Mutex, MovableMutex, Condvar, MovableCondvar};
-        pub use futex_rwlock::{RwLock, MovableRwLock};
+        pub(crate) use futex::{Mutex, MovableMutex, MovableCondvar};
+        pub(crate) use futex_rwlock::{RwLock, MovableRwLock};
     } else {
         mod pthread_mutex;
         mod pthread_rwlock;
         mod pthread_condvar;
-        pub use pthread_mutex::{Mutex, MovableMutex};
-        pub use pthread_rwlock::{RwLock, MovableRwLock};
-        pub use pthread_condvar::{Condvar, MovableCondvar};
+        pub(crate) use pthread_mutex::{Mutex, MovableMutex};
+        pub(crate) use pthread_rwlock::{RwLock, MovableRwLock};
+        pub(crate) use pthread_condvar::MovableCondvar;
     }
 }
index 099aa68706fa394f18855e8701b528ecf9478d01..61c28d696bcaa2dd52b7eaccb726347537ddd8ad 100644 (file)
@@ -1,12 +1,13 @@
 use crate::cell::UnsafeCell;
 use crate::sys::locks::{pthread_mutex, Mutex};
+use crate::sys_common::lazy_box::{LazyBox, LazyInit};
 use crate::time::Duration;
 
 pub struct Condvar {
     inner: UnsafeCell<libc::pthread_cond_t>,
 }
 
-pub type MovableCondvar = Box<Condvar>;
+pub(crate) type MovableCondvar = LazyBox<Condvar>;
 
 unsafe impl Send for Condvar {}
 unsafe impl Sync for Condvar {}
@@ -18,6 +19,14 @@ fn saturating_cast_to_time_t(value: u64) -> libc::time_t {
     if value > <libc::time_t>::MAX as u64 { <libc::time_t>::MAX } else { value as libc::time_t }
 }
 
+impl LazyInit for Condvar {
+    fn init() -> Box<Self> {
+        let mut condvar = Box::new(Self::new());
+        unsafe { condvar.init() };
+        condvar
+    }
+}
+
 impl Condvar {
     pub const fn new() -> Condvar {
         // Might be moved and address is changing it is better to avoid
@@ -32,14 +41,14 @@ pub const fn new() -> Condvar {
         target_os = "android",
         target_os = "redox"
     ))]
-    pub unsafe fn init(&mut self) {}
+    unsafe fn init(&mut self) {}
 
     // NOTE: ESP-IDF's PTHREAD_COND_INITIALIZER support is not released yet
     // So on that platform, init() should always be called
     // Moreover, that platform does not have pthread_condattr_setclock support,
     // hence that initialization should be skipped as well
     #[cfg(target_os = "espidf")]
-    pub unsafe fn init(&mut self) {
+    unsafe fn init(&mut self) {
         let r = libc::pthread_cond_init(self.inner.get(), crate::ptr::null());
         assert_eq!(r, 0);
     }
@@ -52,7 +61,7 @@ pub unsafe fn init(&mut self) {
         target_os = "redox",
         target_os = "espidf"
     )))]
-    pub unsafe fn init(&mut self) {
+    unsafe fn init(&mut self) {
         use crate::mem::MaybeUninit;
         let mut attr = MaybeUninit::<libc::pthread_condattr_t>::uninit();
         let r = libc::pthread_condattr_init(attr.as_mut_ptr());
@@ -179,14 +188,14 @@ pub unsafe fn wait_timeout(&self, mutex: &Mutex, mut dur: Duration) -> bool {
 
     #[inline]
     #[cfg(not(target_os = "dragonfly"))]
-    pub unsafe fn destroy(&self) {
+    unsafe fn destroy(&mut self) {
         let r = libc::pthread_cond_destroy(self.inner.get());
         debug_assert_eq!(r, 0);
     }
 
     #[inline]
     #[cfg(target_os = "dragonfly")]
-    pub unsafe fn destroy(&self) {
+    unsafe fn destroy(&mut self) {
         let r = libc::pthread_cond_destroy(self.inner.get());
         // On DragonFly pthread_cond_destroy() returns EINVAL if called on
         // a condvar that was just initialized with
@@ -195,3 +204,10 @@ pub unsafe fn destroy(&self) {
         debug_assert!(r == 0 || r == libc::EINVAL);
     }
 }
+
+impl Drop for Condvar {
+    #[inline]
+    fn drop(&mut self) {
+        unsafe { self.destroy() };
+    }
+}
index 76840ce74dd604ea87899807f3f96fdb2b98adeb..916e898d8906e2a8e9d22a44173d7773a92a6a45 100644 (file)
@@ -1,12 +1,13 @@
 use crate::cell::UnsafeCell;
 use crate::mem::MaybeUninit;
 use crate::sys::cvt_nz;
+use crate::sys_common::lazy_box::{LazyBox, LazyInit};
 
 pub struct Mutex {
     inner: UnsafeCell<libc::pthread_mutex_t>,
 }
 
-pub type MovableMutex = Box<Mutex>;
+pub(crate) type MovableMutex = LazyBox<Mutex>;
 
 #[inline]
 pub unsafe fn raw(m: &Mutex) -> *mut libc::pthread_mutex_t {
@@ -16,6 +17,14 @@ pub unsafe fn raw(m: &Mutex) -> *mut libc::pthread_mutex_t {
 unsafe impl Send for Mutex {}
 unsafe impl Sync for Mutex {}
 
+impl LazyInit for Mutex {
+    fn init() -> Box<Self> {
+        let mut mutex = Box::new(Self::new());
+        unsafe { mutex.init() };
+        mutex
+    }
+}
+
 impl Mutex {
     pub const fn new() -> Mutex {
         // Might be moved to a different address, so it is better to avoid
@@ -73,13 +82,13 @@ pub unsafe fn try_lock(&self) -> bool {
     }
     #[inline]
     #[cfg(not(target_os = "dragonfly"))]
-    pub unsafe fn destroy(&self) {
+    unsafe fn destroy(&mut self) {
         let r = libc::pthread_mutex_destroy(self.inner.get());
         debug_assert_eq!(r, 0);
     }
     #[inline]
     #[cfg(target_os = "dragonfly")]
-    pub unsafe fn destroy(&self) {
+    unsafe fn destroy(&mut self) {
         let r = libc::pthread_mutex_destroy(self.inner.get());
         // On DragonFly pthread_mutex_destroy() returns EINVAL if called on a
         // mutex that was just initialized with libc::PTHREAD_MUTEX_INITIALIZER.
@@ -89,6 +98,13 @@ pub unsafe fn destroy(&self) {
     }
 }
 
+impl Drop for Mutex {
+    #[inline]
+    fn drop(&mut self) {
+        unsafe { self.destroy() };
+    }
+}
+
 pub(super) struct PthreadMutexAttr<'a>(pub &'a mut MaybeUninit<libc::pthread_mutexattr_t>);
 
 impl Drop for PthreadMutexAttr<'_> {
index 11a0c0457cd1aef5bee3e5682516011e965a6060..75e5759c7879d07caeea7c9a88f1ebd9c756ced4 100644 (file)
@@ -1,5 +1,6 @@
 use crate::cell::UnsafeCell;
 use crate::sync::atomic::{AtomicUsize, Ordering};
+use crate::sys_common::lazy_box::{LazyBox, LazyInit};
 
 pub struct RwLock {
     inner: UnsafeCell<libc::pthread_rwlock_t>,
@@ -7,11 +8,17 @@ pub struct RwLock {
     num_readers: AtomicUsize,
 }
 
-pub type MovableRwLock = Box<RwLock>;
+pub(crate) type MovableRwLock = LazyBox<RwLock>;
 
 unsafe impl Send for RwLock {}
 unsafe impl Sync for RwLock {}
 
+impl LazyInit for RwLock {
+    fn init() -> Box<Self> {
+        Box::new(Self::new())
+    }
+}
+
 impl RwLock {
     pub const fn new() -> RwLock {
         RwLock {
@@ -128,7 +135,7 @@ pub unsafe fn write_unlock(&self) {
         self.raw_unlock();
     }
     #[inline]
-    pub unsafe fn destroy(&self) {
+    unsafe fn destroy(&mut self) {
         let r = libc::pthread_rwlock_destroy(self.inner.get());
         // On DragonFly pthread_rwlock_destroy() returns EINVAL if called on a
         // rwlock that was just initialized with
@@ -141,3 +148,10 @@ pub unsafe fn destroy(&self) {
         }
     }
 }
+
+impl Drop for RwLock {
+    #[inline]
+    fn drop(&mut self) {
+        unsafe { self.destroy() };
+    }
+}
index 8e909aab7f0cabae9793bac4e96677253e5947df..1505878e18c0dcdedb66b266b7f6829f48acb6d0 100644 (file)
@@ -1,5 +1,6 @@
 #![allow(missing_docs, nonstandard_style)]
 
+use crate::ffi::CStr;
 use crate::io::ErrorKind;
 
 pub use self::rand::hashmap_random_keys;
@@ -66,6 +67,15 @@ pub unsafe fn init(argc: isize, argv: *const *const u8) {
     stack_overflow::init();
     args::init(argc, argv);
 
+    // Normally, `thread::spawn` will call `Thread::set_name` but since this thread
+    // already exists, we have to call it ourselves. We only do this on macos
+    // because some unix-like operating systems such as Linux share process-id and
+    // thread-id for the main thread and so renaming the main thread will rename the
+    // process and we only want to enable this on platforms we've tested.
+    if cfg!(target_os = "macos") {
+        thread::Thread::set_name(&CStr::from_bytes_with_nul_unchecked(b"main\0"));
+    }
+
     unsafe fn sanitize_standard_fds() {
         #[cfg(not(miri))]
         // The standard fds are always available in Miri.
index 23bb6d6c15f637fe1a36f61b5f5400d8125cefc9..ef29aa3c8907888d4aa8c4f26564dc9cd5fc898e 100644 (file)
@@ -695,18 +695,94 @@ fn from(a: c_int) -> ExitStatus {
     }
 }
 
+/// Convert a signal number to a readable, searchable name.
+///
+/// This string should be displayed right after the signal number.
+/// If a signal is unrecognized, it returns the empty string, so that
+/// you just get the number like "0". If it is recognized, you'll get
+/// something like "9 (SIGKILL)".
+fn signal_string(signal: i32) -> &'static str {
+    match signal {
+        libc::SIGHUP => " (SIGHUP)",
+        libc::SIGINT => " (SIGINT)",
+        libc::SIGQUIT => " (SIGQUIT)",
+        libc::SIGILL => " (SIGILL)",
+        libc::SIGTRAP => " (SIGTRAP)",
+        libc::SIGABRT => " (SIGABRT)",
+        libc::SIGBUS => " (SIGBUS)",
+        libc::SIGFPE => " (SIGFPE)",
+        libc::SIGKILL => " (SIGKILL)",
+        libc::SIGUSR1 => " (SIGUSR1)",
+        libc::SIGSEGV => " (SIGSEGV)",
+        libc::SIGUSR2 => " (SIGUSR2)",
+        libc::SIGPIPE => " (SIGPIPE)",
+        libc::SIGALRM => " (SIGALRM)",
+        libc::SIGTERM => " (SIGTERM)",
+        libc::SIGCHLD => " (SIGCHLD)",
+        libc::SIGCONT => " (SIGCONT)",
+        libc::SIGSTOP => " (SIGSTOP)",
+        libc::SIGTSTP => " (SIGTSTP)",
+        libc::SIGTTIN => " (SIGTTIN)",
+        libc::SIGTTOU => " (SIGTTOU)",
+        libc::SIGURG => " (SIGURG)",
+        libc::SIGXCPU => " (SIGXCPU)",
+        libc::SIGXFSZ => " (SIGXFSZ)",
+        libc::SIGVTALRM => " (SIGVTALRM)",
+        libc::SIGPROF => " (SIGPROF)",
+        libc::SIGWINCH => " (SIGWINCH)",
+        libc::SIGIO => " (SIGIO)",
+        libc::SIGSYS => " (SIGSYS)",
+        // For information on Linux signals, run `man 7 signal`
+        #[cfg(all(
+            target_os = "linux",
+            any(
+                target_arch = "x86_64",
+                target_arch = "x86",
+                target_arch = "arm",
+                target_arch = "aarch64"
+            )
+        ))]
+        libc::SIGSTKFLT => " (SIGSTKFLT)",
+        #[cfg(target_os = "linux")]
+        libc::SIGPWR => " (SIGPWR)",
+        #[cfg(any(
+            target_os = "macos",
+            target_os = "ios",
+            target_os = "tvos",
+            target_os = "freebsd",
+            target_os = "netbsd",
+            target_os = "openbsd",
+            target_os = "dragonfly"
+        ))]
+        libc::SIGEMT => " (SIGEMT)",
+        #[cfg(any(
+            target_os = "macos",
+            target_os = "ios",
+            target_os = "tvos",
+            target_os = "freebsd",
+            target_os = "netbsd",
+            target_os = "openbsd",
+            target_os = "dragonfly"
+        ))]
+        libc::SIGINFO => " (SIGINFO)",
+        _ => "",
+    }
+}
+
 impl fmt::Display for ExitStatus {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         if let Some(code) = self.code() {
             write!(f, "exit status: {code}")
         } else if let Some(signal) = self.signal() {
+            let signal_string = signal_string(signal);
             if self.core_dumped() {
-                write!(f, "signal: {signal} (core dumped)")
+                write!(f, "signal: {signal}{signal_string} (core dumped)")
             } else {
-                write!(f, "signal: {signal}")
+                write!(f, "signal: {signal}{signal_string}")
             }
         } else if let Some(signal) = self.stopped_signal() {
-            write!(f, "stopped (not terminated) by signal: {signal}")
+            let signal_string = signal_string(signal);
+            write!(f, "stopped (not terminated) by signal: {signal}{signal_string}")
         } else if self.continued() {
             write!(f, "continued (WIFCONTINUED)")
         } else {
index 560c62155d9312b91de398ff19be6e06cf5539fe..e0e2d478fad731129216a02eefe66d7a4055d878 100644 (file)
@@ -14,8 +14,8 @@ fn exitstatus_display_tests() {
 
     let t = |v, s| assert_eq!(s, format!("{}", <ExitStatus as ExitStatusExt>::from_raw(v)));
 
-    t(0x0000f, "signal: 15");
-    t(0x0008b, "signal: 11 (core dumped)");
+    t(0x0000f, "signal: 15 (SIGTERM)");
+    t(0x0008b, "signal: 11 (SIGSEGV) (core dumped)");
     t(0x00000, "exit status: 0");
     t(0x0ff00, "exit status: 255");
 
@@ -24,7 +24,7 @@ fn exitstatus_display_tests() {
     // The purpose of this test is to test our string formatting, not our understanding of the wait
     // status magic numbers.  So restrict these to Linux.
     if cfg!(target_os = "linux") {
-        t(0x0137f, "stopped (not terminated) by signal: 19");
+        t(0x0137f, "stopped (not terminated) by signal: 19 (SIGSTOP)");
         t(0x0ffff, "continued (WIFCONTINUED)");
     }
 
index 8dbe03bad9b0d8e09c2d0e093f7cb0572d022f27..f27bf2b26bdaaaf88c397ffd5544e6600412298a 100644 (file)
@@ -10,9 +10,6 @@ pub const fn new() -> Condvar {
         Condvar {}
     }
 
-    #[inline]
-    pub unsafe fn init(&mut self) {}
-
     #[inline]
     pub unsafe fn notify_one(&self) {}
 
@@ -26,7 +23,4 @@ pub unsafe fn wait(&self, _mutex: &Mutex) {
     pub unsafe fn wait_timeout(&self, _mutex: &Mutex, _dur: Duration) -> bool {
         panic!("condvar wait not supported");
     }
-
-    #[inline]
-    pub unsafe fn destroy(&self) {}
 }
index cad991aae5e961257ef56edccf0e06b36ba5fb8f..56bad71b189f55a53578c44133ca8492314d10b9 100644 (file)
@@ -32,7 +32,4 @@ pub unsafe fn unlock(&self) {
     pub unsafe fn try_lock(&self) -> bool {
         self.locked.replace(true) == false
     }
-
-    #[inline]
-    pub unsafe fn destroy(&self) {}
 }
index 14fd351314c17a9d87601c79f7f2221ca479e3fa..bf6e2d3d080b435e0f625877a8bbe05f501bc461 100644 (file)
@@ -62,7 +62,4 @@ pub unsafe fn read_unlock(&self) {
     pub unsafe fn write_unlock(&self) {
         assert_eq!(self.mode.replace(0), -1);
     }
-
-    #[inline]
-    pub unsafe fn destroy(&self) {}
 }
index 9992e44b0e7566b2fb9f8857550dcb2e29999477..55b5ad314daf023ab0b3ca11d835ec740c10a827 100644 (file)
@@ -54,8 +54,8 @@ pub mod locks {
             #![allow(unsafe_op_in_unsafe_fn)]
             mod futex;
             mod futex_rwlock;
-            pub use futex::{Mutex, MovableMutex, Condvar, MovableCondvar};
-            pub use futex_rwlock::{RwLock, MovableRwLock};
+            pub(crate) use futex::{Mutex, MovableMutex, Condvar, MovableCondvar};
+            pub(crate) use futex_rwlock::{RwLock, MovableRwLock};
         }
         #[path = "atomics/futex.rs"]
         pub mod futex;
index dfd8cfdceee75ab2efbf277e641617f5a49e31e8..59e2c1be0f0f2dc7f86bed106a1f01e061a2d0fe 100644 (file)
@@ -18,9 +18,6 @@ pub const fn new() -> Condvar {
         Condvar { inner: UnsafeCell::new(c::CONDITION_VARIABLE_INIT) }
     }
 
-    #[inline]
-    pub unsafe fn init(&mut self) {}
-
     #[inline]
     pub unsafe fn wait(&self, mutex: &Mutex) {
         let r = c::SleepConditionVariableSRW(self.inner.get(), mutex::raw(mutex), c::INFINITE, 0);
@@ -51,8 +48,4 @@ pub unsafe fn notify_one(&self) {
     pub unsafe fn notify_all(&self) {
         c::WakeAllConditionVariable(self.inner.get())
     }
-
-    pub unsafe fn destroy(&self) {
-        // ...
-    }
 }
index 9fa280b8b765994fdb096a1317f4130f5198004c..08f55844a0efa23bdf56f9ee29c8cd333c34f81a 100644 (file)
@@ -53,9 +53,4 @@ pub unsafe fn try_lock(&self) -> bool {
     pub unsafe fn unlock(&self) {
         c::ReleaseSRWLockExclusive(raw(self));
     }
-
-    #[inline]
-    pub unsafe fn destroy(&self) {
-        // SRWLock does not need to be destroyed.
-    }
 }
index 12906652e0b7170d617800ae402478ade0448f44..a32df85e2f63c266ddd9693d9a1ef4a03bb9f96d 100644 (file)
@@ -38,9 +38,4 @@ pub unsafe fn read_unlock(&self) {
     pub unsafe fn write_unlock(&self) {
         c::ReleaseSRWLockExclusive(self.inner.get())
     }
-
-    #[inline]
-    pub unsafe fn destroy(&self) {
-        // ...
-    }
 }
index 4e9d408291d2a1402a4e34a069637b3dc72c13ec..b3f6d2d0aaed4213ab80f487faf552dea345ee92 100644 (file)
@@ -1,6 +1,6 @@
 #![allow(missing_docs, nonstandard_style)]
 
-use crate::ffi::{OsStr, OsString};
+use crate::ffi::{CStr, OsStr, OsString};
 use crate::io::ErrorKind;
 use crate::os::windows::ffi::{OsStrExt, OsStringExt};
 use crate::path::PathBuf;
 // NOTE: this is not guaranteed to run, for example when Rust code is called externally.
 pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
     stack_overflow::init();
+
+    // Normally, `thread::spawn` will call `Thread::set_name` but since this thread already
+    // exists, we have to call it ourselves.
+    thread::Thread::set_name(&CStr::from_bytes_with_nul_unchecked(b"main\0"));
 }
 
 // SAFETY: must be called only once during runtime cleanup.
index 67d4b1262091acba0d6cc169eea77a12c0ac2e4c..1def0518e0a6fff0825ea90205c2c7b805d82cbb 100644 (file)
@@ -15,9 +15,7 @@ pub struct Condvar {
 impl Condvar {
     /// Creates a new condition variable for use.
     pub fn new() -> Self {
-        let mut c = imp::MovableCondvar::from(imp::Condvar::new());
-        unsafe { c.init() };
-        Self { inner: c, check: CondvarCheck::new() }
+        Self { inner: imp::MovableCondvar::new(), check: CondvarCheck::new() }
     }
 
     /// Signals one waiter on this condition variable to wake up.
@@ -55,9 +53,3 @@ pub unsafe fn wait_timeout(&self, mutex: &MovableMutex, dur: Duration) -> bool {
         self.inner.wait_timeout(mutex.raw(), dur)
     }
 }
-
-impl Drop for Condvar {
-    fn drop(&mut self) {
-        unsafe { self.inner.destroy() };
-    }
-}
index d0d0d59651895c9fa1af49daffc646790da7f057..ce8f36704877fe390558863f5821fc40fcd3c60b 100644 (file)
@@ -1,6 +1,7 @@
 use crate::ptr;
 use crate::sync::atomic::{AtomicPtr, Ordering};
 use crate::sys::locks as imp;
+use crate::sys_common::lazy_box::{LazyBox, LazyInit};
 use crate::sys_common::mutex::MovableMutex;
 
 pub trait CondvarCheck {
@@ -9,7 +10,7 @@ pub trait CondvarCheck {
 
 /// For boxed mutexes, a `Condvar` will check it's only ever used with the same
 /// mutex, based on its (stable) address.
-impl CondvarCheck for Box<imp::Mutex> {
+impl<T: LazyInit> CondvarCheck for LazyBox<T> {
     type Check = SameMutexCheck;
 }
 
diff --git a/library/std/src/sys_common/lazy_box.rs b/library/std/src/sys_common/lazy_box.rs
new file mode 100644 (file)
index 0000000..647c13d
--- /dev/null
@@ -0,0 +1,77 @@
+#![allow(dead_code)] // Only used on some platforms.
+
+// This is used to wrap pthread {Mutex, Condvar, RwLock} in.
+
+use crate::marker::PhantomData;
+use crate::ops::{Deref, DerefMut};
+use crate::ptr::null_mut;
+use crate::sync::atomic::{
+    AtomicPtr,
+    Ordering::{AcqRel, Acquire},
+};
+
+pub(crate) struct LazyBox<T: LazyInit> {
+    ptr: AtomicPtr<T>,
+    _phantom: PhantomData<T>,
+}
+
+pub(crate) trait LazyInit {
+    /// This is called before the box is allocated, to provide the value to
+    /// move into the new box.
+    ///
+    /// It might be called more than once per LazyBox, as multiple threads
+    /// might race to initialize it concurrently, each constructing and initializing
+    /// their own box. (All but one of them will be destroyed right after.)
+    fn init() -> Box<Self>;
+}
+
+impl<T: LazyInit> LazyBox<T> {
+    #[inline]
+    pub const fn new() -> Self {
+        Self { ptr: AtomicPtr::new(null_mut()), _phantom: PhantomData }
+    }
+
+    #[inline]
+    fn get_pointer(&self) -> *mut T {
+        let ptr = self.ptr.load(Acquire);
+        if ptr.is_null() { self.initialize() } else { ptr }
+    }
+
+    #[cold]
+    fn initialize(&self) -> *mut T {
+        let new_ptr = Box::into_raw(T::init());
+        match self.ptr.compare_exchange(null_mut(), new_ptr, AcqRel, Acquire) {
+            Ok(_) => new_ptr,
+            Err(ptr) => {
+                // Lost the race to another thread.
+                // Drop the box we created, and use the one from the other thread instead.
+                drop(unsafe { Box::from_raw(new_ptr) });
+                ptr
+            }
+        }
+    }
+}
+
+impl<T: LazyInit> Deref for LazyBox<T> {
+    type Target = T;
+    #[inline]
+    fn deref(&self) -> &T {
+        unsafe { &*self.get_pointer() }
+    }
+}
+
+impl<T: LazyInit> DerefMut for LazyBox<T> {
+    #[inline]
+    fn deref_mut(&mut self) -> &mut T {
+        unsafe { &mut *self.get_pointer() }
+    }
+}
+
+impl<T: LazyInit> Drop for LazyBox<T> {
+    fn drop(&mut self) {
+        let ptr = *self.ptr.get_mut();
+        if !ptr.is_null() {
+            drop(unsafe { Box::from_raw(ptr) });
+        }
+    }
+}
index 804727fbc54d139ec37c8afb4b66e93e30d915b5..80f56bf7522b67edbf547f77cf8707fded8c9b21 100644 (file)
@@ -24,6 +24,7 @@
 pub mod condvar;
 pub mod fs;
 pub mod io;
+pub mod lazy_box;
 pub mod memchr;
 pub mod mutex;
 pub mod process;
index 12a09c9860501c32cc1d7fa1baf943915d31fa9f..36ea888d8de499cb7d3b5a42dac69a32f11a5781 100644 (file)
@@ -61,9 +61,7 @@ unsafe impl Sync for MovableMutex {}
 impl MovableMutex {
     /// Creates a new mutex.
     pub fn new() -> Self {
-        let mut mutex = imp::MovableMutex::from(imp::Mutex::new());
-        unsafe { mutex.init() };
-        Self(mutex)
+        Self(imp::MovableMutex::new())
     }
 
     pub(super) fn raw(&self) -> &imp::Mutex {
@@ -92,9 +90,3 @@ pub unsafe fn raw_unlock(&self) {
         self.0.unlock()
     }
 }
-
-impl Drop for MovableMutex {
-    fn drop(&mut self) {
-        unsafe { self.0.destroy() };
-    }
-}
index 8f252308de760e8515212aaf4209ecfa9089b032..8921af311d4152bb7b6fc7b4c37763ce35e14915 100644 (file)
@@ -168,13 +168,6 @@ unsafe fn increment_lock_count(&self) {
     }
 }
 
-impl<T> Drop for ReentrantMutex<T> {
-    fn drop(&mut self) {
-        // Safety: We're the unique owner of this mutex and not going to use it afterwards.
-        unsafe { self.mutex.destroy() }
-    }
-}
-
 impl<T> Deref for ReentrantMutexGuard<'_, T> {
     type Target = T;
 
index 12e7a72a344dcc46facb8b226d2cbf0ad6694ecb..abc9fd561f1f60d89d97157474be1274a6b32007 100644 (file)
@@ -74,7 +74,7 @@ fn drop(&mut self) {
 impl MovableRwLock {
     /// Creates a new reader-writer lock for use.
     pub fn new() -> Self {
-        Self(imp::MovableRwLock::from(imp::RwLock::new()))
+        Self(imp::MovableRwLock::new())
     }
 
     /// Acquires shared access to the underlying lock, blocking the current
@@ -126,9 +126,3 @@ pub unsafe fn write_unlock(&self) {
         self.0.write_unlock()
     }
 }
-
-impl Drop for MovableRwLock {
-    fn drop(&mut self) {
-        unsafe { self.0.destroy() };
-    }
-}
index dea8d998bdeda21ce50766a7e740a0c35868c35c..5027a45e0ada033db08b8d86a2f2a546ec958f19 100644 (file)
@@ -49,6 +49,9 @@ opener = "0.5"
 once_cell = "1.7.2"
 xz2 = "0.1"
 
+# Dependencies needed by the build-metrics feature
+sysinfo = { version = "0.24.1", optional = true }
+
 [target.'cfg(windows)'.dependencies.winapi]
 version = "0.3"
 features = [
@@ -64,3 +67,6 @@ features = [
 
 [dev-dependencies]
 pretty_assertions = "0.7"
+
+[features]
+build-metrics = ["sysinfo"]
index a997c4f63abb8ace72ea3265a18486f8159c58bd..d81874bfe7e9707d87cbb7e55647539a20653ce0 100644 (file)
@@ -837,6 +837,9 @@ class RustBuild(object):
             args.append("--locked")
         if self.use_vendored_sources:
             args.append("--frozen")
+        if self.get_toml("metrics", "build"):
+            args.append("--features")
+            args.append("build-metrics")
         run(args, env=env, verbose=self.verbose)
 
     def build_triple(self):
index 17c2d1c79ec5c4cdbb75a8383ebbf9a21a63692c..da13374cee7cdea9ce06ae8175e1803ee13ad71f 100644 (file)
@@ -1364,29 +1364,26 @@ pub fn cargo(
         // get some support for setting `--check-cfg` within build script, it's the least invasive
         // hack that still let's us have cfg checking for the vast majority of the codebase.
         if stage != 0 {
-            // Enable cfg checking of cargo features for everything but std.
+            // Enable cfg checking of cargo features for everything but std and also enable cfg
+            // checking of names and values.
             //
             // Note: `std`, `alloc` and `core` imports some dependencies by #[path] (like
-            // backtrace, core_simd, std_float, ...), those dependencies have their own features
-            // but cargo isn't involved in the #[path] and so cannot pass the complete list of
-            // features, so for that reason we don't enable checking of features for std.
+            // backtrace, core_simd, std_float, ...), those dependencies have their own
+            // features but cargo isn't involved in the #[path] process and so cannot pass the
+            // complete list of features, so for that reason we don't enable checking of
+            // features for std crates.
+            cargo.arg(if mode != Mode::Std {
+                "-Zcheck-cfg=names,values,features"
+            } else {
+                "-Zcheck-cfg=names,values"
+            });
+
+            // Add extra cfg not defined in/by rustc
             //
-            // FIXME: Re-enable this after the beta bump as apperently rustc-perf doesn't use the
-            // beta cargo. See https://github.com/rust-lang/rust/pull/96984#issuecomment-1126678773
-            // #[cfg(not(bootstrap))]
-            // if mode != Mode::Std {
-            //     cargo.arg("-Zcheck-cfg-features"); // -Zcheck-cfg=features after bump
-            // }
-
-            // Enable cfg checking of well known names/values
-            rustflags
-                .arg("-Zunstable-options")
-                // Enable checking of well known names
-                .arg("--check-cfg=names()")
-                // Enable checking of well known values
-                .arg("--check-cfg=values()");
-
-            // Add extra cfg not defined in rustc
+            // Note: Altrough it would seems that "-Zunstable-options" to `rustflags` is useless as
+            // cargo would implicitly add it, it was discover that sometimes bootstrap only use
+            // `rustflags` without `cargo` making it required.
+            rustflags.arg("-Zunstable-options");
             for (restricted_mode, name, values) in EXTRA_CHECK_CFGS {
                 if *restricted_mode == None || *restricted_mode == Some(mode) {
                     // Creating a string of the values by concatenating each value:
@@ -2013,6 +2010,9 @@ pub fn ensure<S: Step>(&'a self, step: S) -> S::Output {
             stack.push(Box::new(step.clone()));
         }
 
+        #[cfg(feature = "build-metrics")]
+        self.metrics.enter_step(&step);
+
         let (out, dur) = {
             let start = Instant::now();
             let zero = Duration::new(0, 0);
@@ -2036,6 +2036,9 @@ pub fn ensure<S: Step>(&'a self, step: S) -> S::Output {
             );
         }
 
+        #[cfg(feature = "build-metrics")]
+        self.metrics.exit_step();
+
         {
             let mut stack = self.stack.borrow_mut();
             let cur_step = stack.pop().expect("step stack empty");
index 8e94fc7c4bea5512395bbe24e1bbd9ef302ab29b..6cb0bd518e278702d43fd3a40d85ebf7fb6b0771 100644 (file)
@@ -550,6 +550,7 @@ struct Build {
         dist_stage: Option<u32> = "dist-stage",
         bench_stage: Option<u32> = "bench-stage",
         patch_binaries_for_nix: Option<bool> = "patch-binaries-for-nix",
+        metrics: Option<bool> = "metrics",
     }
 }
 
index 0f0cf0762ab5df6823ebe0d62656cf43411744a4..fab6168bf38f61164877d49ef4a0bbd90c6bbd66 100644 (file)
 mod toolstate;
 pub mod util;
 
+#[cfg(feature = "build-metrics")]
+mod metrics;
+
 #[cfg(windows)]
 mod job;
 
@@ -312,6 +315,9 @@ pub struct Build {
     prerelease_version: Cell<Option<u32>>,
     tool_artifacts:
         RefCell<HashMap<TargetSelection, HashMap<String, (&'static str, PathBuf, Vec<String>)>>>,
+
+    #[cfg(feature = "build-metrics")]
+    metrics: metrics::BuildMetrics,
 }
 
 #[derive(Debug)]
@@ -501,6 +507,9 @@ pub fn new(config: Config) -> Build {
             delayed_failures: RefCell::new(Vec::new()),
             prerelease_version: Cell::new(None),
             tool_artifacts: Default::default(),
+
+            #[cfg(feature = "build-metrics")]
+            metrics: metrics::BuildMetrics::init(),
         };
 
         build.verbose("finding compilers");
@@ -695,6 +704,9 @@ pub fn build(&mut self) {
             }
             process::exit(1);
         }
+
+        #[cfg(feature = "build-metrics")]
+        self.metrics.persist(self);
     }
 
     /// Clear out `dir` if `input` is newer.
diff --git a/src/bootstrap/metrics.rs b/src/bootstrap/metrics.rs
new file mode 100644 (file)
index 0000000..451febd
--- /dev/null
@@ -0,0 +1,208 @@
+//! This module is responsible for collecting metrics profiling information for the current build
+//! and dumping it to disk as JSON, to aid investigations on build and CI performance.
+//!
+//! As this module requires additional dependencies not present during local builds, it's cfg'd
+//! away whenever the `build.metrics` config option is not set to `true`.
+
+use crate::builder::Step;
+use crate::util::t;
+use crate::Build;
+use serde::{Deserialize, Serialize};
+use std::cell::RefCell;
+use std::fs::File;
+use std::io::BufWriter;
+use std::time::{Duration, Instant};
+use sysinfo::{CpuExt, System, SystemExt};
+
+pub(crate) struct BuildMetrics {
+    state: RefCell<MetricsState>,
+}
+
+impl BuildMetrics {
+    pub(crate) fn init() -> Self {
+        let state = RefCell::new(MetricsState {
+            finished_steps: Vec::new(),
+            running_steps: Vec::new(),
+
+            system_info: System::new(),
+            timer_start: None,
+            invocation_timer_start: Instant::now(),
+        });
+
+        BuildMetrics { state }
+    }
+
+    pub(crate) fn enter_step<S: Step>(&self, step: &S) {
+        let mut state = self.state.borrow_mut();
+
+        // Consider all the stats gathered so far as the parent's.
+        if !state.running_steps.is_empty() {
+            self.collect_stats(&mut *state);
+        }
+
+        state.system_info.refresh_cpu();
+        state.timer_start = Some(Instant::now());
+
+        state.running_steps.push(StepMetrics {
+            type_: std::any::type_name::<S>().into(),
+            debug_repr: format!("{step:?}"),
+
+            cpu_usage_time_sec: 0.0,
+            duration_excluding_children_sec: Duration::ZERO,
+
+            children: Vec::new(),
+        });
+    }
+
+    pub(crate) fn exit_step(&self) {
+        let mut state = self.state.borrow_mut();
+
+        self.collect_stats(&mut *state);
+
+        let step = state.running_steps.pop().unwrap();
+        if state.running_steps.is_empty() {
+            state.finished_steps.push(step);
+            state.timer_start = None;
+        } else {
+            state.running_steps.last_mut().unwrap().children.push(step);
+
+            // Start collecting again for the parent step.
+            state.system_info.refresh_cpu();
+            state.timer_start = Some(Instant::now());
+        }
+    }
+
+    fn collect_stats(&self, state: &mut MetricsState) {
+        let step = state.running_steps.last_mut().unwrap();
+
+        let elapsed = state.timer_start.unwrap().elapsed();
+        step.duration_excluding_children_sec += elapsed;
+
+        state.system_info.refresh_cpu();
+        let cpu = state.system_info.cpus().iter().map(|p| p.cpu_usage()).sum::<f32>();
+        step.cpu_usage_time_sec += cpu as f64 / 100.0 * elapsed.as_secs_f64();
+    }
+
+    pub(crate) fn persist(&self, build: &Build) {
+        let mut state = self.state.borrow_mut();
+        assert!(state.running_steps.is_empty(), "steps are still executing");
+
+        let dest = build.out.join("metrics.json");
+
+        let mut system = System::new();
+        system.refresh_cpu();
+        system.refresh_memory();
+
+        let system_stats = JsonInvocationSystemStats {
+            cpu_threads_count: system.cpus().len(),
+            cpu_model: system.cpus()[0].brand().into(),
+
+            memory_total_bytes: system.total_memory() * 1024,
+        };
+        let steps = std::mem::take(&mut state.finished_steps);
+
+        // Some of our CI builds consist of multiple independent CI invocations. Ensure all the
+        // previous invocations are still present in the resulting file.
+        let mut invocations = match std::fs::read(&dest) {
+            Ok(contents) => t!(serde_json::from_slice::<JsonRoot>(&contents)).invocations,
+            Err(err) => {
+                if err.kind() != std::io::ErrorKind::NotFound {
+                    panic!("failed to open existing metrics file at {}: {err}", dest.display());
+                }
+                Vec::new()
+            }
+        };
+        invocations.push(JsonInvocation {
+            duration_including_children_sec: state.invocation_timer_start.elapsed().as_secs_f64(),
+            children: steps.into_iter().map(|step| self.prepare_json_step(step)).collect(),
+        });
+
+        let json = JsonRoot { system_stats, invocations };
+
+        t!(std::fs::create_dir_all(dest.parent().unwrap()));
+        let mut file = BufWriter::new(t!(File::create(&dest)));
+        t!(serde_json::to_writer(&mut file, &json));
+    }
+
+    fn prepare_json_step(&self, step: StepMetrics) -> JsonNode {
+        JsonNode::RustbuildStep {
+            type_: step.type_,
+            debug_repr: step.debug_repr,
+
+            duration_excluding_children_sec: step.duration_excluding_children_sec.as_secs_f64(),
+            system_stats: JsonStepSystemStats {
+                cpu_utilization_percent: step.cpu_usage_time_sec * 100.0
+                    / step.duration_excluding_children_sec.as_secs_f64(),
+            },
+
+            children: step
+                .children
+                .into_iter()
+                .map(|child| self.prepare_json_step(child))
+                .collect(),
+        }
+    }
+}
+
+struct MetricsState {
+    finished_steps: Vec<StepMetrics>,
+    running_steps: Vec<StepMetrics>,
+
+    system_info: System,
+    timer_start: Option<Instant>,
+    invocation_timer_start: Instant,
+}
+
+struct StepMetrics {
+    type_: String,
+    debug_repr: String,
+
+    cpu_usage_time_sec: f64,
+    duration_excluding_children_sec: Duration,
+
+    children: Vec<StepMetrics>,
+}
+
+#[derive(Serialize, Deserialize)]
+#[serde(rename_all = "snake_case")]
+struct JsonRoot {
+    system_stats: JsonInvocationSystemStats,
+    invocations: Vec<JsonInvocation>,
+}
+
+#[derive(Serialize, Deserialize)]
+#[serde(rename_all = "snake_case")]
+struct JsonInvocation {
+    duration_including_children_sec: f64,
+    children: Vec<JsonNode>,
+}
+
+#[derive(Serialize, Deserialize)]
+#[serde(tag = "kind", rename_all = "snake_case")]
+enum JsonNode {
+    RustbuildStep {
+        #[serde(rename = "type")]
+        type_: String,
+        debug_repr: String,
+
+        duration_excluding_children_sec: f64,
+        system_stats: JsonStepSystemStats,
+
+        children: Vec<JsonNode>,
+    },
+}
+
+#[derive(Serialize, Deserialize)]
+#[serde(rename_all = "snake_case")]
+struct JsonInvocationSystemStats {
+    cpu_threads_count: usize,
+    cpu_model: String,
+
+    memory_total_bytes: u64,
+}
+
+#[derive(Serialize, Deserialize)]
+#[serde(rename_all = "snake_case")]
+struct JsonStepSystemStats {
+    cpu_utilization_percent: f64,
+}
index a41079333b1aabbe3bd39f33c466c00f89f82d3c..79f2338b7abb9618e81f3c652db133c222139da1 100644 (file)
@@ -300,6 +300,9 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
 
         if builder.config.llvm_profile_generate {
             cfg.define("LLVM_BUILD_INSTRUMENTED", "IR");
+            if let Ok(llvm_profile_dir) = std::env::var("LLVM_PROFILE_DIR") {
+                cfg.define("LLVM_PROFILE_DATA_DIR", llvm_profile_dir);
+            }
             cfg.define("LLVM_BUILD_RUNTIME", "No");
         }
         if let Some(path) = builder.config.llvm_profile_use.as_ref() {
index 9b727947f6ad1c9d570a265926eefa2c77fb4b1f..9de970c9c2aa5be160d1221d1c1a8320b961573d 100755 (executable)
@@ -39,12 +39,19 @@ gather_profiles () {
 
 rm -rf /tmp/rustc-pgo
 
+# This path has to be absolute
+LLVM_PROFILE_DIRECTORY_ROOT=/tmp/llvm-pgo
+
 # We collect LLVM profiling information and rustc profiling information in
 # separate phases. This increases build time -- though not by a huge amount --
 # but prevents any problems from arising due to different profiling runtimes
 # being simultaneously linked in.
-
-python3 ../x.py build --target=$PGO_HOST --host=$PGO_HOST \
+# LLVM IR PGO does not respect LLVM_PROFILE_FILE, so we have to set the profiling file
+# path through our custom environment variable. We include the PID in the directory path
+# to avoid updates to profile files being lost because of race conditions.
+LLVM_PROFILE_DIR=${LLVM_PROFILE_DIRECTORY_ROOT}/prof-%p python3 ../x.py build \
+    --target=$PGO_HOST \
+    --host=$PGO_HOST \
     --stage 2 library/std \
     --llvm-profile-generate
 
@@ -64,11 +71,18 @@ RUSTC_BOOTSTRAP=1 \
 gather_profiles "Debug,Opt" "Full" \
 "syn-1.0.89,cargo-0.60.0,serde-1.0.136,ripgrep-13.0.0,regex-1.5.5,clap-3.1.6,hyper-0.14.18"
 
+LLVM_PROFILE_MERGED_FILE=/tmp/llvm-pgo.profdata
+
 # Merge the profile data we gathered for LLVM
 # Note that this uses the profdata from the clang we used to build LLVM,
 # which likely has a different version than our in-tree clang.
-/rustroot/bin/llvm-profdata \
-    merge -o /tmp/llvm-pgo.profdata ./build/$PGO_HOST/llvm/build/profiles
+/rustroot/bin/llvm-profdata merge -o ${LLVM_PROFILE_MERGED_FILE} ${LLVM_PROFILE_DIRECTORY_ROOT}
+
+echo "LLVM PGO statistics"
+du -sh ${LLVM_PROFILE_MERGED_FILE}
+du -sh ${LLVM_PROFILE_DIRECTORY_ROOT}
+echo "Profile file count"
+find ${LLVM_PROFILE_DIRECTORY_ROOT} -type f | wc -l
 
 # Rustbuild currently doesn't support rebuilding LLVM when PGO options
 # change (or any other llvm-related options); so just clear out the relevant
@@ -77,9 +91,12 @@ rm -r ./build/$PGO_HOST/llvm ./build/$PGO_HOST/lld
 
 # Okay, LLVM profiling is done, switch to rustc PGO.
 
+# The path has to be absolute
+RUSTC_PROFILE_DIRECTORY_ROOT=/tmp/rustc-pgo
+
 python3 ../x.py build --target=$PGO_HOST --host=$PGO_HOST \
     --stage 2 library/std \
-    --rust-profile-generate=/tmp/rustc-pgo
+    --rust-profile-generate=${RUSTC_PROFILE_DIRECTORY_ROOT}
 
 # Here we're profiling the `rustc` frontend, so we also include `Check`.
 # The benchmark set includes various stress tests that put the frontend under pressure.
@@ -87,12 +104,21 @@ python3 ../x.py build --target=$PGO_HOST --host=$PGO_HOST \
 # rustc invocation ends. Empirically, this can result in some profiling data being lost.
 # That's why we override the profile path to include the PID. This will produce many more profiling
 # files, but the resulting profile will produce a slightly faster rustc binary.
-LLVM_PROFILE_FILE=/tmp/rustc-pgo/default_%m_%p.profraw gather_profiles "Check,Debug,Opt" "All" \
-"externs,ctfe-stress-5,cargo-0.60.0,token-stream-stress,match-stress,tuple-stress,diesel-1.4.8,bitmaps-3.1.0"
+LLVM_PROFILE_FILE=${RUSTC_PROFILE_DIRECTORY_ROOT}/default_%m_%p.profraw gather_profiles \
+  "Check,Debug,Opt" "All" \
+  "externs,ctfe-stress-5,cargo-0.60.0,token-stream-stress,match-stress,tuple-stress,diesel-1.4.8,bitmaps-3.1.0"
+
+RUSTC_PROFILE_MERGED_FILE=/tmp/rustc-pgo.profdata
 
 # Merge the profile data we gathered
 ./build/$PGO_HOST/llvm/bin/llvm-profdata \
-    merge -o /tmp/rustc-pgo.profdata /tmp/rustc-pgo
+    merge -o ${RUSTC_PROFILE_MERGED_FILE} ${RUSTC_PROFILE_DIRECTORY_ROOT}
+
+echo "Rustc PGO statistics"
+du -sh ${RUSTC_PROFILE_MERGED_FILE}
+du -sh ${RUSTC_PROFILE_DIRECTORY_ROOT}
+echo "Profile file count"
+find ${RUSTC_PROFILE_DIRECTORY_ROOT} -type f | wc -l
 
 # Rustbuild currently doesn't support rebuilding LLVM when PGO options
 # change (or any other llvm-related options); so just clear out the relevant
@@ -102,5 +128,5 @@ rm -r ./build/$PGO_HOST/llvm ./build/$PGO_HOST/lld
 # This produces the actual final set of artifacts, using both the LLVM and rustc
 # collected profiling data.
 $@ \
-    --rust-profile-use=/tmp/rustc-pgo.profdata \
-    --llvm-profile-use=/tmp/llvm-pgo.profdata
+    --rust-profile-use=${RUSTC_PROFILE_MERGED_FILE} \
+    --llvm-profile-use=${LLVM_PROFILE_MERGED_FILE}
index 5f843a13bcd9b574ddbed4e71bf61ed3a12ce5e1..b0314047c070b07ac9fd1860fbf6164c5946fa34 100755 (executable)
@@ -45,6 +45,7 @@ fi
 
 if ! isCI || isCiBranch auto || isCiBranch beta || isCiBranch try; then
     RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set build.print-step-timings --enable-verbose-tests"
+    RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set build.metrics"
 fi
 
 RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-sccache"
index cea9b770f2a20a8b4e66b53c5256ff11eeddf026..ffa1859fc2253b94e530e5e83857142b95c10b71 100755 (executable)
@@ -10,12 +10,14 @@ source "$(cd "$(dirname "$0")" && pwd)/../shared.sh"
 
 upload_dir="$(mktemp -d)"
 
+build_dir=build
+if isLinux; then
+    build_dir=obj/build
+fi
+
 # Release tarballs produced by a dist builder.
 if [[ "${DEPLOY-0}" -eq "1" ]] || [[ "${DEPLOY_ALT-0}" -eq "1" ]]; then
-    dist_dir=build/dist
-    if isLinux; then
-        dist_dir=obj/build/dist
-    fi
+    dist_dir="${build_dir}/dist"
     rm -rf "${dist_dir}/doc"
     cp -r "${dist_dir}"/* "${upload_dir}"
 fi
@@ -23,6 +25,9 @@ fi
 # CPU usage statistics.
 cp cpu-usage.csv "${upload_dir}/cpu-${CI_JOB_NAME}.csv"
 
+# Build metrics generated by x.py.
+cp "${build_dir}/metrics.json" "${upload_dir}/metrics-${CI_JOB_NAME}.json"
+
 # Toolstate data.
 if [[ -n "${DEPLOY_TOOLSTATES_JSON+x}" ]]; then
     cp /tmp/toolstate/toolstates.json "${upload_dir}/${DEPLOY_TOOLSTATES_JSON}"
index 269b6868e29f9a9c4bed287ba3d28c9ba4058714..5eb70ab13dba06f89175116d2d1b385ae7b1551c 100644 (file)
@@ -423,6 +423,8 @@ def check_snapshot(snapshot_name, actual_tree, normalize_to_text):
     else:
         actual_str = flatten(actual_tree)
 
+    expected_str = expected_str.replace("{{channel}}", channel)
+
     # Conditions:
     #  1. Is --bless
     #  2. Are actual and expected tree different
index c725cf93be2f40e6138674f4971cd5576c93ed26..f3070fb35f1d09bf2354a034809c77990b2b267e 100644 (file)
@@ -475,24 +475,14 @@ fn clean_generic_param<'tcx>(
     generics: Option<&hir::Generics<'tcx>>,
     param: &hir::GenericParam<'tcx>,
 ) -> GenericParamDef {
+    let did = cx.tcx.hir().local_def_id(param.hir_id);
     let (name, kind) = match param.kind {
         hir::GenericParamKind::Lifetime { .. } => {
             let outlives = if let Some(generics) = generics {
                 generics
-                    .predicates
-                    .iter()
-                    .flat_map(|pred| {
-                        match pred {
-                            hir::WherePredicate::RegionPredicate(rp)
-                                if rp.lifetime.name == hir::LifetimeName::Param(param.name)
-                                    && !rp.in_where_clause =>
-                            {
-                                rp.bounds
-                            }
-                            _ => &[],
-                        }
-                        .iter()
-                    })
+                    .outlives_for_param(did)
+                    .filter(|bp| !bp.in_where_clause)
+                    .flat_map(|bp| bp.bounds)
                     .map(|bound| match bound {
                         hir::GenericBound::Outlives(lt) => lt.clean(cx),
                         _ => panic!(),
@@ -504,7 +494,6 @@ fn clean_generic_param<'tcx>(
             (param.name.ident().name, GenericParamDefKind::Lifetime { outlives })
         }
         hir::GenericParamKind::Type { ref default, synthetic } => {
-            let did = cx.tcx.hir().local_def_id(param.hir_id);
             let bounds = if let Some(generics) = generics {
                 generics
                     .bounds_for_param(did)
@@ -528,7 +517,7 @@ fn clean_generic_param<'tcx>(
         hir::GenericParamKind::Const { ty, default } => (
             param.name.ident().name,
             GenericParamDefKind::Const {
-                did: cx.tcx.hir().local_def_id(param.hir_id).to_def_id(),
+                did: did.to_def_id(),
                 ty: Box::new(ty.clean(cx)),
                 default: default.map(|ct| {
                     let def_id = cx.tcx.hir().local_def_id(ct.hir_id);
@@ -1459,7 +1448,7 @@ fn clean(&self, cx: &mut DocContext<'tcx>) -> Type {
                 // Turning `fn f(&'_ self)` into `fn f(&self)` isn't the worst thing in the world, though;
                 // there's no case where it could cause the function to fail to compile.
                 let elided =
-                    l.is_elided() || matches!(l.name, LifetimeName::Param(ParamName::Fresh(_)));
+                    l.is_elided() || matches!(l.name, LifetimeName::Param(_, ParamName::Fresh));
                 let lifetime = if elided { None } else { Some(l.clean(cx)) };
                 BorrowedRef { lifetime, mutability: m.mutbl, type_: box m.ty.clean(cx) }
             }
index 1e434458dcef55627a909d4dfe69bf7358ddb755..4605793d0df941bc70cf4dfad9075a45e361c609 100644 (file)
@@ -1667,6 +1667,10 @@ pub(crate) fn is_full_generic(&self) -> bool {
         matches!(self, Type::Generic(_))
     }
 
+    pub(crate) fn is_impl_trait(&self) -> bool {
+        matches!(self, Type::ImplTrait(_))
+    }
+
     pub(crate) fn is_primitive(&self) -> bool {
         self.primitive_type().is_some()
     }
index 2367bde01671163f6fd54caafe8e5f0824ee342d..b236bd7be4f0c0eb9db8ccde0bf628071d3ca83a 100644 (file)
@@ -7,6 +7,7 @@
 pub(crate) use renderer::{run_format, FormatRenderer};
 
 use crate::clean::{self, ItemId};
+use crate::html::render::Context;
 
 /// Specifies whether rendering directly implemented trait items or ones from a certain Deref
 /// impl.
@@ -60,4 +61,41 @@ pub(crate) fn def_id(&self) -> DefId {
             }
         }
     }
+
+    // Returns true if this is an implementation on a "local" type, meaning:
+    // the type is in the current crate, or the type and the trait are both
+    // re-exported by the current crate.
+    pub(crate) fn is_on_local_type(&self, cx: &Context<'_>) -> bool {
+        let cache = cx.cache();
+        let for_type = &self.inner_impl().for_;
+        if let Some(for_type_did) = for_type.def_id(cache) {
+            // The "for" type is local if it's in the paths for the current crate.
+            if cache.paths.contains_key(&for_type_did) {
+                return true;
+            }
+            if let Some(trait_did) = self.trait_did() {
+                // The "for" type and the trait are from the same crate. That could
+                // be different from the current crate, for instance when both were
+                // re-exported from some other crate. But they are local with respect to
+                // each other.
+                if for_type_did.krate == trait_did.krate {
+                    return true;
+                }
+                // Hack: many traits and types in std are re-exported from
+                // core or alloc. In general, rustdoc is capable of recognizing
+                // these implementations as being on local types. However, in at
+                // least one case (https://github.com/rust-lang/rust/issues/97610),
+                // rustdoc gets confused and labels an implementation as being on
+                // a foreign type. To make sure that confusion doesn't pass on to
+                // the reader, consider all implementations in std, core, and alloc
+                // to be on local types.
+                let crate_name = cx.tcx().crate_name(trait_did.krate);
+                if matches!(crate_name.as_str(), "std" | "core" | "alloc") {
+                    return true;
+                }
+            }
+            return false;
+        };
+        true
+    }
 }
index 30946834583213b4fd7275eaf17d1e1a2b28b9e8..b7789493df647a65bcfe6acec7b55bf979559a43 100644 (file)
@@ -881,11 +881,16 @@ fn fmt_type<'cx>(
                 }
             }
         }
-        clean::Slice(ref t) => {
-            primitive_link(f, PrimitiveType::Slice, "[", cx)?;
-            fmt::Display::fmt(&t.print(cx), f)?;
-            primitive_link(f, PrimitiveType::Slice, "]", cx)
-        }
+        clean::Slice(ref t) => match **t {
+            clean::Generic(name) => {
+                primitive_link(f, PrimitiveType::Slice, &format!("[{name}]"), cx)
+            }
+            _ => {
+                primitive_link(f, PrimitiveType::Slice, "[", cx)?;
+                fmt::Display::fmt(&t.print(cx), f)?;
+                primitive_link(f, PrimitiveType::Slice, "]", cx)
+            }
+        },
         clean::Array(ref t, ref n) => {
             primitive_link(f, PrimitiveType::Array, "[", cx)?;
             fmt::Display::fmt(&t.print(cx), f)?;
@@ -924,23 +929,12 @@ fn fmt_type<'cx>(
                 clean::Slice(ref bt) => {
                     // `BorrowedRef{ ... Slice(T) }` is `&[T]`
                     match **bt {
-                        clean::Generic(_) => {
-                            if f.alternate() {
-                                primitive_link(
-                                    f,
-                                    PrimitiveType::Slice,
-                                    &format!("{}{}{}[{:#}]", amp, lt, m, bt.print(cx)),
-                                    cx,
-                                )
-                            } else {
-                                primitive_link(
-                                    f,
-                                    PrimitiveType::Slice,
-                                    &format!("{}{}{}[{}]", amp, lt, m, bt.print(cx)),
-                                    cx,
-                                )
-                            }
-                        }
+                        clean::Generic(name) => primitive_link(
+                            f,
+                            PrimitiveType::Slice,
+                            &format!("{amp}{lt}{m}[{name}]"),
+                            cx,
+                        ),
                         _ => {
                             primitive_link(
                                 f,
index b8d6b340b14dda551da9524b81fd83493bbefeeb..23ce634cf286ba839680ef3291abbba78ae2e74e 100644 (file)
@@ -2281,13 +2281,10 @@ fn print_sidebar_section(
         |sym| format!("<a href=\"#{1}.{0}\">{0}</a>", sym, ItemType::Method),
     );
 
-    let cache = cx.cache();
-    if let Some(implementors) = cache.implementors.get(&it.item_id.expect_def_id()) {
+    if let Some(implementors) = cx.cache().implementors.get(&it.item_id.expect_def_id()) {
         let mut res = implementors
             .iter()
-            .filter(|i| {
-                i.inner_impl().for_.def_id(cache).map_or(false, |d| !cache.paths.contains_key(&d))
-            })
+            .filter(|i| !i.is_on_local_type(cx))
             .filter_map(|i| extract_for_impl_name(&i.impl_item, cx))
             .collect::<Vec<_>>();
 
index dcf36b5e865b9d070be9fdd5f1b038963ec08f41..d115185562ce44344ad2cb87265f4b82618480a8 100644 (file)
@@ -822,9 +822,8 @@ fn trait_item(w: &mut Buffer, cx: &mut Context<'_>, m: &clean::Item, t: &clean::
             }
         }
 
-        let (local, foreign) = implementors.iter().partition::<Vec<_>, _>(|i| {
-            i.inner_impl().for_.def_id(cache).map_or(true, |d| cache.paths.contains_key(&d))
-        });
+        let (local, foreign) =
+            implementors.iter().partition::<Vec<_>, _>(|i| i.is_on_local_type(cx));
 
         let (mut synthetic, mut concrete): (Vec<&&Impl>, Vec<&&Impl>) =
             local.iter().partition(|i| i.inner_impl().kind.is_auto());
index 25c70f0808c6d1e687b41f4c45df7a6237027a71..9f302cc256659b2a24a2652c84018c62f284ffd6 100644 (file)
@@ -226,17 +226,17 @@ fn get_index_type_name(clean_type: &clean::Type) -> Option<Symbol> {
             Some(path.segments.last().unwrap().name)
         }
         // We return an empty name because we don't care about the generic name itself.
-        clean::Generic(_) => Some(kw::Empty),
+        clean::Generic(_) | clean::ImplTrait(_) => Some(kw::Empty),
         clean::Primitive(ref p) => Some(p.as_sym()),
-        clean::BorrowedRef { ref type_, .. } => get_index_type_name(type_),
+        clean::BorrowedRef { ref type_, .. } | clean::RawPointer(_, ref type_) => {
+            get_index_type_name(type_)
+        }
         clean::BareFunction(_)
         | clean::Tuple(_)
         | clean::Slice(_)
         | clean::Array(_, _)
-        | clean::RawPointer(_, _)
         | clean::QPath { .. }
-        | clean::Infer
-        | clean::ImplTrait(_) => None,
+        | clean::Infer => None,
     }
 }
 
@@ -264,10 +264,12 @@ fn insert_ty(
         mut generics: Vec<TypeWithKind>,
         cache: &Cache,
     ) {
-        let is_full_generic = ty.is_full_generic();
+        // generics and impl trait are both identified by their generics,
+        // rather than a type name itself
+        let anonymous = ty.is_full_generic() || ty.is_impl_trait();
         let generics_empty = generics.is_empty();
 
-        if is_full_generic {
+        if anonymous {
             if generics_empty {
                 // This is a type parameter with no trait bounds (for example: `T` in
                 // `fn f<T>(p: T)`, so not useful for the rustdoc search because we would end up
@@ -318,7 +320,7 @@ fn insert_ty(
         if index_ty.name.as_ref().map(|s| s.is_empty() && generics_empty).unwrap_or(true) {
             return;
         }
-        if is_full_generic {
+        if anonymous {
             // We remove the name of the full generic because we have no use for it.
             index_ty.name = Some(String::new());
             res.push(TypeWithKind::from((index_ty, ItemType::Generic)));
@@ -398,6 +400,23 @@ fn insert_ty(
             }
             insert_ty(res, tcx, arg.clone(), ty_generics, cache);
         }
+    } else if let Type::ImplTrait(ref bounds) = *arg {
+        let mut ty_generics = Vec::new();
+        for bound in bounds {
+            if let Some(path) = bound.get_trait_path() {
+                let ty = Type::Path { path };
+                add_generics_and_bounds_as_types(
+                    self_,
+                    generics,
+                    &ty,
+                    tcx,
+                    recurse + 1,
+                    &mut ty_generics,
+                    cache,
+                );
+            }
+        }
+        insert_ty(res, tcx, arg.clone(), ty_generics, cache);
     } else {
         // This is not a type parameter. So for example if we have `T, U: Option<T>`, and we're
         // looking at `Option`, we enter this "else" condition, otherwise if it's `T`, we don't.
index f66ecbf78af7b1960d6d82228147f4b78e743923..bd83b254caacbe76cb7464f9852f931900d22713 100644 (file)
@@ -70,5 +70,13 @@ module.exports = {
         "no-dupe-keys": "error",
         "no-duplicate-case": "error",
         "no-ex-assign": "error",
+        "no-fallthrough": "error",
+        "no-invalid-regexp": "error",
+        "no-import-assign": "error",
+        "no-self-compare": "error",
+        "no-template-curly-in-string": "error",
+        "block-scoped-var": "error",
+        "guard-for-in": "error",
+        "no-alert": "error",
     }
 };
index c69ff04236dcb47c07baf27efa3cae2a031dc5c3..1cd8e39e03648ad5eed7fd213c1aa0f2ebd7f9ed 100644 (file)
@@ -3,44 +3,40 @@
        position: relative;
 }
 
-.setting-line > div {
-       display: inline-block;
-       vertical-align: top;
-       font-size: 17px;
-       padding-top: 2px;
-}
-
-.setting-line > .title {
-       font-size: 19px;
-       width: 100%;
-       max-width: none;
-       border-bottom: 1px solid;
-}
-
-.setting-line .radio-line,
 .setting-line .choices {
        display: flex;
        flex-wrap: wrap;
 }
 
-.setting-line .radio-line .setting-name {
-       flex-grow: 1;
-       margin-top: auto;
-       margin-bottom: auto;
-}
-
 .setting-line .radio-line input {
        margin-right: 0.3em;
+       height: 1.2rem;
+       width: 1.2rem;
+       border: 1px solid;
+       outline: none;
+       -webkit-appearance: none;
+       cursor: pointer;
+       border-radius: 50%;
+}
+.setting-line .radio-line input + span {
+       padding-bottom: 1px;
+}
+
+.radio-line .setting-name {
+       width: 100%;
 }
 
 .radio-line .choice {
-       border-radius: 0.1em;
-       border: 1px solid;
-       margin-left: 0.5em;
        margin-top: 0.1em;
        margin-bottom: 0.1em;
        min-width: 3.8em;
        padding: 0.3em;
+       display: flex;
+       align-items: center;
+       cursor: pointer;
+}
+.radio-line .choice + .choice {
+       margin-left: 0.5em;
 }
 
 .toggle {
        width: 19px;
        left: 4px;
        bottom: 4px;
-       background-color: white;
        transition: .3s;
 }
 
-input:checked + .slider {
-       background-color: #2196F3;
-}
-
-input:focus + .slider {
-       box-shadow: 0 0 0 2px #0a84ff, 0 0 0 6px rgba(10, 132, 255, 0.3);
-}
-
 input:checked + .slider:before {
        transform: translateX(19px);
 }
index d32bb4cf22d6e665823f6e565cb49d7e86438b6c..7303cecc0d61a54443ebcf1a396afaccdda4d28a 100644 (file)
@@ -10,6 +10,38 @@ body, #settings-menu #settings, #settings-menu #settings::before {
        color: #c5c5c5;
 }
 
+.setting-line .radio-line input {
+       border-color: #c5c5c5;
+}
+.setting-line .radio-line input:checked {
+       box-shadow: inset 0 0 0 3px #0f1419;
+       background-color: #ffb454;
+}
+.setting-line .radio-line input:focus {
+       box-shadow: 0 0 1px 1px #ffb454;
+}
+/* In here we combine both `:focus` and `:checked` properties. */
+.setting-line .radio-line input:checked:focus {
+       box-shadow: inset 0 0 0 3px 0f1419,
+               0 0 2px 2px #ffb454;
+}
+.setting-line .radio-line input:hover {
+       border-color: #ffb454 !important;
+}
+
+.slider {
+       background-color: #ccc;
+}
+.slider:before {
+       background-color: white;
+}
+input:checked + .slider {
+       background-color: #ffb454;
+}
+input:focus + .slider {
+       box-shadow: 0 0 0 2px #0a84ff, 0 0 0 6px rgba(10, 132, 255, 0.3);
+}
+
 h1, h2, h3, h4 {
        color: white;
 }
@@ -601,13 +633,6 @@ div.files > .selected {
        background-color: #14191f;
        color: #ffb44c;
 }
-.setting-line > .title {
-       border-bottom-color: #5c6773;
-}
-input:checked + .slider {
-       background-color: #ffb454 !important;
-}
-
 
 .scraped-example-list .scrape-help {
        border-color: #aaa;
index 4957f25bcf358a3e46bb85215104c9c4d1f80227..34a4f446b560b49235c3c2181dd3f27ab49bc716 100644 (file)
@@ -3,6 +3,38 @@ body, #settings-menu #settings, #settings-menu #settings::before {
        color: #ddd;
 }
 
+.setting-line .radio-line input {
+       border-color: #ddd;
+}
+.setting-line .radio-line input:checked {
+       box-shadow: inset 0 0 0 3px #353535;
+       background-color: #2196f3;
+}
+.setting-line .radio-line input:focus {
+       box-shadow: 0 0 1px 1px #2196f3;
+}
+/* In here we combine both `:focus` and `:checked` properties. */
+.setting-line .radio-line input:checked:focus {
+       box-shadow: inset 0 0 0 3px #353535,
+               0 0 2px 2px #2196f3;
+}
+.setting-line .radio-line input:hover {
+       border-color: #2196f3 !important;
+}
+
+.slider {
+       background-color: #ccc;
+}
+.slider:before {
+       background-color: white;
+}
+input:checked + .slider {
+       background-color: #2196F3;
+}
+input:focus + .slider {
+       box-shadow: 0 0 0 2px #0a84ff, 0 0 0 6px rgba(10, 132, 255, 0.3);
+}
+
 h1, h2, h3, h4 {
        color: #ddd;
 }
@@ -472,9 +504,6 @@ div.files > a:hover, div.name:hover {
 div.files > .selected {
        background-color: #333;
 }
-.setting-line > .title {
-       border-bottom-color: #ddd;
-}
 
 .scraped-example-list .scrape-help {
        border-color: #aaa;
index 7d4acc6c61181901b2aa5c1736e8c6932f0634a6..aa6ad2f547333aca23e756dad35f1c0ce52dc1f5 100644 (file)
@@ -5,6 +5,38 @@ body, #settings-menu #settings, #settings-menu #settings::before {
        color: black;
 }
 
+.setting-line .radio-line input {
+       border-color: black;
+}
+.setting-line .radio-line input:checked {
+       box-shadow: inset 0 0 0 3px white;
+       background-color: #2196f3;
+}
+.setting-line .radio-line input:focus {
+       box-shadow: 0 0 1px 1px #2196f3;
+}
+/* In here we combine both `:focus` and `:checked` properties. */
+.setting-line .radio-line input:checked:focus {
+       box-shadow: inset 0 0 0 3px white,
+               0 0 2px 2px #2196f3;
+}
+.setting-line .radio-line input:hover {
+       border-color: #2196f3 !important;
+}
+
+.slider {
+       background-color: #ccc;
+}
+.slider:before {
+       background-color: white;
+}
+input:checked + .slider {
+       background-color: #2196F3;
+}
+input:focus + .slider {
+       box-shadow: 0 0 0 2px #0a84ff, 0 0 0 6px rgba(10, 132, 255, 0.3);
+}
+
 h1, h2, h3, h4 {
        color: black;
 }
@@ -456,9 +488,6 @@ div.files > a:hover, div.name:hover {
 div.files > .selected {
        background-color: #fff;
 }
-.setting-line > .title {
-       border-bottom-color: #D5D5D5;
-}
 
 .scraped-example-list .scrape-help {
        border-color: #555;
index 3d1d942eaa9ee59a26d6987aace289e70b213ea3..41bf0ec8955805ec9e1178a4a61da850689d152c 100644 (file)
                     output += `<label for="${js_data_name}-${option}" class="choice">\
                            <input type="radio" name="${js_data_name}" \
                                 id="${js_data_name}-${option}" value="${option}"${checked}>\
-                           ${option}\
+                           <span>${option}</span>\
                          </label>`;
                 });
                 output += "</div></div>";
index 6a8e4787676e13bcb6a358818af4b23ce585cc00..51a2abc50bc2b2e4c787b49fa7888b0706be1b5e 100644 (file)
@@ -10,7 +10,7 @@
 use rustc_ast::ast;
 use rustc_hir::{def::CtorKind, def_id::DefId};
 use rustc_middle::ty::{self, TyCtxt};
-use rustc_span::Pos;
+use rustc_span::{Pos, Symbol};
 use rustc_target::spec::abi::Abi as RustcAbi;
 
 use rustdoc_json_types::*;
@@ -29,7 +29,9 @@ pub(super) fn convert_item(&self, item: clean::Item) -> Option<Item> {
             .get(&item.item_id)
             .into_iter()
             .flatten()
-            .map(|clean::ItemLink { link, did, .. }| (link.clone(), from_item_id((*did).into())))
+            .map(|clean::ItemLink { link, did, .. }| {
+                (link.clone(), from_item_id((*did).into(), self.tcx))
+            })
             .collect();
         let docs = item.attrs.collapsed_doc_value();
         let attrs = item
@@ -45,7 +47,7 @@ pub(super) fn convert_item(&self, item: clean::Item) -> Option<Item> {
             _ => from_clean_item(item, self.tcx),
         };
         Some(Item {
-            id: from_item_id(item_id),
+            id: from_item_id_with_name(item_id, self.tcx, name),
             crate_id: item_id.krate().as_u32(),
             name: name.map(|sym| sym.to_string()),
             span: self.convert_span(span),
@@ -84,7 +86,7 @@ fn convert_visibility(&self, v: clean::Visibility) -> Visibility {
             Inherited => Visibility::Default,
             Restricted(did) if did.is_crate_root() => Visibility::Crate,
             Restricted(did) => Visibility::Restricted {
-                parent: from_item_id(did.into()),
+                parent: from_item_id(did.into(), self.tcx),
                 path: self.tcx.def_path(did).to_string_no_crate_verbose(),
             },
         }
@@ -173,22 +175,39 @@ fn from_tcx(kind: clean::TypeBindingKind, tcx: TyCtxt<'_>) -> Self {
     }
 }
 
-pub(crate) fn from_item_id(item_id: ItemId) -> Id {
-    struct DisplayDefId(DefId);
+/// It generates an ID as follows:
+///
+/// `CRATE_ID:ITEM_ID[:NAME_ID]` (if there is no name, NAME_ID is not generated).
+pub(crate) fn from_item_id(item_id: ItemId, tcx: TyCtxt<'_>) -> Id {
+    from_item_id_with_name(item_id, tcx, None)
+}
+
+// FIXME: this function (and appending the name at the end of the ID) should be removed when
+// reexports are not inlined anymore for json format. It should be done in #93518.
+pub(crate) fn from_item_id_with_name(item_id: ItemId, tcx: TyCtxt<'_>, name: Option<Symbol>) -> Id {
+    struct DisplayDefId<'a>(DefId, TyCtxt<'a>, Option<Symbol>);
 
-    impl fmt::Display for DisplayDefId {
+    impl<'a> fmt::Display for DisplayDefId<'a> {
         fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-            write!(f, "{}:{}", self.0.krate.as_u32(), u32::from(self.0.index))
+            let name = match self.2 {
+                Some(name) => format!(":{}", name.as_u32()),
+                None => self
+                    .1
+                    .opt_item_name(self.0)
+                    .map(|n| format!(":{}", n.as_u32()))
+                    .unwrap_or_default(),
+            };
+            write!(f, "{}:{}{}", self.0.krate.as_u32(), u32::from(self.0.index), name)
         }
     }
 
     match item_id {
-        ItemId::DefId(did) => Id(format!("{}", DisplayDefId(did))),
+        ItemId::DefId(did) => Id(format!("{}", DisplayDefId(did, tcx, name))),
         ItemId::Blanket { for_, impl_id } => {
-            Id(format!("b:{}-{}", DisplayDefId(impl_id), DisplayDefId(for_)))
+            Id(format!("b:{}-{}", DisplayDefId(impl_id, tcx, None), DisplayDefId(for_, tcx, name)))
         }
         ItemId::Auto { for_, trait_ } => {
-            Id(format!("a:{}-{}", DisplayDefId(trait_), DisplayDefId(for_)))
+            Id(format!("a:{}-{}", DisplayDefId(trait_, tcx, None), DisplayDefId(for_, tcx, name)))
         }
         ItemId::Primitive(ty, krate) => Id(format!("p:{}:{}", krate.as_u32(), ty.as_sym())),
     }
@@ -201,7 +220,7 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum {
     let header = item.fn_header(tcx);
 
     match *item.kind {
-        ModuleItem(m) => ItemEnum::Module(Module { is_crate, items: ids(m.items) }),
+        ModuleItem(m) => ItemEnum::Module(Module { is_crate, items: ids(m.items, tcx) }),
         ImportItem(i) => ItemEnum::Import(i.into_tcx(tcx)),
         StructItem(s) => ItemEnum::Struct(s.into_tcx(tcx)),
         UnionItem(u) => ItemEnum::Union(u.into_tcx(tcx)),
@@ -255,7 +274,7 @@ fn from_tcx(struct_: clean::Struct, tcx: TyCtxt<'_>) -> Self {
             struct_type: from_ctor_kind(struct_type),
             generics: generics.into_tcx(tcx),
             fields_stripped,
-            fields: ids(fields),
+            fields: ids(fields, tcx),
             impls: Vec::new(), // Added in JsonRenderer::item
         }
     }
@@ -268,7 +287,7 @@ fn from_tcx(union_: clean::Union, tcx: TyCtxt<'_>) -> Self {
         Union {
             generics: generics.into_tcx(tcx),
             fields_stripped,
-            fields: ids(fields),
+            fields: ids(fields, tcx),
             impls: Vec::new(), // Added in JsonRenderer::item
         }
     }
@@ -413,7 +432,7 @@ fn from_tcx(ty: clean::Type, tcx: TyCtxt<'_>) -> Self {
         match ty {
             clean::Type::Path { path } => Type::ResolvedPath {
                 name: path.whole_name(),
-                id: from_item_id(path.def_id().into()),
+                id: from_item_id(path.def_id().into(), tcx),
                 args: path.segments.last().map(|args| Box::new(args.clone().args.into_tcx(tcx))),
                 param_names: Vec::new(),
             },
@@ -422,7 +441,7 @@ fn from_tcx(ty: clean::Type, tcx: TyCtxt<'_>) -> Self {
 
                 Type::ResolvedPath {
                     name: first_trait.whole_name(),
-                    id: from_item_id(first_trait.def_id().into()),
+                    id: from_item_id(first_trait.def_id().into(), tcx),
                     args: first_trait
                         .segments
                         .last()
@@ -517,7 +536,7 @@ fn from_tcx(trait_: clean::Trait, tcx: TyCtxt<'_>) -> Self {
         Trait {
             is_auto,
             is_unsafe: unsafety == rustc_hir::Unsafety::Unsafe,
-            items: ids(items),
+            items: ids(items, tcx),
             generics: generics.into_tcx(tcx),
             bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(),
             implementations: Vec::new(), // Added in JsonRenderer::item
@@ -550,7 +569,7 @@ fn from_tcx(impl_: clean::Impl, tcx: TyCtxt<'_>) -> Self {
                 .collect(),
             trait_,
             for_: for_.into_tcx(tcx),
-            items: ids(items),
+            items: ids(items, tcx),
             negative: negative_polarity,
             synthetic,
             blanket_impl: blanket_impl.map(|x| x.into_tcx(tcx)),
@@ -593,21 +612,21 @@ fn from_tcx(enum_: clean::Enum, tcx: TyCtxt<'_>) -> Self {
         Enum {
             generics: generics.into_tcx(tcx),
             variants_stripped,
-            variants: ids(variants),
+            variants: ids(variants, tcx),
             impls: Vec::new(), // Added in JsonRenderer::item
         }
     }
 }
 
 impl FromWithTcx<clean::VariantStruct> for Struct {
-    fn from_tcx(struct_: clean::VariantStruct, _tcx: TyCtxt<'_>) -> Self {
+    fn from_tcx(struct_: clean::VariantStruct, tcx: TyCtxt<'_>) -> Self {
         let fields_stripped = struct_.has_stripped_entries();
         let clean::VariantStruct { struct_type, fields } = struct_;
         Struct {
             struct_type: from_ctor_kind(struct_type),
             generics: Default::default(),
             fields_stripped,
-            fields: ids(fields),
+            fields: ids(fields, tcx),
             impls: Vec::new(),
         }
     }
@@ -630,25 +649,25 @@ fn from_tcx(variant: clean::Variant, tcx: TyCtxt<'_>) -> Self {
                     })
                     .collect(),
             ),
-            Struct(s) => Variant::Struct(ids(s.fields)),
+            Struct(s) => Variant::Struct(ids(s.fields, tcx)),
         }
     }
 }
 
 impl FromWithTcx<clean::Import> for Import {
-    fn from_tcx(import: clean::Import, _tcx: TyCtxt<'_>) -> Self {
+    fn from_tcx(import: clean::Import, tcx: TyCtxt<'_>) -> Self {
         use clean::ImportKind::*;
         match import.kind {
             Simple(s) => Import {
                 source: import.source.path.whole_name(),
                 name: s.to_string(),
-                id: import.source.did.map(ItemId::from).map(from_item_id),
+                id: import.source.did.map(ItemId::from).map(|i| from_item_id(i, tcx)),
                 glob: false,
             },
             Glob => Import {
                 source: import.source.path.whole_name(),
                 name: import.source.path.last().to_string(),
-                id: import.source.did.map(ItemId::from).map(from_item_id),
+                id: import.source.did.map(ItemId::from).map(|i| from_item_id(i, tcx)),
                 glob: true,
             },
         }
@@ -742,6 +761,10 @@ fn from_tcx(kind: ItemType, _tcx: TyCtxt<'_>) -> Self {
     }
 }
 
-fn ids(items: impl IntoIterator<Item = clean::Item>) -> Vec<Id> {
-    items.into_iter().filter(|x| !x.is_stripped()).map(|i| from_item_id(i.item_id)).collect()
+fn ids(items: impl IntoIterator<Item = clean::Item>, tcx: TyCtxt<'_>) -> Vec<Id> {
+    items
+        .into_iter()
+        .filter(|x| !x.is_stripped())
+        .map(|i| from_item_id_with_name(i.item_id, tcx, i.name))
+        .collect()
 }
index 08f61056d853f7952ae53f08ab02c3f8b85d3b49..f338050bee0f9bf78fb5bafc3a911f0fc5886a35 100644 (file)
@@ -16,6 +16,7 @@
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
+use rustc_span::def_id::LOCAL_CRATE;
 
 use rustdoc_json_types as types;
 
@@ -25,7 +26,7 @@
 use crate::error::Error;
 use crate::formats::cache::Cache;
 use crate::formats::FormatRenderer;
-use crate::json::conversions::{from_item_id, IntoWithTcx};
+use crate::json::conversions::{from_item_id, from_item_id_with_name, IntoWithTcx};
 use crate::{clean, try_err};
 
 #[derive(Clone)]
@@ -54,7 +55,7 @@ fn get_trait_implementors(&mut self, id: DefId) -> Vec<types::Id> {
                     .map(|i| {
                         let item = &i.impl_item;
                         self.item(item.clone()).unwrap();
-                        from_item_id(item.item_id)
+                        from_item_id_with_name(item.item_id, self.tcx, item.name)
                     })
                     .collect()
             })
@@ -86,7 +87,7 @@ fn get_impls(&mut self, id: DefId) -> Vec<types::Id> {
 
                         if item.item_id.is_local() || is_primitive_impl {
                             self.item(item.clone()).unwrap();
-                            Some(from_item_id(item.item_id))
+                            Some(from_item_id_with_name(item.item_id, self.tcx, item.name))
                         } else {
                             None
                         }
@@ -105,10 +106,11 @@ fn get_trait_items(&mut self) -> Vec<(types::Id, types::Item)> {
                 if !id.is_local() {
                     let trait_item = &trait_item.trait_;
                     trait_item.items.clone().into_iter().for_each(|i| self.item(i).unwrap());
+                    let item_id = from_item_id(id.into(), self.tcx);
                     Some((
-                        from_item_id(id.into()),
+                        item_id.clone(),
                         types::Item {
-                            id: from_item_id(id.into()),
+                            id: item_id,
                             crate_id: id.krate.as_u32(),
                             name: self
                                 .cache
@@ -176,6 +178,7 @@ fn item(&mut self, item: clean::Item) -> Result<(), Error> {
         // Flatten items that recursively store other items
         item.kind.inner_items().for_each(|i| self.item(i.clone()).unwrap());
 
+        let name = item.name;
         let item_id = item.item_id;
         if let Some(mut new_item) = self.convert_item(item) {
             if let types::ItemEnum::Trait(ref mut t) = new_item.inner {
@@ -187,7 +190,10 @@ fn item(&mut self, item: clean::Item) -> Result<(), Error> {
             } else if let types::ItemEnum::Union(ref mut u) = new_item.inner {
                 u.impls = self.get_impls(item_id.expect_def_id())
             }
-            let removed = self.index.borrow_mut().insert(from_item_id(item_id), new_item.clone());
+            let removed = self
+                .index
+                .borrow_mut()
+                .insert(from_item_id_with_name(item_id, self.tcx, name), new_item.clone());
 
             // FIXME(adotinthevoid): Currently, the index is duplicated. This is a sanity check
             // to make sure the items are unique. The main place this happens is when an item, is
@@ -211,13 +217,15 @@ fn after_krate(&mut self) -> Result<(), Error> {
             self.get_impls(*primitive);
         }
 
+        let e = ExternalCrate { crate_num: LOCAL_CRATE };
+
         let mut index = (*self.index).clone().into_inner();
         index.extend(self.get_trait_items());
         // This needs to be the default HashMap for compatibility with the public interface for
         // rustdoc-json-types
         #[allow(rustc::default_hash_types)]
         let output = types::Crate {
-            root: types::Id(String::from("0:0")),
+            root: types::Id(format!("0:0:{}", e.name(self.tcx).as_u32())),
             crate_version: self.cache.crate_version.clone(),
             includes_private: self.cache.document_private,
             index: index.into_iter().collect(),
@@ -229,7 +237,7 @@ fn after_krate(&mut self) -> Result<(), Error> {
                 .chain(self.cache.external_paths.clone().into_iter())
                 .map(|(k, (path, kind))| {
                     (
-                        from_item_id(k.into()),
+                        from_item_id(k.into(), self.tcx),
                         types::ItemSummary {
                             crate_id: k.krate.as_u32(),
                             path: path.iter().map(|s| s.to_string()).collect(),
index aa7028247bed49d739712b5a4b74b0ad2606a35a..6ea33d763b185d580bccdc3d5afbab4b92e3bb66 100644 (file)
@@ -9,7 +9,7 @@
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir::def_id::DefId;
-use rustc_middle::ty::DefIdTree;
+use rustc_middle::ty::{self, DefIdTree};
 use rustc_span::symbol::sym;
 
 pub(crate) const COLLECT_TRAIT_IMPLS: Pass = Pass {
@@ -81,8 +81,35 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) ->
             // Do not calculate blanket impl list for docs that are not going to be rendered.
             // While the `impl` blocks themselves are only in `libcore`, the module with `doc`
             // attached is directly included in `libstd` as well.
+            let tcx = cx.tcx;
             if did.is_local() {
-                for def_id in prim.impls(cx.tcx) {
+                for def_id in prim.impls(tcx).filter(|def_id| {
+                    // Avoid including impl blocks with filled-in generics.
+                    // https://github.com/rust-lang/rust/issues/94937
+                    //
+                    // FIXME(notriddle): https://github.com/rust-lang/rust/issues/97129
+                    //
+                    // This tactic of using inherent impl blocks for getting
+                    // auto traits and blanket impls is a hack. What we really
+                    // want is to check if `[T]` impls `Send`, which has
+                    // nothing to do with the inherent impl.
+                    //
+                    // Rustdoc currently uses these `impl` block as a source of
+                    // the `Ty`, as well as the `ParamEnv`, `SubstsRef`, and
+                    // `Generics`. To avoid relying on the `impl` block, these
+                    // things would need to be created from wholecloth, in a
+                    // form that is valid for use in type inference.
+                    let ty = tcx.type_of(def_id);
+                    match ty.kind() {
+                        ty::Slice(ty)
+                        | ty::Ref(_, ty, _)
+                        | ty::RawPtr(ty::TypeAndMut { ty, .. }) => {
+                            matches!(ty.kind(), ty::Param(..))
+                        }
+                        ty::Tuple(tys) => tys.iter().all(|ty| matches!(ty.kind(), ty::Param(..))),
+                        _ => true,
+                    }
+                }) {
                     let impls = get_auto_trait_and_blanket_impls(cx, def_id);
                     new_items_external.extend(impls.filter(|i| cx.inlined.insert(i.item_id)));
                 }
index d57868caf7a3af7c621763089958e5d60f0f3d66..00553d3f007fffb44fb66ba4d1426ce065023ad9 100644 (file)
@@ -286,8 +286,8 @@ fn visit_item(
                     self.visit_foreign_item(item, None, om);
                 }
             }
-            // If we're inlining, skip private items.
-            _ if self.inlining && !is_pub => {}
+            // If we're inlining, skip private items or item reexported as "_".
+            _ if self.inlining && (!is_pub || renamed == Some(kw::Underscore)) => {}
             hir::ItemKind::GlobalAsm(..) => {}
             hir::ItemKind::Use(_, hir::UseKind::ListStem) => {}
             hir::ItemKind::Use(path, kind) => {
index 47848665966fc7393cb6f898077994f6dec2b591..c9e2e89ed3aa5a3be77143aa0c86906b4138374a 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 47848665966fc7393cb6f898077994f6dec2b591
+Subproject commit c9e2e89ed3aa5a3be77143aa0c86906b4138374a
diff --git a/src/test/debuginfo/thread-names.rs b/src/test/debuginfo/thread-names.rs
new file mode 100644 (file)
index 0000000..7a35a51
--- /dev/null
@@ -0,0 +1,51 @@
+// compile-flags:-g
+// We can't set the main thread name on Linux because it renames the process (#97191)
+// ignore-linux
+// ignore-android
+// ignore-dragonfly
+// ignore-emscripten
+// ignore-freebsd
+// ignore-haiku
+// ignore-ios
+// ignore-netbsd
+// ignore-openbsd
+// ignore-solaris
+// ignore-sgx
+// ignore-windows-gnu
+
+// === GDB TESTS ==================================================================================
+//
+// gdb-command:run
+//
+// gdb-command:info threads
+// gdb-check:  1    Thread [...] [...] "main" [...]
+// gdb-check:* 2    Thread [...] [...] "my new thread" [...]
+
+// === LLDB TESTS =================================================================================
+//
+// lldb-command:run
+//
+// lldb-command:thread info 1
+// lldb-check:thread #1:[...]name = 'main'[...]
+// lldb-command:thread info 2
+// lldb-check:thread #2:[...]name = 'my new thread'[...]
+
+// === CDB TESTS ==================================================================================
+//
+// cdb-command:g
+//
+// cdb-command:~
+// cdb-check:   0  Id: [...] Suspend: 1 Teb: [...] Unfrozen "main"
+// cdb-check:.  [...]  Id: [...] Suspend: 1 Teb: [...] Unfrozen "my new thread"
+
+use std::thread;
+
+fn main() {
+    let handle = thread::Builder::new().name("my new thread".into()).spawn(|| {
+        zzz(); // #break
+    }).unwrap();
+
+    handle.join().unwrap();
+}
+
+fn zzz() {}
index 466c286c9d7c9d8c07ec627987ea03a43ee27d38..84d72202d527eee6c1ba526700dbed6ae51b0293 100644 (file)
@@ -21,7 +21,7 @@
                                            // + span: $DIR/const_prop_fails_gracefully.rs:7:13: 7:16
                                            // + literal: Const { ty: &i32, val: Unevaluated(FOO, [], None) }
           _2 = &raw const (*_3);           // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:16
-          _1 = move _2 as usize (Misc);    // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:39
+          _1 = move _2 as usize (PointerExposeAddress); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:39
           StorageDead(_2);                 // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:38: 7:39
           StorageDead(_3);                 // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:39: 7:40
           StorageLive(_4);                 // scope 1 at $DIR/const_prop_fails_gracefully.rs:8:5: 8:12
index 1aeeae91d203fcd5adfc8ba5a2c03bb069077b70..037febdf3a579de5f53148e69c8ecd436f7ecd97 100644 (file)
@@ -17,9 +17,9 @@
                                            // mir::Constant
                                            // + span: $DIR/reify_fn_ptr.rs:4:13: 4:17
                                            // + literal: Const { ty: fn() {main}, val: Value(Scalar(<ZST>)) }
-          _2 = move _3 as usize (Misc);    // scope 0 at $DIR/reify_fn_ptr.rs:4:13: 4:26
+          _2 = move _3 as usize (PointerExposeAddress); // scope 0 at $DIR/reify_fn_ptr.rs:4:13: 4:26
           StorageDead(_3);                 // scope 0 at $DIR/reify_fn_ptr.rs:4:25: 4:26
-          _1 = move _2 as *const fn() (Misc); // scope 0 at $DIR/reify_fn_ptr.rs:4:13: 4:41
+          _1 = move _2 as *const fn() (PointerFromExposedAddress); // scope 0 at $DIR/reify_fn_ptr.rs:4:13: 4:41
           StorageDead(_2);                 // scope 0 at $DIR/reify_fn_ptr.rs:4:40: 4:41
           StorageDead(_1);                 // scope 0 at $DIR/reify_fn_ptr.rs:4:41: 4:42
           nop;                             // scope 0 at $DIR/reify_fn_ptr.rs:3:11: 5:2
index 2250159c8166784ae5065a10b6b5d3dea550bca7..2331f63ecdd42199d276193d4dad10fe0f930f07 100644 (file)
           StorageLive(_2);                 // scope 0 at $DIR/provenance_soundness.rs:8:9: 8:11
           StorageLive(_3);                 // scope 0 at $DIR/provenance_soundness.rs:8:14: 8:15
           _3 = _1;                         // scope 0 at $DIR/provenance_soundness.rs:8:14: 8:15
-          _2 = move _3 as usize (Misc);    // scope 0 at $DIR/provenance_soundness.rs:8:14: 8:24
+          _2 = move _3 as usize (PointerExposeAddress); // scope 0 at $DIR/provenance_soundness.rs:8:14: 8:24
           StorageDead(_3);                 // scope 0 at $DIR/provenance_soundness.rs:8:23: 8:24
           StorageLive(_4);                 // scope 1 at $DIR/provenance_soundness.rs:9:9: 9:11
           StorageLive(_5);                 // scope 1 at $DIR/provenance_soundness.rs:9:14: 9:15
           _5 = _1;                         // scope 1 at $DIR/provenance_soundness.rs:9:14: 9:15
-          _4 = move _5 as isize (Misc);    // scope 1 at $DIR/provenance_soundness.rs:9:14: 9:24
+          _4 = move _5 as isize (PointerExposeAddress); // scope 1 at $DIR/provenance_soundness.rs:9:14: 9:24
           StorageDead(_5);                 // scope 1 at $DIR/provenance_soundness.rs:9:23: 9:24
           _0 = const ();                   // scope 0 at $DIR/provenance_soundness.rs:7:32: 10:2
           StorageDead(_4);                 // scope 1 at $DIR/provenance_soundness.rs:10:1: 10:2
diff --git a/src/test/mir-opt/inst_combine_deref.deep_opt.InstCombine.diff b/src/test/mir-opt/inst_combine_deref.deep_opt.InstCombine.diff
deleted file mode 100644 (file)
index 1d20e17..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-- // MIR for `deep_opt` before InstCombine
-+ // MIR for `deep_opt` after InstCombine
-  
-  fn deep_opt() -> (u64, u64, u64) {
-      let mut _0: (u64, u64, u64);         // return place in scope 0 at $DIR/inst_combine_deref.rs:11:18: 11:33
-      let _1: u64;                         // in scope 0 at $DIR/inst_combine_deref.rs:12:9: 12:11
-      let mut _10: u64;                    // in scope 0 at $DIR/inst_combine_deref.rs:21:6: 21:8
-      let mut _11: u64;                    // in scope 0 at $DIR/inst_combine_deref.rs:21:10: 21:12
-      let mut _12: u64;                    // in scope 0 at $DIR/inst_combine_deref.rs:21:14: 21:16
-      scope 1 {
-          debug x1 => _1;                  // in scope 1 at $DIR/inst_combine_deref.rs:12:9: 12:11
-          let _2: u64;                     // in scope 1 at $DIR/inst_combine_deref.rs:13:9: 13:11
-          scope 2 {
-              debug x2 => _2;              // in scope 2 at $DIR/inst_combine_deref.rs:13:9: 13:11
-              let _3: u64;                 // in scope 2 at $DIR/inst_combine_deref.rs:14:9: 14:11
-              scope 3 {
-                  debug x3 => _3;          // in scope 3 at $DIR/inst_combine_deref.rs:14:9: 14:11
-                  let _4: &u64;            // in scope 3 at $DIR/inst_combine_deref.rs:15:9: 15:11
-                  scope 4 {
-                      debug y1 => _4;      // in scope 4 at $DIR/inst_combine_deref.rs:15:9: 15:11
-                      let _5: &u64;        // in scope 4 at $DIR/inst_combine_deref.rs:16:9: 16:11
-                      scope 5 {
-                          debug y2 => _5;  // in scope 5 at $DIR/inst_combine_deref.rs:16:9: 16:11
-                          let _6: &u64;    // in scope 5 at $DIR/inst_combine_deref.rs:17:9: 17:11
-                          scope 6 {
-                              debug y3 => _6; // in scope 6 at $DIR/inst_combine_deref.rs:17:9: 17:11
-                              let _7: u64; // in scope 6 at $DIR/inst_combine_deref.rs:18:9: 18:11
-                              scope 7 {
-                                  debug z1 => _7; // in scope 7 at $DIR/inst_combine_deref.rs:18:9: 18:11
-                                  let _8: u64; // in scope 7 at $DIR/inst_combine_deref.rs:19:9: 19:11
-                                  scope 8 {
-                                      debug z2 => _8; // in scope 8 at $DIR/inst_combine_deref.rs:19:9: 19:11
-                                      let _9: u64; // in scope 8 at $DIR/inst_combine_deref.rs:20:9: 20:11
-                                      scope 9 {
-                                          debug z3 => _9; // in scope 9 at $DIR/inst_combine_deref.rs:20:9: 20:11
-                                      }
-                                  }
-                              }
-                          }
-                      }
-                  }
-              }
-          }
-      }
-  
-      bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/inst_combine_deref.rs:12:9: 12:11
-          _1 = const 1_u64;                // scope 0 at $DIR/inst_combine_deref.rs:12:14: 12:15
-          StorageLive(_2);                 // scope 1 at $DIR/inst_combine_deref.rs:13:9: 13:11
-          _2 = const 2_u64;                // scope 1 at $DIR/inst_combine_deref.rs:13:14: 13:15
-          StorageLive(_3);                 // scope 2 at $DIR/inst_combine_deref.rs:14:9: 14:11
-          _3 = const 3_u64;                // scope 2 at $DIR/inst_combine_deref.rs:14:14: 14:15
-          StorageLive(_4);                 // scope 3 at $DIR/inst_combine_deref.rs:15:9: 15:11
-          _4 = &_1;                        // scope 3 at $DIR/inst_combine_deref.rs:15:14: 15:17
-          StorageLive(_5);                 // scope 4 at $DIR/inst_combine_deref.rs:16:9: 16:11
-          _5 = &_2;                        // scope 4 at $DIR/inst_combine_deref.rs:16:14: 16:17
-          StorageLive(_6);                 // scope 5 at $DIR/inst_combine_deref.rs:17:9: 17:11
-          _6 = &_3;                        // scope 5 at $DIR/inst_combine_deref.rs:17:14: 17:17
-          StorageLive(_7);                 // scope 6 at $DIR/inst_combine_deref.rs:18:9: 18:11
--         _7 = (*_4);                      // scope 6 at $DIR/inst_combine_deref.rs:18:14: 18:17
-+         _7 = _1;                         // scope 6 at $DIR/inst_combine_deref.rs:18:14: 18:17
-          StorageLive(_8);                 // scope 7 at $DIR/inst_combine_deref.rs:19:9: 19:11
--         _8 = (*_5);                      // scope 7 at $DIR/inst_combine_deref.rs:19:14: 19:17
-+         _8 = _2;                         // scope 7 at $DIR/inst_combine_deref.rs:19:14: 19:17
-          StorageLive(_9);                 // scope 8 at $DIR/inst_combine_deref.rs:20:9: 20:11
--         _9 = (*_6);                      // scope 8 at $DIR/inst_combine_deref.rs:20:14: 20:17
-+         _9 = _3;                         // scope 8 at $DIR/inst_combine_deref.rs:20:14: 20:17
-          StorageLive(_10);                // scope 9 at $DIR/inst_combine_deref.rs:21:6: 21:8
-          _10 = _7;                        // scope 9 at $DIR/inst_combine_deref.rs:21:6: 21:8
-          StorageLive(_11);                // scope 9 at $DIR/inst_combine_deref.rs:21:10: 21:12
-          _11 = _8;                        // scope 9 at $DIR/inst_combine_deref.rs:21:10: 21:12
-          StorageLive(_12);                // scope 9 at $DIR/inst_combine_deref.rs:21:14: 21:16
-          _12 = _9;                        // scope 9 at $DIR/inst_combine_deref.rs:21:14: 21:16
-          (_0.0: u64) = move _10;          // scope 9 at $DIR/inst_combine_deref.rs:21:5: 21:17
-          (_0.1: u64) = move _11;          // scope 9 at $DIR/inst_combine_deref.rs:21:5: 21:17
-          (_0.2: u64) = move _12;          // scope 9 at $DIR/inst_combine_deref.rs:21:5: 21:17
-          StorageDead(_12);                // scope 9 at $DIR/inst_combine_deref.rs:21:16: 21:17
-          StorageDead(_11);                // scope 9 at $DIR/inst_combine_deref.rs:21:16: 21:17
-          StorageDead(_10);                // scope 9 at $DIR/inst_combine_deref.rs:21:16: 21:17
-          StorageDead(_9);                 // scope 8 at $DIR/inst_combine_deref.rs:22:1: 22:2
-          StorageDead(_8);                 // scope 7 at $DIR/inst_combine_deref.rs:22:1: 22:2
-          StorageDead(_7);                 // scope 6 at $DIR/inst_combine_deref.rs:22:1: 22:2
-          StorageDead(_6);                 // scope 5 at $DIR/inst_combine_deref.rs:22:1: 22:2
-          StorageDead(_5);                 // scope 4 at $DIR/inst_combine_deref.rs:22:1: 22:2
-          StorageDead(_4);                 // scope 3 at $DIR/inst_combine_deref.rs:22:1: 22:2
-          StorageDead(_3);                 // scope 2 at $DIR/inst_combine_deref.rs:22:1: 22:2
-          StorageDead(_2);                 // scope 1 at $DIR/inst_combine_deref.rs:22:1: 22:2
-          StorageDead(_1);                 // scope 0 at $DIR/inst_combine_deref.rs:22:1: 22:2
-          return;                          // scope 0 at $DIR/inst_combine_deref.rs:22:2: 22:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/inst_combine_deref.do_not_miscompile.InstCombine.diff b/src/test/mir-opt/inst_combine_deref.do_not_miscompile.InstCombine.diff
deleted file mode 100644 (file)
index ee8fcdc..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-- // MIR for `do_not_miscompile` before InstCombine
-+ // MIR for `do_not_miscompile` after InstCombine
-  
-  fn do_not_miscompile() -> () {
-      let mut _0: ();                      // return place in scope 0 at $DIR/inst_combine_deref.rs:54:24: 54:24
-      let _1: i32;                         // in scope 0 at $DIR/inst_combine_deref.rs:55:9: 55:10
-      let mut _5: &i32;                    // in scope 0 at $DIR/inst_combine_deref.rs:59:10: 59:12
-      let _6: &i32;                        // in scope 0 at $DIR/inst_combine_deref.rs:59:10: 59:12
-      let _7: ();                          // in scope 0 at $DIR/inst_combine_deref.rs:60:5: 60:23
-      let mut _8: bool;                    // in scope 0 at $DIR/inst_combine_deref.rs:60:5: 60:23
-      let mut _9: bool;                    // in scope 0 at $DIR/inst_combine_deref.rs:60:13: 60:21
-      let mut _10: i32;                    // in scope 0 at $DIR/inst_combine_deref.rs:60:13: 60:15
-      let mut _11: !;                      // in scope 0 at $DIR/inst_combine_deref.rs:60:5: 60:23
-      scope 1 {
-          debug x => _1;                   // in scope 1 at $DIR/inst_combine_deref.rs:55:9: 55:10
-          let _2: i32;                     // in scope 1 at $DIR/inst_combine_deref.rs:56:9: 56:10
-          scope 2 {
-              debug a => _2;               // in scope 2 at $DIR/inst_combine_deref.rs:56:9: 56:10
-              let mut _3: &i32;            // in scope 2 at $DIR/inst_combine_deref.rs:57:9: 57:14
-              scope 3 {
-                  debug y => _3;           // in scope 3 at $DIR/inst_combine_deref.rs:57:9: 57:14
-                  let _4: &mut &i32;       // in scope 3 at $DIR/inst_combine_deref.rs:58:9: 58:10
-                  scope 4 {
-                      debug z => _4;       // in scope 4 at $DIR/inst_combine_deref.rs:58:9: 58:10
-                  }
-              }
-          }
-      }
-  
-      bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/inst_combine_deref.rs:55:9: 55:10
-          _1 = const 42_i32;               // scope 0 at $DIR/inst_combine_deref.rs:55:13: 55:15
-          StorageLive(_2);                 // scope 1 at $DIR/inst_combine_deref.rs:56:9: 56:10
-          _2 = const 99_i32;               // scope 1 at $DIR/inst_combine_deref.rs:56:13: 56:15
-          StorageLive(_3);                 // scope 2 at $DIR/inst_combine_deref.rs:57:9: 57:14
-          _3 = &_1;                        // scope 2 at $DIR/inst_combine_deref.rs:57:17: 57:19
-          StorageLive(_4);                 // scope 3 at $DIR/inst_combine_deref.rs:58:9: 58:10
-          _4 = &mut _3;                    // scope 3 at $DIR/inst_combine_deref.rs:58:13: 58:19
-          StorageLive(_5);                 // scope 4 at $DIR/inst_combine_deref.rs:59:10: 59:12
-          StorageLive(_6);                 // scope 4 at $DIR/inst_combine_deref.rs:59:10: 59:12
-          _6 = &_2;                        // scope 4 at $DIR/inst_combine_deref.rs:59:10: 59:12
--         _5 = &(*_6);                     // scope 4 at $DIR/inst_combine_deref.rs:59:10: 59:12
-+         _5 = _6;                         // scope 4 at $DIR/inst_combine_deref.rs:59:10: 59:12
-          (*_4) = move _5;                 // scope 4 at $DIR/inst_combine_deref.rs:59:5: 59:12
-          StorageDead(_5);                 // scope 4 at $DIR/inst_combine_deref.rs:59:11: 59:12
-          StorageDead(_6);                 // scope 4 at $DIR/inst_combine_deref.rs:59:12: 59:13
-          StorageLive(_7);                 // scope 4 at $DIR/inst_combine_deref.rs:60:5: 60:23
-          StorageLive(_8);                 // scope 4 at $DIR/inst_combine_deref.rs:60:5: 60:23
-          StorageLive(_9);                 // scope 4 at $DIR/inst_combine_deref.rs:60:13: 60:21
-          StorageLive(_10);                // scope 4 at $DIR/inst_combine_deref.rs:60:13: 60:15
-          _10 = (*_3);                     // scope 4 at $DIR/inst_combine_deref.rs:60:13: 60:15
-          _9 = Eq(move _10, const 99_i32); // scope 4 at $DIR/inst_combine_deref.rs:60:13: 60:21
-          StorageDead(_10);                // scope 4 at $DIR/inst_combine_deref.rs:60:20: 60:21
-          _8 = Not(move _9);               // scope 4 at $DIR/inst_combine_deref.rs:60:5: 60:23
-          StorageDead(_9);                 // scope 4 at $DIR/inst_combine_deref.rs:60:22: 60:23
-          switchInt(move _8) -> [false: bb2, otherwise: bb1]; // scope 4 at $DIR/inst_combine_deref.rs:60:5: 60:23
-      }
-  
-      bb1: {
-          StorageLive(_11);                // scope 4 at $DIR/inst_combine_deref.rs:60:5: 60:23
-          core::panicking::panic(const "assertion failed: *y == 99"); // scope 4 at $DIR/inst_combine_deref.rs:60:5: 60:23
-                                           // mir::Constant
-                                           // + span: $DIR/inst_combine_deref.rs:60:5: 60:23
-                                           // + literal: Const { ty: fn(&'static str) -> ! {core::panicking::panic}, val: Value(Scalar(<ZST>)) }
-                                           // ty::Const
-                                           // + ty: &str
-                                           // + val: Value(Slice { data: Allocation { bytes: [97, 115, 115, 101, 114, 116, 105, 111, 110, 32, 102, 97, 105, 108, 101, 100, 58, 32, 42, 121, 32, 61, 61, 32, 57, 57], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [67108863], len: Size { raw: 26 } }, size: Size { raw: 26 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 26 })
-                                           // mir::Constant
-                                           // + span: $DIR/inst_combine_deref.rs:1:1: 1:1
-                                           // + literal: Const { ty: &str, val: Value(Slice { data: Allocation { bytes: [97, 115, 115, 101, 114, 116, 105, 111, 110, 32, 102, 97, 105, 108, 101, 100, 58, 32, 42, 121, 32, 61, 61, 32, 57, 57], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [67108863], len: Size { raw: 26 } }, size: Size { raw: 26 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 26 }) }
-      }
-  
-      bb2: {
-          _7 = const ();                   // scope 4 at $DIR/inst_combine_deref.rs:60:23: 60:23
-          StorageDead(_8);                 // scope 4 at $DIR/inst_combine_deref.rs:60:22: 60:23
-          StorageDead(_7);                 // scope 4 at $DIR/inst_combine_deref.rs:60:22: 60:23
-          _0 = const ();                   // scope 0 at $DIR/inst_combine_deref.rs:54:24: 61:2
-          StorageDead(_4);                 // scope 3 at $DIR/inst_combine_deref.rs:61:1: 61:2
-          StorageDead(_3);                 // scope 2 at $DIR/inst_combine_deref.rs:61:1: 61:2
-          StorageDead(_2);                 // scope 1 at $DIR/inst_combine_deref.rs:61:1: 61:2
-          StorageDead(_1);                 // scope 0 at $DIR/inst_combine_deref.rs:61:1: 61:2
-          return;                          // scope 0 at $DIR/inst_combine_deref.rs:61:2: 61:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/inst_combine_deref.dont_opt.InstCombine.diff b/src/test/mir-opt/inst_combine_deref.dont_opt.InstCombine.diff
deleted file mode 100644 (file)
index 6903649..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-- // MIR for `dont_opt` before InstCombine
-+ // MIR for `dont_opt` after InstCombine
-  
-  fn dont_opt() -> u64 {
-      let mut _0: u64;                     // return place in scope 0 at $DIR/inst_combine_deref.rs:43:18: 43:21
-      let _1: i32;                         // in scope 0 at $DIR/inst_combine_deref.rs:44:9: 44:10
-      let mut _5: &i32;                    // in scope 0 at $DIR/inst_combine_deref.rs:48:10: 48:14
-      scope 1 {
-          debug y => _1;                   // in scope 1 at $DIR/inst_combine_deref.rs:44:9: 44:10
-          let _2: &i32;                    // in scope 1 at $DIR/inst_combine_deref.rs:45:9: 45:13
-          scope 2 {
-              debug _ref => _2;            // in scope 2 at $DIR/inst_combine_deref.rs:45:9: 45:13
-              let _3: i32;                 // in scope 2 at $DIR/inst_combine_deref.rs:46:9: 46:10
-              scope 3 {
-                  debug x => _3;           // in scope 3 at $DIR/inst_combine_deref.rs:46:9: 46:10
-                  let mut _4: &i32;        // in scope 3 at $DIR/inst_combine_deref.rs:47:9: 47:15
-                  scope 4 {
-                      debug _1 => _4;      // in scope 4 at $DIR/inst_combine_deref.rs:47:9: 47:15
-                      let _6: i32;         // in scope 4 at $DIR/inst_combine_deref.rs:49:9: 49:11
-                      scope 5 {
-                          debug _4 => _6;  // in scope 5 at $DIR/inst_combine_deref.rs:49:9: 49:11
-                      }
-                  }
-              }
-          }
-      }
-  
-      bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/inst_combine_deref.rs:44:9: 44:10
-          _1 = const 5_i32;                // scope 0 at $DIR/inst_combine_deref.rs:44:13: 44:14
-          StorageLive(_2);                 // scope 1 at $DIR/inst_combine_deref.rs:45:9: 45:13
-          _2 = &_1;                        // scope 1 at $DIR/inst_combine_deref.rs:45:16: 45:18
-          StorageLive(_3);                 // scope 2 at $DIR/inst_combine_deref.rs:46:9: 46:10
-          _3 = const 5_i32;                // scope 2 at $DIR/inst_combine_deref.rs:46:13: 46:14
-          StorageLive(_4);                 // scope 3 at $DIR/inst_combine_deref.rs:47:9: 47:15
-          _4 = &_3;                        // scope 3 at $DIR/inst_combine_deref.rs:47:18: 47:20
-          StorageLive(_5);                 // scope 4 at $DIR/inst_combine_deref.rs:48:10: 48:14
--         _5 = &(*_2);                     // scope 4 at $DIR/inst_combine_deref.rs:48:10: 48:14
-+         _5 = _2;                         // scope 4 at $DIR/inst_combine_deref.rs:48:10: 48:14
-          _4 = move _5;                    // scope 4 at $DIR/inst_combine_deref.rs:48:5: 48:14
-          StorageDead(_5);                 // scope 4 at $DIR/inst_combine_deref.rs:48:13: 48:14
-          StorageLive(_6);                 // scope 4 at $DIR/inst_combine_deref.rs:49:9: 49:11
-          _6 = (*_4);                      // scope 4 at $DIR/inst_combine_deref.rs:49:14: 49:17
-          _0 = const 0_u64;                // scope 5 at $DIR/inst_combine_deref.rs:50:5: 50:6
-          StorageDead(_6);                 // scope 4 at $DIR/inst_combine_deref.rs:51:1: 51:2
-          StorageDead(_4);                 // scope 3 at $DIR/inst_combine_deref.rs:51:1: 51:2
-          StorageDead(_3);                 // scope 2 at $DIR/inst_combine_deref.rs:51:1: 51:2
-          StorageDead(_2);                 // scope 1 at $DIR/inst_combine_deref.rs:51:1: 51:2
-          StorageDead(_1);                 // scope 0 at $DIR/inst_combine_deref.rs:51:1: 51:2
-          return;                          // scope 0 at $DIR/inst_combine_deref.rs:51:2: 51:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/inst_combine_deref.opt_struct.InstCombine.diff b/src/test/mir-opt/inst_combine_deref.opt_struct.InstCombine.diff
deleted file mode 100644 (file)
index c867543..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-- // MIR for `opt_struct` before InstCombine
-+ // MIR for `opt_struct` after InstCombine
-  
-  fn opt_struct(_1: S) -> u64 {
-      debug s => _1;                       // in scope 0 at $DIR/inst_combine_deref.rs:30:15: 30:16
-      let mut _0: u64;                     // return place in scope 0 at $DIR/inst_combine_deref.rs:30:24: 30:27
-      let _2: &u64;                        // in scope 0 at $DIR/inst_combine_deref.rs:31:9: 31:10
-      let mut _5: u64;                     // in scope 0 at $DIR/inst_combine_deref.rs:34:5: 34:7
-      let mut _6: u64;                     // in scope 0 at $DIR/inst_combine_deref.rs:34:10: 34:11
-      scope 1 {
-          debug a => _2;                   // in scope 1 at $DIR/inst_combine_deref.rs:31:9: 31:10
-          let _3: &u64;                    // in scope 1 at $DIR/inst_combine_deref.rs:32:9: 32:10
-          scope 2 {
-              debug b => _3;               // in scope 2 at $DIR/inst_combine_deref.rs:32:9: 32:10
-              let _4: u64;                 // in scope 2 at $DIR/inst_combine_deref.rs:33:9: 33:10
-              scope 3 {
-                  debug x => _4;           // in scope 3 at $DIR/inst_combine_deref.rs:33:9: 33:10
-              }
-          }
-      }
-  
-      bb0: {
-          StorageLive(_2);                 // scope 0 at $DIR/inst_combine_deref.rs:31:9: 31:10
-          _2 = &(_1.0: u64);               // scope 0 at $DIR/inst_combine_deref.rs:31:13: 31:17
-          StorageLive(_3);                 // scope 1 at $DIR/inst_combine_deref.rs:32:9: 32:10
-          _3 = &(_1.1: u64);               // scope 1 at $DIR/inst_combine_deref.rs:32:13: 32:17
-          StorageLive(_4);                 // scope 2 at $DIR/inst_combine_deref.rs:33:9: 33:10
--         _4 = (*_2);                      // scope 2 at $DIR/inst_combine_deref.rs:33:13: 33:15
-+         _4 = (_1.0: u64);                // scope 2 at $DIR/inst_combine_deref.rs:33:13: 33:15
-          StorageLive(_5);                 // scope 3 at $DIR/inst_combine_deref.rs:34:5: 34:7
--         _5 = (*_3);                      // scope 3 at $DIR/inst_combine_deref.rs:34:5: 34:7
-+         _5 = (_1.1: u64);                // scope 3 at $DIR/inst_combine_deref.rs:34:5: 34:7
-          StorageLive(_6);                 // scope 3 at $DIR/inst_combine_deref.rs:34:10: 34:11
-          _6 = _4;                         // scope 3 at $DIR/inst_combine_deref.rs:34:10: 34:11
-          _0 = Add(move _5, move _6);      // scope 3 at $DIR/inst_combine_deref.rs:34:5: 34:11
-          StorageDead(_6);                 // scope 3 at $DIR/inst_combine_deref.rs:34:10: 34:11
-          StorageDead(_5);                 // scope 3 at $DIR/inst_combine_deref.rs:34:10: 34:11
-          StorageDead(_4);                 // scope 2 at $DIR/inst_combine_deref.rs:35:1: 35:2
-          StorageDead(_3);                 // scope 1 at $DIR/inst_combine_deref.rs:35:1: 35:2
-          StorageDead(_2);                 // scope 0 at $DIR/inst_combine_deref.rs:35:1: 35:2
-          return;                          // scope 0 at $DIR/inst_combine_deref.rs:35:2: 35:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/inst_combine_deref.simple_opt.InstCombine.diff b/src/test/mir-opt/inst_combine_deref.simple_opt.InstCombine.diff
deleted file mode 100644 (file)
index f52dfe3..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-- // MIR for `simple_opt` before InstCombine
-+ // MIR for `simple_opt` after InstCombine
-  
-  fn simple_opt() -> u64 {
-      let mut _0: u64;                     // return place in scope 0 at $DIR/inst_combine_deref.rs:3:20: 3:23
-      let _1: u64;                         // in scope 0 at $DIR/inst_combine_deref.rs:4:9: 4:10
-      scope 1 {
-          debug x => _1;                   // in scope 1 at $DIR/inst_combine_deref.rs:4:9: 4:10
-          let _2: &u64;                    // in scope 1 at $DIR/inst_combine_deref.rs:5:9: 5:10
-          scope 2 {
-              debug y => _2;               // in scope 2 at $DIR/inst_combine_deref.rs:5:9: 5:10
-              let _3: u64;                 // in scope 2 at $DIR/inst_combine_deref.rs:6:9: 6:10
-              scope 3 {
-                  debug z => _3;           // in scope 3 at $DIR/inst_combine_deref.rs:6:9: 6:10
-              }
-          }
-      }
-  
-      bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/inst_combine_deref.rs:4:9: 4:10
-          _1 = const 5_u64;                // scope 0 at $DIR/inst_combine_deref.rs:4:13: 4:14
-          StorageLive(_2);                 // scope 1 at $DIR/inst_combine_deref.rs:5:9: 5:10
-          _2 = &_1;                        // scope 1 at $DIR/inst_combine_deref.rs:5:13: 5:15
-          StorageLive(_3);                 // scope 2 at $DIR/inst_combine_deref.rs:6:9: 6:10
--         _3 = (*_2);                      // scope 2 at $DIR/inst_combine_deref.rs:6:13: 6:15
-+         _3 = _1;                         // scope 2 at $DIR/inst_combine_deref.rs:6:13: 6:15
-          _0 = _3;                         // scope 3 at $DIR/inst_combine_deref.rs:7:5: 7:6
-          StorageDead(_3);                 // scope 2 at $DIR/inst_combine_deref.rs:8:1: 8:2
-          StorageDead(_2);                 // scope 1 at $DIR/inst_combine_deref.rs:8:1: 8:2
-          StorageDead(_1);                 // scope 0 at $DIR/inst_combine_deref.rs:8:1: 8:2
-          return;                          // scope 0 at $DIR/inst_combine_deref.rs:8:2: 8:2
-      }
-  }
-  
index 9036c57556ddaf109c7c418f3216cba6d2fa6f90..19344c868621264154043b78630c4c44837cb560 100644 (file)
@@ -1,3 +1,6 @@
+// EMIT_MIR tls_access.main.PreCodegen.after.mir
+// compile-flags: -Zmir-opt-level=0
+
 #![feature(thread_local)]
 
 #[thread_local]
@@ -9,6 +12,3 @@ fn main() {
         FOO = 42;
     }
 }
-
-// EMIT_MIR tls_access.main.SimplifyCfg-final.after.mir
-// compile-flags: -Zmir-opt-level=0
diff --git a/src/test/mir-opt/tls_access.main.PreCodegen.after.mir b/src/test/mir-opt/tls_access.main.PreCodegen.after.mir
new file mode 100644 (file)
index 0000000..baa7749
--- /dev/null
@@ -0,0 +1,28 @@
+// MIR for `main` after PreCodegen
+
+fn main() -> () {
+    let mut _0: ();                      // return place in scope 0 at $DIR/tls-access.rs:9:11: 9:11
+    let _2: *mut u8;                     // in scope 0 at $DIR/tls-access.rs:11:18: 11:21
+    let mut _3: *mut u8;                 // in scope 0 at $DIR/tls-access.rs:12:9: 12:12
+    scope 1 {
+        let _1: &u8;                     // in scope 1 at $DIR/tls-access.rs:11:13: 11:14
+        scope 2 {
+            debug a => _1;               // in scope 2 at $DIR/tls-access.rs:11:13: 11:14
+        }
+    }
+
+    bb0: {
+        StorageLive(_1);                 // scope 1 at $DIR/tls-access.rs:11:13: 11:14
+        StorageLive(_2);                 // scope 1 at $DIR/tls-access.rs:11:18: 11:21
+        _2 = &/*tls*/ mut FOO;           // scope 1 at $DIR/tls-access.rs:11:18: 11:21
+        _1 = &(*_2);                     // scope 1 at $DIR/tls-access.rs:11:17: 11:21
+        StorageLive(_3);                 // scope 2 at $DIR/tls-access.rs:12:9: 12:12
+        _3 = &/*tls*/ mut FOO;           // scope 2 at $DIR/tls-access.rs:12:9: 12:12
+        (*_3) = const 42_u8;             // scope 2 at $DIR/tls-access.rs:12:9: 12:17
+        StorageDead(_3);                 // scope 2 at $DIR/tls-access.rs:12:17: 12:18
+        _0 = const ();                   // scope 1 at $DIR/tls-access.rs:10:5: 13:6
+        StorageDead(_2);                 // scope 1 at $DIR/tls-access.rs:13:5: 13:6
+        StorageDead(_1);                 // scope 1 at $DIR/tls-access.rs:13:5: 13:6
+        return;                          // scope 0 at $DIR/tls-access.rs:14:2: 14:2
+    }
+}
diff --git a/src/test/mir-opt/tls_access.main.SimplifyCfg-final.after.mir b/src/test/mir-opt/tls_access.main.SimplifyCfg-final.after.mir
deleted file mode 100644 (file)
index de19a22..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-// MIR for `main` after SimplifyCfg-final
-
-fn main() -> () {
-    let mut _0: ();                      // return place in scope 0 at $DIR/tls-access.rs:6:11: 6:11
-    let _2: *mut u8;                     // in scope 0 at $DIR/tls-access.rs:8:18: 8:21
-    let mut _3: *mut u8;                 // in scope 0 at $DIR/tls-access.rs:9:9: 9:12
-    scope 1 {
-        let _1: &u8;                     // in scope 1 at $DIR/tls-access.rs:8:13: 8:14
-        scope 2 {
-            debug a => _1;               // in scope 2 at $DIR/tls-access.rs:8:13: 8:14
-        }
-    }
-
-    bb0: {
-        StorageLive(_1);                 // scope 1 at $DIR/tls-access.rs:8:13: 8:14
-        StorageLive(_2);                 // scope 1 at $DIR/tls-access.rs:8:18: 8:21
-        StorageLive(_3);                 // scope 2 at $DIR/tls-access.rs:9:9: 9:12
-        _3 = &/*tls*/ mut FOO;           // scope 2 at $DIR/tls-access.rs:9:9: 9:12
-        (*_3) = const 42_u8;             // scope 2 at $DIR/tls-access.rs:9:9: 9:17
-        StorageDead(_3);                 // scope 2 at $DIR/tls-access.rs:9:17: 9:18
-        StorageDead(_2);                 // scope 1 at $DIR/tls-access.rs:10:5: 10:6
-        StorageDead(_1);                 // scope 1 at $DIR/tls-access.rs:10:5: 10:6
-        return;                          // scope 0 at $DIR/tls-access.rs:11:2: 11:2
-    }
-}
index cbfc67e7906032cb825083fece548a3268a75c3e..237a4751a8d6677c669d7c14ac91e4976e5dc783 100644 (file)
@@ -1,5 +1,6 @@
 // This test ensures that the settings menu display is working as expected.
 goto: file://|DOC_PATH|/test_docs/index.html
+show-text: true // needed when we check for colors below.
 // First, we check that the settings page doesn't exist.
 assert-false: "#settings"
 // We now click on the settings button.
@@ -43,6 +44,65 @@ assert: ".setting-line.hidden #preferred-light-theme"
 // We check that the correct theme is selected.
 assert-property: ("#theme .choices #theme-dark", {"checked": "true"})
 
+// Some style checks...
+// First we check the "default" display.
+assert-css: (
+    "#theme-dark",
+    {
+        "border-color": "rgb(221, 221, 221)",
+        "box-shadow": "rgb(53, 53, 53) 0px 0px 0px 3px inset",
+    },
+)
+assert-css: ("#theme-light", {"border-color": "rgb(221, 221, 221)", "box-shadow": "none"})
+// Let's start with the hover.
+move-cursor-to: "#theme-dark"
+assert-css: (
+    "#theme-dark",
+    {
+        "border-color": "rgb(33, 150, 243)",
+        "box-shadow": "rgb(53, 53, 53) 0px 0px 0px 3px inset",
+    },
+)
+move-cursor-to: "#theme-light"
+assert-css: ("#theme-light", {"border-color": "rgb(33, 150, 243)", "box-shadow": "none"})
+move-cursor-to: "#theme-ayu"
+// Let's now check with the focus.
+focus: "#theme-dark"
+assert-css: (
+    "#theme-dark",
+    {
+        "border-color": "rgb(221, 221, 221)",
+        "box-shadow": "rgb(53, 53, 53) 0px 0px 0px 3px inset, rgb(33, 150, 243) 0px 0px 2px 2px",
+    },
+)
+focus: "#theme-light"
+assert-css: (
+    "#theme-light",
+    {
+        "border-color": "rgb(221, 221, 221)",
+        "box-shadow": "rgb(33, 150, 243) 0px 0px 1px 1px",
+    },
+)
+// Now we check we both focus and hover.
+move-cursor-to: "#theme-dark"
+focus: "#theme-dark"
+assert-css: (
+    "#theme-dark",
+    {
+        "border-color": "rgb(33, 150, 243)",
+        "box-shadow": "rgb(53, 53, 53) 0px 0px 0px 3px inset, rgb(33, 150, 243) 0px 0px 2px 2px",
+    },
+)
+move-cursor-to: "#theme-light"
+focus: "#theme-light"
+assert-css: (
+    "#theme-light",
+    {
+        "border-color": "rgb(33, 150, 243)",
+        "box-shadow": "rgb(33, 150, 243) 0px 0px 1px 1px",
+    },
+)
+
 // We now switch the display.
 click: "#use-system-theme"
 // Wait for the hidden element to show up.
diff --git a/src/test/rustdoc-js/impl-trait.js b/src/test/rustdoc-js/impl-trait.js
new file mode 100644 (file)
index 0000000..8d594bf
--- /dev/null
@@ -0,0 +1,51 @@
+// ignore-order
+
+const QUERY = [
+    'Aaaaaaa -> i32',
+    'Aaaaaaa -> Aaaaaaa',
+    'Aaaaaaa -> usize',
+    '-> Aaaaaaa',
+    'Aaaaaaa',
+];
+
+const EXPECTED = [
+    {
+        // Aaaaaaa -> i32
+        'others': [
+            { 'path': 'impl_trait::Ccccccc', 'name': 'eeeeeee' },
+        ],
+    },
+    {
+        // Aaaaaaa -> Aaaaaaa
+        'others': [
+            { 'path': 'impl_trait::Ccccccc', 'name': 'fffffff' },
+        ],
+    },
+    {
+        // Aaaaaaa -> usize
+        'others': [],
+    },
+    {
+        // -> Aaaaaaa
+        'others': [
+            { 'path': 'impl_trait::Ccccccc', 'name': 'fffffff' },
+            { 'path': 'impl_trait::Ccccccc', 'name': 'ddddddd' },
+            { 'path': 'impl_trait', 'name': 'bbbbbbb' },
+        ],
+    },
+    {
+        // Aaaaaaa
+        'others': [
+            { 'path': 'impl_trait', 'name': 'Aaaaaaa' },
+        ],
+        'in_args': [
+            { 'path': 'impl_trait::Ccccccc', 'name': 'fffffff' },
+            { 'path': 'impl_trait::Ccccccc', 'name': 'eeeeeee' },
+        ],
+        'returned': [
+            { 'path': 'impl_trait::Ccccccc', 'name': 'fffffff' },
+            { 'path': 'impl_trait::Ccccccc', 'name': 'ddddddd' },
+            { 'path': 'impl_trait', 'name': 'bbbbbbb' },
+        ],
+    },
+];
diff --git a/src/test/rustdoc-js/impl-trait.rs b/src/test/rustdoc-js/impl-trait.rs
new file mode 100644 (file)
index 0000000..fb8869b
--- /dev/null
@@ -0,0 +1,21 @@
+pub trait Aaaaaaa {}
+
+impl Aaaaaaa for () {}
+
+pub fn bbbbbbb() -> impl Aaaaaaa {
+    ()
+}
+
+pub struct Ccccccc {}
+
+impl Ccccccc {
+    pub fn ddddddd(&self) -> impl Aaaaaaa {
+        ()
+    }
+    pub fn eeeeeee(&self, _x: impl Aaaaaaa) -> i32 {
+        0
+    }
+    pub fn fffffff(&self, x: impl Aaaaaaa) -> impl Aaaaaaa {
+        x
+    }
+}
diff --git a/src/test/rustdoc-js/raw-pointer.js b/src/test/rustdoc-js/raw-pointer.js
new file mode 100644 (file)
index 0000000..140b955
--- /dev/null
@@ -0,0 +1,55 @@
+// ignore-order
+
+const QUERY = [
+    'Aaaaaaa -> i32',
+    'Aaaaaaa -> Aaaaaaa',
+    'Aaaaaaa -> usize',
+    '-> Aaaaaaa',
+    'Aaaaaaa',
+];
+
+const EXPECTED = [
+    {
+        // Aaaaaaa -> i32
+        'others': [
+            { 'path': 'raw_pointer::Ccccccc', 'name': 'eeeeeee' },
+        ],
+    },
+    {
+        // Aaaaaaa -> Aaaaaaa
+        'others': [
+            { 'path': 'raw_pointer::Ccccccc', 'name': 'fffffff' },
+            { 'path': 'raw_pointer::Ccccccc', 'name': 'ggggggg' },
+        ],
+    },
+    {
+        // Aaaaaaa -> usize
+        'others': [],
+    },
+    {
+        // -> Aaaaaaa
+        'others': [
+            { 'path': 'raw_pointer::Ccccccc', 'name': 'fffffff' },
+            { 'path': 'raw_pointer::Ccccccc', 'name': 'ggggggg' },
+            { 'path': 'raw_pointer::Ccccccc', 'name': 'ddddddd' },
+            { 'path': 'raw_pointer', 'name': 'bbbbbbb' },
+        ],
+    },
+    {
+        // Aaaaaaa
+        'others': [
+            { 'path': 'raw_pointer', 'name': 'Aaaaaaa' },
+        ],
+        'in_args': [
+            { 'path': 'raw_pointer::Ccccccc', 'name': 'fffffff' },
+            { 'path': 'raw_pointer::Ccccccc', 'name': 'ggggggg' },
+            { 'path': 'raw_pointer::Ccccccc', 'name': 'eeeeeee' },
+        ],
+        'returned': [
+            { 'path': 'raw_pointer::Ccccccc', 'name': 'fffffff' },
+            { 'path': 'raw_pointer::Ccccccc', 'name': 'ggggggg' },
+            { 'path': 'raw_pointer::Ccccccc', 'name': 'ddddddd' },
+            { 'path': 'raw_pointer', 'name': 'bbbbbbb' },
+        ],
+    },
+];
diff --git a/src/test/rustdoc-js/raw-pointer.rs b/src/test/rustdoc-js/raw-pointer.rs
new file mode 100644 (file)
index 0000000..b8ace2e
--- /dev/null
@@ -0,0 +1,24 @@
+use std::ptr;
+
+pub struct Aaaaaaa {}
+
+pub fn bbbbbbb() -> *const Aaaaaaa {
+    ptr::null()
+}
+
+pub struct Ccccccc {}
+
+impl Ccccccc {
+    pub fn ddddddd(&self) -> *const Aaaaaaa {
+        ptr::null()
+    }
+    pub fn eeeeeee(&self, _x: *const Aaaaaaa) -> i32 {
+        0
+    }
+    pub fn fffffff(&self, x: *const Aaaaaaa) -> *const Aaaaaaa {
+        x
+    }
+    pub fn ggggggg(&self, x: *mut Aaaaaaa) -> *mut Aaaaaaa {
+        x
+    }
+}
diff --git a/src/test/rustdoc-json/reexport/same_type_reexported_more_than_once.rs b/src/test/rustdoc-json/reexport/same_type_reexported_more_than_once.rs
new file mode 100644 (file)
index 0000000..fd6ac83
--- /dev/null
@@ -0,0 +1,17 @@
+// Regression test for https://github.com/rust-lang/rust/issues/97432.
+
+#![feature(no_core)]
+#![no_std]
+#![no_core]
+
+// @has same_type_reexported_more_than_once.json
+// @set trait_id = - "$.index[*][?(@.name=='Trait')].id"
+// @has - "$.index[*][?(@.name=='same_type_reexported_more_than_once')].inner.items[*]" $trait_id
+pub use inner::Trait;
+// @set reexport_id = - "$.index[*][?(@.name=='Reexport')].id"
+// @has - "$.index[*][?(@.name=='same_type_reexported_more_than_once')].inner.items[*]" $reexport_id
+pub use inner::Trait as Reexport;
+
+mod inner {
+    pub trait Trait {}
+}
index b60ab6050d79cb035df45552214841b026ad892c..b54f8200666004f34889f87217065446646aff72 100644 (file)
@@ -3,6 +3,8 @@ error[E0433]: failed to resolve: maybe a missing crate `unresolved_crate`?
    |
 LL | use unresolved_crate::module::Name;
    |     ^^^^^^^^^^^^^^^^ maybe a missing crate `unresolved_crate`?
+   |
+   = help: consider adding `extern crate unresolved_crate` to use the `unresolved_crate` crate
 
 error: Compilation failed, aborting rustdoc
 
index 8213422491120fd6b410ea2121f0be8a99bf1ff3..38fadaa44358f3354383a3fd8976c003410207f9 100644 (file)
@@ -3,6 +3,8 @@ error[E0433]: failed to resolve: maybe a missing crate `r#mod`?
    |
 LL | pub(in crate::r#mod) fn main() {}
    |               ^^^^^ maybe a missing crate `r#mod`?
+   |
+   = help: consider adding `extern crate r#mod` to use the `r#mod` crate
 
 error: Compilation failed, aborting rustdoc
 
diff --git a/src/test/rustdoc/anonymous-reexport.rs b/src/test/rustdoc/anonymous-reexport.rs
new file mode 100644 (file)
index 0000000..6b884ff
--- /dev/null
@@ -0,0 +1,22 @@
+#![crate_name = "foo"]
+
+// This test ensures we don't display anonymous (non-inline) re-exports of public items.
+
+// @has 'foo/index.html'
+// @has - '//*[@id="main-content"]' ''
+// We check that the only "h2" present is for "Bla".
+// @count - '//*[@id="main-content"]/h2' 1
+// @has - '//*[@id="main-content"]/h2' 'Structs'
+// @count - '//*[@id="main-content"]//a[@class="struct"]' 1
+
+mod ext {
+    pub trait Foo {}
+    pub trait Bar {}
+    pub struct S;
+}
+
+pub use crate::ext::Foo as _;
+pub use crate::ext::Bar as _;
+pub use crate::ext::S as _;
+
+pub struct Bla;
diff --git a/src/test/rustdoc/inline_cross/auxiliary/implementors_inline.rs b/src/test/rustdoc/inline_cross/auxiliary/implementors_inline.rs
new file mode 100644 (file)
index 0000000..b003fb3
--- /dev/null
@@ -0,0 +1,18 @@
+pub mod my_trait {
+    pub trait MyTrait {
+        fn my_fn(&self) -> Self;
+    }
+}
+
+pub mod prelude {
+    #[doc(inline)]
+    pub use crate::my_trait::MyTrait;
+}
+
+pub struct SomeStruct;
+
+impl my_trait::MyTrait for SomeStruct {
+    fn my_fn(&self) -> SomeStruct {
+        SomeStruct
+    }
+}
diff --git a/src/test/rustdoc/inline_cross/implementors-js.rs b/src/test/rustdoc/inline_cross/implementors-js.rs
new file mode 100644 (file)
index 0000000..c79f05d
--- /dev/null
@@ -0,0 +1,25 @@
+// aux-build:implementors_inline.rs
+// build-aux-docs
+// ignore-cross-compile
+
+extern crate implementors_inline;
+
+// @!has implementors/implementors_js/trait.MyTrait.js
+// @has implementors/implementors_inline/my_trait/trait.MyTrait.js
+// @!has implementors/implementors_inline/prelude/trait.MyTrait.js
+// @has implementors_inline/my_trait/trait.MyTrait.html
+// @has - '//script/@src' '../../implementors/implementors_inline/my_trait/trait.MyTrait.js'
+// @has implementors_js/trait.MyTrait.html
+// @has - '//script/@src' '../implementors/implementors_inline/my_trait/trait.MyTrait.js'
+/// When re-exporting this trait, the HTML will be inlined,
+/// but, vitally, the JavaScript will be located only at the
+/// one canonical path.
+pub use implementors_inline::prelude::MyTrait;
+
+pub struct OtherStruct;
+
+impl MyTrait for OtherStruct {
+    fn my_fn(&self) -> OtherStruct {
+        OtherStruct
+    }
+}
index ae74fbbc892bbeab685cdd652ab95e8a80e4e5a9..24161c3bb4858e6aa7aec23cf4d95926cbec4ead 100644 (file)
@@ -1,8 +1,10 @@
-#![allow(rustdoc::broken_intra_doc_links)]
+#![forbid(rustdoc::broken_intra_doc_links)]
 
 //! Email me at <hello@example.com>.
 //! Email me at <hello-world@example.com>.
-//! Email me at <hello@localhost> (this warns but will still become a link).
+//! Email me at <hello@localhost>.
+//! Email me at <prim@i32>.
 // @has email_address/index.html '//a[@href="mailto:hello@example.com"]' 'hello@example.com'
 // @has email_address/index.html '//a[@href="mailto:hello-world@example.com"]' 'hello-world@example.com'
 // @has email_address/index.html '//a[@href="mailto:hello@localhost"]' 'hello@localhost'
+// @has email_address/index.html '//a[@href="mailto:prim@i32"]' 'prim@i32'
index ac97b94fb351b558258671d7529e8c5825373591..a8cb16ec34cc01cffb3803c64fab6d144d6dd2e7 100644 (file)
@@ -13,5 +13,5 @@
 // @!has foo/trait.Deref.html '//*[@id="impl-Deref-for-EndianSlice"]//h3[@class="code-header in-band"]' 'impl Deref for EndianSlice'
 pub use realcore::Deref;
 
-// @has foo/trait.Join.html '//*[@id="impl-Join-for-Foo"]//h3[@class="code-header in-band"]' 'impl Join for Foo'
+// @has foo/trait.Join.html '//*[@id="impl-Join"]//h3[@class="code-header in-band"]' 'impl Join for Foo'
 pub use realcore::Join;
diff --git a/src/test/rustdoc/nested-modules.rs b/src/test/rustdoc/nested-modules.rs
new file mode 100644 (file)
index 0000000..1596f46
--- /dev/null
@@ -0,0 +1,42 @@
+#![crate_name = "aCrate"]
+
+mod a_module {
+    pub fn private_function() {}
+
+    pub use a_module::private_function as other_private_function;
+
+    pub mod a_nested_module {
+        // @has aCrate/a_nested_module/index.html '//a[@href="fn.a_nested_public_function.html"]' 'a_nested_public_function'
+        // @has aCrate/a_nested_module/fn.a_nested_public_function.html 'pub fn a_nested_public_function()'
+        pub fn a_nested_public_function() {}
+
+        // @has aCrate/a_nested_module/index.html '//a[@href="fn.another_nested_public_function.html"]' 'another_nested_public_function'
+        // @has aCrate/a_nested_module/fn.another_nested_public_function.html 'pub fn another_nested_public_function()'
+        pub use a_nested_module::a_nested_public_function as another_nested_public_function;
+    }
+
+    // @!has aCrate/a_nested_module/index.html 'yet_another_nested_public_function'
+    pub use a_nested_module::a_nested_public_function as yet_another_nested_public_function;
+
+    // @!has aCrate/a_nested_module/index.html 'one_last_nested_public_function'
+    pub use a_nested_module::another_nested_public_function as one_last_nested_public_function;
+}
+
+// @!has aCrate/index.html 'a_module'
+// @has aCrate/index.html '//a[@href="a_nested_module/index.html"]' 'a_nested_module'
+pub use a_module::a_nested_module;
+
+// @has aCrate/index.html '//a[@href="fn.a_nested_public_function.html"]' 'a_nested_public_function'
+// @has aCrate/index.html '//a[@href="fn.another_nested_public_function.html"]' 'another_nested_public_function'
+// @has aCrate/index.html '//a[@href="fn.yet_another_nested_public_function.html"]' 'yet_another_nested_public_function'
+// @has aCrate/index.html '//a[@href="fn.one_last_nested_public_function.html"]' 'one_last_nested_public_function'
+pub use a_module::{
+    a_nested_module::{a_nested_public_function, another_nested_public_function},
+    one_last_nested_public_function, yet_another_nested_public_function,
+};
+
+// @has aCrate/index.html '//a[@href="fn.private_function.html"]' 'private_function'
+// @!has aCrate/fn.private_function.html 'a_module'
+// @has aCrate/index.html '//a[@href="fn.other_private_function.html"]' 'other_private_function'
+// @!has aCrate/fn.other_private_function.html 'a_module'
+pub use a_module::{other_private_function, private_function};
diff --git a/src/test/rustdoc/primitive-slice-auto-trait.rs b/src/test/rustdoc/primitive-slice-auto-trait.rs
new file mode 100644 (file)
index 0000000..b3f511b
--- /dev/null
@@ -0,0 +1,14 @@
+// compile-flags: --crate-type lib --edition 2018
+
+#![crate_name = "foo"]
+#![feature(rustdoc_internals)]
+
+// @has foo/primitive.slice.html '//a[@class="primitive"]' 'slice'
+// @has - '//span[@class="in-band"]' 'Primitive Type slice'
+// @has - '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!'
+// @has - '//h2[@id="synthetic-implementations"]' 'Auto Trait Implementations'
+// @has - '//div[@id="synthetic-implementations-list"]//h3' 'impl<T> Send for [T] where T: Send'
+// @has - '//div[@id="synthetic-implementations-list"]//h3' 'impl<T> Sync for [T] where T: Sync'
+#[doc(primitive = "slice")]
+/// this is a test!
+mod slice_prim {}
diff --git a/src/test/rustdoc/slice-links.link_box_generic.html b/src/test/rustdoc/slice-links.link_box_generic.html
new file mode 100644 (file)
index 0000000..38aaf20
--- /dev/null
@@ -0,0 +1 @@
+<code>pub fn delta&lt;T&gt;() -&gt; <a class="struct" href="struct.MyBox.html" title="struct foo::MyBox">MyBox</a>&lt;<a class="primitive" href="{{channel}}/core/primitive.slice.html">[T]</a>&gt;</code>
\ No newline at end of file
diff --git a/src/test/rustdoc/slice-links.link_box_u32.html b/src/test/rustdoc/slice-links.link_box_u32.html
new file mode 100644 (file)
index 0000000..42fd721
--- /dev/null
@@ -0,0 +1 @@
+<code>pub fn gamma() -&gt; <a class="struct" href="struct.MyBox.html" title="struct foo::MyBox">MyBox</a>&lt;<a class="primitive" href="{{channel}}/core/primitive.slice.html">[</a><a class="primitive" href="{{channel}}/core/primitive.u32.html">u32</a><a class="primitive" href="{{channel}}/core/primitive.slice.html">]</a>&gt;</code>
\ No newline at end of file
diff --git a/src/test/rustdoc/slice-links.link_slice_generic.html b/src/test/rustdoc/slice-links.link_slice_generic.html
new file mode 100644 (file)
index 0000000..fe79ca7
--- /dev/null
@@ -0,0 +1 @@
+<code>pub fn beta&lt;T&gt;() -&gt; <a class="primitive" href="{{channel}}/core/primitive.slice.html">&amp;'static [T]</a></code>
\ No newline at end of file
diff --git a/src/test/rustdoc/slice-links.link_slice_u32.html b/src/test/rustdoc/slice-links.link_slice_u32.html
new file mode 100644 (file)
index 0000000..c7e430b
--- /dev/null
@@ -0,0 +1 @@
+<code>pub fn alpha() -&gt; <a class="primitive" href="{{channel}}/core/primitive.slice.html">&amp;'static [</a><a class="primitive" href="{{channel}}/core/primitive.u32.html">u32</a><a class="primitive" href="{{channel}}/core/primitive.slice.html">]</a></code>
\ No newline at end of file
diff --git a/src/test/rustdoc/slice-links.rs b/src/test/rustdoc/slice-links.rs
new file mode 100644 (file)
index 0000000..9a78e96
--- /dev/null
@@ -0,0 +1,28 @@
+#![crate_name = "foo"]
+#![no_std]
+
+pub struct MyBox<T: ?Sized>(*const T);
+
+// @has 'foo/fn.alpha.html'
+// @snapshot link_slice_u32 - '//pre[@class="rust fn"]/code'
+pub fn alpha() -> &'static [u32] {
+    loop {}
+}
+
+// @has 'foo/fn.beta.html'
+// @snapshot link_slice_generic - '//pre[@class="rust fn"]/code'
+pub fn beta<T>() -> &'static [T] {
+    loop {}
+}
+
+// @has 'foo/fn.gamma.html'
+// @snapshot link_box_u32 - '//pre[@class="rust fn"]/code'
+pub fn gamma() -> MyBox<[u32]> {
+    loop {}
+}
+
+// @has 'foo/fn.delta.html'
+// @snapshot link_box_generic - '//pre[@class="rust fn"]/code'
+pub fn delta<T>() -> MyBox<[T]> {
+    loop {}
+}
index a90ab7ac4388ef03a9ec4a7acc49d71f1f5ddd07..230194c53779342a6dc11b7954ef839d4e1192b7 100644 (file)
@@ -3,8 +3,8 @@
 #![allow(unused_imports)]
 #![feature(rustc_private)]
 
-extern crate rustc_serialize;
-use rustc_serialize::json::Object;
+extern crate libc;
+use libc::c_void;
 
 pub fn main() {
     println!("Hello world!");
index 6d64aeeda7e117ce26ca4227b4ebfb52f2acc35a..9641470a68ba209700a2e26dccded8e03cbf172e 100644 (file)
@@ -3,42 +3,80 @@
 #![allow(unused_must_use)]
 #![allow(dead_code)]
 #![allow(unused_imports)]
-#![feature(rustc_private)]
-
-extern crate rustc_macros;
-extern crate rustc_serialize;
 
 use std::fmt;
 use std::io::prelude::*;
 use std::io::Cursor;
 use std::slice;
+use std::marker::PhantomData;
+
+trait Encoder {
+    type Error;
+}
+
+trait Encodable<S: Encoder> {
+    fn encode(&self, s: &mut S) -> Result<(), S::Error>;
+}
+
+struct JsonEncoder<'a>(PhantomData<&'a mut ()>);
+
+impl Encoder for JsonEncoder<'_> {
+    type Error = ();
+}
+
+struct AsJson<'a, T> {
+    inner: &'a T,
+}
+
+impl<'a, T: for<'r> Encodable<JsonEncoder<'r>>> fmt::Display for AsJson<'a, T> {
+    /// Encodes a json value into a string
+    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        Ok(())
+    }
+}
+
+fn as_json<T>(t: &T) -> AsJson<'_, T> {
+    AsJson { inner: t }
+}
+
+struct OpaqueEncoder(Vec<u8>);
+
+impl Encoder for OpaqueEncoder {
+    type Error = ();
+}
 
-use rustc_macros::Encodable;
-use rustc_serialize::json;
-use rustc_serialize::opaque;
-use rustc_serialize::{Encodable, Encoder};
 
-#[derive(Encodable)]
 struct Foo {
     baz: bool,
 }
 
-#[derive(Encodable)]
+impl<S: Encoder> Encodable<S> for Foo {
+    fn encode(&self, _s: &mut S) -> Result<(), S::Error> {
+        Ok(())
+    }
+}
+
 struct Bar {
     froboz: usize,
 }
 
+impl<S: Encoder> Encodable<S> for Bar {
+    fn encode(&self, _s: &mut S) -> Result<(), S::Error> {
+        Ok(())
+    }
+}
+
 enum WireProtocol {
     JSON,
     Opaque,
     // ...
 }
 
-fn encode_json<T: for<'a> Encodable<json::Encoder<'a>>>(val: &T, wr: &mut Cursor<Vec<u8>>) {
-    write!(wr, "{}", json::as_json(val));
+fn encode_json<T: for<'a> Encodable<JsonEncoder<'a>>>(val: &T, wr: &mut Cursor<Vec<u8>>) {
+    write!(wr, "{}", as_json(val));
 }
-fn encode_opaque<T: Encodable<opaque::Encoder>>(val: &T, wr: Vec<u8>) {
-    let mut encoder = opaque::Encoder::new(wr);
+fn encode_opaque<T: Encodable<OpaqueEncoder>>(val: &T, wr: Vec<u8>) {
+    let mut encoder = OpaqueEncoder(wr);
     val.encode(&mut encoder);
 }
 
index 5adc2c482f5e8977d55ccd1fda82aaad09e214e0..d8b3914d0d4f777e9e1855dab37d6dfa21855ad0 100644 (file)
@@ -3,21 +3,48 @@
 #![allow(unused_imports)]
 #![allow(unused_must_use)]
 // pretty-expanded FIXME #23616
-#![feature(rustc_private)]
 
-extern crate rustc_serialize;
-
-use rustc_serialize::json;
-use rustc_serialize::{Encodable, Encoder};
 use std::fmt;
+use std::marker::PhantomData;
+
+trait Encoder {
+    type Error;
+}
+
+trait Encodable<S: Encoder> {
+    fn encode(&self, s: &mut S) -> Result<(), S::Error>;
+}
+
+impl<S: Encoder> Encodable<S> for i32 {
+    fn encode(&self, _s: &mut S) -> Result<(), S::Error> {
+        Ok(())
+    }
+}
+
+struct JsonEncoder<'a>(PhantomData<&'a mut ()>);
+
+impl Encoder for JsonEncoder<'_> {
+    type Error = ();
+}
+
+fn encode_json<T: for<'r> Encodable<JsonEncoder<'r>>>(
+    object: &T,
+) -> Result<String, ()> {
+    let s = String::new();
+    {
+        let mut encoder = JsonEncoder(PhantomData);
+        object.encode(&mut encoder)?;
+    }
+    Ok(s)
+}
 
-struct Foo<T: for<'a> Encodable<json::Encoder<'a>>> {
+struct Foo<T: for<'a> Encodable<JsonEncoder<'a>>> {
     v: T,
 }
 
-impl<T: for<'a> Encodable<json::Encoder<'a>>> Drop for Foo<T> {
+impl<T: for<'a> Encodable<JsonEncoder<'a>>> Drop for Foo<T> {
     fn drop(&mut self) {
-        json::encode(&self.v);
+        encode_json(&self.v);
     }
 }
 
index 3d5922d155f2690a26023f6d2021acad06e6a693..571028c5e400571391530091cf97a4cf87de91ee 100644 (file)
@@ -2,27 +2,38 @@
 
 #![allow(non_camel_case_types)]
 #![allow(dead_code)]
-#![feature(rustc_private)]
 
-extern crate rustc_serialize;
-
-use std::collections::HashMap;
-use rustc_serialize::json::{self, Json};
+use std::collections::{BTreeMap, HashMap};
 use std::option;
 
+#[derive(Clone, Debug)]
+enum Json {
+    I64(i64),
+    U64(u64),
+    F64(f64),
+    String(String),
+    Boolean(bool),
+    Array(Array),
+    Object(Object),
+    Null,
+}
+
+type Array = Vec<Json>;
+type Object = BTreeMap<String, Json>;
+
 enum object {
     bool_value(bool),
     int_value(i64),
 }
 
-fn lookup(table: json::Object, key: String, default: String) -> String
+fn lookup(table: Object, key: String, default: String) -> String
 {
     match table.get(&key) {
         option::Option::Some(&Json::String(ref s)) => {
             s.to_string()
         }
         option::Option::Some(value) => {
-            println!("{} was expected to be a string but is a {}", key, value);
+            println!("{} was expected to be a string but is a {:?}", key, value);
             default
         }
         option::Option::None => {
@@ -31,7 +42,7 @@ fn lookup(table: json::Object, key: String, default: String) -> String
     }
 }
 
-fn add_interface(_store: isize, managed_ip: String, data: json::Json) -> (String, object)
+fn add_interface(_store: isize, managed_ip: String, data: Json) -> (String, object)
 {
     match &data {
         &Json::Object(ref interface) => {
@@ -43,13 +54,13 @@ fn add_interface(_store: isize, managed_ip: String, data: json::Json) -> (String
             (label, object::bool_value(false))
         }
         _ => {
-            println!("Expected dict for {} interfaces, found {}", managed_ip, data);
+            println!("Expected dict for {} interfaces, found {:?}", managed_ip, data);
             ("gnos:missing-interface".to_string(), object::bool_value(true))
         }
     }
 }
 
-fn add_interfaces(store: isize, managed_ip: String, device: HashMap<String, json::Json>)
+fn add_interfaces(store: isize, managed_ip: String, device: HashMap<String, Json>)
 -> Vec<(String, object)> {
     match device["interfaces"] {
         Json::Array(ref interfaces) =>
@@ -60,7 +71,7 @@ fn add_interfaces(store: isize, managed_ip: String, device: HashMap<String, json
         }
         _ =>
         {
-            println!("Expected list for {} interfaces, found {}", managed_ip,
+            println!("Expected list for {} interfaces, found {:?}", managed_ip,
                      device["interfaces"]);
             Vec::new()
         }
index 6eed4ce4f0c01ecd1cf8509e2682d2f8e24182c7..8da6d97251ba183b83153bb497a4fd308c82bcb5 100644 (file)
@@ -2,9 +2,13 @@ error[E0282]: type annotations needed
   --> $DIR/infer_array_len.rs:19:9
    |
 LL |     let [_, _] = a.into();
-   |         ^^^^^^ consider giving this pattern a type
+   |         ^^^^^^
    |
    = note: type must be known at this point
+help: consider giving this pattern a type
+   |
+LL |     let [_, _]: _ = a.into();
+   |               +++
 
 error: aborting due to previous error
 
index 8a7b8d22760a273680124f95e8c823c5e70d9541..d2ea08aa47430b60ef72711e5420a58e58896612 100644 (file)
@@ -1,10 +1,13 @@
 error[E0282]: type annotations needed for `Vec<T>`
-  --> $DIR/vector-no-ann.rs:2:16
+  --> $DIR/vector-no-ann.rs:2:9
    |
 LL |     let _foo = Vec::new();
-   |         ----   ^^^^^^^^ cannot infer type for type parameter `T`
-   |         |
-   |         consider giving `_foo` the explicit type `Vec<T>`, where the type parameter `T` is specified
+   |         ^^^^
+   |
+help: consider giving `_foo` an explicit type, where the type for type parameter `T` is specified
+   |
+LL |     let _foo: Vec<T> = Vec::new();
+   |             ++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/ast-json/ast-json-ice.rs b/src/test/ui/ast-json/ast-json-ice.rs
deleted file mode 100644 (file)
index ce93e4b..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-// Test that AST json serialization doesn't ICE (#63728).
-
-// revisions: expand noexpand
-
-//[expand] compile-flags: -Zast-json
-//[noexpand] compile-flags: -Zast-json-noexpand
-
-// check-pass
-// dont-check-compiler-stdout - don't check for any AST change.
-
-enum V {
-    A(i32),
-    B { f: [i64; 3 + 4] }
-}
-
-trait X {
-    type Output;
-    fn read(&self) -> Self::Output;
-    fn write(&mut self, _: Self::Output);
-}
-
-macro_rules! call_println {
-    ($y:ident) => { println!("{}", $y) }
-}
-
-fn main() {
-    let x: (i32) = 35;
-    let y = x as i64<> + 5;
-
-    call_println!(y);
-
-    struct A;
-}
-
-// Regressions tests for issues #78398 and #78510 (captured tokens in associated and foreign items)
-
-struct S;
-
-macro_rules! mac_extern {
-    ($i:item) => {
-        extern "C" { $i }
-    }
-}
-macro_rules! mac_assoc {
-    ($i:item) => {
-        impl S { $i }
-        trait Bar { $i }
-    }
-}
-
-mac_extern! {
-    fn foo();
-}
-mac_assoc! {
-    fn foo() {}
-}
diff --git a/src/test/ui/ast-json/ast-json-noexpand-output.rs b/src/test/ui/ast-json/ast-json-noexpand-output.rs
deleted file mode 100644 (file)
index cba539f..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-// Check that AST json printing works.
-#![crate_type = "lib"]
-
-// check-pass
-// compile-flags: -Zast-json-noexpand
-// normalize-stdout-test ":\d+" -> ":0"
-
-// Only include a single item to reduce how often the test output needs
-// updating.
-extern crate core;
diff --git a/src/test/ui/ast-json/ast-json-noexpand-output.stdout b/src/test/ui/ast-json/ast-json-noexpand-output.stdout
deleted file mode 100644 (file)
index 6f6e9b3..0000000
+++ /dev/null
@@ -1 +0,0 @@
-{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"variant":"Ast","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"spans":{"inner_span":{"lo":0,"hi":0},"inject_use_span":{"lo":0,"hi":0}},"id":0,"is_placeholder":false}
diff --git a/src/test/ui/ast-json/ast-json-output.rs b/src/test/ui/ast-json/ast-json-output.rs
deleted file mode 100644 (file)
index 2e00914..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-// Check that AST json printing works.
-#![crate_type = "lib"]
-
-// check-pass
-// compile-flags: -Zast-json
-// normalize-stdout-test ":\d+" -> ":0"
-
-// Only include a single item to reduce how often the test output needs
-// updating.
-extern crate core;
diff --git a/src/test/ui/ast-json/ast-json-output.stdout b/src/test/ui/ast-json/ast-json-output.stdout
deleted file mode 100644 (file)
index 5637ce5..0000000
+++ /dev/null
@@ -1 +0,0 @@
-{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"variant":"Ast","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"rust_2015","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"spans":{"inner_span":{"lo":0,"hi":0},"inject_use_span":{"lo":0,"hi":0}},"id":0,"is_placeholder":false}
index 34705d4838e76ac979160f0b84c5e9dac894b0c1..109883fbeb7cb2ca77c1417818c67eee68f780b8 100644 (file)
@@ -5,6 +5,12 @@ LL | async fn fut(bufs: &mut [&mut [u8]]) {
    |                    ---------------- these two types are declared with different lifetimes...
 LL |     ListFut(bufs).await
    |             ^^^^ ...but data from `bufs` flows into `bufs` here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter
+   |
+LL | async fn fut<'a>(bufs: &'a mut [&'a mut [u8]]) {
+   |             ++++        ++       ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/issue-76547.rs:39:14
@@ -13,6 +19,12 @@ LL | async fn fut2(bufs: &mut [&mut [u8]]) -> i32 {
    |                     ---------------- these two types are declared with different lifetimes...
 LL |     ListFut2(bufs).await
    |              ^^^^ ...but data from `bufs` flows into `bufs` here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter
+   |
+LL | async fn fut2<'a>(bufs: &'a mut [&'a mut [u8]]) -> i32 {
+   |              ++++        ++       ++
 
 error: aborting due to 2 previous errors
 
index bc30da1e389b3634b8f7d6202bb3d72aa5ed0d84..0a5a52cb79e4ce06dfb9fde3014505e651207e9a 100644 (file)
@@ -7,6 +7,11 @@ LL | async fn fut(bufs: &mut [&mut [u8]]) {
    |                    let's call the lifetime of this reference `'1`
 LL |     ListFut(bufs).await
    |             ^^^^ this usage requires that `'1` must outlive `'2`
+   |
+help: consider introducing a named lifetime parameter
+   |
+LL | async fn fut<'a>(bufs: &'a mut [&'a mut [u8]]) {
+   |             ++++        ++       ++
 
 error: lifetime may not live long enough
   --> $DIR/issue-76547.rs:39:14
@@ -17,6 +22,11 @@ LL | async fn fut2(bufs: &mut [&mut [u8]]) -> i32 {
    |                     let's call the lifetime of this reference `'1`
 LL |     ListFut2(bufs).await
    |              ^^^^ this usage requires that `'1` must outlive `'2`
+   |
+help: consider introducing a named lifetime parameter
+   |
+LL | async fn fut2<'a>(bufs: &'a mut [&'a mut [u8]]) -> i32 {
+   |              ++++        ++       ++
 
 error: aborting due to 2 previous errors
 
index 2ff85a27a4645266ce804891dcbff92842a22049..f5409a7ca5d29ecd7c9a88a4bbd248d9f8712135 100644 (file)
@@ -1,14 +1,12 @@
-error[E0623]: lifetime mismatch
+error[E0621]: explicit lifetime required in the type of `foo`
   --> $DIR/issue-63388-1.rs:19:9
    |
 LL |         &'a self, foo: &dyn Foo
-   |                        -------- this parameter and the return type are declared with different lifetimes...
-LL |     ) -> &dyn Foo
-   |          --------
+   |                        -------- help: add explicit lifetime `'a` to the type of `foo`: `&'a (dyn Foo + 'a)`
 ...
 LL |         foo
-   |         ^^^ ...but data from `foo` is returned here
+   |         ^^^ lifetime `'a` required
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0623`.
+For more information about this error, try `rustc --explain E0621`.
index eee0cee278b9ca857902f526cda783b67900b9b0..9263a81bb6af42c3a4f2e20d3f7f6986548ff7d0 100644 (file)
@@ -1,17 +1,16 @@
-error: lifetime may not live long enough
+error[E0621]: explicit lifetime required in the type of `foo`
   --> $DIR/issue-63388-1.rs:17:5
    |
-LL |       async fn do_sth<'a>(
-   |                       -- lifetime `'a` defined here
 LL |           &'a self, foo: &dyn Foo
-   |                          - let's call the lifetime of this reference `'1`
+   |                          -------- help: add explicit lifetime `'a` to the type of `foo`: `&'a (dyn Foo + 'a)`
 LL |       ) -> &dyn Foo
 LL | /     {
 LL | |
 LL | |         foo
 LL | |
 LL | |     }
-   | |_____^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1`
+   | |_____^ lifetime `'a` required
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0621`.
index c45d2a42177cece425f85812021754f3fc18efdf..f00f92954064095e13e9e4e0a7194b63fafea198 100644 (file)
@@ -15,9 +15,9 @@ async fn do_sth<'a>(
         &'a self, foo: &dyn Foo
     ) -> &dyn Foo
     {
-        //[nll]~^ ERROR lifetime may not live long enough
+        //[nll]~^ ERROR explicit lifetime required in the type of `foo` [E0621]
         foo
-        //[base]~^ ERROR lifetime mismatch
+        //[base]~^ ERROR explicit lifetime required in the type of `foo` [E0621]
     }
 }
 
index 0e606eac1e8b6d1a17fa74f30a163a63b1f4f4e9..158a4500bde77cc9ba6a63dc11aafb224b4ed9fb 100644 (file)
@@ -2,7 +2,7 @@
 
 fn function(#[inline] param: u32) {
     //~^ ERROR attribute should be applied to function or closure
-    //~| ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes
+    //~| ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes
 }
 
 fn main() {}
index 003f43d371a35ba59154d1880f8d462a37f9368e..306e862cb58d41f178560ff6bad07e3e9b2d71e4 100644 (file)
@@ -1,4 +1,4 @@
-error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
+error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
   --> $DIR/attrs-on-params.rs:3:13
    |
 LL | fn function(#[inline] param: u32) {
index 41c3cea3021354d56ba96a3a97adcd726fee0e50..439762546381ec45c9364ea3f061f019298326d3 100644 (file)
@@ -3,12 +3,16 @@ error[E0433]: failed to resolve: maybe a missing crate `nonexistent`?
    |
 LL |     pub(in nonexistent) field: u8
    |            ^^^^^^^^^^^ maybe a missing crate `nonexistent`?
+   |
+   = help: consider adding `extern crate nonexistent` to use the `nonexistent` crate
 
 error[E0433]: failed to resolve: maybe a missing crate `nonexistent`?
   --> $DIR/field-attributes-vis-unresolved.rs:22:12
    |
 LL |     pub(in nonexistent) u8
    |            ^^^^^^^^^^^ maybe a missing crate `nonexistent`?
+   |
+   = help: consider adding `extern crate nonexistent` to use the `nonexistent` crate
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/borrowck/issue-71546.rs b/src/test/ui/borrowck/issue-71546.rs
new file mode 100644 (file)
index 0000000..943f7f8
--- /dev/null
@@ -0,0 +1,19 @@
+// Regression test for #71546.
+
+// ignore-compare-mode-nll
+// NLL stderr is different from the original one.
+
+pub fn serialize_as_csv<V>(value: &V) -> Result<String, &str>
+where
+    V: 'static,
+    for<'a> &'a V: IntoIterator,
+    for<'a> <&'a V as IntoIterator>::Item: ToString + 'static,
+{
+    let csv_str: String = value //~ ERROR: the associated type `<&'a V as IntoIterator>::Item` may not live long enough
+        .into_iter()
+        .map(|elem| elem.to_string())
+        .collect::<String>();
+    Ok(csv_str)
+}
+
+fn main() {}
diff --git a/src/test/ui/borrowck/issue-71546.stderr b/src/test/ui/borrowck/issue-71546.stderr
new file mode 100644 (file)
index 0000000..d479ca8
--- /dev/null
@@ -0,0 +1,20 @@
+error[E0310]: the associated type `<&'a V as IntoIterator>::Item` may not live long enough
+  --> $DIR/issue-71546.rs:12:27
+   |
+LL |       let csv_str: String = value
+   |  ___________________________^
+LL | |         .into_iter()
+LL | |         .map(|elem| elem.to_string())
+   | |_____________________________________^
+   |
+   = help: consider adding an explicit lifetime bound `<&'a V as IntoIterator>::Item: 'static`...
+   = note: ...so that the type `<&'a V as IntoIterator>::Item` will meet its required lifetime bounds...
+note: ...that is required by this bound
+  --> $DIR/issue-71546.rs:10:55
+   |
+LL |     for<'a> <&'a V as IntoIterator>::Item: ToString + 'static,
+   |                                                       ^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0310`.
index 2005bd4dd5ca7e7d67e4535238f9409c49d70ee7..db7586bee4953f9310eca084799bd571bd0ac682 100644 (file)
@@ -2,7 +2,12 @@ error[E0282]: type annotations needed
   --> $DIR/expect-two-infer-vars-supply-ty-with-bound-region.rs:8:27
    |
 LL |     with_closure(|x: u32, y| {});
-   |                           ^ consider giving this closure parameter a type
+   |                           ^
+   |
+help: consider giving this closure parameter an explicit type
+   |
+LL |     with_closure(|x: u32, y: B| {});
+   |                            +++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/closures/add_semicolon_non_block_closure.rs b/src/test/ui/closures/add_semicolon_non_block_closure.rs
new file mode 100644 (file)
index 0000000..3ae91be
--- /dev/null
@@ -0,0 +1,11 @@
+fn foo(_f: impl Fn()) {}
+
+fn bar() -> i32 {
+    1
+}
+
+fn main() {
+    foo(|| bar())
+    //~^ ERROR mismatched types [E0308]
+    //~| HELP consider using a semicolon here
+}
diff --git a/src/test/ui/closures/add_semicolon_non_block_closure.stderr b/src/test/ui/closures/add_semicolon_non_block_closure.stderr
new file mode 100644 (file)
index 0000000..ed829fc
--- /dev/null
@@ -0,0 +1,16 @@
+error[E0308]: mismatched types
+  --> $DIR/add_semicolon_non_block_closure.rs:8:12
+   |
+LL | fn main() {
+   |           - expected `()` because of default return type
+LL |     foo(|| bar())
+   |            ^^^^^ expected `()`, found `i32`
+   |
+help: consider using a semicolon here
+   |
+LL |     foo(|| { bar(); })
+   |            +      +++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
index 54825cb746d4298cdeacabcc5ec9de61afca6ee8..38d9d08ce36ab4c2d6c0bd62cf44dbc7d1bee2e7 100644 (file)
@@ -8,7 +8,12 @@ error[E0282]: type annotations needed
   --> $DIR/issue-52437.rs:2:30
    |
 LL |     [(); &(&'static: loop { |x| {}; }) as *const _ as usize]
-   |                              ^ consider giving this closure parameter a type
+   |                              ^
+   |
+help: consider giving this closure parameter an explicit type
+   |
+LL |     [(); &(&'static: loop { |x: _| {}; }) as *const _ as usize]
+   |                               +++
 
 error[E0308]: mismatched types
   --> $DIR/issue-52437.rs:2:5
diff --git a/src/test/ui/codegen/auxiliary/issue-97708-aux.rs b/src/test/ui/codegen/auxiliary/issue-97708-aux.rs
new file mode 100644 (file)
index 0000000..e296bd3
--- /dev/null
@@ -0,0 +1,41 @@
+use std::{ptr::NonNull, task::Poll};
+
+struct TaskRef;
+
+struct Header {
+    vtable: &'static Vtable,
+}
+
+struct Vtable {
+    poll: unsafe fn(TaskRef) -> Poll<()>,
+    deallocate: unsafe fn(NonNull<Header>),
+}
+
+// in the "Header" type, which is a private type in maitake
+impl Header {
+    pub(crate) const fn new_stub() -> Self {
+        unsafe fn nop(_ptr: TaskRef) -> Poll<()> {
+            Poll::Pending
+        }
+
+        unsafe fn nop_deallocate(ptr: NonNull<Header>) {
+            unreachable!("stub task ({ptr:p}) should never be deallocated!");
+        }
+
+        Self { vtable: &Vtable { poll: nop, deallocate: nop_deallocate } }
+    }
+}
+
+// This is a public type in `maitake`
+#[repr(transparent)]
+#[cfg_attr(loom, allow(dead_code))]
+pub struct TaskStub {
+    hdr: Header,
+}
+
+impl TaskStub {
+    /// Create a new unique stub [`Task`].
+    pub const fn new() -> Self {
+        Self { hdr: Header::new_stub() }
+    }
+}
diff --git a/src/test/ui/codegen/issue-97708.rs b/src/test/ui/codegen/issue-97708.rs
new file mode 100644 (file)
index 0000000..8cb28e9
--- /dev/null
@@ -0,0 +1,9 @@
+// build-pass
+// aux-build:issue-97708-aux.rs
+
+extern crate issue_97708_aux;
+use issue_97708_aux::TaskStub;
+
+static TASK_STUB: TaskStub = TaskStub::new();
+
+fn main() {}
index aff51ee9e2f541514975efbd1175be5e2b24b67a..2eb3fd56783147fd58047c9f214dadb9ae12fe54 100644 (file)
@@ -5,6 +5,7 @@ LL | impl Bar for Baz { }
    |      ^^^ type aliases cannot be used as traits
    |
 help: you might have meant to use `#![feature(trait_alias)]` instead of a `type` alias
+  --> $DIR/two_files_data.rs:5:1
    |
 LL | trait Bar = dyn Foo;
    |
index 9cf5ed38c9c6bf8a838f6126934db39a1aae2058..e1e4acd4cd82dbcced8342cf369ff3ab22fd55ac 100644 (file)
@@ -35,37 +35,37 @@ error[E0322]: explicit impls for the `Sized` trait are not permitted
   --> $DIR/coherence-impls-sized.rs:14:1
    |
 LL | impl Sized for TestE {}
-   | ^^^^^^^^^^^^^^^^^^^^ impl of 'Sized' not allowed
+   | ^^^^^^^^^^^^^^^^^^^^ impl of `Sized` not allowed
 
 error[E0322]: explicit impls for the `Sized` trait are not permitted
   --> $DIR/coherence-impls-sized.rs:17:1
    |
 LL | impl Sized for MyType {}
-   | ^^^^^^^^^^^^^^^^^^^^^ impl of 'Sized' not allowed
+   | ^^^^^^^^^^^^^^^^^^^^^ impl of `Sized` not allowed
 
 error[E0322]: explicit impls for the `Sized` trait are not permitted
   --> $DIR/coherence-impls-sized.rs:20:1
    |
 LL | impl Sized for (MyType, MyType) {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of 'Sized' not allowed
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `Sized` not allowed
 
 error[E0322]: explicit impls for the `Sized` trait are not permitted
   --> $DIR/coherence-impls-sized.rs:24:1
    |
 LL | impl Sized for &'static NotSync {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of 'Sized' not allowed
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `Sized` not allowed
 
 error[E0322]: explicit impls for the `Sized` trait are not permitted
   --> $DIR/coherence-impls-sized.rs:27:1
    |
 LL | impl Sized for [MyType] {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^ impl of 'Sized' not allowed
+   | ^^^^^^^^^^^^^^^^^^^^^^^ impl of `Sized` not allowed
 
 error[E0322]: explicit impls for the `Sized` trait are not permitted
   --> $DIR/coherence-impls-sized.rs:31:1
    |
 LL | impl Sized for &'static [NotSync] {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of 'Sized' not allowed
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `Sized` not allowed
 
 error: aborting due to 9 previous errors
 
diff --git a/src/test/ui/conditional-compilation/cfg_accessible-bugs.rs b/src/test/ui/conditional-compilation/cfg_accessible-bugs.rs
new file mode 100644 (file)
index 0000000..ae18bc5
--- /dev/null
@@ -0,0 +1,18 @@
+// This test is a collection of test that should pass.
+//
+// check-fail
+
+#![feature(cfg_accessible)]
+#![feature(trait_alias)]
+
+trait TraitAlias = std::fmt::Debug + Send;
+
+// FIXME: Currently shows "cannot determine" but should be `false`
+#[cfg_accessible(unresolved)] //~ ERROR cannot determine
+const C: bool = true;
+
+// FIXME: Currently shows "not sure" but should be `false`
+#[cfg_accessible(TraitAlias::unresolved)] //~ ERROR not sure whether the path is accessible or not
+const D: bool = true;
+
+fn main() {}
diff --git a/src/test/ui/conditional-compilation/cfg_accessible-bugs.stderr b/src/test/ui/conditional-compilation/cfg_accessible-bugs.stderr
new file mode 100644 (file)
index 0000000..81f0238
--- /dev/null
@@ -0,0 +1,16 @@
+error: not sure whether the path is accessible or not
+  --> $DIR/cfg_accessible-bugs.rs:15:18
+   |
+LL | #[cfg_accessible(TraitAlias::unresolved)]
+   |                  ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the type may have associated items, but we are currently not checking them
+
+error: cannot determine whether the path is accessible or not
+  --> $DIR/cfg_accessible-bugs.rs:11:1
+   |
+LL | #[cfg_accessible(unresolved)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/conditional-compilation/cfg_accessible-not_sure.edition2015.stderr b/src/test/ui/conditional-compilation/cfg_accessible-not_sure.edition2015.stderr
new file mode 100644 (file)
index 0000000..7d5dd58
--- /dev/null
@@ -0,0 +1,122 @@
+error: not sure whether the path is accessible or not
+  --> $DIR/cfg_accessible-not_sure.rs:14:18
+   |
+LL | #[cfg_accessible(Struct::existing)]
+   |                  ^^^^^^^^^^^^^^^^
+   |
+   = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+  --> $DIR/cfg_accessible-not_sure.rs:16:18
+   |
+LL | #[cfg_accessible(Struct::unresolved)]
+   |                  ^^^^^^^^^^^^^^^^^^
+   |
+   = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+  --> $DIR/cfg_accessible-not_sure.rs:25:18
+   |
+LL | #[cfg_accessible(Union::existing)]
+   |                  ^^^^^^^^^^^^^^^
+   |
+   = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+  --> $DIR/cfg_accessible-not_sure.rs:27:18
+   |
+LL | #[cfg_accessible(Union::unresolved)]
+   |                  ^^^^^^^^^^^^^^^^^
+   |
+   = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+  --> $DIR/cfg_accessible-not_sure.rs:36:18
+   |
+LL | #[cfg_accessible(Enum::Existing::existing)]
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+  --> $DIR/cfg_accessible-not_sure.rs:38:18
+   |
+LL | #[cfg_accessible(Enum::Existing::unresolved)]
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+  --> $DIR/cfg_accessible-not_sure.rs:40:18
+   |
+LL | #[cfg_accessible(Enum::unresolved)]
+   |                  ^^^^^^^^^^^^^^^^
+   |
+   = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+  --> $DIR/cfg_accessible-not_sure.rs:50:18
+   |
+LL | #[cfg_accessible(Trait::existing)]
+   |                  ^^^^^^^^^^^^^^^
+   |
+   = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+  --> $DIR/cfg_accessible-not_sure.rs:52:18
+   |
+LL | #[cfg_accessible(Trait::unresolved)]
+   |                  ^^^^^^^^^^^^^^^^^
+   |
+   = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+  --> $DIR/cfg_accessible-not_sure.rs:59:18
+   |
+LL | #[cfg_accessible(TypeAlias::existing)]
+   |                  ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+  --> $DIR/cfg_accessible-not_sure.rs:61:18
+   |
+LL | #[cfg_accessible(TypeAlias::unresolved)]
+   |                  ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+  --> $DIR/cfg_accessible-not_sure.rs:70:18
+   |
+LL | #[cfg_accessible(ForeignType::unresolved)]
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+  --> $DIR/cfg_accessible-not_sure.rs:79:18
+   |
+LL | #[cfg_accessible(AssocType::AssocType::unresolved)]
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+  --> $DIR/cfg_accessible-not_sure.rs:84:18
+   |
+LL | #[cfg_accessible(u8::unresolved)]
+   |                  ^^^^^^^^^^^^^^
+   |
+   = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+  --> $DIR/cfg_accessible-not_sure.rs:86:18
+   |
+LL | #[cfg_accessible(u8::is_ascii)]
+   |                  ^^^^^^^^^^^^
+   |
+   = note: the type may have associated items, but we are currently not checking them
+
+error: aborting due to 15 previous errors
+
diff --git a/src/test/ui/conditional-compilation/cfg_accessible-not_sure.edition2021.stderr b/src/test/ui/conditional-compilation/cfg_accessible-not_sure.edition2021.stderr
new file mode 100644 (file)
index 0000000..7d5dd58
--- /dev/null
@@ -0,0 +1,122 @@
+error: not sure whether the path is accessible or not
+  --> $DIR/cfg_accessible-not_sure.rs:14:18
+   |
+LL | #[cfg_accessible(Struct::existing)]
+   |                  ^^^^^^^^^^^^^^^^
+   |
+   = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+  --> $DIR/cfg_accessible-not_sure.rs:16:18
+   |
+LL | #[cfg_accessible(Struct::unresolved)]
+   |                  ^^^^^^^^^^^^^^^^^^
+   |
+   = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+  --> $DIR/cfg_accessible-not_sure.rs:25:18
+   |
+LL | #[cfg_accessible(Union::existing)]
+   |                  ^^^^^^^^^^^^^^^
+   |
+   = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+  --> $DIR/cfg_accessible-not_sure.rs:27:18
+   |
+LL | #[cfg_accessible(Union::unresolved)]
+   |                  ^^^^^^^^^^^^^^^^^
+   |
+   = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+  --> $DIR/cfg_accessible-not_sure.rs:36:18
+   |
+LL | #[cfg_accessible(Enum::Existing::existing)]
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+  --> $DIR/cfg_accessible-not_sure.rs:38:18
+   |
+LL | #[cfg_accessible(Enum::Existing::unresolved)]
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+  --> $DIR/cfg_accessible-not_sure.rs:40:18
+   |
+LL | #[cfg_accessible(Enum::unresolved)]
+   |                  ^^^^^^^^^^^^^^^^
+   |
+   = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+  --> $DIR/cfg_accessible-not_sure.rs:50:18
+   |
+LL | #[cfg_accessible(Trait::existing)]
+   |                  ^^^^^^^^^^^^^^^
+   |
+   = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+  --> $DIR/cfg_accessible-not_sure.rs:52:18
+   |
+LL | #[cfg_accessible(Trait::unresolved)]
+   |                  ^^^^^^^^^^^^^^^^^
+   |
+   = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+  --> $DIR/cfg_accessible-not_sure.rs:59:18
+   |
+LL | #[cfg_accessible(TypeAlias::existing)]
+   |                  ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+  --> $DIR/cfg_accessible-not_sure.rs:61:18
+   |
+LL | #[cfg_accessible(TypeAlias::unresolved)]
+   |                  ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+  --> $DIR/cfg_accessible-not_sure.rs:70:18
+   |
+LL | #[cfg_accessible(ForeignType::unresolved)]
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+  --> $DIR/cfg_accessible-not_sure.rs:79:18
+   |
+LL | #[cfg_accessible(AssocType::AssocType::unresolved)]
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+  --> $DIR/cfg_accessible-not_sure.rs:84:18
+   |
+LL | #[cfg_accessible(u8::unresolved)]
+   |                  ^^^^^^^^^^^^^^
+   |
+   = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+  --> $DIR/cfg_accessible-not_sure.rs:86:18
+   |
+LL | #[cfg_accessible(u8::is_ascii)]
+   |                  ^^^^^^^^^^^^
+   |
+   = note: the type may have associated items, but we are currently not checking them
+
+error: aborting due to 15 previous errors
+
diff --git a/src/test/ui/conditional-compilation/cfg_accessible-not_sure.rs b/src/test/ui/conditional-compilation/cfg_accessible-not_sure.rs
new file mode 100644 (file)
index 0000000..d68acd2
--- /dev/null
@@ -0,0 +1,89 @@
+// revisions: edition2015 edition2021
+// [edition2015]compile-flags: --edition=2015
+// [edition2021]compile-flags: --edition=2021
+
+#![feature(extern_types)]
+#![feature(cfg_accessible)]
+
+// Struct::unresolved - error
+
+struct Struct {
+    existing: u8,
+}
+
+#[cfg_accessible(Struct::existing)] //~ ERROR not sure
+const A: bool = true;
+#[cfg_accessible(Struct::unresolved)] //~ ERROR not sure
+const B: bool = true;
+
+// Union::unresolved - error
+
+struct Union {
+    existing: u8,
+}
+
+#[cfg_accessible(Union::existing)] //~ ERROR not sure
+const A: bool = true;
+#[cfg_accessible(Union::unresolved)] //~ ERROR not sure
+const B: bool = true;
+
+// Enum::unresolved - error
+
+enum Enum {
+    Existing { existing: u8 },
+}
+
+#[cfg_accessible(Enum::Existing::existing)] //~ ERROR not sure
+const A: bool = true;
+#[cfg_accessible(Enum::Existing::unresolved)] //~ ERROR not sure
+const B: bool = true;
+#[cfg_accessible(Enum::unresolved)] //~ ERROR not sure
+const C: bool = true;
+
+// Trait::unresolved - false or error, depending on edition (error if you can write Trait::foo
+// instead of <dyn Trait>::foo for methods like impl dyn Trait { fn foo() {} })
+
+trait Trait {}
+impl dyn Trait { fn existing() {} }
+
+// FIXME: Should be a error for edition > 2015
+#[cfg_accessible(Trait::existing)] //~ ERROR not sure
+const A: bool = true;
+#[cfg_accessible(Trait::unresolved)] //~ ERROR not sure
+const B: bool = true;
+
+// TypeAlias::unresolved - error
+
+type TypeAlias = Struct;
+
+#[cfg_accessible(TypeAlias::existing)] //~ ERROR not sure
+const A: bool = true;
+#[cfg_accessible(TypeAlias::unresolved)] //~ ERROR not sure
+const B: bool = true;
+
+// ForeignType::unresolved - error
+
+extern {
+    type ForeignType;
+}
+
+#[cfg_accessible(ForeignType::unresolved)] //~ ERROR not sure
+const A: bool = true;
+
+// AssocType::unresolved - error
+
+trait AssocType {
+    type AssocType;
+}
+
+#[cfg_accessible(AssocType::AssocType::unresolved)] //~ ERROR not sure
+const A: bool = true;
+
+// PrimitiveType::unresolved - error
+
+#[cfg_accessible(u8::unresolved)] //~ ERROR not sure
+const A: bool = true;
+#[cfg_accessible(u8::is_ascii)] //~ ERROR not sure
+const B: bool = true;
+
+fn main() {}
diff --git a/src/test/ui/conditional-compilation/cfg_accessible-private.rs b/src/test/ui/conditional-compilation/cfg_accessible-private.rs
new file mode 100644 (file)
index 0000000..5b09567
--- /dev/null
@@ -0,0 +1,21 @@
+// check-pass
+
+#![feature(cfg_accessible)]
+
+mod private {
+    struct Struct;
+    enum Enum{}
+    union Union{_a:u8}
+}
+
+#[cfg_accessible(private::Struct)]
+const A: bool = true;
+
+#[cfg_accessible(private::Enum)]
+const A: bool = true;
+
+#[cfg_accessible(private::Union)]
+const A: bool = true;
+
+const A: bool = false; // Will conflict if any of those is accessible
+fn main() {}
index 07b0be5b1ae2606e37576b693db30c9ad125f09a..df380d0d16f14ea3418bc664b96b26d384ddc667 100644 (file)
@@ -5,20 +5,35 @@ mod m {
     struct ExistingPrivate;
 }
 
+trait Trait {
+    type Assoc;
+}
+
+enum Enum {
+    Existing,
+}
+
+#[cfg_accessible(Enum)]
+struct ExistingResolved;
+
+#[cfg_accessible(Enum::Existing)]
+struct ExistingResolvedVariant;
+
 #[cfg_accessible(m::ExistingPublic)]
 struct ExistingPublic;
 
-// FIXME: Not implemented yet.
-#[cfg_accessible(m::ExistingPrivate)] //~ ERROR not sure whether the path is accessible or not
+#[cfg_accessible(m::ExistingPrivate)]
 struct ExistingPrivate;
 
-// FIXME: Not implemented yet.
-#[cfg_accessible(m::NonExistent)] //~ ERROR not sure whether the path is accessible or not
-struct ExistingPrivate;
+#[cfg_accessible(m::NonExistent)]
+struct NonExistingPrivate;
 
 #[cfg_accessible(n::AccessibleExpanded)] // OK, `cfg_accessible` can wait and retry.
 struct AccessibleExpanded;
 
+#[cfg_accessible(Trait::Assoc)]
+struct AccessibleTraitAssoc;
+
 macro_rules! generate_accessible_expanded {
     () => {
         mod n {
@@ -29,15 +44,12 @@ mod n {
 
 generate_accessible_expanded!();
 
-struct S {
-    field: u8,
-}
-
-// FIXME: Not implemented yet.
-#[cfg_accessible(S::field)] //~ ERROR not sure whether the path is accessible or not
-struct Field;
-
 fn main() {
     ExistingPublic;
     AccessibleExpanded;
+    AccessibleTraitAssoc;
+
+    ExistingPrivate; //~ ERROR cannot find
+    NonExistingPrivate; //~ ERROR cannot find
+    NonExistingTraitAlias; //~ ERROR cannot find
 }
index 167765cd66ee6d045cdce7d7bc23b88e7e7ea0a8..e3731a1ad7128e9db68641811942c925ddb67e7d 100644 (file)
@@ -1,38 +1,27 @@
-error: not sure whether the path is accessible or not
-  --> $DIR/cfg_accessible.rs:12:18
+error[E0425]: cannot find value `ExistingPrivate` in this scope
+  --> $DIR/cfg_accessible.rs:52:5
    |
-LL | #[cfg_accessible(m::ExistingPrivate)]
-   |                  ^^^^^^^^^^^^^^^^^^
+LL |     ExistingPrivate;
+   |     ^^^^^^^^^^^^^^^ not found in this scope
    |
-note: `cfg_accessible` is not fully implemented
-  --> $DIR/cfg_accessible.rs:12:18
+note: unit struct `m::ExistingPrivate` exists but is inaccessible
+  --> $DIR/cfg_accessible.rs:5:5
    |
-LL | #[cfg_accessible(m::ExistingPrivate)]
-   |                  ^^^^^^^^^^^^^^^^^^
+LL |     struct ExistingPrivate;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ not accessible
 
-error: not sure whether the path is accessible or not
-  --> $DIR/cfg_accessible.rs:16:18
+error[E0425]: cannot find value `NonExistingPrivate` in this scope
+  --> $DIR/cfg_accessible.rs:53:5
    |
-LL | #[cfg_accessible(m::NonExistent)]
-   |                  ^^^^^^^^^^^^^^
-   |
-note: `cfg_accessible` is not fully implemented
-  --> $DIR/cfg_accessible.rs:16:18
-   |
-LL | #[cfg_accessible(m::NonExistent)]
-   |                  ^^^^^^^^^^^^^^
+LL |     NonExistingPrivate;
+   |     ^^^^^^^^^^^^^^^^^^ not found in this scope
 
-error: not sure whether the path is accessible or not
-  --> $DIR/cfg_accessible.rs:37:18
-   |
-LL | #[cfg_accessible(S::field)]
-   |                  ^^^^^^^^
-   |
-note: `cfg_accessible` is not fully implemented
-  --> $DIR/cfg_accessible.rs:37:18
+error[E0425]: cannot find value `NonExistingTraitAlias` in this scope
+  --> $DIR/cfg_accessible.rs:54:5
    |
-LL | #[cfg_accessible(S::field)]
-   |                  ^^^^^^^^
+LL |     NonExistingTraitAlias;
+   |     ^^^^^^^^^^^^^^^^^^^^^ not found in this scope
 
 error: aborting due to 3 previous errors
 
+For more information about this error, try `rustc --explain E0425`.
index cccf433e32864ae0c58c21ec0b8519d91bc3161f..227b2f4022365ae7cab2a676577504e94b181dde 100644 (file)
@@ -1,10 +1,13 @@
 error[E0282]: type annotations needed for `Foo<N>`
-  --> $DIR/doesnt_infer.rs:11:15
+  --> $DIR/doesnt_infer.rs:11:9
    |
 LL |     let foo = Foo::foo();
-   |         ---   ^^^^^^^^ cannot infer the value of const parameter `N`
-   |         |
-   |         consider giving `foo` the explicit type `Foo<N>`, where the const parameter `N` is specified
+   |         ^^^
+   |
+help: consider giving `foo` an explicit type, where the the value of const parameter `N` is specified
+   |
+LL |     let foo: Foo<N> = Foo::foo();
+   |            ++++++++
 
 error: aborting due to previous error
 
index 347cd2364b2667cff9bb7103c23376cf4ef90006..463605e2431d609bd2ae7dbdd60723ab61b323e4 100644 (file)
@@ -1,10 +1,8 @@
 error[E0283]: type annotations needed for `Mask<_, LANES>`
-  --> $DIR/issue-91614.rs:6:13
+  --> $DIR/issue-91614.rs:6:9
    |
 LL |     let y = Mask::<_, _>::splat(false);
-   |         -   ^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T`
-   |         |
-   |         consider giving `y` the explicit type `Mask<_, LANES>`, where the type parameter `T` is specified
+   |         ^
    |
    = note: cannot satisfy `_: MaskElement`
 note: required by a bound in `Mask::<T, LANES>::splat`
@@ -12,6 +10,10 @@ note: required by a bound in `Mask::<T, LANES>::splat`
    |
 LL |     T: MaskElement,
    |        ^^^^^^^^^^^ required by this bound in `Mask::<T, LANES>::splat`
+help: consider giving `y` an explicit type, where the type for type parameter `T` is specified
+   |
+LL |     let y: Mask<_, LANES> = Mask::<_, _>::splat(false);
+   |          ++++++++++++++++
 
 error: aborting due to previous error
 
index e59f1ac8027de3edde0a3324e2a32d848c99d57b..9e8328d37017ea0ee92fd90ed4de5f2064761ecb 100644 (file)
@@ -2,13 +2,18 @@ error[E0282]: type annotations needed
   --> $DIR/const_eval_resolve_canonical.rs:26:9
    |
 LL |     let mut _q = Default::default();
-   |         ^^^^^^ consider giving `_q` a type
+   |         ^^^^^^
+   |
+help: consider giving `_q` an explicit type
+   |
+LL |     let mut _q: _ = Default::default();
+   |               +++
 
 error[E0283]: type annotations needed
   --> $DIR/const_eval_resolve_canonical.rs:29:10
    |
 LL |     _q = foo::<_, 2>(_q);
-   |          ^^^^^^^^^^^ cannot infer type
+   |          ^^^^^^^^^^^ cannot infer the value of the constant `{ N + 1 }`
    |
 note: multiple `impl`s satisfying `(): Foo<{ N + 1 }>` found
   --> $DIR/const_eval_resolve_canonical.rs:8:1
index c918651ba62d986d603e3df5c19d22e3e74ecc38..7390a007742fcce629a9c166f1c6a79596c7570e 100644 (file)
@@ -6,6 +6,7 @@ LL |     If<{ FRAC <= 32 }>: True,
    |
    = note: the crate this constant originates from uses `#![feature(generic_const_exprs)]`
 help: consider enabling this feature
+  --> $DIR/issue-94287.rs:1:1
    |
 LL | #![feature(generic_const_exprs)]
    |
index 828f497240395eafa5d9f965126fc87bcb5eb0c2..93e45a88a6c2056604a6dd95564948979ed1bf7c 100644 (file)
@@ -2,12 +2,12 @@ error[E0282]: type annotations needed
   --> $DIR/cannot-infer-const-args.rs:6:5
    |
 LL |     foo();
-   |     ^^^ cannot infer the value of const parameter `X` declared on the function `foo`
+   |     ^^^ cannot infer the value of the const parameter `X` declared on the function `foo`
    |
-help: consider specifying the const argument
+help: consider specifying the generic argument
    |
 LL |     foo::<X>();
-   |     ~~~~~~~~
+   |        +++++
 
 error: aborting due to previous error
 
index a625ed2bdc3b20a11e8cafa9f7bb9ef4fd860fdf..1682b26ac8777bb64f527b345a061e890fef7450 100644 (file)
@@ -2,12 +2,12 @@ error[E0282]: type annotations needed
   --> $DIR/issue-77092.rs:11:26
    |
 LL |         println!("{:?}", take_array_from_mut(&mut arr, i));
-   |                          ^^^^^^^^^^^^^^^^^^^ cannot infer the value of const parameter `N` declared on the function `take_array_from_mut`
+   |                          ^^^^^^^^^^^^^^^^^^^ cannot infer the value of the const parameter `N` declared on the function `take_array_from_mut`
    |
-help: consider specifying the const argument
+help: consider specifying the generic arguments
    |
-LL |         println!("{:?}", take_array_from_mut::<N>(&mut arr, i));
-   |                          ~~~~~~~~~~~~~~~~~~~~~~~~
+LL |         println!("{:?}", take_array_from_mut::<i32, N>(&mut arr, i));
+   |                                             ++++++++++
 
 error: aborting due to previous error
 
index 53d92e5ae725d1c060d3eff112eb931968036ea6..ff6da535bd264eb90a980b264373b6de68e120b9 100644 (file)
@@ -2,12 +2,12 @@ error[E0282]: type annotations needed
   --> $DIR/method-chain.rs:15:33
    |
 LL |     Foo.bar().bar().bar().bar().baz();
-   |                                 ^^^ cannot infer the value of const parameter `N` declared on the associated function `baz`
+   |                                 ^^^ cannot infer the value of the const parameter `N` declared on the associated function `baz`
    |
-help: consider specifying the const argument
+help: consider specifying the generic argument
    |
 LL |     Foo.bar().bar().bar().bar().baz::<N>();
-   |                                 ~~~~~~~~
+   |                                    +++++
 
 error: aborting due to previous error
 
index acf59170c369e6bcfc5c41629a51b71f49309970..98ea8df825265a4e2f8f7b54e247a8b1df492663 100644 (file)
@@ -2,12 +2,12 @@ error[E0282]: type annotations needed
   --> $DIR/one-param-uninferred.rs:9:23
    |
 LL |     let _: [u8; 17] = foo();
-   |                       ^^^ cannot infer the value of const parameter `M` declared on the function `foo`
+   |                       ^^^ cannot infer the value of the const parameter `M` declared on the function `foo`
    |
-help: consider specifying the const argument
+help: consider specifying the generic arguments
    |
-LL |     let _: [u8; 17] = foo::<M>();
-   |                       ~~~~~~~~
+LL |     let _: [u8; 17] = foo::<17_usize, M>();
+   |                          +++++++++++++++
 
 error: aborting due to previous error
 
index a6c79fc058a43fd31c0b9842d65623f44d056dc3..3980ecea86362f9e3323df0c12606de456ce23a4 100644 (file)
@@ -2,12 +2,12 @@ error[E0282]: type annotations needed
   --> $DIR/uninferred-consts.rs:9:9
    |
 LL |     Foo.foo();
-   |         ^^^ cannot infer the value of const parameter `A` declared on the associated function `foo`
+   |         ^^^ cannot infer the value of the const parameter `A` declared on the associated function `foo`
    |
-help: consider specifying the const argument
+help: consider specifying the generic arguments
    |
-LL |     Foo.foo::<A>();
-   |         ~~~~~~~~
+LL |     Foo.foo::<A, B>();
+   |            ++++++++
 
 error: aborting due to previous error
 
index 3f44a54e80adc9cd5a284e96c19ec3c73b5eed8a..362b8554b2fcb91617bc1a4c371c44753b4928a2 100644 (file)
@@ -1,16 +1,13 @@
 error[E0282]: type annotations needed
-  --> $DIR/issue-83249.rs:19:13
+  --> $DIR/issue-83249.rs:19:9
    |
 LL |     let _ = foo([0; 1]);
-   |         -   ^^^ cannot infer type for type parameter `T` declared on the function `foo`
-   |         |
-   |         consider giving this pattern a type
+   |         ^
    |
-help: type parameter declared here
-  --> $DIR/issue-83249.rs:12:8
+help: consider giving this pattern a type
    |
-LL | fn foo<T: Foo>(_: [u8; T::N]) -> T {
-   |        ^
+LL |     let _: _ = foo([0; 1]);
+   |          +++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-ptr/allowed_slices.rs b/src/test/ui/const-ptr/allowed_slices.rs
new file mode 100644 (file)
index 0000000..645283d
--- /dev/null
@@ -0,0 +1,106 @@
+// run-pass
+#![feature(
+    const_slice_from_raw_parts,
+    slice_from_ptr_range,
+    const_slice_from_ptr_range,
+    pointer_byte_offsets,
+    const_pointer_byte_offsets
+)]
+use std::{
+    mem::MaybeUninit,
+    ptr,
+    slice::{from_ptr_range, from_raw_parts},
+};
+
+// Dangling is ok, as long as it's either for ZST reads or for no reads
+pub static S0: &[u32] = unsafe { from_raw_parts(dangling(), 0) };
+pub static S1: &[()] = unsafe { from_raw_parts(dangling(), 3) };
+
+// References are always valid of reads of a single element (basically `slice::from_ref`)
+pub static S2: &[u32] = unsafe { from_raw_parts(&D0, 1) };
+pub static S3: &[MaybeUninit<&u32>] = unsafe { from_raw_parts(&D1, 1) };
+
+// Reinterpreting data is fine, as long as layouts match
+pub static S4: &[u8] = unsafe { from_raw_parts((&D0) as *const _ as _, 3) };
+// This is only valid because D1 has uninitialized bytes, if it was an initialized pointer,
+// that would reinterpret pointers as integers which is UB in CTFE.
+pub static S5: &[MaybeUninit<u8>] = unsafe { from_raw_parts((&D1) as *const _ as _, 2) };
+// Even though u32 and [bool; 4] have different layouts, D0 has a value that
+// is valid as [bool; 4], so this is not UB (it's basically a transmute)
+pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) };
+
+// Structs are considered single allocated objects,
+// as long as you don't reinterpret padding as initialized
+// data everything is ok.
+pub static S7: &[u16] = unsafe {
+    let ptr = (&D2 as *const Struct as *const u16).byte_add(4);
+
+    from_raw_parts(ptr, 3)
+};
+pub static S8: &[MaybeUninit<u16>] = unsafe {
+    let ptr = &D2 as *const Struct as *const MaybeUninit<u16>;
+
+    from_raw_parts(ptr, 6)
+};
+
+pub static R0: &[u32] = unsafe { from_ptr_range(dangling()..dangling()) };
+// from_ptr_range panics on zst
+//pub static R1: &[()] = unsafe { from_ptr_range(dangling(), dangling().byte_add(3)) };
+pub static R2: &[u32] = unsafe {
+    let ptr = &D0 as *const u32;
+    from_ptr_range(ptr..ptr.add(1))
+};
+pub static R3: &[MaybeUninit<&u32>] = unsafe {
+    let ptr = &D1 as *const MaybeUninit<&u32>;
+    from_ptr_range(ptr..ptr.add(1))
+};
+pub static R4: &[u8] = unsafe {
+    let ptr = &D0 as *const u32 as *const u8;
+    from_ptr_range(ptr..ptr.add(3))
+};
+pub static R5: &[MaybeUninit<u8>] = unsafe {
+    let ptr = &D1 as *const MaybeUninit<&u32> as *const MaybeUninit<u8>;
+    from_ptr_range(ptr..ptr.add(2))
+};
+pub static R6: &[bool] = unsafe {
+    let ptr = &D0 as *const u32 as *const bool;
+    from_ptr_range(ptr..ptr.add(4))
+};
+pub static R7: &[u16] = unsafe {
+    let d2 = &D2;
+    let l = &d2.b as *const u32 as *const u16;
+    let r = &d2.d as *const u8 as *const u16;
+
+    from_ptr_range(l..r)
+};
+pub static R8: &[MaybeUninit<u16>] = unsafe {
+    let d2 = &D2;
+    let l = d2 as *const Struct as *const MaybeUninit<u16>;
+    let r = &d2.d as *const u8 as *const MaybeUninit<u16>;
+
+    from_ptr_range(l..r)
+};
+
+// Using valid slice is always valid
+pub static R9: &[u32] = unsafe { from_ptr_range(R0.as_ptr_range()) };
+pub static R10: &[u32] = unsafe { from_ptr_range(R2.as_ptr_range()) };
+
+const D0: u32 = (1 << 16) | 1;
+const D1: MaybeUninit<&u32> = MaybeUninit::uninit();
+const D2: Struct = Struct { a: 1, b: 2, c: 3, d: 4 };
+
+const fn dangling<T>() -> *const T {
+    ptr::NonNull::dangling().as_ptr() as _
+}
+
+#[repr(C)]
+struct Struct {
+    a: u8,
+    // _pad: [MaybeUninit<u8>; 3]
+    b: u32,
+    c: u16,
+    d: u8,
+    // _pad: [MaybeUninit<u8>; 1]
+}
+
+fn main() {}
diff --git a/src/test/ui/const-ptr/forbidden_slices.32bit.stderr b/src/test/ui/const-ptr/forbidden_slices.32bit.stderr
new file mode 100644 (file)
index 0000000..5b0b9aa
--- /dev/null
@@ -0,0 +1,280 @@
+error[E0080]: could not evaluate static initializer
+  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+   |
+LL |         &*ptr::slice_from_raw_parts(data, len)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         dereferencing pointer failed: null pointer is not a valid pointer
+   |         inside `std::slice::from_raw_parts::<u32>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
+   |
+  ::: $DIR/forbidden_slices.rs:19:34
+   |
+LL | pub static S0: &[u32] = unsafe { from_raw_parts(ptr::null(), 0) };
+   |                                  ------------------------------ inside `S0` at $DIR/forbidden_slices.rs:19:34
+
+error[E0080]: could not evaluate static initializer
+  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+   |
+LL |         &*ptr::slice_from_raw_parts(data, len)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         dereferencing pointer failed: null pointer is not a valid pointer
+   |         inside `std::slice::from_raw_parts::<()>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
+   |
+  ::: $DIR/forbidden_slices.rs:20:33
+   |
+LL | pub static S1: &[()] = unsafe { from_raw_parts(ptr::null(), 0) };
+   |                                 ------------------------------ inside `S1` at $DIR/forbidden_slices.rs:20:33
+
+error[E0080]: could not evaluate static initializer
+  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+   |
+LL |         &*ptr::slice_from_raw_parts(data, len)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         dereferencing pointer failed: ALLOC_ID has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
+   |         inside `std::slice::from_raw_parts::<u32>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
+   |
+  ::: $DIR/forbidden_slices.rs:23:34
+   |
+LL | pub static S2: &[u32] = unsafe { from_raw_parts(&D0, 2) };
+   |                                  ---------------------- inside `S2` at $DIR/forbidden_slices.rs:23:34
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/forbidden_slices.rs:26:1
+   |
+LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>[0]: encountered uninitialized bytes
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 4) {
+               ╾─ALLOC_ID─╼ 01 00 00 00                         │ ╾──╼....
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/forbidden_slices.rs:28:1
+   |
+LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, size_of::<&u32>()) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>: encountered a pointer, but expected plain (non-pointer) bytes
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 4) {
+               ╾─ALLOC_ID─╼ 04 00 00 00                         │ ╾──╼....
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/forbidden_slices.rs:30:1
+   |
+LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>[0]: encountered 0x11, but expected a boolean
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 4) {
+               ╾─ALLOC_ID─╼ 04 00 00 00                         │ ╾──╼....
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/forbidden_slices.rs:33:1
+   |
+LL | / pub static S7: &[u16] = unsafe {
+LL | |
+LL | |     let ptr = (&D2 as *const Struct as *const u16).byte_add(1);
+LL | |
+LL | |     from_raw_parts(ptr, 4)
+LL | | };
+   | |__^ type validation failed: encountered an unaligned reference (required 2 byte alignment but found 1)
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 4) {
+               ╾─A_ID+0x1─╼ 04 00 00 00                         │ ╾──╼....
+           }
+
+error[E0080]: could not evaluate static initializer
+  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+   |
+LL |         &*ptr::slice_from_raw_parts(data, len)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         dereferencing pointer failed: ALLOC_ID has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
+   |         inside `std::slice::from_raw_parts::<u64>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
+   |
+  ::: $DIR/forbidden_slices.rs:44:5
+   |
+LL |     from_raw_parts(ptr, 1)
+   |     ---------------------- inside `S8` at $DIR/forbidden_slices.rs:44:5
+
+error[E0080]: could not evaluate static initializer
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+LL |         unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                  |
+   |                  out-of-bounds offset_from: null pointer is not a valid pointer
+   |                  inside `ptr::const_ptr::<impl *const u32>::sub_ptr` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+  ::: $SRC_DIR/core/src/slice/raw.rs:LL:COL
+   |
+LL |     unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) }
+   |                                          ------------------------------ inside `from_ptr_range::<u32>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
+   |
+  ::: $DIR/forbidden_slices.rs:47:34
+   |
+LL | pub static R0: &[u32] = unsafe { from_ptr_range(ptr::null()..ptr::null()) };
+   |                                  ---------------------------------------- inside `R0` at $DIR/forbidden_slices.rs:47:34
+
+error[E0080]: could not evaluate static initializer
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+LL |         assert!(0 < pointee_size && pointee_size <= isize::MAX as usize);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         the evaluated program panicked at 'assertion failed: 0 < pointee_size && pointee_size <= isize::MAX as usize', $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |         inside `ptr::const_ptr::<impl *const ()>::sub_ptr` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+  ::: $SRC_DIR/core/src/slice/raw.rs:LL:COL
+   |
+LL |     unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) }
+   |                                          ------------------------------ inside `from_ptr_range::<()>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
+   |
+  ::: $DIR/forbidden_slices.rs:48:33
+   |
+LL | pub static R1: &[()] = unsafe { from_ptr_range(ptr::null()..ptr::null()) };
+   |                                 ---------------------------------------- inside `R1` at $DIR/forbidden_slices.rs:48:33
+   |
+   = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0080]: could not evaluate static initializer
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+LL |         unsafe { intrinsics::offset(self, count) }
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                  |
+   |                  pointer arithmetic failed: ALLOC_ID has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
+   |                  inside `ptr::const_ptr::<impl *const u32>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+...
+LL |         unsafe { self.offset(count as isize) }
+   |                  --------------------------- inside `ptr::const_ptr::<impl *const u32>::add` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+  ::: $DIR/forbidden_slices.rs:51:25
+   |
+LL |     from_ptr_range(ptr..ptr.add(2))
+   |                         ---------- inside `R2` at $DIR/forbidden_slices.rs:51:25
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/forbidden_slices.rs:53:1
+   |
+LL | / pub static R4: &[u8] = unsafe {
+LL | |
+LL | |     let ptr = (&D1) as *const MaybeUninit<&u32> as *const u8;
+LL | |     from_ptr_range(ptr..ptr.add(1))
+LL | | };
+   | |__^ type validation failed at .<deref>[0]: encountered uninitialized bytes
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 4) {
+               ╾ALLOC_ID─╼ 01 00 00 00                         │ ╾──╼....
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/forbidden_slices.rs:58:1
+   |
+LL | / pub static R5: &[u8] = unsafe {
+LL | |
+LL | |     let ptr = &D3 as *const &u32;
+LL | |     from_ptr_range(ptr.cast()..ptr.add(1).cast())
+LL | | };
+   | |__^ type validation failed at .<deref>: encountered a pointer, but expected plain (non-pointer) bytes
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 4) {
+               ╾ALLOC_ID─╼ 04 00 00 00                         │ ╾──╼....
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/forbidden_slices.rs:63:1
+   |
+LL | / pub static R6: &[bool] = unsafe {
+LL | |
+LL | |     let ptr = &D0 as *const u32 as *const bool;
+LL | |     from_ptr_range(ptr..ptr.add(4))
+LL | | };
+   | |__^ type validation failed at .<deref>[0]: encountered 0x11, but expected a boolean
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 4) {
+               ╾ALLOC_ID─╼ 04 00 00 00                         │ ╾──╼....
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/forbidden_slices.rs:68:1
+   |
+LL | / pub static R7: &[u16] = unsafe {
+LL | |
+LL | |     let ptr = (&D2 as *const Struct as *const u16).byte_add(1);
+LL | |     from_ptr_range(ptr..ptr.add(4))
+LL | | };
+   | |__^ type validation failed: encountered an unaligned reference (required 2 byte alignment but found 1)
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 4) {
+               ╾A_ID+0x1─╼ 04 00 00 00                         │ ╾──╼....
+           }
+
+error[E0080]: could not evaluate static initializer
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+LL |         unsafe { intrinsics::offset(self, count) }
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                  |
+   |                  pointer arithmetic failed: ALLOC_ID has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
+   |                  inside `ptr::const_ptr::<impl *const u64>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+...
+LL |         unsafe { self.offset(count as isize) }
+   |                  --------------------------- inside `ptr::const_ptr::<impl *const u64>::add` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+  ::: $DIR/forbidden_slices.rs:75:25
+   |
+LL |     from_ptr_range(ptr..ptr.add(1))
+   |                         ---------- inside `R8` at $DIR/forbidden_slices.rs:75:25
+
+error[E0080]: could not evaluate static initializer
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+LL |         unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                  |
+   |                  ptr_offset_from_unsigned cannot compute offset of pointers into different allocations.
+   |                  inside `ptr::const_ptr::<impl *const u32>::sub_ptr` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+  ::: $SRC_DIR/core/src/slice/raw.rs:LL:COL
+   |
+LL |     unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) }
+   |                                          ------------------------------ inside `from_ptr_range::<u32>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
+   |
+  ::: $DIR/forbidden_slices.rs:80:34
+   |
+LL | pub static R9: &[u32] = unsafe { from_ptr_range(&D0..(&D0 as *const u32).add(1)) };
+   |                                  ----------------------------------------------- inside `R9` at $DIR/forbidden_slices.rs:80:34
+
+error[E0080]: could not evaluate static initializer
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+LL |         unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                  |
+   |                  ptr_offset_from_unsigned cannot compute offset of pointers into different allocations.
+   |                  inside `ptr::const_ptr::<impl *const u32>::sub_ptr` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+  ::: $SRC_DIR/core/src/slice/raw.rs:LL:COL
+   |
+LL |     unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) }
+   |                                          ------------------------------ inside `from_ptr_range::<u32>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
+   |
+  ::: $DIR/forbidden_slices.rs:81:35
+   |
+LL | pub static R10: &[u32] = unsafe { from_ptr_range(&D0..&D0) };
+   |                                   ------------------------ inside `R10` at $DIR/forbidden_slices.rs:81:35
+
+error: aborting due to 18 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/const-ptr/forbidden_slices.64bit.stderr b/src/test/ui/const-ptr/forbidden_slices.64bit.stderr
new file mode 100644 (file)
index 0000000..b75e6c5
--- /dev/null
@@ -0,0 +1,280 @@
+error[E0080]: could not evaluate static initializer
+  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+   |
+LL |         &*ptr::slice_from_raw_parts(data, len)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         dereferencing pointer failed: null pointer is not a valid pointer
+   |         inside `std::slice::from_raw_parts::<u32>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
+   |
+  ::: $DIR/forbidden_slices.rs:19:34
+   |
+LL | pub static S0: &[u32] = unsafe { from_raw_parts(ptr::null(), 0) };
+   |                                  ------------------------------ inside `S0` at $DIR/forbidden_slices.rs:19:34
+
+error[E0080]: could not evaluate static initializer
+  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+   |
+LL |         &*ptr::slice_from_raw_parts(data, len)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         dereferencing pointer failed: null pointer is not a valid pointer
+   |         inside `std::slice::from_raw_parts::<()>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
+   |
+  ::: $DIR/forbidden_slices.rs:20:33
+   |
+LL | pub static S1: &[()] = unsafe { from_raw_parts(ptr::null(), 0) };
+   |                                 ------------------------------ inside `S1` at $DIR/forbidden_slices.rs:20:33
+
+error[E0080]: could not evaluate static initializer
+  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+   |
+LL |         &*ptr::slice_from_raw_parts(data, len)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         dereferencing pointer failed: ALLOC_ID has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
+   |         inside `std::slice::from_raw_parts::<u32>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
+   |
+  ::: $DIR/forbidden_slices.rs:23:34
+   |
+LL | pub static S2: &[u32] = unsafe { from_raw_parts(&D0, 2) };
+   |                                  ---------------------- inside `S2` at $DIR/forbidden_slices.rs:23:34
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/forbidden_slices.rs:26:1
+   |
+LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>[0]: encountered uninitialized bytes
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 16, align: 8) {
+               ╾───────ALLOC_ID───────╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/forbidden_slices.rs:28:1
+   |
+LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, size_of::<&u32>()) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>: encountered a pointer, but expected plain (non-pointer) bytes
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 16, align: 8) {
+               ╾───────ALLOC_ID───────╼ 08 00 00 00 00 00 00 00 │ ╾──────╼........
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/forbidden_slices.rs:30:1
+   |
+LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>[0]: encountered 0x11, but expected a boolean
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 16, align: 8) {
+               ╾───────ALLOC_ID───────╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/forbidden_slices.rs:33:1
+   |
+LL | / pub static S7: &[u16] = unsafe {
+LL | |
+LL | |     let ptr = (&D2 as *const Struct as *const u16).byte_add(1);
+LL | |
+LL | |     from_raw_parts(ptr, 4)
+LL | | };
+   | |__^ type validation failed: encountered an unaligned reference (required 2 byte alignment but found 1)
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 16, align: 8) {
+               ╾─────ALLOC_ID+0x1─────╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
+           }
+
+error[E0080]: could not evaluate static initializer
+  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+   |
+LL |         &*ptr::slice_from_raw_parts(data, len)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         dereferencing pointer failed: ALLOC_ID has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
+   |         inside `std::slice::from_raw_parts::<u64>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
+   |
+  ::: $DIR/forbidden_slices.rs:44:5
+   |
+LL |     from_raw_parts(ptr, 1)
+   |     ---------------------- inside `S8` at $DIR/forbidden_slices.rs:44:5
+
+error[E0080]: could not evaluate static initializer
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+LL |         unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                  |
+   |                  out-of-bounds offset_from: null pointer is not a valid pointer
+   |                  inside `ptr::const_ptr::<impl *const u32>::sub_ptr` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+  ::: $SRC_DIR/core/src/slice/raw.rs:LL:COL
+   |
+LL |     unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) }
+   |                                          ------------------------------ inside `from_ptr_range::<u32>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
+   |
+  ::: $DIR/forbidden_slices.rs:47:34
+   |
+LL | pub static R0: &[u32] = unsafe { from_ptr_range(ptr::null()..ptr::null()) };
+   |                                  ---------------------------------------- inside `R0` at $DIR/forbidden_slices.rs:47:34
+
+error[E0080]: could not evaluate static initializer
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+LL |         assert!(0 < pointee_size && pointee_size <= isize::MAX as usize);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         the evaluated program panicked at 'assertion failed: 0 < pointee_size && pointee_size <= isize::MAX as usize', $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |         inside `ptr::const_ptr::<impl *const ()>::sub_ptr` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+  ::: $SRC_DIR/core/src/slice/raw.rs:LL:COL
+   |
+LL |     unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) }
+   |                                          ------------------------------ inside `from_ptr_range::<()>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
+   |
+  ::: $DIR/forbidden_slices.rs:48:33
+   |
+LL | pub static R1: &[()] = unsafe { from_ptr_range(ptr::null()..ptr::null()) };
+   |                                 ---------------------------------------- inside `R1` at $DIR/forbidden_slices.rs:48:33
+   |
+   = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0080]: could not evaluate static initializer
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+LL |         unsafe { intrinsics::offset(self, count) }
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                  |
+   |                  pointer arithmetic failed: ALLOC_ID has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
+   |                  inside `ptr::const_ptr::<impl *const u32>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+...
+LL |         unsafe { self.offset(count as isize) }
+   |                  --------------------------- inside `ptr::const_ptr::<impl *const u32>::add` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+  ::: $DIR/forbidden_slices.rs:51:25
+   |
+LL |     from_ptr_range(ptr..ptr.add(2))
+   |                         ---------- inside `R2` at $DIR/forbidden_slices.rs:51:25
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/forbidden_slices.rs:53:1
+   |
+LL | / pub static R4: &[u8] = unsafe {
+LL | |
+LL | |     let ptr = (&D1) as *const MaybeUninit<&u32> as *const u8;
+LL | |     from_ptr_range(ptr..ptr.add(1))
+LL | | };
+   | |__^ type validation failed at .<deref>[0]: encountered uninitialized bytes
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 16, align: 8) {
+               ╾──────ALLOC_ID───────╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/forbidden_slices.rs:58:1
+   |
+LL | / pub static R5: &[u8] = unsafe {
+LL | |
+LL | |     let ptr = &D3 as *const &u32;
+LL | |     from_ptr_range(ptr.cast()..ptr.add(1).cast())
+LL | | };
+   | |__^ type validation failed at .<deref>: encountered a pointer, but expected plain (non-pointer) bytes
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 16, align: 8) {
+               ╾──────ALLOC_ID───────╼ 08 00 00 00 00 00 00 00 │ ╾──────╼........
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/forbidden_slices.rs:63:1
+   |
+LL | / pub static R6: &[bool] = unsafe {
+LL | |
+LL | |     let ptr = &D0 as *const u32 as *const bool;
+LL | |     from_ptr_range(ptr..ptr.add(4))
+LL | | };
+   | |__^ type validation failed at .<deref>[0]: encountered 0x11, but expected a boolean
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 16, align: 8) {
+               ╾──────ALLOC_ID───────╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/forbidden_slices.rs:68:1
+   |
+LL | / pub static R7: &[u16] = unsafe {
+LL | |
+LL | |     let ptr = (&D2 as *const Struct as *const u16).byte_add(1);
+LL | |     from_ptr_range(ptr..ptr.add(4))
+LL | | };
+   | |__^ type validation failed: encountered an unaligned reference (required 2 byte alignment but found 1)
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 16, align: 8) {
+               ╾────ALLOC_ID+0x1─────╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
+           }
+
+error[E0080]: could not evaluate static initializer
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+LL |         unsafe { intrinsics::offset(self, count) }
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                  |
+   |                  pointer arithmetic failed: ALLOC_ID has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
+   |                  inside `ptr::const_ptr::<impl *const u64>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+...
+LL |         unsafe { self.offset(count as isize) }
+   |                  --------------------------- inside `ptr::const_ptr::<impl *const u64>::add` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+  ::: $DIR/forbidden_slices.rs:75:25
+   |
+LL |     from_ptr_range(ptr..ptr.add(1))
+   |                         ---------- inside `R8` at $DIR/forbidden_slices.rs:75:25
+
+error[E0080]: could not evaluate static initializer
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+LL |         unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                  |
+   |                  ptr_offset_from_unsigned cannot compute offset of pointers into different allocations.
+   |                  inside `ptr::const_ptr::<impl *const u32>::sub_ptr` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+  ::: $SRC_DIR/core/src/slice/raw.rs:LL:COL
+   |
+LL |     unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) }
+   |                                          ------------------------------ inside `from_ptr_range::<u32>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
+   |
+  ::: $DIR/forbidden_slices.rs:80:34
+   |
+LL | pub static R9: &[u32] = unsafe { from_ptr_range(&D0..(&D0 as *const u32).add(1)) };
+   |                                  ----------------------------------------------- inside `R9` at $DIR/forbidden_slices.rs:80:34
+
+error[E0080]: could not evaluate static initializer
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+LL |         unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                  |
+   |                  ptr_offset_from_unsigned cannot compute offset of pointers into different allocations.
+   |                  inside `ptr::const_ptr::<impl *const u32>::sub_ptr` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+  ::: $SRC_DIR/core/src/slice/raw.rs:LL:COL
+   |
+LL |     unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) }
+   |                                          ------------------------------ inside `from_ptr_range::<u32>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
+   |
+  ::: $DIR/forbidden_slices.rs:81:35
+   |
+LL | pub static R10: &[u32] = unsafe { from_ptr_range(&D0..&D0) };
+   |                                   ------------------------ inside `R10` at $DIR/forbidden_slices.rs:81:35
+
+error: aborting due to 18 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/const-ptr/forbidden_slices.rs b/src/test/ui/const-ptr/forbidden_slices.rs
new file mode 100644 (file)
index 0000000..4465da4
--- /dev/null
@@ -0,0 +1,99 @@
+// stderr-per-bitwidth
+// normalize-stderr-test "alloc[0-9]+" -> "ALLOC_ID"
+// normalize-stderr-test "a[0-9]+\+0x" -> "A_ID+0x"
+// error-pattern: could not evaluate static initializer
+#![feature(
+    const_slice_from_raw_parts,
+    slice_from_ptr_range,
+    const_slice_from_ptr_range,
+    pointer_byte_offsets,
+    const_pointer_byte_offsets
+)]
+use std::{
+    mem::{size_of, MaybeUninit},
+    ptr,
+    slice::{from_ptr_range, from_raw_parts},
+};
+
+// Null is never valid for reads
+pub static S0: &[u32] = unsafe { from_raw_parts(ptr::null(), 0) };
+pub static S1: &[()] = unsafe { from_raw_parts(ptr::null(), 0) };
+
+// Out of bounds
+pub static S2: &[u32] = unsafe { from_raw_parts(&D0, 2) };
+
+// Reading uninitialized  data
+pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) }; //~ ERROR: it is undefined behavior to use this value
+// Reinterpret pointers as integers (UB in CTFE.)
+pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, size_of::<&u32>()) }; //~ ERROR: it is undefined behavior to use this value
+// Layout mismatch
+pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) }; //~ ERROR: it is undefined behavior to use this value
+
+// Reading padding is not ok
+pub static S7: &[u16] = unsafe {
+    //~^ ERROR: it is undefined behavior to use this value
+    let ptr = (&D2 as *const Struct as *const u16).byte_add(1);
+
+    from_raw_parts(ptr, 4)
+};
+
+// Unaligned read
+pub static S8: &[u64] = unsafe {
+    let ptr = (&D4 as *const [u32; 2] as *const u32).byte_add(1).cast::<u64>();
+
+    from_raw_parts(ptr, 1)
+};
+
+pub static R0: &[u32] = unsafe { from_ptr_range(ptr::null()..ptr::null()) };
+pub static R1: &[()] = unsafe { from_ptr_range(ptr::null()..ptr::null()) };
+pub static R2: &[u32] = unsafe {
+    let ptr = &D0 as *const u32;
+    from_ptr_range(ptr..ptr.add(2))
+};
+pub static R4: &[u8] = unsafe {
+    //~^ ERROR: it is undefined behavior to use this value
+    let ptr = (&D1) as *const MaybeUninit<&u32> as *const u8;
+    from_ptr_range(ptr..ptr.add(1))
+};
+pub static R5: &[u8] = unsafe {
+    //~^ ERROR: it is undefined behavior to use this value
+    let ptr = &D3 as *const &u32;
+    from_ptr_range(ptr.cast()..ptr.add(1).cast())
+};
+pub static R6: &[bool] = unsafe {
+    //~^ ERROR: it is undefined behavior to use this value
+    let ptr = &D0 as *const u32 as *const bool;
+    from_ptr_range(ptr..ptr.add(4))
+};
+pub static R7: &[u16] = unsafe {
+    //~^ ERROR: it is undefined behavior to use this value
+    let ptr = (&D2 as *const Struct as *const u16).byte_add(1);
+    from_ptr_range(ptr..ptr.add(4))
+};
+pub static R8: &[u64] = unsafe {
+    let ptr = (&D4 as *const [u32; 2] as *const u32).byte_add(1).cast::<u64>();
+    from_ptr_range(ptr..ptr.add(1))
+};
+
+// This is sneaky: &D0 and &D0 point to different objects
+// (even if at runtime they have the same address)
+pub static R9: &[u32] = unsafe { from_ptr_range(&D0..(&D0 as *const u32).add(1)) };
+pub static R10: &[u32] = unsafe { from_ptr_range(&D0..&D0) };
+
+const D0: u32 = 0x11;
+const D1: MaybeUninit<&u32> = MaybeUninit::uninit();
+const D2: Struct = Struct { a: 1, b: 2, c: 3, d: 4 };
+const D3: &u32 = &42;
+const D4: [u32; 2] = [17, 42];
+
+#[repr(C)]
+struct Struct {
+    a: u8,
+    // _pad: [MaybeUninit<u8>; 3]
+    b: u32,
+    c: u16,
+    d: u8,
+    // _pad: [MaybeUninit<u8>; 1]
+}
+
+fn main() {}
diff --git a/src/test/ui/consts/issue-54387.rs b/src/test/ui/consts/issue-54387.rs
new file mode 100644 (file)
index 0000000..60e3a02
--- /dev/null
@@ -0,0 +1,12 @@
+// check-pass
+
+pub struct GstRc {
+    _obj: *const (),
+    _borrowed: bool,
+}
+
+const FOO: Option<GstRc> = None;
+
+fn main() {
+    let _meh = FOO;
+}
index caa582d87f527295e587364270f9893ff04077d9..21a419711a989c6a60f00dda3ffbe06f8171e34b 100644 (file)
@@ -2,25 +2,23 @@ error[E0282]: type annotations needed
   --> $DIR/issue-64662.rs:2:9
    |
 LL |     A = foo(),
-   |         ^^^ cannot infer type for type parameter `T` declared on the function `foo`
+   |         ^^^ cannot infer type of the type parameter `T` declared on the function `foo`
    |
-help: type parameter declared here
-  --> $DIR/issue-64662.rs:6:14
+help: consider specifying the generic argument
    |
-LL | const fn foo<T>() -> isize {
-   |              ^
+LL |     A = foo::<T>(),
+   |            +++++
 
 error[E0282]: type annotations needed
   --> $DIR/issue-64662.rs:3:9
    |
 LL |     B = foo(),
-   |         ^^^ cannot infer type for type parameter `T` declared on the function `foo`
+   |         ^^^ cannot infer type of the type parameter `T` declared on the function `foo`
    |
-help: type parameter declared here
-  --> $DIR/issue-64662.rs:6:14
+help: consider specifying the generic argument
    |
-LL | const fn foo<T>() -> isize {
-   |              ^
+LL |     B = foo::<T>(),
+   |            +++++
 
 error: aborting due to 2 previous errors
 
index 2a44e56a3302c87054e9f145b4cc9e9d49521df2..58aaf978dc7d675cad5fdbf6df75ac013e298a60 100644 (file)
@@ -5,12 +5,7 @@ LL |     Void(Void),
    |     ^^^^^^^^^^
    |
    = note: `-W dead-code` implied by `-W unused`
-note: `Foo` has a derived impl for the trait `Debug`, but this is intentionally ignored during dead code analysis
-  --> $DIR/derive-uninhabited-enum-38885.rs:10:10
-   |
-LL | #[derive(Debug)]
-   |          ^^^^^
-   = note: this warning originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: `Foo` has a derived impl for the trait `Debug`, but this is intentionally ignored during dead code analysis
 
 warning: 1 warning emitted
 
index 67bb574315a72331ccffe78954b15eab4418a34e..031b8ce713eb4c9d3fd5e0b88bc296f032cc3905 100644 (file)
@@ -16,12 +16,7 @@ error: field is never read: `f`
 LL | struct B { f: () }
    |            ^^^^^
    |
-note: `B` has a derived impl for the trait `Clone`, but this is intentionally ignored during dead code analysis
-  --> $DIR/clone-debug-dead-code.rs:9:10
-   |
-LL | #[derive(Clone)]
-   |          ^^^^^
-   = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: `B` has a derived impl for the trait `Clone`, but this is intentionally ignored during dead code analysis
 
 error: field is never read: `f`
   --> $DIR/clone-debug-dead-code.rs:14:12
@@ -29,12 +24,7 @@ error: field is never read: `f`
 LL | struct C { f: () }
    |            ^^^^^
    |
-note: `C` has a derived impl for the trait `Debug`, but this is intentionally ignored during dead code analysis
-  --> $DIR/clone-debug-dead-code.rs:13:10
-   |
-LL | #[derive(Debug)]
-   |          ^^^^^
-   = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: `C` has a derived impl for the trait `Debug`, but this is intentionally ignored during dead code analysis
 
 error: field is never read: `f`
   --> $DIR/clone-debug-dead-code.rs:18:12
@@ -42,12 +32,7 @@ error: field is never read: `f`
 LL | struct D { f: () }
    |            ^^^^^
    |
-note: `D` has derived impls for the traits `Clone` and `Debug`, but these are intentionally ignored during dead code analysis
-  --> $DIR/clone-debug-dead-code.rs:17:10
-   |
-LL | #[derive(Debug,Clone)]
-   |          ^^^^^ ^^^^^
-   = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: `D` has derived impls for the traits `Clone` and `Debug`, but these are intentionally ignored during dead code analysis
 
 error: field is never read: `f`
   --> $DIR/clone-debug-dead-code.rs:21:12
index adec6c7a5c5a39114adb97815e6eccf0a36f72e7..6f0e4d55aeb0432f33146021b8a866cc3267cf6e 100644 (file)
@@ -1,7 +1,7 @@
 use std::fmt::Debug;
 
 #[derive(Debug)]
-pub struct Irrelevant<Irrelevant> { //~ ERROR type arguments are not allowed for this type
+pub struct Irrelevant<Irrelevant> { //~ ERROR type arguments are not allowed on type parameter
     irrelevant: Irrelevant,
 }
 
index eedd54f1e9f0c91dd71047c19c50837f241a7610..ac797a8f50152e0c4a8cab24419255d44c28504b 100644 (file)
@@ -1,11 +1,19 @@
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on type parameter `Irrelevant`
   --> $DIR/issue-97343.rs:4:23
    |
 LL | #[derive(Debug)]
-   |          ----- in this derive macro expansion
+   |          -----
+   |          |
+   |          not allowed on this
+   |          in this derive macro expansion
 LL | pub struct Irrelevant<Irrelevant> {
    |                       ^^^^^^^^^^ type argument not allowed
    |
+note: type parameter `Irrelevant` defined here
+  --> $DIR/issue-97343.rs:4:23
+   |
+LL | pub struct Irrelevant<Irrelevant> {
+   |                       ^^^^^^^^^^
    = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to previous error
index 23dad2c16b22c95fa286b29ac19c1b6508e48c7d..570bbac2b21f649d6d1df5ae37c123e786a2ba93 100644 (file)
@@ -6,6 +6,7 @@ LL |     produces_async! {}
    |
    = note: this error originates in the macro `produces_async` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: escape `async` to use it as an identifier
+  --> $DIR/auxiliary/edition-kw-macro-2018.rs:7:19
    |
 LL |     () => (pub fn r#async() {})
    |                   ++
index 67f9aa6041399b4ecf2a4afc33ecc487f849a171..69f275746bdc44be3db5b5552e5cd8e2c0759317 100644 (file)
@@ -6,6 +6,7 @@ LL |     produces_async! {}
    |
    = note: this error originates in the macro `produces_async` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: escape `async` to use it as an identifier
+  --> $DIR/auxiliary/edition-kw-macro-2018.rs:7:19
    |
 LL |     () => (pub fn r#async() {})
    |                   ++
index 54360c4f47b3e453bef19dd8480f1b11fed4e670..38cfd13b9b88e742a10453c06bb392d5e5c7a225 100644 (file)
@@ -2,7 +2,7 @@ error[E0322]: explicit impls for the `DiscriminantKind` trait are not permitted
   --> $DIR/forbidden-discriminant-kind-impl.rs:9:1
    |
 LL | impl DiscriminantKind for NewType {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of 'DiscriminantKind' not allowed
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `DiscriminantKind` not allowed
 
 error: aborting due to previous error
 
index 577e286fcc6cefec77937fe163e54353331b121a..e0e437e18ae8c6a4b9c93c9ce4a48501fbcd416a 100644 (file)
@@ -1,8 +1,16 @@
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
   --> $DIR/E0109.rs:1:14
    |
 LL | type X = u32<i32>;
-   |              ^^^ type argument not allowed
+   |          --- ^^^ type argument not allowed
+   |          |
+   |          not allowed on this
+   |
+help: primitive type `u32` doesn't have generic parameters
+   |
+LL - type X = u32<i32>;
+LL + type X = u32;
+   | 
 
 error: aborting due to previous error
 
index b0221318087384aa7d9f856489f6dc93fc6a3274..15e1b959193fae7cdd99407326d20d13af060134 100644 (file)
@@ -1,8 +1,16 @@
-error[E0109]: lifetime arguments are not allowed for this type
+error[E0109]: lifetime arguments are not allowed on this type
   --> $DIR/E0110.rs:1:14
    |
 LL | type X = u32<'static>;
-   |              ^^^^^^^ lifetime argument not allowed
+   |          --- ^^^^^^^ lifetime argument not allowed
+   |          |
+   |          not allowed on this
+   |
+help: primitive type `u32` doesn't have generic parameters
+   |
+LL - type X = u32<'static>;
+LL + type X = u32;
+   | 
 
 error: aborting due to previous error
 
index 4376437823cf674ede0a89f805f713925e2e0961..92917678e4c02697ac5990a9174838d28f0091b2 100644 (file)
@@ -1,5 +1,5 @@
 fn foo<'a, 'b, 'a>(x: &'a str, y: &'b str) {
-    //~^ ERROR E0263
+    //~^ ERROR E0403
 }
 
 fn main() {}
index 4dae02b85c36ca82f419080dc24e5e3e54a10a57..e3f9aea296a2c351664c8b824c03dd637fb242d8 100644 (file)
@@ -1,11 +1,11 @@
-error[E0263]: lifetime name `'a` declared twice in the same scope
+error[E0403]: the name `'a` is already used for a generic parameter in this item's generic parameters
   --> $DIR/E0263.rs:1:16
    |
 LL | fn foo<'a, 'b, 'a>(x: &'a str, y: &'b str) {
-   |        --      ^^ declared twice
+   |        --      ^^ already used
    |        |
-   |        previous declaration here
+   |        first use of `'a`
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0263`.
+For more information about this error, try `rustc --explain E0403`.
index 0f610a5e42f65060ad380ad2161ce35d80825e49..d01aa3617c764c1fe9f0c95b65a69bf689c59dc1 100644 (file)
@@ -2,7 +2,12 @@ error[E0282]: type annotations needed
   --> $DIR/E0282.rs:2:9
    |
 LL |     let x = "hello".chars().rev().collect();
-   |         ^ consider giving `x` a type
+   |         ^
+   |
+help: consider giving `x` an explicit type
+   |
+LL |     let x: _ = "hello".chars().rev().collect();
+   |          +++
 
 error: aborting due to previous error
 
index e2bab486064f0fa8c38a9f5a4ff4cd5ce28eb6b9..a107160d11a35bc25ab2adfa9bae60f54950a25e 100644 (file)
@@ -10,10 +10,7 @@ error[E0283]: type annotations needed
   --> $DIR/E0283.rs:35:24
    |
 LL |     let bar = foo_impl.into() * 1u32;
-   |               ---------^^^^--
-   |               |        |
-   |               |        cannot infer type for type parameter `T` declared on the trait `Into`
-   |               this method call resolves to `T`
+   |                        ^^^^
    |
 note: multiple `impl`s satisfying `Impl: Into<_>` found
   --> $DIR/E0283.rs:17:1
@@ -23,10 +20,10 @@ LL | impl Into<u32> for Impl {
    = note: and another `impl` found in the `core` crate:
            - impl<T, U> Into<U> for T
              where U: From<T>;
-help: use the fully qualified path for the potential candidate
+help: try using a fully qualified path to specify the expected types
    |
-LL |     let bar = <Impl as Into<u32>>::into(foo_impl) * 1u32;
-   |               ++++++++++++++++++++++++++        ~
+LL |     let bar = <Impl as Into<T>>::into(foo_impl) * 1u32;
+   |               ++++++++++++++++++++++++        ~
 
 error: aborting due to 2 previous errors
 
index 5c1dcb4d4f9b34a8984157b9c73eea45e283b9c8..de54a417253d406a36d29920a2f6346b1895b6ea 100644 (file)
@@ -6,7 +6,7 @@ LL | impl Eq for &dyn DynEq {}
    |
    = note: expected trait `<&dyn DynEq as PartialEq>`
               found trait `<&(dyn DynEq + 'static) as PartialEq>`
-note: the lifetime `'_` as defined here...
+note: the anonymous lifetime as defined here...
   --> $DIR/E0308-2.rs:9:13
    |
 LL | impl Eq for &dyn DynEq {}
index e58c9d3116a1c6af71b47ae788e1aaf43c63b37d..81715621dd921d07e061c56cb93b3266732e9ce2 100644 (file)
@@ -36,13 +36,12 @@ error[E0282]: type annotations needed
   --> $DIR/E0401.rs:11:5
    |
 LL |     bfnr(x);
-   |     ^^^^ cannot infer type for type parameter `U` declared on the function `bfnr`
+   |     ^^^^ cannot infer type of the type parameter `U` declared on the function `bfnr`
    |
-help: type parameter declared here
-  --> $DIR/E0401.rs:4:13
+help: consider specifying the generic arguments
    |
-LL |     fn bfnr<U, V: Baz<U>, W: Fn()>(y: T) {
-   |             ^
+LL |     bfnr::<U, V, W>(x);
+   |         +++++++++++
 
 error: aborting due to 4 previous errors
 
index afb031c2252343033751903a847bd37d079aa1d6..ed9536f164ef0ed51f67c677cf5538f3f8f90639 100644 (file)
@@ -3,6 +3,8 @@ error[E0432]: unresolved import `something`
    |
 LL | use something::Foo;
    |     ^^^^^^^^^ maybe a missing crate `something`?
+   |
+   = help: consider adding `extern crate something` to use the `something` crate
 
 error: aborting due to previous error
 
index 2f4c220ee9505d7b2978c4df5fd50f1ae2860b2a..3bae23a4aaa78e7e987d11d93d24ef6cd249a3ee 100644 (file)
@@ -3,12 +3,16 @@ error[E0432]: unresolved import `core`
    |
 LL | use core::default;
    |     ^^^^ maybe a missing crate `core`?
+   |
+   = help: consider adding `extern crate core` to use the `core` crate
 
 error[E0433]: failed to resolve: maybe a missing crate `core`?
   --> $DIR/feature-gate-extern_absolute_paths.rs:4:19
    |
 LL |     let _: u8 = ::core::default::Default();
    |                   ^^^^ maybe a missing crate `core`?
+   |
+   = help: consider adding `extern crate core` to use the `core` crate
 
 error: aborting due to 2 previous errors
 
index 5776c0b1e0c77c7403f1c5ca8c2c02774a679e64..ca9d71a7a8b667755682b7a73a83ec74eaf33061 100644 (file)
@@ -102,7 +102,7 @@ fn label_break_match(c: u8, xe: u8, ye: i8) {
             0 => break 'a 0,
             v if { if v % 2 == 0 { break 'a 1; }; v % 3 == 0 } => { x += 1; },
             v if { 'b: { break 'b v == 5; } } => { x = 41; },
-            _ => 'b: { //~ WARNING `'b` shadows a label
+            _ => 'b: {
                 break 'b ();
             },
         }
@@ -128,8 +128,8 @@ macro_rules! mac1 {
         0
     };
     assert_eq!(x, 0);
-    let x: u8 = 'a: { //~ WARNING `'a` shadows a label
-        'b: { //~ WARNING `'b` shadows a label
+    let x: u8 = 'a: {
+        'b: {
             if true {
                 mac1!('a, 1);
             }
diff --git a/src/test/ui/for-loop-while/label_break_value.stderr b/src/test/ui/for-loop-while/label_break_value.stderr
deleted file mode 100644 (file)
index b1eb320..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-warning: label name `'b` shadows a label name that is already in scope
-  --> $DIR/label_break_value.rs:105:18
-   |
-LL |             v if { 'b: { break 'b v == 5; } } => { x = 41; },
-   |                    -- first declared here
-LL |             _ => 'b: {
-   |                  ^^ label `'b` already in scope
-
-warning: label name `'a` shadows a label name that is already in scope
-  --> $DIR/label_break_value.rs:131:17
-   |
-LL |     let x: u8 = 'a: {
-   |                 -- first declared here
-...
-LL |     let x: u8 = 'a: {
-   |                 ^^ label `'a` already in scope
-
-warning: label name `'b` shadows a label name that is already in scope
-  --> $DIR/label_break_value.rs:132:9
-   |
-LL |         'b: {
-   |         -- first declared here
-...
-LL |         'b: {
-   |         ^^ label `'b` already in scope
-
-warning: 3 warnings emitted
-
index e603c8463b578ce6c2c942b5174f8cbdae2f4a79..149bf17b83cba808ffb0c67cf28186d3c1086450 100644 (file)
@@ -20,14 +20,11 @@ macro_rules! mac2 {
     macro_rules! mac3 {
         ($val:expr) => {
             'a: {
-            //~^ WARNING `'a` shadows a label
-            //~| WARNING `'a` shadows a label
-            //~| WARNING `'a` shadows a label
                 $val
             }
         };
     }
-    let x: u8 = mac3!('b: { //~ WARNING `'b` shadows a label
+    let x: u8 = mac3!('b: {
         if true {
             break 'a 3; //~ ERROR undeclared label `'a` [E0426]
         }
index 549b394e14b101e564d39214ce33d8368a01879b..7182b8f598f193de0a4f822ab1f37e95e72ea950 100644 (file)
@@ -10,7 +10,7 @@ LL |                 mac2!(2);
    = note: this error originates in the macro `mac2` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0426]: use of undeclared label `'a`
-  --> $DIR/label_break_value_invalid.rs:32:19
+  --> $DIR/label_break_value_invalid.rs:29:19
    |
 LL |     let x: u8 = mac3!('b: {
    |                       -- a label with a similar name is reachable
@@ -22,68 +22,11 @@ LL |             break 'a 3;
    |                   help: try using similarly named label: `'b`
 
 error[E0426]: use of undeclared label `'a`
-  --> $DIR/label_break_value_invalid.rs:37:29
+  --> $DIR/label_break_value_invalid.rs:34:29
    |
 LL |     let x: u8 = mac3!(break 'a 4);
    |                             ^^ undeclared label `'a`
 
-warning: label name `'a` shadows a label name that is already in scope
-  --> $DIR/label_break_value_invalid.rs:22:13
-   |
-LL |       let x: u8 = 'a: {
-   |                   -- first declared here
-...
-LL |               'a: {
-   |               ^^ label `'a` already in scope
-...
-LL |       let x: u8 = mac3!('b: {
-   |  _________________-
-LL | |         if true {
-LL | |             break 'a 3;
-LL | |         }
-LL | |         0
-LL | |     });
-   | |______- in this macro invocation
-   |
-   = note: this warning originates in the macro `mac3` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'b` shadows a label name that is already in scope
-  --> $DIR/label_break_value_invalid.rs:30:23
-   |
-LL |         'b: {
-   |         -- first declared here
-...
-LL |     let x: u8 = mac3!('b: {
-   |                       ^^ label `'b` already in scope
-
-warning: label name `'a` shadows a label name that is already in scope
-  --> $DIR/label_break_value_invalid.rs:22:13
-   |
-LL |     let x: u8 = 'a: {
-   |                 -- first declared here
-...
-LL |             'a: {
-   |             ^^ label `'a` already in scope
-...
-LL |     let x: u8 = mac3!(break 'a 4);
-   |                 ----------------- in this macro invocation
-   |
-   = note: this warning originates in the macro `mac3` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'a` shadows a label name that is already in scope
-  --> $DIR/label_break_value_invalid.rs:22:13
-   |
-LL |             'a: {
-   |             ^^
-   |             |
-   |             first declared here
-   |             label `'a` already in scope
-...
-LL |     let x: u8 = mac3!(break 'a 4);
-   |                 ----------------- in this macro invocation
-   |
-   = note: this warning originates in the macro `mac3` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to 3 previous errors; 4 warnings emitted
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0426`.
index 580b135ac2d712fdff96b5cc299c226f74f48c6b..b1b38f6b9194b1f12016ae4c3f2bb599e3453b63 100644 (file)
@@ -1,10 +1,13 @@
 error[E0282]: type annotations needed
-  --> $DIR/for-loop-unconstrained-element-type.rs:8:9
+  --> $DIR/for-loop-unconstrained-element-type.rs:8:14
    |
 LL |     for i in Vec::new() { }
-   |         ^    ---------- the element type for this iterator is not specified
-   |         |
-   |         cannot infer type
+   |              ^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `Vec`
+   |
+help: consider specifying the generic argument
+   |
+LL |     for i in Vec::<T>::new() { }
+   |                 +++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/generator/issue-87142.rs b/src/test/ui/generator/issue-87142.rs
new file mode 100644 (file)
index 0000000..fc10d04
--- /dev/null
@@ -0,0 +1,32 @@
+// compile-flags: -Cdebuginfo=2
+// build-pass
+
+// Regression test for #87142
+// This test needs the above flags and the "lib" crate type.
+
+#![feature(type_alias_impl_trait, generator_trait, generators)]
+#![crate_type = "lib"]
+
+use std::ops::Generator;
+
+pub trait GeneratorProviderAlt: Sized {
+    type Gen: Generator<(), Return = (), Yield = ()>;
+
+    fn start(ctx: Context<Self>) -> Self::Gen;
+}
+
+pub struct Context<G: 'static + GeneratorProviderAlt> {
+    pub link: Box<G::Gen>,
+}
+
+impl GeneratorProviderAlt for () {
+    type Gen = impl Generator<(), Return = (), Yield = ()>;
+    fn start(ctx: Context<Self>) -> Self::Gen {
+        move || {
+            match ctx {
+                _ => (),
+            }
+            yield ();
+        }
+    }
+}
index f01da8c61ed1d8d47cfd4c861b57ecbc13e08c29..c55b0530c9da89030b20455159b3c0765007a800 100644 (file)
@@ -10,4 +10,9 @@ fn foo<'a>(arg: Box<dyn X<Y('a) = &'a ()>>) {}
   //~| ERROR this associated type takes 0 generic arguments but 1 generic argument
   //~| ERROR this associated type takes 1 lifetime argument but 0 lifetime arguments
 
+
+fn bar<'a>(arg: Box<dyn X<Y() = ()>>) {}
+  //~^ ERROR: parenthesized generic arguments cannot be used
+  //~| ERROR this associated type takes 1 lifetime argument but 0 lifetime arguments
+
 fn main() {}
index 6014a02c4d96fb40f4e29cdbe325e0e8bd66b0c9..162214063e7d28851193fb38d220ec673bcfab84 100644 (file)
@@ -9,6 +9,19 @@ error: parenthesized generic arguments cannot be used in associated type constra
    |
 LL | fn foo<'a>(arg: Box<dyn X<Y('a) = &'a ()>>) {}
    |                           ^^^^^
+   |
+help: use angle brackets instead
+   |
+LL | fn foo<'a>(arg: Box<dyn X<Y<'a> = &'a ()>>) {}
+   |                            ~  ~
+
+error: parenthesized generic arguments cannot be used in associated type constraints
+  --> $DIR/gat-trait-path-parenthesised-args.rs:14:27
+   |
+LL | fn bar<'a>(arg: Box<dyn X<Y() = ()>>) {}
+   |                           ^--
+   |                            |
+   |                            help: remove these parentheses
 
 error[E0107]: this associated type takes 1 lifetime argument but 0 lifetime arguments were supplied
   --> $DIR/gat-trait-path-parenthesised-args.rs:7:27
@@ -40,6 +53,22 @@ note: associated type defined here, with 0 generic parameters
 LL |   type Y<'a>;
    |        ^
 
-error: aborting due to 4 previous errors
+error[E0107]: this associated type takes 1 lifetime argument but 0 lifetime arguments were supplied
+  --> $DIR/gat-trait-path-parenthesised-args.rs:14:27
+   |
+LL | fn bar<'a>(arg: Box<dyn X<Y() = ()>>) {}
+   |                           ^ expected 1 lifetime argument
+   |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/gat-trait-path-parenthesised-args.rs:4:8
+   |
+LL |   type Y<'a>;
+   |        ^ --
+help: add missing lifetime argument
+   |
+LL | fn bar<'a>(arg: Box<dyn X<Y('a) = ()>>) {}
+   |                             ++
+
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0107`.
index a9c465cdd7ea2eb999926995e6d1d43ccd7f8701..c2785fee387fa986d13220a9491f3a37b4af18a2 100644 (file)
@@ -2,7 +2,12 @@ error[E0282]: type annotations needed
   --> $DIR/issue-91762.rs:25:15
    |
 LL |         ret = <Self::Base as Functor>::fmap(arg);
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T` declared on the associated function `fmap`
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the associated function `fmap`
+   |
+help: consider specifying the generic arguments
+   |
+LL |         ret = <Self::Base as Functor>::fmap::<T, U>(arg);
+   |                                            ++++++++
 
 error: aborting due to previous error
 
index 1458bf0c4a49341147eb47f4bf57c7601c8e5199..76d39c88b61c3e38863642186da8178524577030 100644 (file)
@@ -8,7 +8,7 @@ LL |     type A = u32;
    |           ^ lifetimes do not match type in trait
 
 error[E0049]: type `B` has 1 type parameter but its trait declaration has 0 type parameters
-  --> $DIR/parameter_number_and_kind_impl.rs:17:12
+  --> $DIR/parameter_number_and_kind_impl.rs:17:16
    |
 LL |     type B<'a, 'b>;
    |            --  --
@@ -16,9 +16,7 @@ LL |     type B<'a, 'b>;
    |            expected 0 type parameters
 ...
 LL |     type B<'a, T> = Vec<T>;
-   |            ^^  ^
-   |            |
-   |            found 1 type parameter
+   |                ^ found 1 type parameter
 
 error[E0195]: lifetime parameters or bounds on type `C` do not match the trait declaration
   --> $DIR/parameter_number_and_kind_impl.rs:19:11
index 857757f8940dc41668d6f0de58e4376e7217dc46..be765920975b3703ae2ad55f073f42ebdc5d6801 100644 (file)
@@ -1,3 +1,19 @@
+error[E0496]: lifetime name `'a` shadows a lifetime name that is already in scope
+  --> $DIR/shadowing.rs:4:14
+   |
+LL | trait Shadow<'a> {
+   |              -- first declared here
+LL |     type Bar<'a>;
+   |              ^^ lifetime `'a` already in scope
+
+error[E0496]: lifetime name `'a` shadows a lifetime name that is already in scope
+  --> $DIR/shadowing.rs:13:14
+   |
+LL | impl<'a> NoShadow<'a> for &'a u32 {
+   |      -- first declared here
+LL |     type Bar<'a> = i32;
+   |              ^^ lifetime `'a` already in scope
+
 error[E0403]: the name `T` is already used for a generic parameter in this item's generic parameters
   --> $DIR/shadowing.rs:18:14
    |
@@ -14,22 +30,6 @@ LL | impl<T> NoShadowT<T> for Option<T> {
 LL |     type Bar<T> = i32;
    |              ^ already used
 
-error[E0496]: lifetime name `'a` shadows a lifetime name that is already in scope
-  --> $DIR/shadowing.rs:13:14
-   |
-LL | impl<'a> NoShadow<'a> for &'a u32 {
-   |      -- first declared here
-LL |     type Bar<'a> = i32;
-   |              ^^ lifetime `'a` already in scope
-
-error[E0496]: lifetime name `'a` shadows a lifetime name that is already in scope
-  --> $DIR/shadowing.rs:4:14
-   |
-LL | trait Shadow<'a> {
-   |              -- first declared here
-LL |     type Bar<'a>;
-   |              ^^ lifetime `'a` already in scope
-
 error: aborting due to 4 previous errors
 
 Some errors have detailed explanations: E0403, E0496.
index e7312b51dbcb8be2d664c84a25599cd6c5e0e284..8971fb62626cbfb99a4a635b4a9eb06c5d684724 100644 (file)
@@ -5,12 +5,12 @@
 
 #[rustc_macro_transparency = "semitransparent"]
 macro m($a:lifetime) {
-    fn g<$a, 'a>() {} //~ ERROR lifetime name `'a` declared twice
+    fn g<$a, 'a>() {} //~ ERROR the name `'a` is already used for a generic parameter
 }
 
 #[rustc_macro_transparency = "transparent"]
 macro n($a:lifetime) {
-    fn h<$a, 'a>() {} //~ ERROR lifetime name `'a` declared twice
+    fn h<$a, 'a>() {} //~ ERROR the name `'a` is already used for a generic parameter
 }
 
 m!('a);
index 4d41ebaa4373359c2ba8837f9bc4aa72974f1110..9f1a75147272dbb3a9c1c5625e7f015381422967 100644 (file)
@@ -1,31 +1,31 @@
-error[E0263]: lifetime name `'a` declared twice in the same scope
+error[E0403]: the name `'a` is already used for a generic parameter in this item's generic parameters
   --> $DIR/duplicate_lifetimes.rs:8:14
    |
 LL |     fn g<$a, 'a>() {}
-   |              ^^ declared twice
+   |              ^^ already used
 ...
 LL | m!('a);
    | ------
    | |  |
-   | |  previous declaration here
+   | |  first use of `'a`
    | in this macro invocation
    |
    = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0263]: lifetime name `'a` declared twice in the same scope
+error[E0403]: the name `'a` is already used for a generic parameter in this item's generic parameters
   --> $DIR/duplicate_lifetimes.rs:13:14
    |
 LL |     fn h<$a, 'a>() {}
-   |              ^^ declared twice
+   |              ^^ already used
 ...
 LL | n!('a);
    | ------
    | |  |
-   | |  previous declaration here
+   | |  first use of `'a`
    | in this macro invocation
    |
    = note: this error originates in the macro `n` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0263`.
+For more information about this error, try `rustc --explain E0403`.
index 491855d7becd153cd14b1051767942c9b96a6ee5..8cf66f31a0a1df988a64920a26ef70e0b3136f6b 100644 (file)
 macro_rules! loop_x {
     ($e: expr) => {
         // $e shouldn't be able to interact with this 'x
-        'x: loop { $e }
-        //~^ WARNING shadows a label name that is already in scope
-        //~| WARNING shadows a label name that is already in scope
-        //~| WARNING shadows a label name that is already in scope
-        //~| WARNING shadows a label name that is already in scope
-    }
+        'x: loop {
+            $e
+        }
+    };
 }
 
 macro_rules! while_true {
     ($e: expr) => {
         // $e shouldn't be able to interact with this 'x
-        'x: while 1 + 1 == 2 { $e }
-        //~^ WARNING shadows a label name that is already in scope
-        //~| WARNING shadows a label name that is already in scope
-        //~| WARNING shadows a label name that is already in scope
-        //~| WARNING shadows a label name that is already in scope
-        //~| WARNING shadows a label name that is already in scope
-    }
+        'x: while 1 + 1 == 2 {
+            $e
+        }
+    };
 }
 
 macro_rules! run_once {
     ($e: expr) => {
         // ditto
-        'x: for _ in 0..1 { $e }
-        //~^ WARNING shadows a label name that is already in scope
-        //~| WARNING shadows a label name that is already in scope
-        //~| WARNING shadows a label name that is already in scope
-        //~| WARNING shadows a label name that is already in scope
-        //~| WARNING shadows a label name that is already in scope
-        //~| WARNING shadows a label name that is already in scope
-        //~| WARNING shadows a label name that is already in scope
-    }
+        'x: for _ in 0..1 {
+            $e
+        }
+    };
 }
 
 pub fn main() {
@@ -62,8 +52,6 @@ pub fn main() {
 
     let k: isize = {
         'x: for _ in 0..1 {
-            //~^ WARNING shadows a label name that is already in scope
-            //~| WARNING shadows a label name that is already in scope
             // ditto
             loop_x!(break 'x);
             i += 1;
@@ -74,10 +62,6 @@ pub fn main() {
 
     let l: isize = {
         'x: for _ in 0..1 {
-            //~^ WARNING shadows a label name that is already in scope
-            //~| WARNING shadows a label name that is already in scope
-            //~| WARNING shadows a label name that is already in scope
-            //~| WARNING shadows a label name that is already in scope
             // ditto
             while_true!(break 'x);
             i += 1;
@@ -88,12 +72,6 @@ pub fn main() {
 
     let n: isize = {
         'x: for _ in 0..1 {
-            //~^ WARNING shadows a label name that is already in scope
-            //~| WARNING shadows a label name that is already in scope
-            //~| WARNING shadows a label name that is already in scope
-            //~| WARNING shadows a label name that is already in scope
-            //~| WARNING shadows a label name that is already in scope
-            //~| WARNING shadows a label name that is already in scope
             // ditto
             run_once!(continue 'x);
             i += 1;
diff --git a/src/test/ui/hygiene/hygienic-labels-in-let.stderr b/src/test/ui/hygiene/hygienic-labels-in-let.stderr
deleted file mode 100644 (file)
index 519e3c0..0000000
+++ /dev/null
@@ -1,334 +0,0 @@
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels-in-let.rs:16:9
-   |
-LL |         'x: loop { $e }
-   |         ^^ label `'x` already in scope
-...
-LL |         'x: loop {
-   |         -- first declared here
-LL |             // this 'x should refer to the outer loop, lexically
-LL |             loop_x!(break 'x);
-   |             ----------------- in this macro invocation
-   |
-   = note: this warning originates in the macro `loop_x` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels-in-let.rs:64:9
-   |
-LL |         'x: loop {
-   |         -- first declared here
-...
-LL |         'x: for _ in 0..1 {
-   |         ^^ label `'x` already in scope
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels-in-let.rs:64:9
-   |
-LL |         'x: loop { $e }
-   |         -- first declared here
-...
-LL |         'x: for _ in 0..1 {
-   |         ^^ label `'x` already in scope
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels-in-let.rs:16:9
-   |
-LL |         'x: loop { $e }
-   |         ^^ label `'x` already in scope
-...
-LL |         'x: loop {
-   |         -- first declared here
-...
-LL |             loop_x!(break 'x);
-   |             ----------------- in this macro invocation
-   |
-   = note: this warning originates in the macro `loop_x` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels-in-let.rs:16:9
-   |
-LL |         'x: loop { $e }
-   |         ^^
-   |         |
-   |         first declared here
-   |         label `'x` already in scope
-...
-LL |             loop_x!(break 'x);
-   |             ----------------- in this macro invocation
-   |
-   = note: this warning originates in the macro `loop_x` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels-in-let.rs:16:9
-   |
-LL |         'x: loop { $e }
-   |         ^^ label `'x` already in scope
-...
-LL |         'x: for _ in 0..1 {
-   |         -- first declared here
-...
-LL |             loop_x!(break 'x);
-   |             ----------------- in this macro invocation
-   |
-   = note: this warning originates in the macro `loop_x` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels-in-let.rs:76:9
-   |
-LL |         'x: loop {
-   |         -- first declared here
-...
-LL |         'x: for _ in 0..1 {
-   |         ^^ label `'x` already in scope
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels-in-let.rs:76:9
-   |
-LL |         'x: loop { $e }
-   |         -- first declared here
-...
-LL |         'x: for _ in 0..1 {
-   |         ^^ label `'x` already in scope
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels-in-let.rs:76:9
-   |
-LL |         'x: for _ in 0..1 {
-   |         -- first declared here
-...
-LL |         'x: for _ in 0..1 {
-   |         ^^ label `'x` already in scope
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels-in-let.rs:76:9
-   |
-LL |         'x: loop { $e }
-   |         -- first declared here
-...
-LL |         'x: for _ in 0..1 {
-   |         ^^ label `'x` already in scope
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels-in-let.rs:27:9
-   |
-LL |         'x: while 1 + 1 == 2 { $e }
-   |         ^^ label `'x` already in scope
-...
-LL |         'x: loop {
-   |         -- first declared here
-...
-LL |             while_true!(break 'x);
-   |             --------------------- in this macro invocation
-   |
-   = note: this warning originates in the macro `while_true` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels-in-let.rs:27:9
-   |
-LL |         'x: loop { $e }
-   |         -- first declared here
-...
-LL |         'x: while 1 + 1 == 2 { $e }
-   |         ^^ label `'x` already in scope
-...
-LL |             while_true!(break 'x);
-   |             --------------------- in this macro invocation
-   |
-   = note: this warning originates in the macro `while_true` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels-in-let.rs:27:9
-   |
-LL |         'x: while 1 + 1 == 2 { $e }
-   |         ^^ label `'x` already in scope
-...
-LL |         'x: for _ in 0..1 {
-   |         -- first declared here
-...
-LL |             while_true!(break 'x);
-   |             --------------------- in this macro invocation
-   |
-   = note: this warning originates in the macro `while_true` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels-in-let.rs:27:9
-   |
-LL |         'x: loop { $e }
-   |         -- first declared here
-...
-LL |         'x: while 1 + 1 == 2 { $e }
-   |         ^^ label `'x` already in scope
-...
-LL |             while_true!(break 'x);
-   |             --------------------- in this macro invocation
-   |
-   = note: this warning originates in the macro `while_true` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels-in-let.rs:27:9
-   |
-LL |         'x: while 1 + 1 == 2 { $e }
-   |         ^^ label `'x` already in scope
-...
-LL |         'x: for _ in 0..1 {
-   |         -- first declared here
-...
-LL |             while_true!(break 'x);
-   |             --------------------- in this macro invocation
-   |
-   = note: this warning originates in the macro `while_true` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels-in-let.rs:90:9
-   |
-LL |         'x: loop {
-   |         -- first declared here
-...
-LL |         'x: for _ in 0..1 {
-   |         ^^ label `'x` already in scope
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels-in-let.rs:90:9
-   |
-LL |         'x: loop { $e }
-   |         -- first declared here
-...
-LL |         'x: for _ in 0..1 {
-   |         ^^ label `'x` already in scope
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels-in-let.rs:90:9
-   |
-LL |         'x: for _ in 0..1 {
-   |         -- first declared here
-...
-LL |         'x: for _ in 0..1 {
-   |         ^^ label `'x` already in scope
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels-in-let.rs:90:9
-   |
-LL |         'x: loop { $e }
-   |         -- first declared here
-...
-LL |         'x: for _ in 0..1 {
-   |         ^^ label `'x` already in scope
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels-in-let.rs:90:9
-   |
-LL |         'x: for _ in 0..1 {
-   |         -- first declared here
-...
-LL |         'x: for _ in 0..1 {
-   |         ^^ label `'x` already in scope
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels-in-let.rs:90:9
-   |
-LL |         'x: while 1 + 1 == 2 { $e }
-   |         -- first declared here
-...
-LL |         'x: for _ in 0..1 {
-   |         ^^ label `'x` already in scope
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels-in-let.rs:39:9
-   |
-LL |         'x: for _ in 0..1 { $e }
-   |         ^^ label `'x` already in scope
-...
-LL |         'x: loop {
-   |         -- first declared here
-...
-LL |             run_once!(continue 'x);
-   |             ---------------------- in this macro invocation
-   |
-   = note: this warning originates in the macro `run_once` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels-in-let.rs:39:9
-   |
-LL |         'x: loop { $e }
-   |         -- first declared here
-...
-LL |         'x: for _ in 0..1 { $e }
-   |         ^^ label `'x` already in scope
-...
-LL |             run_once!(continue 'x);
-   |             ---------------------- in this macro invocation
-   |
-   = note: this warning originates in the macro `run_once` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels-in-let.rs:39:9
-   |
-LL |         'x: for _ in 0..1 { $e }
-   |         ^^ label `'x` already in scope
-...
-LL |         'x: for _ in 0..1 {
-   |         -- first declared here
-...
-LL |             run_once!(continue 'x);
-   |             ---------------------- in this macro invocation
-   |
-   = note: this warning originates in the macro `run_once` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels-in-let.rs:39:9
-   |
-LL |         'x: loop { $e }
-   |         -- first declared here
-...
-LL |         'x: for _ in 0..1 { $e }
-   |         ^^ label `'x` already in scope
-...
-LL |             run_once!(continue 'x);
-   |             ---------------------- in this macro invocation
-   |
-   = note: this warning originates in the macro `run_once` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels-in-let.rs:39:9
-   |
-LL |         'x: for _ in 0..1 { $e }
-   |         ^^ label `'x` already in scope
-...
-LL |         'x: for _ in 0..1 {
-   |         -- first declared here
-...
-LL |             run_once!(continue 'x);
-   |             ---------------------- in this macro invocation
-   |
-   = note: this warning originates in the macro `run_once` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels-in-let.rs:39:9
-   |
-LL |         'x: while 1 + 1 == 2 { $e }
-   |         -- first declared here
-...
-LL |         'x: for _ in 0..1 { $e }
-   |         ^^ label `'x` already in scope
-...
-LL |             run_once!(continue 'x);
-   |             ---------------------- in this macro invocation
-   |
-   = note: this warning originates in the macro `run_once` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels-in-let.rs:39:9
-   |
-LL |         'x: for _ in 0..1 { $e }
-   |         ^^ label `'x` already in scope
-...
-LL |         'x: for _ in 0..1 {
-   |         -- first declared here
-...
-LL |             run_once!(continue 'x);
-   |             ---------------------- in this macro invocation
-   |
-   = note: this warning originates in the macro `run_once` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: 28 warnings emitted
-
index c9f494b68b4a812a5e73599bfec24b70a2127d7f..6a7d81f045bfc587f40e0e191cd748ea199b9e1b 100644 (file)
 macro_rules! loop_x {
     ($e: expr) => {
         // $e shouldn't be able to interact with this 'x
-        'x: loop { $e }
-        //~^ WARNING shadows a label name that is already in scope
-        //~| WARNING shadows a label name that is already in scope
-        //~| WARNING shadows a label name that is already in scope
-        //~| WARNING shadows a label name that is already in scope
-    }
+        'x: loop {
+            $e
+        }
+    };
 }
 
 macro_rules! run_once {
     ($e: expr) => {
         // ditto
-        'x: for _ in 0..1 { $e }
-        //~^ WARNING shadows a label name that is already in scope
-        //~| WARNING shadows a label name that is already in scope
-        //~| WARNING shadows a label name that is already in scope
-        //~| WARNING shadows a label name that is already in scope
-        //~| WARNING shadows a label name that is already in scope
-        //~| WARNING shadows a label name that is already in scope
-        //~| WARNING shadows a label name that is already in scope
-    }
+        'x: for _ in 0..1 {
+            $e
+        }
+    };
 }
 
 macro_rules! while_x {
     ($e: expr) => {
         // ditto
-        'x: while 1 + 1 == 2 { $e }
-        //~^ WARNING shadows a label name that is already in scope
-        //~| WARNING shadows a label name that is already in scope
-        //~| WARNING shadows a label name that is already in scope
-        //~| WARNING shadows a label name that is already in scope
-        //~| WARNING shadows a label name that is already in scope
-    }
+        'x: while 1 + 1 == 2 {
+            $e
+        }
+    };
 }
 
 pub fn main() {
@@ -52,32 +42,17 @@ pub fn main() {
     }
 
     'x: loop {
-        //~^ WARNING shadows a label name that is already in scope
-        //~| WARNING shadows a label name that is already in scope
-
         // ditto
         loop_x!(break 'x);
         panic!("break doesn't act hygienically inside infinite loop");
     }
 
     'x: while 1 + 1 == 2 {
-        //~^ WARNING shadows a label name that is already in scope
-        //~| WARNING shadows a label name that is already in scope
-        //~| WARNING shadows a label name that is already in scope
-        //~| WARNING shadows a label name that is already in scope
-
         while_x!(break 'x);
         panic!("break doesn't act hygienically inside infinite while loop");
     }
 
     'x: for _ in 0..1 {
-        //~^ WARNING shadows a label name that is already in scope
-        //~| WARNING shadows a label name that is already in scope
-        //~| WARNING shadows a label name that is already in scope
-        //~| WARNING shadows a label name that is already in scope
-        //~| WARNING shadows a label name that is already in scope
-        //~| WARNING shadows a label name that is already in scope
-
         // ditto
         run_once!(continue 'x);
         panic!("continue doesn't act hygienically inside for loop");
diff --git a/src/test/ui/hygiene/hygienic-labels.stderr b/src/test/ui/hygiene/hygienic-labels.stderr
deleted file mode 100644 (file)
index f0b891f..0000000
+++ /dev/null
@@ -1,334 +0,0 @@
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels.rs:13:9
-   |
-LL |         'x: loop { $e }
-   |         ^^ label `'x` already in scope
-...
-LL |     'x: for _ in 0..1 {
-   |     -- first declared here
-LL |         // this 'x should refer to the outer loop, lexically
-LL |         loop_x!(break 'x);
-   |         ----------------- in this macro invocation
-   |
-   = note: this warning originates in the macro `loop_x` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels.rs:54:5
-   |
-LL |     'x: for _ in 0..1 {
-   |     -- first declared here
-...
-LL |     'x: loop {
-   |     ^^ label `'x` already in scope
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels.rs:54:5
-   |
-LL |         'x: loop { $e }
-   |         -- first declared here
-...
-LL |     'x: loop {
-   |     ^^ label `'x` already in scope
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels.rs:13:9
-   |
-LL |         'x: loop { $e }
-   |         ^^ label `'x` already in scope
-...
-LL |     'x: for _ in 0..1 {
-   |     -- first declared here
-...
-LL |         loop_x!(break 'x);
-   |         ----------------- in this macro invocation
-   |
-   = note: this warning originates in the macro `loop_x` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels.rs:13:9
-   |
-LL |         'x: loop { $e }
-   |         ^^
-   |         |
-   |         first declared here
-   |         label `'x` already in scope
-...
-LL |         loop_x!(break 'x);
-   |         ----------------- in this macro invocation
-   |
-   = note: this warning originates in the macro `loop_x` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels.rs:13:9
-   |
-LL |         'x: loop { $e }
-   |         ^^ label `'x` already in scope
-...
-LL |     'x: loop {
-   |     -- first declared here
-...
-LL |         loop_x!(break 'x);
-   |         ----------------- in this macro invocation
-   |
-   = note: this warning originates in the macro `loop_x` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels.rs:63:5
-   |
-LL |     'x: for _ in 0..1 {
-   |     -- first declared here
-...
-LL |     'x: while 1 + 1 == 2 {
-   |     ^^ label `'x` already in scope
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels.rs:63:5
-   |
-LL |         'x: loop { $e }
-   |         -- first declared here
-...
-LL |     'x: while 1 + 1 == 2 {
-   |     ^^ label `'x` already in scope
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels.rs:63:5
-   |
-LL |     'x: loop {
-   |     -- first declared here
-...
-LL |     'x: while 1 + 1 == 2 {
-   |     ^^ label `'x` already in scope
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels.rs:63:5
-   |
-LL |         'x: loop { $e }
-   |         -- first declared here
-...
-LL |     'x: while 1 + 1 == 2 {
-   |     ^^ label `'x` already in scope
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels.rs:38:9
-   |
-LL |         'x: while 1 + 1 == 2 { $e }
-   |         ^^ label `'x` already in scope
-...
-LL |     'x: for _ in 0..1 {
-   |     -- first declared here
-...
-LL |         while_x!(break 'x);
-   |         ------------------ in this macro invocation
-   |
-   = note: this warning originates in the macro `while_x` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels.rs:38:9
-   |
-LL |         'x: loop { $e }
-   |         -- first declared here
-...
-LL |         'x: while 1 + 1 == 2 { $e }
-   |         ^^ label `'x` already in scope
-...
-LL |         while_x!(break 'x);
-   |         ------------------ in this macro invocation
-   |
-   = note: this warning originates in the macro `while_x` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels.rs:38:9
-   |
-LL |         'x: while 1 + 1 == 2 { $e }
-   |         ^^ label `'x` already in scope
-...
-LL |     'x: loop {
-   |     -- first declared here
-...
-LL |         while_x!(break 'x);
-   |         ------------------ in this macro invocation
-   |
-   = note: this warning originates in the macro `while_x` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels.rs:38:9
-   |
-LL |         'x: loop { $e }
-   |         -- first declared here
-...
-LL |         'x: while 1 + 1 == 2 { $e }
-   |         ^^ label `'x` already in scope
-...
-LL |         while_x!(break 'x);
-   |         ------------------ in this macro invocation
-   |
-   = note: this warning originates in the macro `while_x` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels.rs:38:9
-   |
-LL |         'x: while 1 + 1 == 2 { $e }
-   |         ^^ label `'x` already in scope
-...
-LL |     'x: while 1 + 1 == 2 {
-   |     -- first declared here
-...
-LL |         while_x!(break 'x);
-   |         ------------------ in this macro invocation
-   |
-   = note: this warning originates in the macro `while_x` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels.rs:73:5
-   |
-LL |     'x: for _ in 0..1 {
-   |     -- first declared here
-...
-LL |     'x: for _ in 0..1 {
-   |     ^^ label `'x` already in scope
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels.rs:73:5
-   |
-LL |         'x: loop { $e }
-   |         -- first declared here
-...
-LL |     'x: for _ in 0..1 {
-   |     ^^ label `'x` already in scope
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels.rs:73:5
-   |
-LL |     'x: loop {
-   |     -- first declared here
-...
-LL |     'x: for _ in 0..1 {
-   |     ^^ label `'x` already in scope
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels.rs:73:5
-   |
-LL |         'x: loop { $e }
-   |         -- first declared here
-...
-LL |     'x: for _ in 0..1 {
-   |     ^^ label `'x` already in scope
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels.rs:73:5
-   |
-LL |     'x: while 1 + 1 == 2 {
-   |     -- first declared here
-...
-LL |     'x: for _ in 0..1 {
-   |     ^^ label `'x` already in scope
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels.rs:73:5
-   |
-LL |         'x: while 1 + 1 == 2 { $e }
-   |         -- first declared here
-...
-LL |     'x: for _ in 0..1 {
-   |     ^^ label `'x` already in scope
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels.rs:24:9
-   |
-LL |         'x: for _ in 0..1 { $e }
-   |         ^^ label `'x` already in scope
-...
-LL |     'x: for _ in 0..1 {
-   |     -- first declared here
-...
-LL |         run_once!(continue 'x);
-   |         ---------------------- in this macro invocation
-   |
-   = note: this warning originates in the macro `run_once` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels.rs:24:9
-   |
-LL |         'x: loop { $e }
-   |         -- first declared here
-...
-LL |         'x: for _ in 0..1 { $e }
-   |         ^^ label `'x` already in scope
-...
-LL |         run_once!(continue 'x);
-   |         ---------------------- in this macro invocation
-   |
-   = note: this warning originates in the macro `run_once` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels.rs:24:9
-   |
-LL |         'x: for _ in 0..1 { $e }
-   |         ^^ label `'x` already in scope
-...
-LL |     'x: loop {
-   |     -- first declared here
-...
-LL |         run_once!(continue 'x);
-   |         ---------------------- in this macro invocation
-   |
-   = note: this warning originates in the macro `run_once` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels.rs:24:9
-   |
-LL |         'x: loop { $e }
-   |         -- first declared here
-...
-LL |         'x: for _ in 0..1 { $e }
-   |         ^^ label `'x` already in scope
-...
-LL |         run_once!(continue 'x);
-   |         ---------------------- in this macro invocation
-   |
-   = note: this warning originates in the macro `run_once` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels.rs:24:9
-   |
-LL |         'x: for _ in 0..1 { $e }
-   |         ^^ label `'x` already in scope
-...
-LL |     'x: while 1 + 1 == 2 {
-   |     -- first declared here
-...
-LL |         run_once!(continue 'x);
-   |         ---------------------- in this macro invocation
-   |
-   = note: this warning originates in the macro `run_once` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels.rs:24:9
-   |
-LL |         'x: for _ in 0..1 { $e }
-   |         ^^ label `'x` already in scope
-...
-LL |         'x: while 1 + 1 == 2 { $e }
-   |         -- first declared here
-...
-LL |         run_once!(continue 'x);
-   |         ---------------------- in this macro invocation
-   |
-   = note: this warning originates in the macro `run_once` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
-  --> $DIR/hygienic-labels.rs:24:9
-   |
-LL |         'x: for _ in 0..1 { $e }
-   |         ^^ label `'x` already in scope
-...
-LL |     'x: for _ in 0..1 {
-   |     -- first declared here
-...
-LL |         run_once!(continue 'x);
-   |         ---------------------- in this macro invocation
-   |
-   = note: this warning originates in the macro `run_once` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: 28 warnings emitted
-
index a7428f9bf129fa859e344d4c7960d618ff6f0c4e..d881af9ed8fe13c655fed5ecff9544c72fbb4bf1 100644 (file)
@@ -29,17 +29,17 @@ fn baa(b: bool) -> impl std::fmt::Debug {
 }
 
 fn muh() -> Result<(), impl std::fmt::Debug> {
-    Err("whoops")?; //~^ ERROR type annotations needed
-    Ok(())
+    Err("whoops")?;
+    Ok(()) //~ ERROR type annotations needed
 }
 
 fn muh2() -> Result<(), impl std::fmt::Debug> {
-    return Err(From::from("foo")); //~^ ERROR type annotations needed
+    return Err(From::from("foo")); //~ ERROR type annotations needed
     Ok(())
 }
 
 fn muh3() -> Result<(), impl std::fmt::Debug> {
-    Err(From::from("foo")) //~^ ERROR type annotations needed
+    Err(From::from("foo")) //~ ERROR type annotations needed
 }
 
 fn main() {}
index 5209d7a5743498831e20266c9cd4ae8d14164504..1ff777e65037c11b9872c7ded5cee41a4033637d 100644 (file)
@@ -1,20 +1,35 @@
 error[E0282]: type annotations needed
-  --> $DIR/cross-return-site-inference.rs:31:24
+  --> $DIR/cross-return-site-inference.rs:33:5
    |
-LL | fn muh() -> Result<(), impl std::fmt::Debug> {
-   |                        ^^^^^^^^^^^^^^^^^^^^ cannot infer type
+LL |     Ok(())
+   |     ^^ cannot infer type of the type parameter `E` declared on the enum `Result`
+   |
+help: consider specifying the generic arguments
+   |
+LL |     Ok::<(), E>(())
+   |       +++++++++
 
 error[E0282]: type annotations needed
-  --> $DIR/cross-return-site-inference.rs:36:25
+  --> $DIR/cross-return-site-inference.rs:37:12
+   |
+LL |     return Err(From::from("foo"));
+   |            ^^^ cannot infer type of the type parameter `E` declared on the enum `Result`
    |
-LL | fn muh2() -> Result<(), impl std::fmt::Debug> {
-   |                         ^^^^^^^^^^^^^^^^^^^^ cannot infer type
+help: consider specifying the generic arguments
+   |
+LL |     return Err::<(), E>(From::from("foo"));
+   |               +++++++++
 
 error[E0282]: type annotations needed
-  --> $DIR/cross-return-site-inference.rs:41:25
+  --> $DIR/cross-return-site-inference.rs:42:5
+   |
+LL |     Err(From::from("foo"))
+   |     ^^^ cannot infer type of the type parameter `E` declared on the enum `Result`
+   |
+help: consider specifying the generic arguments
    |
-LL | fn muh3() -> Result<(), impl std::fmt::Debug> {
-   |                         ^^^^^^^^^^^^^^^^^^^^ cannot infer type
+LL |     Err::<(), E>(From::from("foo"))
+   |        +++++++++
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/impl-trait/diagnostics/fully-qualified-path-impl-trait.rs b/src/test/ui/impl-trait/diagnostics/fully-qualified-path-impl-trait.rs
new file mode 100644 (file)
index 0000000..3a47710
--- /dev/null
@@ -0,0 +1,15 @@
+trait Foo<T> {
+    fn foo(self, f: impl FnOnce());
+}
+
+impl<T> Foo<T> for () {
+    fn foo(self, f: impl FnOnce()) {
+        f()
+    }
+}
+
+fn main() {
+    // FIXME: This should ideally use a fully qualified path
+    // without mentioning the generic arguments of `foo`.
+    ().foo(|| ()) //~ ERROR type annotations needed
+}
diff --git a/src/test/ui/impl-trait/diagnostics/fully-qualified-path-impl-trait.stderr b/src/test/ui/impl-trait/diagnostics/fully-qualified-path-impl-trait.stderr
new file mode 100644 (file)
index 0000000..a1a629b
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0282]: type annotations needed
+  --> $DIR/fully-qualified-path-impl-trait.rs:14:8
+   |
+LL |     ().foo(|| ())
+   |        ^^^ cannot infer type for type parameter `T` declared on the trait `Foo`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
index 001f9ee48775847377ed7575cfeea2a70087dda3..98f0bd1af2813174a9a2055499adffc91c089249 100644 (file)
@@ -1,7 +1,7 @@
 use std::marker::PhantomData;
 
 fn weird() -> PhantomData<impl Sized> {
-    PhantomData //~^ ERROR type annotations needed
+    PhantomData //~ ERROR type annotations needed
 }
 
 fn main() {}
index b637ca694c203e09efd782dc8014f9c7cf8ba380..4ac3c238fe95897e4c30ac43f8f4b242c12b0786 100644 (file)
@@ -1,8 +1,13 @@
 error[E0282]: type annotations needed
-  --> $DIR/fallback_inference.rs:3:27
+  --> $DIR/fallback_inference.rs:4:5
    |
-LL | fn weird() -> PhantomData<impl Sized> {
-   |                           ^^^^^^^^^^ cannot infer type
+LL |     PhantomData
+   |     ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `PhantomData`
+   |
+help: consider specifying the generic argument
+   |
+LL |     PhantomData::<T>
+   |                +++++
 
 error: aborting due to previous error
 
index 7876add5aa6cb8392149ba922a1d1e280dc341f5..970d84120e07e89187999c4da5769a9c659ee2c8 100644 (file)
@@ -5,8 +5,8 @@
 #![feature(type_alias_impl_trait)]
 
 fn reify_as() -> Thunk<impl FnOnce(Continuation) -> Continuation> {
-    Thunk::new(|mut cont| { //~ ERROR type annotations needed
-        cont.reify_as();
+    Thunk::new(|mut cont| {
+        cont.reify_as(); //~ ERROR type annotations needed
         cont
     })
 }
@@ -14,8 +14,8 @@ fn reify_as() -> Thunk<impl FnOnce(Continuation) -> Continuation> {
 type Tait = impl FnOnce(Continuation) -> Continuation;
 
 fn reify_as_tait() -> Thunk<Tait> {
-    Thunk::new(|mut cont| { //~ ERROR type annotations needed
-        cont.reify_as();
+    Thunk::new(|mut cont| {
+        cont.reify_as(); //~ ERROR type annotations needed
         cont
     })
 }
index dcf1982312f294616b2f3198646ef20595b45c68..11ba5aa7867fe0e42fe559f2d186f96677cdc1d4 100644 (file)
@@ -1,16 +1,16 @@
 error[E0282]: type annotations needed
-  --> $DIR/hidden-type-is-opaque-2.rs:8:17
+  --> $DIR/hidden-type-is-opaque-2.rs:9:9
    |
-LL |     Thunk::new(|mut cont| {
-   |                 ^^^^^^^^ consider giving this closure parameter a type
+LL |         cont.reify_as();
+   |         ^^^^ cannot infer type
    |
    = note: type must be known at this point
 
 error[E0282]: type annotations needed
-  --> $DIR/hidden-type-is-opaque-2.rs:17:17
+  --> $DIR/hidden-type-is-opaque-2.rs:18:9
    |
-LL |     Thunk::new(|mut cont| {
-   |                 ^^^^^^^^ consider giving this closure parameter a type
+LL |         cont.reify_as();
+   |         ^^^^ cannot infer type
    |
    = note: type must be known at this point
 
diff --git a/src/test/ui/impl-trait/issue-54966.rs b/src/test/ui/impl-trait/issue-54966.rs
new file mode 100644 (file)
index 0000000..0ed3c4b
--- /dev/null
@@ -0,0 +1,6 @@
+// issue-54966: ICE returning an unknown type with impl FnMut
+
+fn generate_duration() -> Oper<impl FnMut()> {}
+//~^ ERROR cannot find type `Oper` in this scope
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/issue-54966.stderr b/src/test/ui/impl-trait/issue-54966.stderr
new file mode 100644 (file)
index 0000000..aa9a61c
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0412]: cannot find type `Oper` in this scope
+  --> $DIR/issue-54966.rs:3:27
+   |
+LL | fn generate_duration() -> Oper<impl FnMut()> {}
+   |                           ^^^^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0412`.
index 36047d23fedda6f182aec29649c3bcf9da3b3bc8..3c39aa6ce5bb953c98034b29eb964e69d9d46a6c 100644 (file)
@@ -2,7 +2,12 @@ error[E0282]: type annotations needed for `RaceBuilder<T, Never<T>>`
   --> $DIR/issue-84073.rs:32:16
    |
 LL |     Race::new(|race| race.when());
-   |                ^^^^ consider giving this closure parameter the explicit type `RaceBuilder<T, Never<T>>`, where the type parameter `T` is specified
+   |                ^^^^
+   |
+help: consider giving this closure parameter an explicit type, where the type for type parameter `T` is specified
+   |
+LL |     Race::new(|race: RaceBuilder<T, Never<T>>| race.when());
+   |                    ++++++++++++++++++++++++++
 
 error: aborting due to previous error
 
index e2abf71c110b906b4a5bd89972c53be6ada271eb..09047cdcbe15ca5f8d0b211bfc0075ed8b51d203 100644 (file)
@@ -16,7 +16,12 @@ error[E0282]: type annotations needed
   --> $DIR/issue-86719.rs:9:10
    |
 LL |         |_| true
-   |          ^ consider giving this closure parameter a type
+   |          ^
+   |
+help: consider giving this closure parameter an explicit type
+   |
+LL |         |_: _| true
+   |           +++
 
 error: aborting due to 3 previous errors
 
index c4fc49225e9a00daf5ce0a64d5a0ebca7d1e5b32..e8575b76b0930c3c8499054ad3335d51cf5c43b6 100644 (file)
@@ -18,7 +18,12 @@ error[E0282]: type annotations needed
   --> $DIR/issue-92305.rs:7:5
    |
 LL |     iter::empty()
-   |     ^^^^^^^^^^^ cannot infer type for type parameter `T` declared on the function `empty`
+   |     ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty`
+   |
+help: consider specifying the generic argument
+   |
+LL |     iter::empty::<T>()
+   |                +++++
 
 error[E0282]: type annotations needed
   --> $DIR/issue-92305.rs:10:35
index 7bb413be59ff3666cab5df8873a73181bbc96b10..ca75c9c18bd280811c72d131934603b8392da5f3 100644 (file)
@@ -3,6 +3,8 @@ error[E0432]: unresolved import `main`
    |
 LL | use main::bar;
    |     ^^^^ maybe a missing crate `main`?
+   |
+   = help: consider adding `extern crate main` to use the `main` crate
 
 error: aborting due to previous error
 
index a76fd30991493249b5829e96a5a682fa2df71e45..019ef9ad56a1f87f626c0f90b06e5ab90f1f9410 100644 (file)
@@ -3,6 +3,8 @@ error[E0432]: unresolved import `unresolved`
    |
 LL | use unresolved::*;
    |     ^^^^^^^^^^ maybe a missing crate `unresolved`?
+   |
+   = help: consider adding `extern crate unresolved` to use the `unresolved` crate
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/imports/issue-26873-multifile/A/B.rs b/src/test/ui/imports/issue-26873-multifile/A/B.rs
new file mode 100644 (file)
index 0000000..ab7b0d8
--- /dev/null
@@ -0,0 +1,4 @@
+// run-pass
+use super::*;
+
+pub struct S;
diff --git a/src/test/ui/imports/issue-26873-multifile/A/C.rs b/src/test/ui/imports/issue-26873-multifile/A/C.rs
new file mode 100644 (file)
index 0000000..b287283
--- /dev/null
@@ -0,0 +1,6 @@
+// run-pass
+use super::*;
+
+use super::B::S;
+
+pub struct T { i: i32 }
diff --git a/src/test/ui/imports/issue-26873-multifile/A/mod.rs b/src/test/ui/imports/issue-26873-multifile/A/mod.rs
new file mode 100644 (file)
index 0000000..0f18772
--- /dev/null
@@ -0,0 +1,5 @@
+// run-pass
+pub mod B;
+pub mod C;
+
+pub use self::C::T;
diff --git a/src/test/ui/imports/issue-26873-multifile/compiletest-ignore-dir b/src/test/ui/imports/issue-26873-multifile/compiletest-ignore-dir
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/test/ui/imports/issue-26873-multifile/issue-26873-multifile.rs b/src/test/ui/imports/issue-26873-multifile/issue-26873-multifile.rs
new file mode 100644 (file)
index 0000000..da2acf6
--- /dev/null
@@ -0,0 +1,11 @@
+// run-pass
+#![allow(dead_code)]
+#![allow(unused_imports)]
+#![allow(non_snake_case)]
+
+// ignore-pretty issue #37195
+
+#[path = "issue-26873-multifile/mod.rs"]
+mod multifile;
+
+fn main() {}
diff --git a/src/test/ui/imports/issue-26873-multifile/issue-26873-onefile.rs b/src/test/ui/imports/issue-26873-multifile/issue-26873-onefile.rs
new file mode 100644 (file)
index 0000000..f06c649
--- /dev/null
@@ -0,0 +1,25 @@
+// run-pass
+#![allow(dead_code)]
+#![allow(unused_imports)]
+#![allow(non_snake_case)]
+
+mod A {
+    pub mod B {
+        use super::*;
+
+        pub struct S;
+    }
+
+    pub mod C {
+        use super::*;
+        use super::B::S;
+
+        pub struct T;
+    }
+
+    pub use self::C::T;
+}
+
+use A::*;
+
+fn main() {}
diff --git a/src/test/ui/imports/issue-26873-multifile/mod.rs b/src/test/ui/imports/issue-26873-multifile/mod.rs
new file mode 100644 (file)
index 0000000..a1ba53f
--- /dev/null
@@ -0,0 +1,4 @@
+// run-pass
+mod A;
+
+use self::A::*;
diff --git a/src/test/ui/imports/issue-26873-onefile.rs b/src/test/ui/imports/issue-26873-onefile.rs
deleted file mode 100644 (file)
index f06c649..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-// run-pass
-#![allow(dead_code)]
-#![allow(unused_imports)]
-#![allow(non_snake_case)]
-
-mod A {
-    pub mod B {
-        use super::*;
-
-        pub struct S;
-    }
-
-    pub mod C {
-        use super::*;
-        use super::B::S;
-
-        pub struct T;
-    }
-
-    pub use self::C::T;
-}
-
-use A::*;
-
-fn main() {}
index d3bf404c99a974b95673befcdb3f5e72c296fd4c..c4e5c55589914a11312b2873cef5b1b5649266c1 100644 (file)
@@ -3,18 +3,24 @@ error[E0432]: unresolved import `abc`
    |
 LL | use abc::one_el;
    |     ^^^ maybe a missing crate `abc`?
+   |
+   = help: consider adding `extern crate abc` to use the `abc` crate
 
 error[E0432]: unresolved import `abc`
   --> $DIR/issue-33464.rs:5:5
    |
 LL | use abc::{a, bbb, cccccc};
    |     ^^^ maybe a missing crate `abc`?
+   |
+   = help: consider adding `extern crate abc` to use the `abc` crate
 
 error[E0432]: unresolved import `a_very_long_name`
   --> $DIR/issue-33464.rs:7:5
    |
 LL | use a_very_long_name::{el, el2};
    |     ^^^^^^^^^^^^^^^^ maybe a missing crate `a_very_long_name`?
+   |
+   = help: consider adding `extern crate a_very_long_name` to use the `a_very_long_name` crate
 
 error: aborting due to 3 previous errors
 
index caf9d5d6d627755a1c5a95319061630ee56f2da2..2e1b468603d47c7966a34dc9cf605ebddd374947 100644 (file)
@@ -3,6 +3,8 @@ error[E0432]: unresolved import `issue_36881_aux`
    |
 LL |     use issue_36881_aux::Foo;
    |         ^^^^^^^^^^^^^^^ maybe a missing crate `issue_36881_aux`?
+   |
+   = help: consider adding `extern crate issue_36881_aux` to use the `issue_36881_aux` crate
 
 error: aborting due to previous error
 
index 944d544098ab4e07c081bdeefcc1b6f732b32bd4..75185cad3b764885eb3bb0881f7408b8a853f108 100644 (file)
@@ -3,6 +3,8 @@ error[E0432]: unresolved import `libc`
    |
 LL |     use libc::*;
    |         ^^^^ maybe a missing crate `libc`?
+   |
+   = help: consider adding `extern crate libc` to use the `libc` crate
 
 error[E0658]: use of unstable library feature 'rustc_private': this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead?
   --> $DIR/issue-37887.rs:2:5
index a0e7bf8b61f6e4ceb79617cb9528b59be35952ee..29c7556dac432a5f459e13a5648aeadfd7ba73b1 100644 (file)
@@ -3,6 +3,8 @@ error[E0432]: unresolved import `nonexistent_module`
    |
 LL |     use nonexistent_module::mac;
    |         ^^^^^^^^^^^^^^^^^^ maybe a missing crate `nonexistent_module`?
+   |
+   = help: consider adding `extern crate nonexistent_module` to use the `nonexistent_module` crate
 
 error[E0659]: `mac` is ambiguous
   --> $DIR/issue-53269.rs:8:5
index 07de3d95902efa10090592a6f28f735b7751f31a..788fcc830ae9abc95ba519b99375e2aadd7b6be6 100644 (file)
@@ -12,6 +12,8 @@ error[E0432]: unresolved import `non_existent`
    |
 LL | use non_existent::non_existent;
    |     ^^^^^^^^^^^^ maybe a missing crate `non_existent`?
+   |
+   = help: consider adding `extern crate non_existent` to use the `non_existent` crate
 
 error: cannot determine resolution for the derive macro `NonExistent`
   --> $DIR/issue-55457.rs:5:10
index efab4f6a74f835ee30a53680977b9ce2c8de799d..6caf15bc7240163fab97cfb774cc5fd9f475859d 100644 (file)
@@ -3,24 +3,32 @@ error[E0433]: failed to resolve: maybe a missing crate `clippy`?
    |
 LL | use clippy::a::b;
    |     ^^^^^^ maybe a missing crate `clippy`?
+   |
+   = help: consider adding `extern crate clippy` to use the `clippy` crate
 
 error[E0432]: unresolved import `clippy`
   --> $DIR/tool-mod-child.rs:1:5
    |
 LL | use clippy::a;
    |     ^^^^^^ maybe a missing crate `clippy`?
+   |
+   = help: consider adding `extern crate clippy` to use the `clippy` crate
 
 error[E0433]: failed to resolve: maybe a missing crate `rustdoc`?
   --> $DIR/tool-mod-child.rs:5:5
    |
 LL | use rustdoc::a::b;
    |     ^^^^^^^ maybe a missing crate `rustdoc`?
+   |
+   = help: consider adding `extern crate rustdoc` to use the `rustdoc` crate
 
 error[E0432]: unresolved import `rustdoc`
   --> $DIR/tool-mod-child.rs:4:5
    |
 LL | use rustdoc::a;
    |     ^^^^^^^ maybe a missing crate `rustdoc`?
+   |
+   = help: consider adding `extern crate rustdoc` to use the `rustdoc` crate
 
 error: aborting due to 4 previous errors
 
index ddf3608933909d7f6bfb6d28f360aa3b0e05624c..73f9d1bfb6c618757f7c18ebaea51c2f7a31779e 100644 (file)
@@ -15,24 +15,32 @@ error[E0432]: unresolved import `foo`
    |
 LL | use foo::bar;
    |     ^^^ maybe a missing crate `foo`?
+   |
+   = help: consider adding `extern crate foo` to use the `foo` crate
 
 error[E0432]: unresolved import `baz`
   --> $DIR/unresolved-imports-used.rs:12:5
    |
 LL | use baz::*;
    |     ^^^ maybe a missing crate `baz`?
+   |
+   = help: consider adding `extern crate baz` to use the `baz` crate
 
 error[E0432]: unresolved import `foo2`
   --> $DIR/unresolved-imports-used.rs:14:5
    |
 LL | use foo2::bar2;
    |     ^^^^ maybe a missing crate `foo2`?
+   |
+   = help: consider adding `extern crate foo2` to use the `foo2` crate
 
 error[E0432]: unresolved import `baz2`
   --> $DIR/unresolved-imports-used.rs:15:5
    |
 LL | use baz2::*;
    |     ^^^^ maybe a missing crate `baz2`?
+   |
+   = help: consider adding `extern crate baz2` to use the `baz2` crate
 
 error[E0603]: function `quz` is private
   --> $DIR/unresolved-imports-used.rs:9:10
index 47ef1948aee9fcab453c46c92602cd45070c5b45..a08342371b3b5ae15e6b2321a2d43cca87d57d3e 100644 (file)
@@ -3,12 +3,6 @@ error[E0282]: type annotations needed
    |
 LL |     InMemoryStore.get_raw(&String::default());
    |                   ^^^^^^^ cannot infer type for type parameter `K`
-   |
-help: type parameter declared here
-  --> $DIR/ambiguous_type_parameter.rs:9:6
-   |
-LL | impl<K> Store<String, HashMap<K, String>> for InMemoryStore {
-   |      ^
 
 error: aborting due to previous error
 
index 233604833612aa4a79fd283e43eb235fa6cc4dbb..0579cf238a9da03b4c12fea17c4033ff9582da97 100644 (file)
@@ -1,11 +1,13 @@
 error[E0282]: type annotations needed
   --> $DIR/cannot-infer-async.rs:13:9
    |
-LL |     let fut = async {
-   |         --- consider giving `fut` a type
-...
 LL |         Ok(())
-   |         ^^ cannot infer type for type parameter `E` declared on the enum `Result`
+   |         ^^ cannot infer type of the type parameter `E` declared on the enum `Result`
+   |
+help: consider specifying the generic arguments
+   |
+LL |         Ok::<(), E>(())
+   |           +++++++++
 
 error: aborting due to previous error
 
index a3b957179b1b1540235013a13e119027f3f6332c..ae879db68ec1302dc5a62f368ced9f624361cf9c 100644 (file)
@@ -5,10 +5,9 @@ fn main() {
     // note about the `?` operator in the closure body, which isn't relevant to
     // the inference.
     let x = |r| {
-        //~^ ERROR type annotations needed
         let v = r?;
         Ok(v)
     };
 
-    let _ = x(x(Ok(())));
+    let _ = x(x(Ok(())));  //~ ERROR type annotations needed for `Result<(), E>`
 }
index a6ddb7ae908fc0fbacb9423d5fde5da0e152cfd5..3ad8e3cda16e54b8d58ce2d9b1f40c3e4df629eb 100644 (file)
@@ -1,8 +1,13 @@
 error[E0282]: type annotations needed for `Result<(), E>`
-  --> $DIR/cannot-infer-closure-circular.rs:7:14
+  --> $DIR/cannot-infer-closure-circular.rs:12:9
    |
-LL |     let x = |r| {
-   |              ^ consider giving this closure parameter the explicit type `Result<(), E>`, where the type parameter `E` is specified
+LL |     let _ = x(x(Ok(())));
+   |         ^
+   |
+help: consider giving this pattern a type, where the type for type parameter `E` is specified
+   |
+LL |     let _: Result<(), E> = x(x(Ok(())));
+   |          +++++++++++++++
 
 error: aborting due to previous error
 
index 6e84b6d5ad0bddb7206966f1954bb23d77833526..1c350b18f5a6fa0f9ccd457c483e2aa6d5e4fcef 100644 (file)
@@ -1,6 +1,6 @@
 fn main() {
     let x = |a: (), b: ()| {
         Err(a)?;
-        Ok(b) //~ ERROR type annotations needed for the closure
+        Ok(b) //~ ERROR type annotations needed
     };
 }
index f8026fafeb2c4db7ed39c95508d8bcf88f833d8a..a4b818e6e2bb8fb8d3d9886764d80f8a56f22ffd 100644 (file)
@@ -1,13 +1,13 @@
-error[E0282]: type annotations needed for the closure `fn((), ()) -> Result<(), _>`
+error[E0282]: type annotations needed
   --> $DIR/cannot-infer-closure.rs:4:9
    |
 LL |         Ok(b)
-   |         ^^ cannot infer type for type parameter `E` declared on the enum `Result`
+   |         ^^ cannot infer type of the type parameter `E` declared on the enum `Result`
    |
-help: give this closure an explicit return type without `_` placeholders
+help: consider specifying the generic arguments
    |
-LL |     let x = |a: (), b: ()| -> Result<(), _> {
-   |                            ++++++++++++++++
+LL |         Ok::<(), E>(b)
+   |           +++++++++
 
 error: aborting due to previous error
 
index 6e897a3edfdc3c1d0bc0cc22314e7779e0b5d14b..976827a4478608504075ca40b8266f867979e7d1 100644 (file)
@@ -16,7 +16,8 @@ fn infallible() -> Result<(), std::convert::Infallible> {
 
 fn main() {
     let x = || -> Result<_, QualifiedError<_>> {
-        infallible()?; //~ ERROR type annotations needed
+        //~^ ERROR type annotations needed for `Result<(), QualifiedError<_>>`
+        infallible()?;
         Ok(())
     };
 }
index 3542eb6848caf23863446267634a03dbd9f10791..220602c124cb15a47f41c261f570008285fa26f4 100644 (file)
@@ -1,10 +1,10 @@
-error[E0282]: type annotations needed for the closure `fn() -> Result<(), QualifiedError<_>>`
-  --> $DIR/cannot-infer-partial-try-return.rs:19:9
+error[E0282]: type annotations needed for `Result<(), QualifiedError<_>>`
+  --> $DIR/cannot-infer-partial-try-return.rs:18:13
    |
-LL |         infallible()?;
-   |         ^^^^^^^^^^^^^ cannot infer type
+LL |     let x = || -> Result<_, QualifiedError<_>> {
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: give this closure an explicit return type without `_` placeholders
+help: try giving this closure an explicit return type
    |
 LL |     let x = || -> Result<(), QualifiedError<_>> {
    |                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
index 51fac5f79df475c54592504c9bef7914a09d745d..fd58844c2380a6ec8df46ff44af0595c99674b35 100644 (file)
@@ -1,46 +1,40 @@
 error[E0283]: type annotations needed for `Foo<i32, &str, W, Z>`
-  --> $DIR/erase-type-params-in-label.rs:2:15
+  --> $DIR/erase-type-params-in-label.rs:2:9
    |
 LL |     let foo = foo(1, "");
-   |         ---   ^^^ cannot infer type for type parameter `W` declared on the function `foo`
-   |         |
-   |         consider giving `foo` the explicit type `Foo<_, _, W, Z>`, where the type parameter `W` is specified
+   |         ^^^
    |
-help: type parameter declared here
-  --> $DIR/erase-type-params-in-label.rs:25:14
-   |
-LL | fn foo<T, K, W: Default, Z: Default>(t: T, k: K) -> Foo<T, K, W, Z> {
-   |              ^
    = note: cannot satisfy `_: Default`
 note: required by a bound in `foo`
   --> $DIR/erase-type-params-in-label.rs:25:17
    |
 LL | fn foo<T, K, W: Default, Z: Default>(t: T, k: K) -> Foo<T, K, W, Z> {
    |                 ^^^^^^^ required by this bound in `foo`
+help: consider giving `foo` an explicit type, where the type for type parameter `W` is specified
+   |
+LL |     let foo: Foo<i32, &str, W, Z> = foo(1, "");
+   |            ++++++++++++++++++++++
 help: consider specifying the type arguments in the function call
    |
 LL |     let foo = foo::<T, K, W, Z>(1, "");
    |                  ++++++++++++++
 
 error[E0283]: type annotations needed for `Bar<i32, &str, Z>`
-  --> $DIR/erase-type-params-in-label.rs:5:15
+  --> $DIR/erase-type-params-in-label.rs:5:9
    |
 LL |     let bar = bar(1, "");
-   |         ---   ^^^ cannot infer type for type parameter `Z` declared on the function `bar`
-   |         |
-   |         consider giving `bar` the explicit type `Bar<_, _, Z>`, where the type parameter `Z` is specified
+   |         ^^^
    |
-help: type parameter declared here
-  --> $DIR/erase-type-params-in-label.rs:14:14
-   |
-LL | fn bar<T, K, Z: Default>(t: T, k: K) -> Bar<T, K, Z> {
-   |              ^
    = note: cannot satisfy `_: Default`
 note: required by a bound in `bar`
   --> $DIR/erase-type-params-in-label.rs:14:17
    |
 LL | fn bar<T, K, Z: Default>(t: T, k: K) -> Bar<T, K, Z> {
    |                 ^^^^^^^ required by this bound in `bar`
+help: consider giving `bar` an explicit type, where the type for type parameter `Z` is specified
+   |
+LL |     let bar: Bar<i32, &str, Z> = bar(1, "");
+   |            +++++++++++++++++++
 help: consider specifying the type arguments in the function call
    |
 LL |     let bar = bar::<T, K, Z>(1, "");
index 0369196c9108eda7de5377a4d9d4563762ada94c..db153d38aaa9f160155911cac50ca13b8908964b 100644 (file)
@@ -2,9 +2,7 @@ error[E0283]: type annotations needed
   --> $DIR/issue-71732.rs:18:10
    |
 LL |         .get(&"key".into())
-   |          ^^^  ------------ this method call resolves to `T`
-   |          |
-   |          cannot infer type for type parameter `Q` declared on the associated function `get`
+   |          ^^^ cannot infer type of the type parameter `Q` declared on the associated function `get`
    |
    = note: multiple `impl`s satisfying `String: Borrow<_>` found in the following crates: `alloc`, `core`:
            - impl Borrow<str> for String;
@@ -15,6 +13,10 @@ note: required by a bound in `HashMap::<K, V, S>::get`
    |
 LL |         K: Borrow<Q>,
    |            ^^^^^^^^^ required by this bound in `HashMap::<K, V, S>::get`
+help: consider specifying the generic argument
+   |
+LL |         .get::<Q>(&"key".into())
+   |             +++++
 help: consider specifying the type argument in the function call
    |
 LL |         .get::<Q>(&"key".into())
index 0077c73474818e181af889ba661ee676e9946eae..3c53d8126e778b370144b20ee89636ad3db563b2 100644 (file)
@@ -1,16 +1,18 @@
 error[E0283]: type annotations needed
-  --> $DIR/issue-72616.rs:20:30
+  --> $DIR/issue-72616.rs:20:37
    |
 LL |         if String::from("a") == "a".try_into().unwrap() {}
-   |                              ^^ -------------- this method call resolves to `Result<T, <Self as TryInto<T>>::Error>`
-   |                              |
-   |                              cannot infer type
+   |                                     ^^^^^^^^
    |
    = note: multiple `impl`s satisfying `String: PartialEq<_>` found in the `alloc` crate:
            - impl PartialEq for String;
            - impl<'a, 'b> PartialEq<&'a str> for String;
            - impl<'a, 'b> PartialEq<Cow<'a, str>> for String;
            - impl<'a, 'b> PartialEq<str> for String;
+help: try using a fully qualified path to specify the expected types
+   |
+LL |         if String::from("a") == <&str as TryInto<T>>::try_into("a").unwrap() {}
+   |                                 +++++++++++++++++++++++++++++++   ~
 
 error: aborting due to previous error
 
index 9ca8f35fd545a4abb34cbae54e3ee8b9a8765443..4ffaf820b826729f7a26a8f3872e680c888c8e91 100644 (file)
@@ -1,10 +1,13 @@
 error[E0282]: type annotations needed for `[usize; _]`
-  --> $DIR/issue-83606.rs:8:13
+  --> $DIR/issue-83606.rs:8:9
    |
 LL |     let _ = foo("foo"); //<- Do not suggest `foo::<N>("foo");`!
-   |         -   ^^^ cannot infer the value of const parameter `N` declared on the function `foo`
-   |         |
-   |         consider giving this pattern the explicit type `[_; N]`, where the const parameter `N` is specified
+   |         ^
+   |
+help: consider giving this pattern a type, where the the value of const parameter `N` is specified
+   |
+LL |     let _: [usize; _] = foo("foo"); //<- Do not suggest `foo::<N>("foo");`!
+   |          ++++++++++++
 
 error: aborting due to previous error
 
index edf97c0aed47ee04b51a62d76543e763a82a06e5..6641b29b30b0be56ecb6f6d07108dbc5ee0c0230 100644 (file)
@@ -1,20 +1,19 @@
 error[E0283]: type annotations needed
-  --> $DIR/issue-86162-1.rs:7:5
+  --> $DIR/issue-86162-1.rs:7:9
    |
 LL |     foo(gen()); //<- Do not suggest `foo::<impl Clone>()`!
-   |     ^^^ cannot infer type for type parameter `impl Clone` declared on the function `foo`
+   |         ^^^ cannot infer type of the type parameter `T` declared on the function `gen`
    |
-help: type parameter declared here
-  --> $DIR/issue-86162-1.rs:3:11
-   |
-LL | fn foo(x: impl Clone) {}
-   |           ^^^^^^^^^^
    = note: cannot satisfy `_: Clone`
 note: required by a bound in `foo`
   --> $DIR/issue-86162-1.rs:3:16
    |
 LL | fn foo(x: impl Clone) {}
    |                ^^^^^ required by this bound in `foo`
+help: consider specifying the generic argument
+   |
+LL |     foo(gen::<T>()); //<- Do not suggest `foo::<impl Clone>()`!
+   |            +++++
 
 error: aborting due to previous error
 
index c642ebb057603b51aba7d53ffb803e103e2a48d5..d2a026a9269c66b25f63ebf44d7488b849c7d745 100644 (file)
@@ -1,20 +1,19 @@
 error[E0283]: type annotations needed
-  --> $DIR/issue-86162-2.rs:12:5
+  --> $DIR/issue-86162-2.rs:12:14
    |
 LL |     Foo::bar(gen()); //<- Do not suggest `Foo::bar::<impl Clone>()`!
-   |     ^^^^^^^^ cannot infer type for type parameter `impl Clone` declared on the associated function `bar`
+   |              ^^^ cannot infer type of the type parameter `T` declared on the function `gen`
    |
-help: type parameter declared here
-  --> $DIR/issue-86162-2.rs:8:15
-   |
-LL |     fn bar(x: impl Clone) {}
-   |               ^^^^^^^^^^
    = note: cannot satisfy `_: Clone`
 note: required by a bound in `Foo::bar`
   --> $DIR/issue-86162-2.rs:8:20
    |
 LL |     fn bar(x: impl Clone) {}
    |                    ^^^^^ required by this bound in `Foo::bar`
+help: consider specifying the generic argument
+   |
+LL |     Foo::bar(gen::<T>()); //<- Do not suggest `Foo::bar::<impl Clone>()`!
+   |                 +++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-11319.rs b/src/test/ui/issues/issue-11319.rs
deleted file mode 100644 (file)
index ab69ab2..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-fn main() {
-    match Some(10) {
-    //~^ NOTE `match` arms have incompatible types
-        Some(5) => false,
-        //~^ NOTE this is found to be of type `bool`
-        Some(2) => true,
-        //~^ NOTE this is found to be of type `bool`
-        None    => (),
-        //~^ ERROR `match` arms have incompatible types
-        //~| NOTE expected `bool`, found `()`
-        _       => true
-    }
-}
diff --git a/src/test/ui/issues/issue-11319.stderr b/src/test/ui/issues/issue-11319.stderr
deleted file mode 100644 (file)
index fc44205..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-error[E0308]: `match` arms have incompatible types
-  --> $DIR/issue-11319.rs:8:20
-   |
-LL | /     match Some(10) {
-LL | |
-LL | |         Some(5) => false,
-   | |                    ----- this is found to be of type `bool`
-LL | |
-LL | |         Some(2) => true,
-   | |                    ---- this is found to be of type `bool`
-LL | |
-LL | |         None    => (),
-   | |                    ^^ expected `bool`, found `()`
-...  |
-LL | |         _       => true
-LL | |     }
-   | |_____- `match` arms have incompatible types
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0308`.
index 3ea15439df25a69276b8239ea62fe125587282e2..806b7f0ac05e960d3f8fac5c5e7378b39b8e362c 100644 (file)
@@ -1,11 +1,13 @@
 error[E0282]: type annotations needed for `&T`
-  --> $DIR/issue-12187-1.rs:6:10
+  --> $DIR/issue-12187-1.rs:6:9
    |
 LL |     let &v = new();
-   |         -^
-   |         ||
-   |         |cannot infer type
-   |         consider giving this pattern the explicit type `&T`, with the type parameters specified
+   |         ^^
+   |
+help: consider giving this pattern a type, where the placeholders `_` are specified
+   |
+LL |     let &v: &T = new();
+   |           ++++
 
 error: aborting due to previous error
 
index a5e65c65beb2fe6b059a635330bea9468d0bf030..a1fa0a2b00245d03ca17ab1b94973f1bd7862622 100644 (file)
@@ -1,11 +1,13 @@
 error[E0282]: type annotations needed for `&T`
-  --> $DIR/issue-12187-2.rs:6:10
+  --> $DIR/issue-12187-2.rs:6:9
    |
 LL |     let &v = new();
-   |         -^
-   |         ||
-   |         |cannot infer type
-   |         consider giving this pattern the explicit type `&T`, with the type parameters specified
+   |         ^^
+   |
+help: consider giving this pattern a type, where the placeholders `_` are specified
+   |
+LL |     let &v: &T = new();
+   |           ++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-13853-2.rs b/src/test/ui/issues/issue-13853-2.rs
deleted file mode 100644 (file)
index 27319c9..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-trait FromStructReader<'a> { }
-trait ResponseHook {
-     fn get(&self);
-}
-fn foo(res : Box<dyn ResponseHook>) { res.get } //~ ERROR attempted to take value of method
-fn main() {}
diff --git a/src/test/ui/issues/issue-13853-2.stderr b/src/test/ui/issues/issue-13853-2.stderr
deleted file mode 100644 (file)
index 92068df..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-error[E0615]: attempted to take value of method `get` on type `Box<(dyn ResponseHook + 'static)>`
-  --> $DIR/issue-13853-2.rs:5:43
-   |
-LL | fn foo(res : Box<dyn ResponseHook>) { res.get }
-   |                                           ^^^ method, not a field
-   |
-help: use parentheses to call the method
-   |
-LL | fn foo(res : Box<dyn ResponseHook>) { res.get() }
-   |                                              ++
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0615`.
diff --git a/src/test/ui/issues/issue-13853-5.rs b/src/test/ui/issues/issue-13853-5.rs
deleted file mode 100644 (file)
index 2afdf95..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-trait Deserializer<'a> { }
-
-trait Deserializable {
-    fn deserialize_token<'a, D: Deserializer<'a>>(_: D, _: &'a str) -> Self;
-}
-
-impl<'a, T: Deserializable> Deserializable for &'a str {
-    //~^ ERROR type parameter `T` is not constrained
-    fn deserialize_token<D: Deserializer<'a>>(_x: D, _y: &'a str) -> &'a str {
-    }
-}
-
-fn main() {}
diff --git a/src/test/ui/issues/issue-13853-5.stderr b/src/test/ui/issues/issue-13853-5.stderr
deleted file mode 100644 (file)
index 3d8f824..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates
-  --> $DIR/issue-13853-5.rs:7:10
-   |
-LL | impl<'a, T: Deserializable> Deserializable for &'a str {
-   |          ^ unconstrained type parameter
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0207`.
diff --git a/src/test/ui/issues/issue-13853.rs b/src/test/ui/issues/issue-13853.rs
deleted file mode 100644 (file)
index ac9886d..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-trait Node {
-    fn zomg();
-}
-
-trait Graph<N: Node> {
-    fn nodes<'a, I: Iterator<Item=&'a N>>(&'a self) -> I
-        where N: 'a;
-}
-
-impl<N: Node> Graph<N> for Vec<N> {
-    fn nodes<'a, I: Iterator<Item=&'a N>>(&self) -> I
-        where N: 'a
-    {
-        self.iter() //~ ERROR mismatched types
-    }
-}
-
-struct Stuff;
-
-impl Node for Stuff {
-    fn zomg() {
-        println!("zomg");
-    }
-}
-
-fn iterate<N: Node, G: Graph<N>>(graph: &G) {
-    for node in graph.iter() { //~ ERROR no method named `iter` found
-        node.zomg();
-    }
-}
-
-pub fn main() {
-    let graph = Vec::new();
-
-    graph.push(Stuff);
-
-    iterate(graph); //~ ERROR mismatched types
-}
diff --git a/src/test/ui/issues/issue-13853.stderr b/src/test/ui/issues/issue-13853.stderr
deleted file mode 100644 (file)
index 657bda5..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-error[E0308]: mismatched types
-  --> $DIR/issue-13853.rs:14:9
-   |
-LL |     fn nodes<'a, I: Iterator<Item=&'a N>>(&self) -> I
-   |                  - this type parameter              - expected `I` because of return type
-...
-LL |         self.iter()
-   |         ^^^^^^^^^^^ expected type parameter `I`, found struct `std::slice::Iter`
-   |
-   = note: expected type parameter `I`
-                      found struct `std::slice::Iter<'_, N>`
-
-error[E0599]: no method named `iter` found for reference `&G` in the current scope
-  --> $DIR/issue-13853.rs:27:23
-   |
-LL |     for node in graph.iter() {
-   |                       ^^^^ method not found in `&G`
-
-error[E0308]: mismatched types
-  --> $DIR/issue-13853.rs:37:13
-   |
-LL |     iterate(graph);
-   |     ------- ^^^^^
-   |     |       |
-   |     |       expected reference, found struct `Vec`
-   |     |       help: consider borrowing here: `&graph`
-   |     arguments to this function are incorrect
-   |
-   = note: expected reference `&_`
-                 found struct `Vec<Stuff>`
-note: function defined here
-  --> $DIR/issue-13853.rs:26:4
-   |
-LL | fn iterate<N: Node, G: Graph<N>>(graph: &G) {
-   |    ^^^^^^^                       ---------
-
-error: aborting due to 3 previous errors
-
-Some errors have detailed explanations: E0308, E0599.
-For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/issues/issue-14933.rs b/src/test/ui/issues/issue-14933.rs
deleted file mode 100644 (file)
index bd95332..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-// check-pass
-// pretty-expanded FIXME #23616
-
-pub type BigRat<T = isize> = T;
-
-fn main() {}
diff --git a/src/test/ui/issues/issue-14958.rs b/src/test/ui/issues/issue-14958.rs
deleted file mode 100644 (file)
index a12564c..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-// run-pass
-// pretty-expanded FIXME #23616
-
-#![feature(fn_traits, unboxed_closures)]
-
-trait Foo { fn dummy(&self) { }}
-
-struct Bar;
-
-impl<'a> std::ops::Fn<(&'a (dyn Foo+'a),)> for Bar {
-    extern "rust-call" fn call(&self, _: (&'a dyn Foo,)) {}
-}
-
-impl<'a> std::ops::FnMut<(&'a (dyn Foo+'a),)> for Bar {
-    extern "rust-call" fn call_mut(&mut self, a: (&'a dyn Foo,)) { self.call(a) }
-}
-
-impl<'a> std::ops::FnOnce<(&'a (dyn Foo+'a),)> for Bar {
-    type Output = ();
-    extern "rust-call" fn call_once(self, a: (&'a dyn Foo,)) { self.call(a) }
-}
-
-struct Baz;
-
-impl Foo for Baz {}
-
-fn main() {
-    let bar = Bar;
-    let baz = &Baz;
-    bar(baz);
-}
index 09e20c0c777314202c0c0fe590ae82b3de989be0..6eb56ca5516bfb2e7c371c96411b709d3bd1644b 100644 (file)
@@ -2,9 +2,14 @@ error[E0282]: type annotations needed
   --> $DIR/issue-16966.rs:2:5
    |
 LL |     panic!(std::default::Default::default());
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `M` declared on the function `begin_panic`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `M` declared on the function `begin_panic`
    |
    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider specifying the generic argument
+  --> $SRC_DIR/std/src/panic.rs:LL:COL
+   |
+LL |         $crate::rt::begin_panic::<M>($msg)
+   |                                +++++
 
 error: aborting due to previous error
 
index 48405a292f3aa9d0e8e8fa4c984f14e068830f63..5f45a2f844321e40873647d4efad028fc5f07023 100644 (file)
@@ -1,10 +1,13 @@
 error[E0282]: type annotations needed for `B<T>`
-  --> $DIR/issue-17551.rs:6:15
+  --> $DIR/issue-17551.rs:6:9
    |
 LL |     let foo = B(marker::PhantomData);
-   |         ---   ^ cannot infer type for type parameter `T` declared on the struct `B`
-   |         |
-   |         consider giving `foo` the explicit type `B<T>`, where the type parameter `T` is specified
+   |         ^^^
+   |
+help: consider giving `foo` an explicit type, where the type for type parameter `T` is specified
+   |
+LL |     let foo: B<T> = B(marker::PhantomData);
+   |            ++++++
 
 error: aborting due to previous error
 
index c68265f71f2594e3f94e18c3acba17d9afcbbe69..88b5fbec6cf03a860e548461e3c0309ae753db21 100644 (file)
@@ -11,7 +11,7 @@ note: the anonymous lifetime defined here...
    |
 LL |     fn say(self: &Pair<&str, isize>) {
    |                        ^^^^
-note: ...does not necessarily outlive the lifetime `'_` as defined here
+note: ...does not necessarily outlive the anonymous lifetime as defined here
   --> $DIR/issue-17905-2.rs:5:5
    |
 LL |     &str,
@@ -25,7 +25,7 @@ LL |     fn say(self: &Pair<&str, isize>) {
    |
    = note: expected struct `Pair<&str, _>`
               found struct `Pair<&str, _>`
-note: the lifetime `'_` as defined here...
+note: the anonymous lifetime as defined here...
   --> $DIR/issue-17905-2.rs:5:5
    |
 LL |     &str,
index 9b890be3c789b44d86c580d05725db5f0a2d6718..605ff3829d19a6a70e88f7f83fa22763a3c6e2e4 100644 (file)
@@ -2,7 +2,12 @@ error[E0282]: type annotations needed
   --> $DIR/issue-18159.rs:2:9
    |
 LL |     let x;
-   |         ^ consider giving `x` a type
+   |         ^
+   |
+help: consider giving `x` an explicit type
+   |
+LL |     let x: _;
+   |          +++
 
 error: aborting due to previous error
 
index 6330364c92b6a68e62061c3dc46c31f5ef4dfe4b..73468c7ca1687c9f1289a1d32cf87c14eab39cbf 100644 (file)
@@ -1,8 +1,6 @@
-error[E0282]: type annotations needed for `(_,)`
+error[E0282]: type annotations needed
   --> $DIR/issue-20261.rs:4:11
    |
-LL |     for (ref i,) in [].iter() {
-   |                     --------- this method call resolves to `std::slice::Iter<'_, T>`
 LL |         i.clone();
    |           ^^^^^ cannot infer type
    |
index 32fba4cb2177dab3270f2e72c58502d5d583bd8d..82cf49de8227ef303d8c67b20f86acd7966e747c 100644 (file)
@@ -1,4 +1,4 @@
 fn main() {
-    let x = panic!();
-    x.clone(); //~ ERROR type annotations needed
+    let x = panic!(); //~ ERROR type annotations needed
+    x.clone();
 }
index a2bcc8a8ceaf0e94b23c1495c0aa102537112258..e0d946205ad0a30e7c5358532c1aa1d479cccdd7 100644 (file)
@@ -1,12 +1,14 @@
 error[E0282]: type annotations needed
-  --> $DIR/issue-2151.rs:3:5
+  --> $DIR/issue-2151.rs:2:9
    |
 LL |     let x = panic!();
-   |         - consider giving `x` a type
-LL |     x.clone();
-   |     ^ cannot infer type
+   |         ^
    |
    = note: type must be known at this point
+help: consider giving `x` an explicit type
+   |
+LL |     let x: _ = panic!();
+   |          +++
 
 error: aborting due to previous error
 
index 28e8a722804813c00159db59a68ef5fe4ab9bb4b..bb8a58d3d2ecc63c36340bff5de941e6379f08ca 100644 (file)
@@ -1,3 +1,3 @@
 fn is_copy<T: ::std::marker<i32>::Copy>() {}
-//~^ ERROR type arguments are not allowed for this type [E0109]
+//~^ ERROR type arguments are not allowed on module `marker` [E0109]
 fn main() {}
index c5929397f6501e57e300e65c5ce64aa914941289..66911f081d76cd74f2e2ec78f717e7b4dbcb7a62 100644 (file)
@@ -1,8 +1,10 @@
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on module `marker`
   --> $DIR/issue-22706.rs:1:29
    |
 LL | fn is_copy<T: ::std::marker<i32>::Copy>() {}
-   |                             ^^^ type argument not allowed
+   |                      ------ ^^^ type argument not allowed
+   |                      |
+   |                      not allowed on this
 
 error: aborting due to previous error
 
index 12b2eb48e7eaa2987d341590f80595f040d88ba6..1403ecbd92d49df96d866d01e532d8a0e3a67567 100644 (file)
@@ -2,7 +2,12 @@ error[E0282]: type annotations needed for `Expr<'_, VAR>`
   --> $DIR/issue-23046.rs:17:15
    |
 LL |     let ex = |x| {
-   |               ^ consider giving this closure parameter the explicit type `Expr<'_, VAR>`, where the type parameter `VAR` is specified
+   |               ^
+   |
+help: consider giving this closure parameter an explicit type, where the type for type parameter `VAR` is specified
+   |
+LL |     let ex = |x: Expr<'_, VAR>| {
+   |                +++++++++++++++
 
 error: aborting due to previous error
 
index e6b8367f74fb56830708e4251c91ed79e4161d6a..4622501f33edae7a823ab372401f1d233f1a7a19 100644 (file)
@@ -15,7 +15,12 @@ error[E0282]: type annotations needed
   --> $DIR/issue-24036.rs:9:15
    |
 LL |         1 => |c| c + 1,
-   |               ^ consider giving this closure parameter a type
+   |               ^
+   |
+help: consider giving this closure parameter an explicit type
+   |
+LL |         1 => |c: _| c + 1,
+   |                +++
 
 error: aborting due to 2 previous errors
 
index 8b4dbb6e460a5ac697ad57d3f852a6fe748871ac..b7f0f613e8091f3f1a2c34fbe2d1694e53e87f23 100644 (file)
@@ -5,9 +5,10 @@
 struct Foo<T> {foo: PhantomData<T>}
 
 fn main() {
-    let (tx, rx) = channel();
-
+    let (tx, rx) = //~ ERROR type annotations needed
+        channel();
+    // FIXME(#89862): Suggest adding a generic argument to `channel` instead
     spawn(move || {
-        tx.send(Foo{ foo: PhantomData }); //~ ERROR E0282
+        tx.send(Foo{ foo: PhantomData });
     });
 }
index 6a970bc049491454fb95ec7d9112926570264710..ffcb73849527fd2d3f0a4555dcdcd0ba2abc03c4 100644 (file)
@@ -1,11 +1,13 @@
 error[E0282]: type annotations needed for `(Sender<Foo<T>>, std::sync::mpsc::Receiver<Foo<T>>)`
-  --> $DIR/issue-25368.rs:11:17
+  --> $DIR/issue-25368.rs:8:9
    |
-LL |     let (tx, rx) = channel();
-   |         -------- consider giving this pattern the explicit type `(Sender<Foo<T>>, std::sync::mpsc::Receiver<Foo<T>>)`, where the type parameter `T` is specified
-...
-LL |         tx.send(Foo{ foo: PhantomData });
-   |                 ^^^ cannot infer type for type parameter `T` declared on the struct `Foo`
+LL |     let (tx, rx) =
+   |         ^^^^^^^^
+   |
+help: consider giving this pattern a type, where the type for type parameter `T` is specified
+   |
+LL |     let (tx, rx): (Sender<Foo<T>>, std::sync::mpsc::Receiver<Foo<T>>) =
+   |                 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-26873-multifile.rs b/src/test/ui/issues/issue-26873-multifile.rs
deleted file mode 100644 (file)
index da2acf6..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-// run-pass
-#![allow(dead_code)]
-#![allow(unused_imports)]
-#![allow(non_snake_case)]
-
-// ignore-pretty issue #37195
-
-#[path = "issue-26873-multifile/mod.rs"]
-mod multifile;
-
-fn main() {}
diff --git a/src/test/ui/issues/issue-26873-multifile/A/B.rs b/src/test/ui/issues/issue-26873-multifile/A/B.rs
deleted file mode 100644 (file)
index ab7b0d8..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-// run-pass
-use super::*;
-
-pub struct S;
diff --git a/src/test/ui/issues/issue-26873-multifile/A/C.rs b/src/test/ui/issues/issue-26873-multifile/A/C.rs
deleted file mode 100644 (file)
index b287283..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-// run-pass
-use super::*;
-
-use super::B::S;
-
-pub struct T { i: i32 }
diff --git a/src/test/ui/issues/issue-26873-multifile/A/mod.rs b/src/test/ui/issues/issue-26873-multifile/A/mod.rs
deleted file mode 100644 (file)
index 0f18772..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-// run-pass
-pub mod B;
-pub mod C;
-
-pub use self::C::T;
diff --git a/src/test/ui/issues/issue-26873-multifile/compiletest-ignore-dir b/src/test/ui/issues/issue-26873-multifile/compiletest-ignore-dir
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/src/test/ui/issues/issue-26873-multifile/mod.rs b/src/test/ui/issues/issue-26873-multifile/mod.rs
deleted file mode 100644 (file)
index a1ba53f..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-// run-pass
-mod A;
-
-use self::A::*;
diff --git a/src/test/ui/issues/issue-28098.rs b/src/test/ui/issues/issue-28098.rs
deleted file mode 100644 (file)
index 62a90d9..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-fn main() {
-    let _ = Iterator::next(&mut ());
-    //~^ ERROR `()` is not an iterator
-    //~| ERROR `()` is not an iterator
-
-    for _ in false {}
-    //~^ ERROR `bool` is not an iterator
-
-    let _ = Iterator::next(&mut ());
-    //~^ ERROR `()` is not an iterator
-
-    other()
-}
-
-pub fn other() {
-    // check errors are still reported globally
-
-    let _ = Iterator::next(&mut ());
-    //~^ ERROR `()` is not an iterator
-    //~| ERROR `()` is not an iterator
-
-    let _ = Iterator::next(&mut ());
-    //~^ ERROR `()` is not an iterator
-
-    for _ in false {}
-    //~^ ERROR `bool` is not an iterator
-}
diff --git a/src/test/ui/issues/issue-28098.stderr b/src/test/ui/issues/issue-28098.stderr
deleted file mode 100644 (file)
index 3beb992..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-error[E0277]: `()` is not an iterator
-  --> $DIR/issue-28098.rs:2:28
-   |
-LL |     let _ = Iterator::next(&mut ());
-   |             -------------- ^^^^^^^ `()` is not an iterator
-   |             |
-   |             required by a bound introduced by this call
-   |
-   = help: the trait `Iterator` is not implemented for `()`
-
-error[E0277]: `bool` is not an iterator
-  --> $DIR/issue-28098.rs:6:14
-   |
-LL |     for _ in false {}
-   |              ^^^^^ `bool` is not an iterator
-   |
-   = help: the trait `Iterator` is not implemented for `bool`
-   = note: required because of the requirements on the impl of `IntoIterator` for `bool`
-
-error[E0277]: `()` is not an iterator
-  --> $DIR/issue-28098.rs:9:28
-   |
-LL |     let _ = Iterator::next(&mut ());
-   |             -------------- ^^^^^^^ `()` is not an iterator
-   |             |
-   |             required by a bound introduced by this call
-   |
-   = help: the trait `Iterator` is not implemented for `()`
-
-error[E0277]: `()` is not an iterator
-  --> $DIR/issue-28098.rs:2:13
-   |
-LL |     let _ = Iterator::next(&mut ());
-   |             ^^^^^^^^^^^^^^ `()` is not an iterator
-   |
-   = help: the trait `Iterator` is not implemented for `()`
-
-error[E0277]: `()` is not an iterator
-  --> $DIR/issue-28098.rs:18:28
-   |
-LL |     let _ = Iterator::next(&mut ());
-   |             -------------- ^^^^^^^ `()` is not an iterator
-   |             |
-   |             required by a bound introduced by this call
-   |
-   = help: the trait `Iterator` is not implemented for `()`
-
-error[E0277]: `()` is not an iterator
-  --> $DIR/issue-28098.rs:22:28
-   |
-LL |     let _ = Iterator::next(&mut ());
-   |             -------------- ^^^^^^^ `()` is not an iterator
-   |             |
-   |             required by a bound introduced by this call
-   |
-   = help: the trait `Iterator` is not implemented for `()`
-
-error[E0277]: `bool` is not an iterator
-  --> $DIR/issue-28098.rs:25:14
-   |
-LL |     for _ in false {}
-   |              ^^^^^ `bool` is not an iterator
-   |
-   = help: the trait `Iterator` is not implemented for `bool`
-   = note: required because of the requirements on the impl of `IntoIterator` for `bool`
-
-error[E0277]: `()` is not an iterator
-  --> $DIR/issue-28098.rs:18:13
-   |
-LL |     let _ = Iterator::next(&mut ());
-   |             ^^^^^^^^^^^^^^ `()` is not an iterator
-   |
-   = help: the trait `Iterator` is not implemented for `()`
-
-error: aborting due to 8 previous errors
-
-For more information about this error, try `rustc --explain E0277`.
index a029948ca3b82bba510816c6dc1d7fdbd3c6dd3c..ca57b2d7e01d212c76ee02a09bbab791de9e25b7 100644 (file)
@@ -1,8 +1,13 @@
 error[E0282]: type annotations needed
-  --> $DIR/issue-47486.rs:3:31
+  --> $DIR/issue-47486.rs:3:11
    |
 LL |     [0u8; std::mem::size_of::<_>()];
-   |                               ^ cannot infer type
+   |           ^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `size_of`
+   |
+help: consider specifying the generic argument
+   |
+LL |     [0u8; std::mem::size_of::<_>()];
+   |                            ~~~~~
 
 error[E0308]: mismatched types
   --> $DIR/issue-47486.rs:2:10
index 9fa15dc9679147bfeb8dca8c6cc8df4fb5622353..3191bd3de32fef352599ac0102d017cd8215cf91 100644 (file)
@@ -2,7 +2,12 @@ error[E0282]: type annotations needed
   --> $DIR/issue-5062.rs:1:29
    |
 LL | fn main() { format!("{:?}", None); }
-   |                             ^^^^ cannot infer type for type parameter `T` declared on the enum `Option`
+   |                             ^^^^ cannot infer type of the type parameter `T` declared on the enum `Option`
+   |
+help: consider specifying the generic argument
+   |
+LL | fn main() { format!("{:?}", None::<T>); }
+   |                                 +++++
 
 error: aborting due to previous error
 
index c0a74a679efd1be2914d1cacddce408261e372a0..c979c7b2cdd7636a64f423be9b1e8c5a6710f8a5 100644 (file)
@@ -2,7 +2,6 @@ fn main() {
     let tiles = Default::default();
     for row in &mut tiles {
         for tile in row {
-            //~^ NOTE the element type for this iterator is not specified
             *tile = 0;
             //~^ ERROR type annotations needed
             //~| NOTE cannot infer type
index 8501ae6a1d029b6ec1cd0b0a029c96003b4c6835..399b421ab163ec9512653d040abf6dd4a6a31dfd 100644 (file)
@@ -1,9 +1,6 @@
 error[E0282]: type annotations needed
-  --> $DIR/issue-51116.rs:6:13
+  --> $DIR/issue-51116.rs:5:13
    |
-LL |         for tile in row {
-   |                     --- the element type for this iterator is not specified
-LL |
 LL |             *tile = 0;
    |             ^^^^^ cannot infer type
    |
diff --git a/src/test/ui/issues/issue-54387.rs b/src/test/ui/issues/issue-54387.rs
deleted file mode 100644 (file)
index 60e3a02..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-// check-pass
-
-pub struct GstRc {
-    _obj: *const (),
-    _borrowed: bool,
-}
-
-const FOO: Option<GstRc> = None;
-
-fn main() {
-    let _meh = FOO;
-}
diff --git a/src/test/ui/issues/issue-54966.rs b/src/test/ui/issues/issue-54966.rs
deleted file mode 100644 (file)
index 0ed3c4b..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-// issue-54966: ICE returning an unknown type with impl FnMut
-
-fn generate_duration() -> Oper<impl FnMut()> {}
-//~^ ERROR cannot find type `Oper` in this scope
-
-fn main() {}
diff --git a/src/test/ui/issues/issue-54966.stderr b/src/test/ui/issues/issue-54966.stderr
deleted file mode 100644 (file)
index aa9a61c..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0412]: cannot find type `Oper` in this scope
-  --> $DIR/issue-54966.rs:3:27
-   |
-LL | fn generate_duration() -> Oper<impl FnMut()> {}
-   |                           ^^^^ not found in this scope
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0412`.
index dc2942225e3de6205b0e6d1c723acbda0b768304..8846912a8ff79bb11d6daeda27101d845d4f61cd 100644 (file)
@@ -3,7 +3,7 @@
 impl<E> Gcm<E> {
     pub fn crash(e: E) -> Self {
         Self::<E>(e)
-        //~^ ERROR type arguments are not allowed for this type
+        //~^ ERROR type arguments are not allowed on self constructor
     }
 }
 
index 2f184b1aae171847761d1aa750b09411866fa899..211b0dde48c2e24046245cfe994138bd1257970b 100644 (file)
@@ -1,8 +1,10 @@
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on self constructor
   --> $DIR/issue-57924.rs:5:16
    |
 LL |         Self::<E>(e)
-   |                ^ type argument not allowed
+   |         ----   ^ type argument not allowed
+   |         |
+   |         not allowed on this
 
 error: aborting due to previous error
 
index 6dae1e1347b7a402263dff8570ac2bdc31e0061d..29db3fdb47104815247640c37fcb33494f3325b1 100644 (file)
@@ -10,9 +10,9 @@ fn from(a: A) -> B {
 fn main() {
     let c1 = ();
     c1::<()>;
-    //~^ ERROR type arguments are not allowed for this type
+    //~^ ERROR type arguments are not allowed on local variable
 
     let c1 = A {};
     c1::<dyn Into<B>>;
-    //~^ ERROR type arguments are not allowed for this type
+    //~^ ERROR type arguments are not allowed on local variable
 }
index 5d2d9e83c9b9c2d5f5b628df0f495e15922bd0d9..9076f4f9385ba178073a6f532423ec9c7cd31876 100644 (file)
@@ -1,14 +1,18 @@
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on local variable
   --> $DIR/issue-60989.rs:12:10
    |
 LL |     c1::<()>;
-   |          ^^ type argument not allowed
+   |     --   ^^ type argument not allowed
+   |     |
+   |     not allowed on this
 
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on local variable
   --> $DIR/issue-60989.rs:16:10
    |
 LL |     c1::<dyn Into<B>>;
-   |          ^^^^^^^^^^^ type argument not allowed
+   |     --   ^^^^^^^^^^^ type argument not allowed
+   |     |
+   |     not allowed on this
 
 error: aborting due to 2 previous errors
 
index da16f95dc3de657075db68693ed9b6018f838486..8dbdd9a2735317cd0a45305989be0548967c3780 100644 (file)
@@ -2,7 +2,12 @@ error[E0282]: type annotations needed
   --> $DIR/issue-6458-2.rs:3:21
    |
 LL |     format!("{:?}", None);
-   |                     ^^^^ cannot infer type for type parameter `T` declared on the enum `Option`
+   |                     ^^^^ cannot infer type of the type parameter `T` declared on the enum `Option`
+   |
+help: consider specifying the generic argument
+   |
+LL |     format!("{:?}", None::<T>);
+   |                         +++++
 
 error: aborting due to previous error
 
index a71c159db0b0ebb1a32e60c327d7f22df21a952b..2c3ec1a331ff83f998f5413ab9391d6c3938235e 100644 (file)
@@ -2,7 +2,12 @@ error[E0282]: type annotations needed
   --> $DIR/issue-6458-3.rs:4:5
    |
 LL |     mem::transmute(0);
-   |     ^^^^^^^^^^^^^^ cannot infer type for type parameter `U` declared on the function `transmute`
+   |     ^^^^^^^^^^^^^^ cannot infer type of the type parameter `U` declared on the function `transmute`
+   |
+help: consider specifying the generic arguments
+   |
+LL |     mem::transmute::<i32, U>(0);
+   |                   ++++++++++
 
 error: aborting due to previous error
 
index f548692d785830f649b0ba637b89f75da3aac0e7..2e93c13855f565ec95fb2b6fd965078e81e4b135 100644 (file)
@@ -1,14 +1,13 @@
 error[E0282]: type annotations needed
-  --> $DIR/issue-6458.rs:9:4
+  --> $DIR/issue-6458.rs:9:22
    |
 LL |    foo(TypeWithState(marker::PhantomData));
-   |    ^^^ cannot infer type for type parameter `State` declared on the function `foo`
+   |                      ^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `PhantomData`
    |
-help: type parameter declared here
-  --> $DIR/issue-6458.rs:6:12
+help: consider specifying the generic argument
    |
-LL | pub fn foo<State>(_: TypeWithState<State>) {}
-   |            ^^^^^
+LL |    foo(TypeWithState(marker::PhantomData::<T>));
+   |                                         +++++
 
 error: aborting due to previous error
 
index bfeb38d6471e420bc65ac31f3998b35e247397fc..fcabcdea74fc299305032f124e33ee9ce56aeff3 100644 (file)
@@ -6,7 +6,7 @@ LL | impl T1 for &dyn T2 {}
    |
    = note: expected trait `<&dyn T2 as T0>`
               found trait `<&(dyn T2 + 'static) as T0>`
-note: the lifetime `'_` as defined here...
+note: the anonymous lifetime as defined here...
   --> $DIR/issue-65230.rs:8:13
    |
 LL | impl T1 for &dyn T2 {}
index e8cb18f5c1e62bcc2ef14398a524296ad5f9babc..1c55560cb7c723f8e37f0dc6275000d2fa715ec9 100644 (file)
@@ -30,7 +30,7 @@ error[E0282]: type annotations needed
   --> $DIR/issue-66706.rs:2:11
    |
 LL |     [0; [|_: _ &_| ()].len()]
-   |           ^ consider giving this closure parameter a type
+   |           ^ cannot infer type
 
 error[E0308]: mismatched types
   --> $DIR/issue-66706.rs:2:5
diff --git a/src/test/ui/issues/issue-68091-unicode-ident-after-if.rs b/src/test/ui/issues/issue-68091-unicode-ident-after-if.rs
deleted file mode 100644 (file)
index 00f90cc..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-macro_rules! x {
-    ($($c:tt)*) => {
-        $($c)ö* {} //~ ERROR missing condition for `if` expression
-    };             //~| ERROR mismatched types
-}
-
-fn main() {
-    x!(if);
-}
diff --git a/src/test/ui/issues/issue-68091-unicode-ident-after-if.stderr b/src/test/ui/issues/issue-68091-unicode-ident-after-if.stderr
deleted file mode 100644 (file)
index cdd4c67..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-error: missing condition for `if` expression
-  --> $DIR/issue-68091-unicode-ident-after-if.rs:3:14
-   |
-LL |         $($c)ö* {}
-   |              ^ expected if condition here
-
-error[E0308]: mismatched types
-  --> $DIR/issue-68091-unicode-ident-after-if.rs:3:17
-   |
-LL |         $($c)ö* {}
-   |                 ^^ expected `bool`, found `()`
-...
-LL |     x!(if);
-   |     ------ in this macro invocation
-   |
-   = note: this error originates in the macro `x` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/issues/issue-68092-unicode-ident-after-incomplete-expr.rs b/src/test/ui/issues/issue-68092-unicode-ident-after-incomplete-expr.rs
deleted file mode 100644 (file)
index 1a90b47..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-macro_rules! x {
-    ($($c:tt)*) => {
-        $($c)ö* //~ ERROR macro expansion ends with an incomplete expression: expected expression
-    };
-}
-
-fn main() {
-    x!(!);
-}
diff --git a/src/test/ui/issues/issue-68092-unicode-ident-after-incomplete-expr.stderr b/src/test/ui/issues/issue-68092-unicode-ident-after-incomplete-expr.stderr
deleted file mode 100644 (file)
index 0b9c364..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-error: macro expansion ends with an incomplete expression: expected expression
-  --> $DIR/issue-68092-unicode-ident-after-incomplete-expr.rs:3:14
-   |
-LL |         $($c)ö*
-   |              ^ expected expression
-
-error: aborting due to previous error
-
index 378fdc97dd315559ceb83bf4b93f59d0625c2bcb..6c4eafbc8b3a1cbf92fbd91dc24504f4b84c61f5 100644 (file)
@@ -1,22 +1,20 @@
 error[E0282]: type annotations needed
   --> $DIR/issue-69455.rs:29:20
    |
-LL |     type Output;
-   |     ------------ `<Self as Test<Rhs>>::Output` defined here
-...
 LL |     println!("{}", 23u64.test(xs.iter().sum()));
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |                    |
-   |                    this method call resolves to `<Self as Test<Rhs>>::Output`
-   |                    cannot infer type for type parameter `T` declared on the associated function `new_display`
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the associated function `new_display`
    |
    = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider specifying the generic argument
+   |
+LL |     println!("{}", 23u64.test(xs.iter().sum())::<T>);
+   |                                               +++++
 
 error[E0283]: type annotations needed
-  --> $DIR/issue-69455.rs:29:26
+  --> $DIR/issue-69455.rs:29:41
    |
 LL |     println!("{}", 23u64.test(xs.iter().sum()));
-   |                          ^^^^ cannot infer type for type parameter `Rhs` declared on the trait `Test`
+   |                                         ^^^ cannot infer type of the type parameter `S` declared on the associated function `sum`
    |
 note: multiple `impl`s satisfying `u64: Test<_>` found
   --> $DIR/issue-69455.rs:11:1
@@ -26,7 +24,7 @@ LL | impl Test<u32> for u64 {
 ...
 LL | impl Test<u64> for u64 {
    | ^^^^^^^^^^^^^^^^^^^^^^
-help: consider specifying the type argument in the method call
+help: consider specifying the generic argument
    |
 LL |     println!("{}", 23u64.test(xs.iter().sum::<S>()));
    |                                            +++++
index b53923eec1d8868a5d4da3b0e364120811f9801f..9c71ecffa2682ac34e61608aa504cc1669090402 100644 (file)
@@ -8,7 +8,7 @@ error[E0283]: type annotations needed
   --> $DIR/issue-69683.rs:30:10
    |
 LL |     0u16.foo(b);
-   |          ^^^ cannot infer type for type parameter `I` declared on the trait `Foo`
+   |          ^^^
    |
 note: multiple `impl`s satisfying `u8: Element<_>` found
   --> $DIR/issue-69683.rs:5:1
@@ -26,6 +26,10 @@ LL |     u8: Element<I>,
 LL | {
 LL |     fn foo(self, x: <u8 as Element<I>>::Array);
    |        --- required by a bound in this
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <u16 as Foo<I>>::foo(0u16, b);
+   |     +++++++++++++++++++++    ~
 
 error: aborting due to 2 previous errors
 
index 4c11f3544948e694becba10e8d13aa8c0c0699f1..c6e6ea1e096af76068f6be6627d27cd95e66cd24 100644 (file)
@@ -9,6 +9,7 @@ LL |     assert_eq!(a, 0);
    |
    = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: you might have forgotten to call this function
+  --> $SRC_DIR/core/src/macros/mod.rs:LL:COL
    |
 LL |                 if !(*left_val() == *right_val) {
    |                               ++
index f1ec678b20193fe4d7d196196eca65cb39239ebb..9edf14ef291f9e5d3484c9af459574bd9356addd 100644 (file)
@@ -12,51 +12,60 @@ error[E0283]: type annotations needed
   --> $DIR/issue-72690.rs:7:22
    |
 LL |     String::from("x".as_ref());
-   |                  ----^^^^^^--
-   |                  |   |
-   |                  |   cannot infer type for type parameter `T` declared on the trait `AsRef`
-   |                  this method call resolves to `&T`
+   |                      ^^^^^^
    |
    = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
            - impl AsRef<OsStr> for str;
            - impl AsRef<Path> for str;
            - impl AsRef<[u8]> for str;
            - impl AsRef<str> for str;
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     String::from(<str as AsRef<T>>::as_ref("x"));
+   |                  ++++++++++++++++++++++++++   ~
 
 error[E0282]: type annotations needed
   --> $DIR/issue-72690.rs:12:6
    |
 LL |     |x| String::from("x".as_ref());
-   |      ^ consider giving this closure parameter a type
+   |      ^
+   |
+help: consider giving this closure parameter an explicit type
+   |
+LL |     |x: _| String::from("x".as_ref());
+   |       +++
 
 error[E0283]: type annotations needed
   --> $DIR/issue-72690.rs:12:26
    |
 LL |     |x| String::from("x".as_ref());
-   |                      ----^^^^^^--
-   |                      |   |
-   |                      |   cannot infer type for type parameter `T` declared on the trait `AsRef`
-   |                      this method call resolves to `&T`
+   |                          ^^^^^^
    |
    = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
            - impl AsRef<OsStr> for str;
            - impl AsRef<Path> for str;
            - impl AsRef<[u8]> for str;
            - impl AsRef<str> for str;
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     |x| String::from(<str as AsRef<T>>::as_ref("x"));
+   |                      ++++++++++++++++++++++++++   ~
 
 error[E0283]: type annotations needed for `&T`
-  --> $DIR/issue-72690.rs:17:17
+  --> $DIR/issue-72690.rs:17:9
    |
 LL |     let _ = "x".as_ref();
-   |         -       ^^^^^^ cannot infer type for type parameter `T` declared on the trait `AsRef`
-   |         |
-   |         consider giving this pattern the explicit type `&T`, where the type parameter `T` is specified
+   |         ^
    |
    = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
            - impl AsRef<OsStr> for str;
            - impl AsRef<Path> for str;
            - impl AsRef<[u8]> for str;
            - impl AsRef<str> for str;
+help: consider giving this pattern a type, where the type for type parameter `T` is specified
+   |
+LL |     let _: &T = "x".as_ref();
+   |          ++++
 
 error[E0283]: type annotations needed
   --> $DIR/issue-72690.rs:21:5
@@ -72,16 +81,17 @@ error[E0283]: type annotations needed
   --> $DIR/issue-72690.rs:21:22
    |
 LL |     String::from("x".as_ref());
-   |                  ----^^^^^^--
-   |                  |   |
-   |                  |   cannot infer type for type parameter `T` declared on the trait `AsRef`
-   |                  this method call resolves to `&T`
+   |                      ^^^^^^
    |
    = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
            - impl AsRef<OsStr> for str;
            - impl AsRef<Path> for str;
            - impl AsRef<[u8]> for str;
            - impl AsRef<str> for str;
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     String::from(<str as AsRef<T>>::as_ref("x"));
+   |                  ++++++++++++++++++++++++++   ~
 
 error[E0283]: type annotations needed
   --> $DIR/issue-72690.rs:28:5
@@ -97,16 +107,17 @@ error[E0283]: type annotations needed
   --> $DIR/issue-72690.rs:28:22
    |
 LL |     String::from("x".as_ref());
-   |                  ----^^^^^^--
-   |                  |   |
-   |                  |   cannot infer type for type parameter `T` declared on the trait `AsRef`
-   |                  this method call resolves to `&T`
+   |                      ^^^^^^
    |
    = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
            - impl AsRef<OsStr> for str;
            - impl AsRef<Path> for str;
            - impl AsRef<[u8]> for str;
            - impl AsRef<str> for str;
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     String::from(<str as AsRef<T>>::as_ref("x"));
+   |                  ++++++++++++++++++++++++++   ~
 
 error[E0283]: type annotations needed
   --> $DIR/issue-72690.rs:37:5
@@ -122,16 +133,17 @@ error[E0283]: type annotations needed
   --> $DIR/issue-72690.rs:37:22
    |
 LL |     String::from("x".as_ref());
-   |                  ----^^^^^^--
-   |                  |   |
-   |                  |   cannot infer type for type parameter `T` declared on the trait `AsRef`
-   |                  this method call resolves to `&T`
+   |                      ^^^^^^
    |
    = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
            - impl AsRef<OsStr> for str;
            - impl AsRef<Path> for str;
            - impl AsRef<[u8]> for str;
            - impl AsRef<str> for str;
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     String::from(<str as AsRef<T>>::as_ref("x"));
+   |                  ++++++++++++++++++++++++++   ~
 
 error[E0283]: type annotations needed
   --> $DIR/issue-72690.rs:46:5
@@ -147,16 +159,17 @@ error[E0283]: type annotations needed
   --> $DIR/issue-72690.rs:46:22
    |
 LL |     String::from("x".as_ref());
-   |                  ----^^^^^^--
-   |                  |   |
-   |                  |   cannot infer type for type parameter `T` declared on the trait `AsRef`
-   |                  this method call resolves to `&T`
+   |                      ^^^^^^
    |
    = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
            - impl AsRef<OsStr> for str;
            - impl AsRef<Path> for str;
            - impl AsRef<[u8]> for str;
            - impl AsRef<str> for str;
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     String::from(<str as AsRef<T>>::as_ref("x"));
+   |                  ++++++++++++++++++++++++++   ~
 
 error[E0283]: type annotations needed
   --> $DIR/issue-72690.rs:53:5
@@ -172,16 +185,17 @@ error[E0283]: type annotations needed
   --> $DIR/issue-72690.rs:53:22
    |
 LL |     String::from("x".as_ref());
-   |                  ----^^^^^^--
-   |                  |   |
-   |                  |   cannot infer type for type parameter `T` declared on the trait `AsRef`
-   |                  this method call resolves to `&T`
+   |                      ^^^^^^
    |
    = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
            - impl AsRef<OsStr> for str;
            - impl AsRef<Path> for str;
            - impl AsRef<[u8]> for str;
            - impl AsRef<str> for str;
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     String::from(<str as AsRef<T>>::as_ref("x"));
+   |                  ++++++++++++++++++++++++++   ~
 
 error[E0283]: type annotations needed
   --> $DIR/issue-72690.rs:62:5
@@ -197,16 +211,17 @@ error[E0283]: type annotations needed
   --> $DIR/issue-72690.rs:62:22
    |
 LL |     String::from("x".as_ref());
-   |                  ----^^^^^^--
-   |                  |   |
-   |                  |   cannot infer type for type parameter `T` declared on the trait `AsRef`
-   |                  this method call resolves to `&T`
+   |                      ^^^^^^
    |
    = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
            - impl AsRef<OsStr> for str;
            - impl AsRef<Path> for str;
            - impl AsRef<[u8]> for str;
            - impl AsRef<str> for str;
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     String::from(<str as AsRef<T>>::as_ref("x"));
+   |                  ++++++++++++++++++++++++++   ~
 
 error: aborting due to 17 previous errors
 
index 59be0f3be11e6a2d3a408778bbb3af3a6e9b0999..3aee61bd5a54c047a0afdc6f48380f55a769c1b0 100644 (file)
@@ -1,10 +1,13 @@
 error[E0282]: type annotations needed for `&[_; 0]`
-  --> $DIR/issue-7813.rs:2:13
+  --> $DIR/issue-7813.rs:2:9
    |
 LL |     let v = &[];
-   |         -   ^^^ cannot infer type
-   |         |
-   |         consider giving `v` the explicit type `&[_; 0]`, with the type parameters specified
+   |         ^
+   |
+help: consider giving `v` an explicit type, where the placeholders `_` are specified
+   |
+LL |     let v: &[_; 0] = &[];
+   |          +++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-8153.rs b/src/test/ui/issues/issue-8153.rs
deleted file mode 100644 (file)
index 81a8f53..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-// Test that duplicate methods in impls are not allowed
-
-struct Foo;
-
-trait Bar {
-    fn bar(&self) -> isize;
-}
-
-impl Bar for Foo {
-    fn bar(&self) -> isize {1}
-    fn bar(&self) -> isize {2} //~ ERROR duplicate definitions
-}
-
-fn main() {
-    println!("{}", Foo.bar());
-}
diff --git a/src/test/ui/issues/issue-8153.stderr b/src/test/ui/issues/issue-8153.stderr
deleted file mode 100644 (file)
index 4389c3d..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-error[E0201]: duplicate definitions with name `bar`:
-  --> $DIR/issue-8153.rs:11:5
-   |
-LL |     fn bar(&self) -> isize {1}
-   |     -------------------------- previous definition of `bar` here
-LL |     fn bar(&self) -> isize {2}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ duplicate definition
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0201`.
diff --git a/src/test/ui/iterators/issue-28098.rs b/src/test/ui/iterators/issue-28098.rs
new file mode 100644 (file)
index 0000000..62a90d9
--- /dev/null
@@ -0,0 +1,27 @@
+fn main() {
+    let _ = Iterator::next(&mut ());
+    //~^ ERROR `()` is not an iterator
+    //~| ERROR `()` is not an iterator
+
+    for _ in false {}
+    //~^ ERROR `bool` is not an iterator
+
+    let _ = Iterator::next(&mut ());
+    //~^ ERROR `()` is not an iterator
+
+    other()
+}
+
+pub fn other() {
+    // check errors are still reported globally
+
+    let _ = Iterator::next(&mut ());
+    //~^ ERROR `()` is not an iterator
+    //~| ERROR `()` is not an iterator
+
+    let _ = Iterator::next(&mut ());
+    //~^ ERROR `()` is not an iterator
+
+    for _ in false {}
+    //~^ ERROR `bool` is not an iterator
+}
diff --git a/src/test/ui/iterators/issue-28098.stderr b/src/test/ui/iterators/issue-28098.stderr
new file mode 100644 (file)
index 0000000..3beb992
--- /dev/null
@@ -0,0 +1,77 @@
+error[E0277]: `()` is not an iterator
+  --> $DIR/issue-28098.rs:2:28
+   |
+LL |     let _ = Iterator::next(&mut ());
+   |             -------------- ^^^^^^^ `()` is not an iterator
+   |             |
+   |             required by a bound introduced by this call
+   |
+   = help: the trait `Iterator` is not implemented for `()`
+
+error[E0277]: `bool` is not an iterator
+  --> $DIR/issue-28098.rs:6:14
+   |
+LL |     for _ in false {}
+   |              ^^^^^ `bool` is not an iterator
+   |
+   = help: the trait `Iterator` is not implemented for `bool`
+   = note: required because of the requirements on the impl of `IntoIterator` for `bool`
+
+error[E0277]: `()` is not an iterator
+  --> $DIR/issue-28098.rs:9:28
+   |
+LL |     let _ = Iterator::next(&mut ());
+   |             -------------- ^^^^^^^ `()` is not an iterator
+   |             |
+   |             required by a bound introduced by this call
+   |
+   = help: the trait `Iterator` is not implemented for `()`
+
+error[E0277]: `()` is not an iterator
+  --> $DIR/issue-28098.rs:2:13
+   |
+LL |     let _ = Iterator::next(&mut ());
+   |             ^^^^^^^^^^^^^^ `()` is not an iterator
+   |
+   = help: the trait `Iterator` is not implemented for `()`
+
+error[E0277]: `()` is not an iterator
+  --> $DIR/issue-28098.rs:18:28
+   |
+LL |     let _ = Iterator::next(&mut ());
+   |             -------------- ^^^^^^^ `()` is not an iterator
+   |             |
+   |             required by a bound introduced by this call
+   |
+   = help: the trait `Iterator` is not implemented for `()`
+
+error[E0277]: `()` is not an iterator
+  --> $DIR/issue-28098.rs:22:28
+   |
+LL |     let _ = Iterator::next(&mut ());
+   |             -------------- ^^^^^^^ `()` is not an iterator
+   |             |
+   |             required by a bound introduced by this call
+   |
+   = help: the trait `Iterator` is not implemented for `()`
+
+error[E0277]: `bool` is not an iterator
+  --> $DIR/issue-28098.rs:25:14
+   |
+LL |     for _ in false {}
+   |              ^^^^^ `bool` is not an iterator
+   |
+   = help: the trait `Iterator` is not implemented for `bool`
+   = note: required because of the requirements on the impl of `IntoIterator` for `bool`
+
+error[E0277]: `()` is not an iterator
+  --> $DIR/issue-28098.rs:18:13
+   |
+LL |     let _ = Iterator::next(&mut ());
+   |             ^^^^^^^^^^^^^^ `()` is not an iterator
+   |
+   = help: the trait `Iterator` is not implemented for `()`
+
+error: aborting due to 8 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
index 247d6b0ed71635129b3b7c8604abe5bcaec52954..54ee45c28679a598f37ac0aaa7f3f6958deb1dc7 100644 (file)
@@ -14,6 +14,8 @@ error[E0432]: unresolved import `r#extern`
    |
 LL | use extern::foo;
    |     ^^^^^^ maybe a missing crate `r#extern`?
+   |
+   = help: consider adding `extern crate r#extern` to use the `r#extern` crate
 
 error: aborting due to 2 previous errors
 
index 3b5683a7748fa86ff795d874ff069ac8cd88305a..57f8ca74f83dd4f81fff6dc02264766c46cb0400 100644 (file)
@@ -9,12 +9,7 @@ note: the lint level is defined here
    |
 LL | #![deny(dead_code)]
    |         ^^^^^^^^^
-note: `Enum` has a derived impl for the trait `Clone`, but this is intentionally ignored during dead code analysis
-  --> $DIR/unused-variant.rs:3:10
-   |
-LL | #[derive(Clone)]
-   |          ^^^^^
-   = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: `Enum` has a derived impl for the trait `Clone`, but this is intentionally ignored during dead code analysis
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/lint/rfc-2383-lint-reason/expect_on_fn_params.rs b/src/test/ui/lint/rfc-2383-lint-reason/expect_on_fn_params.rs
new file mode 100644 (file)
index 0000000..5fdb710
--- /dev/null
@@ -0,0 +1,15 @@
+// check-pass
+#![feature(lint_reasons)]
+
+#[warn(unused_variables)]
+
+/// This should catch the unused_variables lint and not emit anything
+fn check_fulfilled_expectation(#[expect(unused_variables)] unused_value: u32) {}
+
+fn check_unfulfilled_expectation(#[expect(unused_variables)] used_value: u32) {
+    //~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations]
+    //~| NOTE `#[warn(unfulfilled_lint_expectations)]` on by default
+    println!("I use the value {used_value}");
+}
+
+fn main() {}
diff --git a/src/test/ui/lint/rfc-2383-lint-reason/expect_on_fn_params.stderr b/src/test/ui/lint/rfc-2383-lint-reason/expect_on_fn_params.stderr
new file mode 100644 (file)
index 0000000..69f7cda
--- /dev/null
@@ -0,0 +1,10 @@
+warning: this lint expectation is unfulfilled
+  --> $DIR/expect_on_fn_params.rs:9:43
+   |
+LL | fn check_unfulfilled_expectation(#[expect(unused_variables)] used_value: u32) {
+   |                                           ^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(unfulfilled_lint_expectations)]` on by default
+
+warning: 1 warning emitted
+
index 4bb1a437d2409c79d5b9dcf04695d6b4f8437c15..85adc9ab3bfbeb583b183770eba5228238904894 100644 (file)
@@ -1,3 +1,12 @@
+warning: label name `'many_used_shadowed` shadows a label name that is already in scope
+  --> $DIR/unused_labels.rs:62:9
+   |
+LL |     'many_used_shadowed: for _ in 0..10 {
+   |     ------------------- first declared here
+LL |
+LL |         'many_used_shadowed: for _ in 0..10 {
+   |         ^^^^^^^^^^^^^^^^^^^ label `'many_used_shadowed` already in scope
+
 warning: unused label
   --> $DIR/unused_labels.rs:11:5
    |
@@ -52,14 +61,5 @@ warning: unused label
 LL |     'unused_block_label: {
    |     ^^^^^^^^^^^^^^^^^^^
 
-warning: label name `'many_used_shadowed` shadows a label name that is already in scope
-  --> $DIR/unused_labels.rs:62:9
-   |
-LL |     'many_used_shadowed: for _ in 0..10 {
-   |     ------------------- first declared here
-LL |
-LL |         'many_used_shadowed: for _ in 0..10 {
-   |         ^^^^^^^^^^^^^^^^^^^ label `'many_used_shadowed` already in scope
-
 warning: 9 warnings emitted
 
diff --git a/src/test/ui/loops/loops-reject-duplicate-labels-2.rs b/src/test/ui/loops/loops-reject-duplicate-labels-2.rs
deleted file mode 100644 (file)
index 68a19a8..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-// check-pass
-#![feature(label_break_value)]
-
-// Issue #21633: reject duplicate loop labels and block labels in function bodies.
-//
-// This is testing the generalization (to the whole function body)
-// discussed here:
-// https://internals.rust-lang.org/t/psa-rejecting-duplicate-loop-labels/1833
-
-#[allow(unused_labels)]
-pub fn foo() {
-    { 'fl: for _ in 0..10 { break; } }
-    { 'fl: loop { break; } }             //~ WARN label name `'fl` shadows a label name that is already in scope
-    { 'lf: loop { break; } }
-    { 'lf: for _ in 0..10 { break; } }   //~ WARN label name `'lf` shadows a label name that is already in scope
-    { 'wl: while 2 > 1 { break; } }
-    { 'wl: loop { break; } }             //~ WARN label name `'wl` shadows a label name that is already in scope
-    { 'lw: loop { break; } }
-    { 'lw: while 2 > 1 { break; } }      //~ WARN label name `'lw` shadows a label name that is already in scope
-    { 'fw: for _ in 0..10 { break; } }
-    { 'fw: while 2 > 1 { break; } }      //~ WARN label name `'fw` shadows a label name that is already in scope
-    { 'wf: while 2 > 1 { break; } }
-    { 'wf: for _ in 0..10 { break; } }   //~ WARN label name `'wf` shadows a label name that is already in scope
-    { 'tl: while let Some(_) = None::<i32> { break; } }
-    { 'tl: loop { break; } }             //~ WARN label name `'tl` shadows a label name that is already in scope
-    { 'lt: loop { break; } }
-    { 'lt: while let Some(_) = None::<i32> { break; } }
-                                         //~^ WARN label name `'lt` shadows a label name that is already in scope
-    { 'bl: {} }
-    { 'bl: {} } //~ WARN label name `'bl` shadows a label name that is already in scope
-}
-
-
-pub fn main() {
-    foo();
-}
diff --git a/src/test/ui/loops/loops-reject-duplicate-labels-2.stderr b/src/test/ui/loops/loops-reject-duplicate-labels-2.stderr
deleted file mode 100644 (file)
index 2c372fc..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-warning: label name `'fl` shadows a label name that is already in scope
-  --> $DIR/loops-reject-duplicate-labels-2.rs:13:7
-   |
-LL |     { 'fl: for _ in 0..10 { break; } }
-   |       --- first declared here
-LL |     { 'fl: loop { break; } }
-   |       ^^^ label `'fl` already in scope
-
-warning: label name `'lf` shadows a label name that is already in scope
-  --> $DIR/loops-reject-duplicate-labels-2.rs:15:7
-   |
-LL |     { 'lf: loop { break; } }
-   |       --- first declared here
-LL |     { 'lf: for _ in 0..10 { break; } }
-   |       ^^^ label `'lf` already in scope
-
-warning: label name `'wl` shadows a label name that is already in scope
-  --> $DIR/loops-reject-duplicate-labels-2.rs:17:7
-   |
-LL |     { 'wl: while 2 > 1 { break; } }
-   |       --- first declared here
-LL |     { 'wl: loop { break; } }
-   |       ^^^ label `'wl` already in scope
-
-warning: label name `'lw` shadows a label name that is already in scope
-  --> $DIR/loops-reject-duplicate-labels-2.rs:19:7
-   |
-LL |     { 'lw: loop { break; } }
-   |       --- first declared here
-LL |     { 'lw: while 2 > 1 { break; } }
-   |       ^^^ label `'lw` already in scope
-
-warning: label name `'fw` shadows a label name that is already in scope
-  --> $DIR/loops-reject-duplicate-labels-2.rs:21:7
-   |
-LL |     { 'fw: for _ in 0..10 { break; } }
-   |       --- first declared here
-LL |     { 'fw: while 2 > 1 { break; } }
-   |       ^^^ label `'fw` already in scope
-
-warning: label name `'wf` shadows a label name that is already in scope
-  --> $DIR/loops-reject-duplicate-labels-2.rs:23:7
-   |
-LL |     { 'wf: while 2 > 1 { break; } }
-   |       --- first declared here
-LL |     { 'wf: for _ in 0..10 { break; } }
-   |       ^^^ label `'wf` already in scope
-
-warning: label name `'tl` shadows a label name that is already in scope
-  --> $DIR/loops-reject-duplicate-labels-2.rs:25:7
-   |
-LL |     { 'tl: while let Some(_) = None::<i32> { break; } }
-   |       --- first declared here
-LL |     { 'tl: loop { break; } }
-   |       ^^^ label `'tl` already in scope
-
-warning: label name `'lt` shadows a label name that is already in scope
-  --> $DIR/loops-reject-duplicate-labels-2.rs:27:7
-   |
-LL |     { 'lt: loop { break; } }
-   |       --- first declared here
-LL |     { 'lt: while let Some(_) = None::<i32> { break; } }
-   |       ^^^ label `'lt` already in scope
-
-warning: label name `'bl` shadows a label name that is already in scope
-  --> $DIR/loops-reject-duplicate-labels-2.rs:30:7
-   |
-LL |     { 'bl: {} }
-   |       --- first declared here
-LL |     { 'bl: {} }
-   |       ^^^ label `'bl` already in scope
-
-warning: 9 warnings emitted
-
diff --git a/src/test/ui/loops/loops-reject-duplicate-labels.rs b/src/test/ui/loops/loops-reject-duplicate-labels.rs
deleted file mode 100644 (file)
index c34bcf3..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-// check-pass
-#![feature(label_break_value)]
-
-// Issue #21633: reject duplicate loop labels and block labels in function bodies.
-
-#[allow(unused_labels)]
-fn foo() {
-    'fl: for _ in 0..10 { break; }
-    'fl: loop { break; }           //~ WARN label name `'fl` shadows a label name that is already in scope
-
-    'lf: loop { break; }
-    'lf: for _ in 0..10 { break; } //~ WARN label name `'lf` shadows a label name that is already in scope
-    'wl: while 2 > 1 { break; }
-    'wl: loop { break; }           //~ WARN label name `'wl` shadows a label name that is already in scope
-    'lw: loop { break; }
-    'lw: while 2 > 1 { break; }    //~ WARN label name `'lw` shadows a label name that is already in scope
-    'fw: for _ in 0..10 { break; }
-    'fw: while 2 > 1 { break; }    //~ WARN label name `'fw` shadows a label name that is already in scope
-    'wf: while 2 > 1 { break; }
-    'wf: for _ in 0..10 { break; } //~ WARN label name `'wf` shadows a label name that is already in scope
-    'tl: while let Some(_) = None::<i32> { break; }
-    'tl: loop { break; }           //~ WARN label name `'tl` shadows a label name that is already in scope
-    'lt: loop { break; }
-    'lt: while let Some(_) = None::<i32> { break; }
-                                   //~^ WARN label name `'lt` shadows a label name that is already in scope
-    'bl: {}
-    'bl: {} //~ WARN label name `'bl` shadows a label name that is already in scope
-}
-
-// Note however that it is okay for the same label to be reused in
-// different methods of one impl, as illustrated here.
-
-struct S;
-impl S {
-    fn m1(&self) { 'okay: loop { break 'okay; } }
-    fn m2(&self) { 'okay: loop { break 'okay; } }
-    fn m3(&self) { 'okay: { break 'okay; } }
-    fn m4(&self) { 'okay: { break 'okay; } }
-}
-
-
-pub fn main() {
-    let s = S;
-    s.m1();
-    s.m2();
-    s.m3();
-    s.m4();
-    foo();
-}
diff --git a/src/test/ui/loops/loops-reject-duplicate-labels.stderr b/src/test/ui/loops/loops-reject-duplicate-labels.stderr
deleted file mode 100644 (file)
index 3bf3af7..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-warning: label name `'fl` shadows a label name that is already in scope
-  --> $DIR/loops-reject-duplicate-labels.rs:9:5
-   |
-LL |     'fl: for _ in 0..10 { break; }
-   |     --- first declared here
-LL |     'fl: loop { break; }
-   |     ^^^ label `'fl` already in scope
-
-warning: label name `'lf` shadows a label name that is already in scope
-  --> $DIR/loops-reject-duplicate-labels.rs:12:5
-   |
-LL |     'lf: loop { break; }
-   |     --- first declared here
-LL |     'lf: for _ in 0..10 { break; }
-   |     ^^^ label `'lf` already in scope
-
-warning: label name `'wl` shadows a label name that is already in scope
-  --> $DIR/loops-reject-duplicate-labels.rs:14:5
-   |
-LL |     'wl: while 2 > 1 { break; }
-   |     --- first declared here
-LL |     'wl: loop { break; }
-   |     ^^^ label `'wl` already in scope
-
-warning: label name `'lw` shadows a label name that is already in scope
-  --> $DIR/loops-reject-duplicate-labels.rs:16:5
-   |
-LL |     'lw: loop { break; }
-   |     --- first declared here
-LL |     'lw: while 2 > 1 { break; }
-   |     ^^^ label `'lw` already in scope
-
-warning: label name `'fw` shadows a label name that is already in scope
-  --> $DIR/loops-reject-duplicate-labels.rs:18:5
-   |
-LL |     'fw: for _ in 0..10 { break; }
-   |     --- first declared here
-LL |     'fw: while 2 > 1 { break; }
-   |     ^^^ label `'fw` already in scope
-
-warning: label name `'wf` shadows a label name that is already in scope
-  --> $DIR/loops-reject-duplicate-labels.rs:20:5
-   |
-LL |     'wf: while 2 > 1 { break; }
-   |     --- first declared here
-LL |     'wf: for _ in 0..10 { break; }
-   |     ^^^ label `'wf` already in scope
-
-warning: label name `'tl` shadows a label name that is already in scope
-  --> $DIR/loops-reject-duplicate-labels.rs:22:5
-   |
-LL |     'tl: while let Some(_) = None::<i32> { break; }
-   |     --- first declared here
-LL |     'tl: loop { break; }
-   |     ^^^ label `'tl` already in scope
-
-warning: label name `'lt` shadows a label name that is already in scope
-  --> $DIR/loops-reject-duplicate-labels.rs:24:5
-   |
-LL |     'lt: loop { break; }
-   |     --- first declared here
-LL |     'lt: while let Some(_) = None::<i32> { break; }
-   |     ^^^ label `'lt` already in scope
-
-warning: label name `'bl` shadows a label name that is already in scope
-  --> $DIR/loops-reject-duplicate-labels.rs:27:5
-   |
-LL |     'bl: {}
-   |     --- first declared here
-LL |     'bl: {}
-   |     ^^^ label `'bl` already in scope
-
-warning: 9 warnings emitted
-
diff --git a/src/test/ui/loops/loops-reject-labels-shadowing-lifetimes.rs b/src/test/ui/loops/loops-reject-labels-shadowing-lifetimes.rs
deleted file mode 100644 (file)
index 741ea0c..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-// Issue #21633: reject duplicate loop labels in function bodies.
-// This is testing interaction between lifetime-params and labels.
-
-// check-pass
-
-#![allow(dead_code, unused_variables)]
-
-fn foo() {
-    fn foo<'a>() {
-        'a: loop { break 'a; }
-        //~^ WARN label name `'a` shadows a lifetime name that is already in scope
-    }
-
-    struct Struct<'b, 'c> { _f: &'b i8, _g: &'c i8 }
-    enum Enum<'d, 'e> { A(&'d i8), B(&'e i8) }
-
-    impl<'d, 'e> Struct<'d, 'e> {
-        fn meth_okay() {
-            'a: loop { break 'a; }
-            'b: loop { break 'b; }
-            'c: loop { break 'c; }
-        }
-    }
-
-    impl <'d, 'e> Enum<'d, 'e> {
-        fn meth_okay() {
-            'a: loop { break 'a; }
-            'b: loop { break 'b; }
-            'c: loop { break 'c; }
-        }
-    }
-
-    impl<'bad, 'c> Struct<'bad, 'c> {
-        fn meth_bad(&self) {
-            'bad: loop { break 'bad; }
-            //~^ WARN label name `'bad` shadows a lifetime name that is already in scope
-        }
-    }
-
-    impl<'b, 'bad> Struct<'b, 'bad> {
-        fn meth_bad2(&self) {
-            'bad: loop { break 'bad; }
-            //~^ WARN label name `'bad` shadows a lifetime name that is already in scope
-        }
-    }
-
-    impl<'b, 'c> Struct<'b, 'c> {
-        fn meth_bad3<'bad>(x: &'bad i8) {
-            'bad: loop { break 'bad; }
-            //~^ WARN label name `'bad` shadows a lifetime name that is already in scope
-        }
-
-        fn meth_bad4<'a,'bad>(x: &'a i8, y: &'bad i8) {
-            'bad: loop { break 'bad; }
-            //~^ WARN label name `'bad` shadows a lifetime name that is already in scope
-        }
-    }
-
-    impl <'bad, 'e> Enum<'bad, 'e> {
-        fn meth_bad(&self) {
-            'bad: loop { break 'bad; }
-            //~^ WARN label name `'bad` shadows a lifetime name that is already in scope
-        }
-    }
-    impl <'d, 'bad> Enum<'d, 'bad> {
-        fn meth_bad2(&self) {
-            'bad: loop { break 'bad; }
-            //~^ WARN label name `'bad` shadows a lifetime name that is already in scope
-        }
-    }
-    impl <'d, 'e> Enum<'d, 'e> {
-        fn meth_bad3<'bad>(x: &'bad i8) {
-            'bad: loop { break 'bad; }
-            //~^ WARN label name `'bad` shadows a lifetime name that is already in scope
-        }
-
-        fn meth_bad4<'a,'bad>(x: &'bad i8) {
-            'bad: loop { break 'bad; }
-            //~^ WARN label name `'bad` shadows a lifetime name that is already in scope
-        }
-    }
-
-    trait HasDefaultMethod1<'bad> {
-        fn meth_okay() {
-            'c: loop { break 'c; }
-        }
-        fn meth_bad(&self) {
-            'bad: loop { break 'bad; }
-            //~^ WARN label name `'bad` shadows a lifetime name that is already in scope
-        }
-    }
-    trait HasDefaultMethod2<'a,'bad> {
-        fn meth_bad(&self) {
-            'bad: loop { break 'bad; }
-            //~^ WARN label name `'bad` shadows a lifetime name that is already in scope
-        }
-    }
-    trait HasDefaultMethod3<'a,'b> {
-        fn meth_bad<'bad>(&self) {
-            'bad: loop { break 'bad; }
-            //~^ WARN label name `'bad` shadows a lifetime name that is already in scope
-        }
-    }
-}
-
-
-pub fn main() {
-    foo();
-}
diff --git a/src/test/ui/loops/loops-reject-labels-shadowing-lifetimes.stderr b/src/test/ui/loops/loops-reject-labels-shadowing-lifetimes.stderr
deleted file mode 100644 (file)
index 0d96c0b..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-warning: label name `'a` shadows a lifetime name that is already in scope
-  --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:10:9
-   |
-LL |     fn foo<'a>() {
-   |            -- first declared here
-LL |         'a: loop { break 'a; }
-   |         ^^ lifetime `'a` already in scope
-
-warning: label name `'bad` shadows a lifetime name that is already in scope
-  --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:35:13
-   |
-LL |     impl<'bad, 'c> Struct<'bad, 'c> {
-   |          ---- first declared here
-LL |         fn meth_bad(&self) {
-LL |             'bad: loop { break 'bad; }
-   |             ^^^^ lifetime `'bad` already in scope
-
-warning: label name `'bad` shadows a lifetime name that is already in scope
-  --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:42:13
-   |
-LL |     impl<'b, 'bad> Struct<'b, 'bad> {
-   |              ---- first declared here
-LL |         fn meth_bad2(&self) {
-LL |             'bad: loop { break 'bad; }
-   |             ^^^^ lifetime `'bad` already in scope
-
-warning: label name `'bad` shadows a lifetime name that is already in scope
-  --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:49:13
-   |
-LL |         fn meth_bad3<'bad>(x: &'bad i8) {
-   |                      ---- first declared here
-LL |             'bad: loop { break 'bad; }
-   |             ^^^^ lifetime `'bad` already in scope
-
-warning: label name `'bad` shadows a lifetime name that is already in scope
-  --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:54:13
-   |
-LL |         fn meth_bad4<'a,'bad>(x: &'a i8, y: &'bad i8) {
-   |                         ---- first declared here
-LL |             'bad: loop { break 'bad; }
-   |             ^^^^ lifetime `'bad` already in scope
-
-warning: label name `'bad` shadows a lifetime name that is already in scope
-  --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:61:13
-   |
-LL |     impl <'bad, 'e> Enum<'bad, 'e> {
-   |           ---- first declared here
-LL |         fn meth_bad(&self) {
-LL |             'bad: loop { break 'bad; }
-   |             ^^^^ lifetime `'bad` already in scope
-
-warning: label name `'bad` shadows a lifetime name that is already in scope
-  --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:67:13
-   |
-LL |     impl <'d, 'bad> Enum<'d, 'bad> {
-   |               ---- first declared here
-LL |         fn meth_bad2(&self) {
-LL |             'bad: loop { break 'bad; }
-   |             ^^^^ lifetime `'bad` already in scope
-
-warning: label name `'bad` shadows a lifetime name that is already in scope
-  --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:73:13
-   |
-LL |         fn meth_bad3<'bad>(x: &'bad i8) {
-   |                      ---- first declared here
-LL |             'bad: loop { break 'bad; }
-   |             ^^^^ lifetime `'bad` already in scope
-
-warning: label name `'bad` shadows a lifetime name that is already in scope
-  --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:78:13
-   |
-LL |         fn meth_bad4<'a,'bad>(x: &'bad i8) {
-   |                         ---- first declared here
-LL |             'bad: loop { break 'bad; }
-   |             ^^^^ lifetime `'bad` already in scope
-
-warning: label name `'bad` shadows a lifetime name that is already in scope
-  --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:88:13
-   |
-LL |     trait HasDefaultMethod1<'bad> {
-   |                             ---- first declared here
-...
-LL |             'bad: loop { break 'bad; }
-   |             ^^^^ lifetime `'bad` already in scope
-
-warning: label name `'bad` shadows a lifetime name that is already in scope
-  --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:94:13
-   |
-LL |     trait HasDefaultMethod2<'a,'bad> {
-   |                                ---- first declared here
-LL |         fn meth_bad(&self) {
-LL |             'bad: loop { break 'bad; }
-   |             ^^^^ lifetime `'bad` already in scope
-
-warning: label name `'bad` shadows a lifetime name that is already in scope
-  --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:100:13
-   |
-LL |         fn meth_bad<'bad>(&self) {
-   |                     ---- first declared here
-LL |             'bad: loop { break 'bad; }
-   |             ^^^^ lifetime `'bad` already in scope
-
-warning: 12 warnings emitted
-
diff --git a/src/test/ui/loops/loops-reject-lifetime-shadowing-label.rs b/src/test/ui/loops/loops-reject-lifetime-shadowing-label.rs
deleted file mode 100644 (file)
index ce2d07e..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-// check-pass
-#![feature(label_break_value)]
-#![allow(dead_code, unused_variables)]
-
-// Issue #21633:  reject duplicate loop labels and block labels in function bodies.
-//
-// Test rejection of lifetimes in *expressions* that shadow labels.
-
-fn foo() {
-    // Reusing lifetime `'a` in function item is okay.
-    fn foo<'a>(x: &'a i8) -> i8 { *x }
-
-    // So is reusing `'a` in struct item
-    struct S1<'a> { x: &'a i8 } impl<'a> S1<'a> { fn m(&self) {} }
-    // and a method item
-    struct S2; impl S2 { fn m<'a>(&self) {} }
-
-    let z = 3_i8;
-
-    'a: loop {
-        let b = Box::new(|x: &i8| *x) as Box<dyn for <'a> Fn(&'a i8) -> i8>;
-        //~^ WARN lifetime name `'a` shadows a label name that is already in scope
-        assert_eq!((*b)(&z), z);
-        break 'a;
-    }
-
-    'b: {
-        let b = Box::new(|x: &()| ()) as Box<dyn for <'b> Fn(&'b ())>;
-        //~^ WARN lifetime name `'b` shadows a label name that is already in scope
-        break 'b;
-    }
-}
-
-pub fn main() {
-    foo();
-}
diff --git a/src/test/ui/loops/loops-reject-lifetime-shadowing-label.stderr b/src/test/ui/loops/loops-reject-lifetime-shadowing-label.stderr
deleted file mode 100644 (file)
index 9702b71..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-warning: lifetime name `'a` shadows a label name that is already in scope
-  --> $DIR/loops-reject-lifetime-shadowing-label.rs:21:55
-   |
-LL |     'a: loop {
-   |     -- first declared here
-LL |         let b = Box::new(|x: &i8| *x) as Box<dyn for <'a> Fn(&'a i8) -> i8>;
-   |                                                       ^^ label `'a` already in scope
-
-warning: lifetime name `'b` shadows a label name that is already in scope
-  --> $DIR/loops-reject-lifetime-shadowing-label.rs:28:55
-   |
-LL |     'b: {
-   |     -- first declared here
-LL |         let b = Box::new(|x: &()| ()) as Box<dyn for <'b> Fn(&'b ())>;
-   |                                                       ^^ label `'b` already in scope
-
-warning: 2 warnings emitted
-
index 2e9da6f9dc88c4cbce392717a3740df743cd43fb..59017da3b696ee3385502b1322673683efecd574 100644 (file)
@@ -18,7 +18,7 @@ macro_rules! br {
 }
 macro_rules! br2 {
     ($b:lifetime) => {
-        'b: loop { //~ WARNING `'b` shadows a label name that is already in scope
+        'b: loop {
             break $b; // this $b should refer to the outer loop.
         }
     }
diff --git a/src/test/ui/macros/macro-lifetime-used-with-labels.stderr b/src/test/ui/macros/macro-lifetime-used-with-labels.stderr
deleted file mode 100644 (file)
index 69334e2..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-warning: label name `'b` shadows a label name that is already in scope
-  --> $DIR/macro-lifetime-used-with-labels.rs:21:9
-   |
-LL |         'b: loop {
-   |         ^^ label `'b` already in scope
-...
-LL |     'b: loop {
-   |     -- first declared here
-LL |         br2!('b);
-   |         -------- in this macro invocation
-   |
-   = note: this warning originates in the macro `br2` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: 1 warning emitted
-
diff --git a/src/test/ui/match/issue-11319.rs b/src/test/ui/match/issue-11319.rs
new file mode 100644 (file)
index 0000000..ab69ab2
--- /dev/null
@@ -0,0 +1,13 @@
+fn main() {
+    match Some(10) {
+    //~^ NOTE `match` arms have incompatible types
+        Some(5) => false,
+        //~^ NOTE this is found to be of type `bool`
+        Some(2) => true,
+        //~^ NOTE this is found to be of type `bool`
+        None    => (),
+        //~^ ERROR `match` arms have incompatible types
+        //~| NOTE expected `bool`, found `()`
+        _       => true
+    }
+}
diff --git a/src/test/ui/match/issue-11319.stderr b/src/test/ui/match/issue-11319.stderr
new file mode 100644 (file)
index 0000000..fc44205
--- /dev/null
@@ -0,0 +1,21 @@
+error[E0308]: `match` arms have incompatible types
+  --> $DIR/issue-11319.rs:8:20
+   |
+LL | /     match Some(10) {
+LL | |
+LL | |         Some(5) => false,
+   | |                    ----- this is found to be of type `bool`
+LL | |
+LL | |         Some(2) => true,
+   | |                    ---- this is found to be of type `bool`
+LL | |
+LL | |         None    => (),
+   | |                    ^^ expected `bool`, found `()`
+...  |
+LL | |         _       => true
+LL | |     }
+   | |_____- `match` arms have incompatible types
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
index 77df9921b754ac197d295029eac40558cc31e42b..9eadb88a8ba814d6ce7b6fa01365f3f2571c0ac8 100644 (file)
@@ -2,7 +2,12 @@ error[E0282]: type annotations needed
   --> $DIR/match-unresolved-one-arm.rs:4:9
    |
 LL |     let x = match () {
-   |         ^ consider giving `x` a type
+   |         ^
+   |
+help: consider giving `x` an explicit type
+   |
+LL |     let x: _ = match () {
+   |          +++
 
 error: aborting due to previous error
 
index f33672433dee41c028d158f99d364d79c5d37ca3..66e7ada3ac5fd9d43b20f7aba0cd4eb53d5b61fb 100644 (file)
@@ -1,10 +1,13 @@
 error[E0282]: type annotations needed for `Vec<T>`
-  --> $DIR/method-ambig-one-trait-unknown-int-type.rs:24:17
+  --> $DIR/method-ambig-one-trait-unknown-int-type.rs:24:9
    |
 LL |     let mut x = Vec::new();
-   |         -----   ^^^^^^^^ cannot infer type for type parameter `T`
-   |         |
-   |         consider giving `x` the explicit type `Vec<T>`, where the type parameter `T` is specified
+   |         ^^^^^
+   |
+help: consider giving `x` an explicit type, where the type for type parameter `T` is specified
+   |
+LL |     let mut x: Vec<T> = Vec::new();
+   |              ++++++++
 
 error[E0283]: type annotations needed
   --> $DIR/method-ambig-one-trait-unknown-int-type.rs:26:7
index 09978b35f7e8a10df591bb901aeef37ea8e9ff62..0af58bc61f49ea88416d71682d3c51229927efe8 100644 (file)
@@ -46,6 +46,7 @@ LL |     bar.pow(2);
    |         ^^^
    |
 help: you must specify a type for this binding, like `i32`
+  --> $DIR/auxiliary/macro-in-other-crate.rs:3:29
    |
 LL |     ($ident:ident) => { let $ident: i32 = 42; }
    |                             ~~~~~~~~~~~
index 2aa2b0e6a3c2c062071485cf219f489948fd4c30..722539fca6b8e228686ef120c9b798bafe975ef9 100644 (file)
@@ -2,13 +2,12 @@ error[E0282]: type annotations needed
   --> $DIR/missing-type-parameter.rs:4:5
    |
 LL |     foo();
-   |     ^^^ cannot infer type for type parameter `X` declared on the function `foo`
+   |     ^^^ cannot infer type of the type parameter `X` declared on the function `foo`
    |
-help: type parameter declared here
-  --> $DIR/missing-type-parameter.rs:1:8
+help: consider specifying the generic argument
    |
-LL | fn foo<X>() { }
-   |        ^
+LL |     foo::<X>();
+   |        +++++
 
 error: aborting due to previous error
 
index 9328d1a9045e57b4483d7cd1a5ce01e8f48217df..959024c46f4ffe601e9e52c22b822f65abe15dbc 100644 (file)
@@ -5,5 +5,5 @@ mod Mod {
 fn main() {
     Mod::FakeVariant::<i32>(0);
     Mod::<i32>::FakeVariant(0);
-    //~^ ERROR type arguments are not allowed for this type [E0109]
+    //~^ ERROR type arguments are not allowed on module `Mod` [E0109]
 }
index d6815c91e5e9ec477ea32e3dcb736961d431fbba..15da1d155a337fc17a2a26a3fa81ba91f350dfae 100644 (file)
@@ -1,8 +1,10 @@
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on module `Mod`
   --> $DIR/mod-subitem-as-enum-variant.rs:7:11
    |
 LL |     Mod::<i32>::FakeVariant(0);
-   |           ^^^ type argument not allowed
+   |     ---   ^^^ type argument not allowed
+   |     |
+   |     not allowed on this
 
 error: aborting due to previous error
 
index ba1b745ba84229115cbcd68041bef850ab1f8fa2..45acf5beb121794ed3797b639a4d99db49d60efd 100644 (file)
@@ -21,7 +21,7 @@ fn duplicate_tup2<A: Copy, B: Copy>(t: (A, B)) -> ((A, B), (A, B)) {
     (t, t) //~ use of moved value: `t`
 }
 
-fn duplicate_custom<T: Trait + Copy>(t: S<T>) -> (S<T>, S<T>) {
+fn duplicate_custom<T: Copy + Trait>(t: S<T>) -> (S<T>, S<T>) {
     //~^ HELP consider restricting type parameter `T`
     (t, t) //~ use of moved value: `t`
 }
@@ -39,14 +39,14 @@ trait A {}
 trait B {}
 
 // Test where bounds are added with different bound placements
-fn duplicate_custom_1<T: Trait + Copy>(t: S<T>) -> (S<T>, S<T>) where {
+fn duplicate_custom_1<T: Copy + Trait>(t: S<T>) -> (S<T>, S<T>) where {
     //~^ HELP consider restricting type parameter `T`
     (t, t) //~ use of moved value: `t`
 }
 
 fn duplicate_custom_2<T>(t: S<T>) -> (S<T>, S<T>)
 where
-    T: A + Trait + Copy,
+    T: A + Copy + Trait,
     //~^ HELP consider further restricting this bound
 {
     (t, t) //~ use of moved value: `t`
@@ -54,14 +54,14 @@ where
 
 fn duplicate_custom_3<T>(t: S<T>) -> (S<T>, S<T>)
 where
-    T: A + Trait + Copy,
+    T: A + Copy + Trait,
     //~^ HELP consider further restricting this bound
     T: B,
 {
     (t, t) //~ use of moved value: `t`
 }
 
-fn duplicate_custom_4<T: A + Trait + Copy>(t: S<T>) -> (S<T>, S<T>)
+fn duplicate_custom_4<T: A + Copy + Trait>(t: S<T>) -> (S<T>, S<T>)
 //~^ HELP consider further restricting this bound
 where
     T: B,
index 2353cd079a3704fab897aab06c24a99f19ae64b2..5a84e3b81a6565e7de14817cb7fbf6dea2fdebf0 100644 (file)
@@ -75,7 +75,7 @@ LL |     (t, t)
    |
 help: consider restricting type parameter `T`
    |
-LL | fn duplicate_custom<T: Trait + Copy>(t: S<T>) -> (S<T>, S<T>) {
+LL | fn duplicate_custom<T: Copy + Trait>(t: S<T>) -> (S<T>, S<T>) {
    |                      ++++++++++++++
 
 error[E0382]: use of moved value: `t`
@@ -91,7 +91,7 @@ LL |     (t, t)
    |
 help: consider restricting type parameter `T`
    |
-LL | fn duplicate_custom_1<T: Trait + Copy>(t: S<T>) -> (S<T>, S<T>) where {
+LL | fn duplicate_custom_1<T: Copy + Trait>(t: S<T>) -> (S<T>, S<T>) where {
    |                        ++++++++++++++
 
 error[E0382]: use of moved value: `t`
@@ -107,7 +107,7 @@ LL |     (t, t)
    |
 help: consider further restricting this bound
    |
-LL |     T: A + Trait + Copy,
+LL |     T: A + Copy + Trait,
    |          ++++++++++++++
 
 error[E0382]: use of moved value: `t`
@@ -123,7 +123,7 @@ LL |     (t, t)
    |
 help: consider further restricting this bound
    |
-LL |     T: A + Trait + Copy,
+LL |     T: A + Copy + Trait,
    |          ++++++++++++++
 
 error[E0382]: use of moved value: `t`
@@ -139,7 +139,7 @@ LL |     (t, t)
    |
 help: consider further restricting this bound
    |
-LL | fn duplicate_custom_4<T: A + Trait + Copy>(t: S<T>) -> (S<T>, S<T>)
+LL | fn duplicate_custom_4<T: A + Copy + Trait>(t: S<T>) -> (S<T>, S<T>)
    |                            ++++++++++++++
 
 error[E0382]: use of moved value: `t`
index 259f378f70b5c825f03fe2e803122f3bee13509c..7b1fac082e42f18a4774857bcdf50a6642a74305 100644 (file)
@@ -4,7 +4,7 @@ error[E0312]: lifetime of reference outlives lifetime of borrowed content...
 LL |         self.y = b.z
    |                  ^^^
    |
-note: ...the reference is valid for the lifetime `'_` as defined here...
+note: ...the reference is valid for the anonymous lifetime as defined here...
   --> $DIR/issue-52742.rs:15:10
    |
 LL | impl Foo<'_, '_> {
index 6828418a78ec1afa0f719a2c7c1395d20d51c9e5..1a2165e0a9dac1578af9ee00974cd4e37901d4a4 100644 (file)
@@ -2,7 +2,7 @@ error: lifetime may not live long enough
   --> $DIR/issue-52742.rs:17:9
    |
 LL |     fn take_bar(&mut self, b: Bar<'_>) {
-   |                 ---------         -- let's call this `'1`
+   |                 ---------  - has type `Bar<'1>`
    |                 |
    |                 has type `&mut Foo<'_, '2>`
 LL |         self.y = b.z
index cc87954732c4e5466ce037eadcada77c93061795..2ec6a7af3f25747af97e73c1ec28ab741c9b9cac 100644 (file)
@@ -14,7 +14,7 @@ note: ...so that reference does not outlive borrowed content
    |
 LL |         Foo { bar }
    |               ^^^
-note: but, the lifetime must be valid for the lifetime `'_` as defined here...
+note: but, the lifetime must be valid for the anonymous lifetime as defined here...
   --> $DIR/issue-55394.rs:11:10
    |
 LL | impl Foo<'_> {
diff --git a/src/test/ui/overloaded/issue-14958.rs b/src/test/ui/overloaded/issue-14958.rs
new file mode 100644 (file)
index 0000000..a12564c
--- /dev/null
@@ -0,0 +1,31 @@
+// run-pass
+// pretty-expanded FIXME #23616
+
+#![feature(fn_traits, unboxed_closures)]
+
+trait Foo { fn dummy(&self) { }}
+
+struct Bar;
+
+impl<'a> std::ops::Fn<(&'a (dyn Foo+'a),)> for Bar {
+    extern "rust-call" fn call(&self, _: (&'a dyn Foo,)) {}
+}
+
+impl<'a> std::ops::FnMut<(&'a (dyn Foo+'a),)> for Bar {
+    extern "rust-call" fn call_mut(&mut self, a: (&'a dyn Foo,)) { self.call(a) }
+}
+
+impl<'a> std::ops::FnOnce<(&'a (dyn Foo+'a),)> for Bar {
+    type Output = ();
+    extern "rust-call" fn call_once(self, a: (&'a dyn Foo,)) { self.call(a) }
+}
+
+struct Baz;
+
+impl Foo for Baz {}
+
+fn main() {
+    let bar = Bar;
+    let baz = &Baz;
+    bar(baz);
+}
diff --git a/src/test/ui/parser/issue-68091-unicode-ident-after-if.rs b/src/test/ui/parser/issue-68091-unicode-ident-after-if.rs
new file mode 100644 (file)
index 0000000..00f90cc
--- /dev/null
@@ -0,0 +1,9 @@
+macro_rules! x {
+    ($($c:tt)*) => {
+        $($c)ö* {} //~ ERROR missing condition for `if` expression
+    };             //~| ERROR mismatched types
+}
+
+fn main() {
+    x!(if);
+}
diff --git a/src/test/ui/parser/issue-68091-unicode-ident-after-if.stderr b/src/test/ui/parser/issue-68091-unicode-ident-after-if.stderr
new file mode 100644 (file)
index 0000000..cdd4c67
--- /dev/null
@@ -0,0 +1,20 @@
+error: missing condition for `if` expression
+  --> $DIR/issue-68091-unicode-ident-after-if.rs:3:14
+   |
+LL |         $($c)ö* {}
+   |              ^ expected if condition here
+
+error[E0308]: mismatched types
+  --> $DIR/issue-68091-unicode-ident-after-if.rs:3:17
+   |
+LL |         $($c)ö* {}
+   |                 ^^ expected `bool`, found `()`
+...
+LL |     x!(if);
+   |     ------ in this macro invocation
+   |
+   = note: this error originates in the macro `x` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/parser/issue-68092-unicode-ident-after-incomplete-expr.rs b/src/test/ui/parser/issue-68092-unicode-ident-after-incomplete-expr.rs
new file mode 100644 (file)
index 0000000..1a90b47
--- /dev/null
@@ -0,0 +1,9 @@
+macro_rules! x {
+    ($($c:tt)*) => {
+        $($c)ö* //~ ERROR macro expansion ends with an incomplete expression: expected expression
+    };
+}
+
+fn main() {
+    x!(!);
+}
diff --git a/src/test/ui/parser/issue-68092-unicode-ident-after-incomplete-expr.stderr b/src/test/ui/parser/issue-68092-unicode-ident-after-incomplete-expr.stderr
new file mode 100644 (file)
index 0000000..0b9c364
--- /dev/null
@@ -0,0 +1,8 @@
+error: macro expansion ends with an incomplete expression: expected expression
+  --> $DIR/issue-68092-unicode-ident-after-incomplete-expr.rs:3:14
+   |
+LL |         $($c)ö*
+   |              ^ expected expression
+
+error: aborting due to previous error
+
index 34f1397ce1d5bb62afeaf5a567a938801b75c092..85c9fe409dbe9f68181902acc62d50267c5c24dd 100644 (file)
@@ -116,7 +116,12 @@ error[E0282]: type annotations needed
   --> $DIR/issue-67377-invalid-syntax-in-enum-discriminant.rs:26:14
    |
 LL |         V = [Vec::new; { [0].len() ].len() as isize,
-   |              ^^^^^^^^ cannot infer type for type parameter `T`
+   |              ^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `Vec`
+   |
+help: consider specifying the generic argument
+   |
+LL |         V = [Vec::<T>::new; { [0].len() ].len() as isize,
+   |                 +++++
 
 error: aborting due to 14 previous errors
 
index 427234e97cf55c2f6f0e7ad2fb5b04cf06764335..bad241634cbe62b94242286000ac42978cff6ef1 100644 (file)
@@ -40,24 +40,26 @@ LL |   let v : Vec<'a> = vec![];
    |                 +
 
 error[E0282]: type annotations needed for `Vec<T>`
-  --> $DIR/missing-closing-angle-bracket-eq-constraint.rs:7:25
+  --> $DIR/missing-closing-angle-bracket-eq-constraint.rs:7:7
    |
 LL |   let v : Vec<(u32,_) = vec![];
-   |       -                 ^^^^^^ cannot infer type for type parameter `T`
-   |       |
-   |       consider giving `v` the explicit type `Vec<T>`, where the type parameter `T` is specified
+   |       ^
+   |
+help: consider giving `v` an explicit type, where the type for type parameter `T` is specified
    |
-   = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
+LL |   let v: Vec<T> : Vec<(u32,_) = vec![];
+   |        ++++++++
 
 error[E0282]: type annotations needed for `Vec<T>`
-  --> $DIR/missing-closing-angle-bracket-eq-constraint.rs:18:20
+  --> $DIR/missing-closing-angle-bracket-eq-constraint.rs:18:7
    |
 LL |   let v : Vec<'a = vec![];
-   |       -            ^^^^^^ cannot infer type for type parameter `T`
-   |       |
-   |       consider giving `v` the explicit type `Vec<T>`, where the type parameter `T` is specified
+   |       ^
+   |
+help: consider giving `v` an explicit type, where the type for type parameter `T` is specified
    |
-   = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
+LL |   let v: Vec<T> : Vec<'a = vec![];
+   |        ++++++++
 
 error: aborting due to 5 previous errors
 
index 01e793e8685993804b4ac61072ec14b55f6da452..98481167a59d1c87ba7a21d706fdcb43608e946d 100644 (file)
@@ -1,8 +1,8 @@
 fn main() {
-    let x;
+    let x; //~ ERROR type annotations needed
 
     match x {
-        (..) => {} //~ ERROR type annotations needed
+        (..) => {}
         _ => {}
     }
 
index 598b6a3794ef72a18d9144547447fbee7fcfe634..11b28987848d6c0458cf830ac1e69ad545bdad80 100644 (file)
@@ -1,13 +1,14 @@
 error[E0282]: type annotations needed
-  --> $DIR/pat-tuple-bad-type.rs:5:9
+  --> $DIR/pat-tuple-bad-type.rs:2:9
    |
 LL |     let x;
-   |         - consider giving `x` a type
-...
-LL |         (..) => {}
-   |         ^^^^ cannot infer type
+   |         ^
    |
    = note: type must be known at this point
+help: consider giving `x` an explicit type
+   |
+LL |     let x: _;
+   |          +++
 
 error[E0308]: mismatched types
   --> $DIR/pat-tuple-bad-type.rs:10:9
index 06b6e80b44f7aca098b99fe304306199f019690b..e6a4e5f19b716ecd44949a0fe713ab756944fc41 100644 (file)
@@ -189,7 +189,12 @@ error[E0282]: type annotations needed
   --> $DIR/rest-pat-semantic-disallowed.rs:33:9
    |
 LL |     let x @ ..;
-   |         ^^^^^^ consider giving this pattern a type
+   |         ^^^^^^
+   |
+help: consider giving this pattern a type
+   |
+LL |     let x @ ..: _;
+   |               +++
 
 error: aborting due to 23 previous errors
 
index 5a85aef2b175b4539bdb77b319b48ce75115be4e..c81520c35cd41d1ac27b36964c6549ac389d02be 100644 (file)
@@ -3,6 +3,8 @@ error[E0433]: failed to resolve: maybe a missing crate `bad`?
    |
 LL |     pub(in bad::path) mod m1 {}
    |            ^^^ maybe a missing crate `bad`?
+   |
+   = help: consider adding `extern crate bad` to use the `bad` crate
 
 error[E0742]: visibilities can only be restricted to ancestor modules
   --> $DIR/test.rs:51:12
index a2e30e2e93b5a63f009dccf6280be1cc887cdd34..2bc34f3c6bfc072a427d6041e3249ce4faa41117 100644 (file)
 
 #[proc_macro]
 pub fn expand_expr_is(input: TokenStream) -> TokenStream {
-    expand_expr_is_inner(input, false)
-}
-
-#[proc_macro]
-pub fn expand_expr_is_trim(input: TokenStream) -> TokenStream {
-    expand_expr_is_inner(input, true)
-}
-
-fn expand_expr_is_inner(input: TokenStream, trim_invisible: bool) -> TokenStream {
     let mut iter = input.into_iter();
     let mut expected_tts = Vec::new();
     loop {
@@ -31,18 +22,14 @@ fn expand_expr_is_inner(input: TokenStream, trim_invisible: bool) -> TokenStream
         }
     }
 
-    // If requested, trim the "invisible" delimiters at the start and end.
-    let expected = expected_tts.into_iter().collect::<TokenStream>().to_string();
-    let expected = if trim_invisible {
-        let len1 = "/*«*/ ".len();
-        let len2 = " /*»*/".len();
-        &expected[len1..expected.len() - len2]
-    } else {
-        &expected[..]
-    };
-    let expanded = iter.collect::<TokenStream>().expand_expr().unwrap().to_string();
-
-    assert_eq!(expected, expanded);
+    let expected = expected_tts.into_iter().collect::<TokenStream>();
+    let expanded = iter.collect::<TokenStream>().expand_expr().expect("expand_expr failed");
+    assert!(
+        expected.to_string() == expanded.to_string(),
+        "assert failed\nexpected: `{}`\nexpanded: `{}`",
+        expected.to_string(),
+        expanded.to_string()
+    );
 
     TokenStream::new()
 }
index 3d0e7eaff00d853f5356582cf0bbb7152163f839..4de8746a1b4602b64cbcbb9c101563dae7f64b31 100644 (file)
@@ -1,5 +1,4 @@
 PRINT-BANG INPUT (DISPLAY): self
-PRINT-BANG RE-COLLECTED (DISPLAY): /*«*/ self /*»*/
 PRINT-BANG INPUT (DEBUG): TokenStream [
     Group {
         delimiter: None,
@@ -14,10 +13,8 @@ PRINT-BANG INPUT (DEBUG): TokenStream [
 ]
 PRINT-BANG INPUT (DISPLAY): 1 + 1, { "a" }, let a = 1;, String, my_name, 'a, my_val = 30,
 std::option::Option, pub(in some::path) , [a b c], -30
-PRINT-BANG RE-COLLECTED (DISPLAY): /*«*/ 1 + 1 /*»*/, /*«*/ { "a" } /*»*/, /*«*/ let a = 1 /*»*/, /*«*/
-String /*»*/, my_name, /*«*/ 'a /*»*/, /*«*/ my_val = 30 /*»*/, /*«*/
-std :: option :: Option /*»*/, /*«*/ pub(in some :: path) /*»*/, [a b c],
-/*«*/ - 30 /*»*/
+PRINT-BANG RE-COLLECTED (DISPLAY): 1 + 1, { "a" }, let a = 1, String, my_name, 'a, my_val = 30,
+std :: option :: Option, pub(in some :: path), [a b c], - 30
 PRINT-BANG INPUT (DEBUG): TokenStream [
     Group {
         delimiter: None,
@@ -298,7 +295,6 @@ PRINT-BANG INPUT (DEBUG): TokenStream [
     },
 ]
 PRINT-BANG INPUT (DISPLAY): (a, b)
-PRINT-BANG RE-COLLECTED (DISPLAY): /*«*/ (a, b) /*»*/
 PRINT-BANG INPUT (DEBUG): TokenStream [
     Group {
         delimiter: None,
index 5fe6ff72b4544a93276baf6f8054cd9f6892b822..7e6b540332c7963c95654412c6378c84e7d01400 100644 (file)
@@ -1,5 +1,5 @@
 PRINT-BANG INPUT (DISPLAY): Vec<u8>
-PRINT-BANG RE-COLLECTED (DISPLAY): /*«*/ Vec < u8 > /*»*/
+PRINT-BANG RE-COLLECTED (DISPLAY): Vec < u8 >
 PRINT-BANG INPUT (DEBUG): TokenStream [
     Group {
         delimiter: None,
index edcb30f892cdf0b359018eccd74bee28a87643f5..d1146d970306264b1485cfc6f243bd51134a62f4 100644 (file)
@@ -2,9 +2,9 @@
 
 extern crate expand_expr;
 
-use expand_expr::{check_expand_expr_file, echo_pm, expand_expr_fail, expand_expr_is};
-use expand_expr::{expand_expr_is_trim, recursive_expand};
-
+use expand_expr::{
+    check_expand_expr_file, echo_pm, expand_expr_fail, expand_expr_is, recursive_expand,
+};
 
 // Check builtin macros can be expanded.
 
@@ -47,21 +47,21 @@ macro_rules! echo_expr {
 
 macro_rules! simple_lit {
     ($l:literal) => {
-        expand_expr_is_trim!($l, $l);
-        expand_expr_is_trim!($l, echo_lit!($l));
-        expand_expr_is_trim!($l, echo_expr!($l));
-        expand_expr_is_trim!($l, echo_tts!($l));
-        expand_expr_is_trim!($l, echo_pm!($l));
+        expand_expr_is!($l, $l);
+        expand_expr_is!($l, echo_lit!($l));
+        expand_expr_is!($l, echo_expr!($l));
+        expand_expr_is!($l, echo_tts!($l));
+        expand_expr_is!($l, echo_pm!($l));
         const _: () = {
             macro_rules! mac {
                 () => {
                     $l
                 };
             }
-            expand_expr_is_trim!($l, mac!());
-            expand_expr_is_trim!($l, echo_expr!(mac!()));
-            expand_expr_is_trim!($l, echo_tts!(mac!()));
-            expand_expr_is_trim!($l, echo_pm!(mac!()));
+            expand_expr_is!($l, mac!());
+            expand_expr_is!($l, echo_expr!(mac!()));
+            expand_expr_is!($l, echo_tts!(mac!()));
+            expand_expr_is!($l, echo_pm!(mac!()));
         };
     };
 }
index 04b516fd254243550031cc841af0047137c05c87..686d53e8876608a322b87badfbd6f4cd5b0b580f 100644 (file)
@@ -1,6 +1,5 @@
 PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = #[allow(warnings)] 0 ; 0 }, }
-PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E
-{ V = { let _ = /*«*/ #[allow(warnings)] #[allow(warnings)] 0 /*»*/ ; 0 }, }
+PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = #[allow(warnings)] #[allow(warnings)] 0 ; 0 }, }
 PRINT-DERIVE INPUT (DEBUG): TokenStream [
     Ident {
         ident: "enum",
@@ -124,7 +123,7 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [
     },
 ]
 PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = { 0; } ; 0 }, }
-PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { /*«*/ 0 /*»*/ } ; 0 }, }
+PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { 0 } ; 0 }, }
 PRINT-DERIVE INPUT (DEBUG): TokenStream [
     Ident {
         ident: "enum",
@@ -204,7 +203,6 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [
     },
 ]
 PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = { {} } ; 0 }, }
-PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { /*«*/ {} /*»*/ } ; 0 }, }
 PRINT-DERIVE INPUT (DEBUG): TokenStream [
     Ident {
         ident: "enum",
@@ -283,7 +281,7 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [
     },
 ]
 PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = { PATH; } ; 0 }, }
-PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { /*«*/ PATH /*»*/ } ; 0 }, }
+PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { PATH } ; 0 }, }
 PRINT-DERIVE INPUT (DEBUG): TokenStream [
     Ident {
         ident: "enum",
@@ -361,7 +359,7 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [
     },
 ]
 PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = { 0 + 1; } ; 0 }, }
-PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { /*«*/ 0 + 1 /*»*/ } ; 0 }, }
+PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { 0 + 1 } ; 0 }, }
 PRINT-DERIVE INPUT (DEBUG): TokenStream [
     Ident {
         ident: "enum",
@@ -452,7 +450,7 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [
     },
 ]
 PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = { PATH + 1; } ; 0 }, }
-PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { /*«*/ PATH + 1 /*»*/ } ; 0 }, }
+PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { PATH + 1 } ; 0 }, }
 PRINT-DERIVE INPUT (DEBUG): TokenStream [
     Ident {
         ident: "enum",
index 55818969c71781c5829b4f67fac0e49d858bed54..0fda6654ff37051f9a4c3c18d72256ee430fb547 100644 (file)
@@ -96,7 +96,6 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
     },
 ]
 PRINT-BANG INPUT (DISPLAY): 1 + 1 * 2
-PRINT-BANG RE-COLLECTED (DISPLAY): /*«*/ 1 + 1 /*»*/ * 2
 PRINT-BANG INPUT (DEBUG): TokenStream [
     Group {
         delimiter: None,
index 6cf8043c34f81fd95307d67482e54782877994af..60a400a5deabfd0d57f6b3d4a1dc338aad28f172 100644 (file)
@@ -1,7 +1,7 @@
 PRINT-BANG INPUT (DISPLAY): foo! { #[fake_attr] mod bar {
     #![doc = r" Foo"]
 } }
-PRINT-BANG DEEP-RE-COLLECTED (DISPLAY): foo! { #[fake_attr] /*«*/ mod bar { #! [doc = r" Foo"] } /*»*/ }
+PRINT-BANG DEEP-RE-COLLECTED (DISPLAY): foo! { #[fake_attr] mod bar { #! [doc = r" Foo"] } }
 PRINT-BANG INPUT (DEBUG): TokenStream [
     Ident {
         ident: "foo",
index adbd653ead4b7e5ddc1b35c455a4bd0caa8ebf66..4b7ed874307d8f6c65dc8ad6cfb139945c6e0876 100644 (file)
@@ -1,5 +1,4 @@
 PRINT-BANG INPUT (DISPLAY): ;
-PRINT-BANG RE-COLLECTED (DISPLAY): /*«*/ ; /*»*/
 PRINT-BANG INPUT (DEBUG): TokenStream [
     Group {
         delimiter: None,
index b912e426d5d993869e647655e92a68158af3a0da..a3d24dd26fe978f19f3dac03d4f96773b613c215 100644 (file)
@@ -1,6 +1,4 @@
 PRINT-BANG INPUT (DISPLAY): 0 + 1 + 2 + 3
-PRINT-BANG RE-COLLECTED (DISPLAY): /*«*/ 0 + 1 + 2 /*»*/ + 3
-PRINT-BANG DEEP-RE-COLLECTED (DISPLAY): /*«*/ /*«*/ /*«*/ 0 /*»*/ + 1 /*»*/ + 2 /*»*/ + 3
 PRINT-BANG INPUT (DEBUG): TokenStream [
     Group {
         delimiter: None,
index 0d2f33b41750d1401c43e0d76dbd7c98d1e58ca8..6b410f0bfb7e3b856c06f1db4deb0e5248aac630 100644 (file)
@@ -1,5 +1,4 @@
 PRINT-BANG INPUT (DISPLAY): "hi" 1 + (25) + 1 (1 + 1)
-PRINT-BANG RE-COLLECTED (DISPLAY): "hi" /*«*/ 1 + (25) + 1 /*»*/ (1 + 1)
 PRINT-BANG INPUT (DEBUG): TokenStream [
     Literal {
         kind: Str,
@@ -72,9 +71,6 @@ PRINT-BANG INPUT (DEBUG): TokenStream [
     },
 ]
 PRINT-BANG INPUT (DISPLAY): "hi" "hello".len() + "world".len() (1 + 1)
-PRINT-BANG RE-COLLECTED (DISPLAY): "hi" /*«*/ "hello".len() + "world".len() /*»*/ (1 + 1)
-PRINT-BANG DEEP-RE-COLLECTED (DISPLAY): "hi" /*«*/ /*«*/ "hello".len() /*»*/ + /*«*/ "world".len() /*»*/ /*»*/
-(1 + 1)
 PRINT-BANG INPUT (DEBUG): TokenStream [
     Literal {
         kind: Str,
index 32981e7011d970a7182718fe542bb120067c1247..4d884348f2ca423df47d1f8aa3b77f28670566a2 100644 (file)
@@ -1,5 +1,5 @@
 PRINT-ATTR_ARGS INPUT (DISPLAY): a, line!(), b
-PRINT-ATTR_ARGS RE-COLLECTED (DISPLAY): a, /*«*/ line! () /*»*/, b
+PRINT-ATTR_ARGS RE-COLLECTED (DISPLAY): a, line! (), b
 PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
     Ident {
         ident: "a",
index ba18ca75d7fe4dc2743da1d8cfda7d9390f7b377..c08e5308138c966deb834cceb151ad98e058099f 100644 (file)
@@ -1,5 +1,5 @@
 PRINT-BANG INPUT (DISPLAY): struct S;
-PRINT-BANG RE-COLLECTED (DISPLAY): /*«*/ struct S ; /*»*/
+PRINT-BANG RE-COLLECTED (DISPLAY): struct S ;
 PRINT-BANG INPUT (DEBUG): TokenStream [
     Group {
         delimiter: None,
index 71e5065a87a8888c63c19e433bc597cb38c55cc9..354657db4db380f5b068a3f04c1e94793b86a5ef 100644 (file)
@@ -8,16 +8,16 @@
 
 macro one($a:expr, $b:expr) {
     two!($a, $b);
-    //~^ ERROR first parent: /*«*/ "hello" /*»*/
-    //~| ERROR second parent: /*«*/ "world" /*»*/
+    //~^ ERROR first parent: "hello"
+    //~| ERROR second parent: "world"
 }
 
 macro two($a:expr, $b:expr) {
     three!($a, $b);
-    //~^ ERROR first final: /*«*/ "hello" /*»*/
-    //~| ERROR second final: /*«*/ "world" /*»*/
-    //~| ERROR first final: /*«*/ "yay" /*»*/
-    //~| ERROR second final: /*«*/ "rust" /*»*/
+    //~^ ERROR first final: "hello"
+    //~| ERROR second final: "world"
+    //~| ERROR first final: "yay"
+    //~| ERROR second final: "rust"
 }
 
 // forwarding tokens directly doesn't create a new source chain
 
 fn main() {
     one!("hello", "world");
-    //~^ ERROR first grandparent: /*«*/ "hello" /*»*/
-    //~| ERROR second grandparent: /*«*/ "world" /*»*/
-    //~| ERROR first source: /*«*/ "hello" /*»*/
-    //~| ERROR second source: /*«*/ "world" /*»*/
+    //~^ ERROR first grandparent: "hello"
+    //~| ERROR second grandparent: "world"
+    //~| ERROR first source: "hello"
+    //~| ERROR second source: "world"
 
     two!("yay", "rust");
-    //~^ ERROR first parent: /*«*/ "yay" /*»*/
-    //~| ERROR second parent: /*«*/ "rust" /*»*/
-    //~| ERROR first source: /*«*/ "yay" /*»*/
-    //~| ERROR second source: /*«*/ "rust" /*»*/
+    //~^ ERROR first parent: "yay"
+    //~| ERROR second parent: "rust"
+    //~| ERROR first source: "yay"
+    //~| ERROR second source: "rust"
 
     three!("hip", "hop");
     //~^ ERROR first final: "hip"
index e42218ea70117b3ed05144b789e5bcf044618870..4548269b507930fb1bd407fbca12afc4f5e9f9a8 100644 (file)
@@ -1,4 +1,4 @@
-error: first final: /*«*/ "hello" /*»*/
+error: first final: "hello"
   --> $DIR/parent-source-spans.rs:16:12
    |
 LL |     three!($a, $b);
@@ -9,7 +9,7 @@ LL |     one!("hello", "world");
    |
    = note: this error originates in the macro `two` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: second final: /*«*/ "world" /*»*/
+error: second final: "world"
   --> $DIR/parent-source-spans.rs:16:16
    |
 LL |     three!($a, $b);
@@ -20,7 +20,7 @@ LL |     one!("hello", "world");
    |
    = note: this error originates in the macro `two` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: first parent: /*«*/ "hello" /*»*/
+error: first parent: "hello"
   --> $DIR/parent-source-spans.rs:10:5
    |
 LL |     two!($a, $b);
@@ -31,7 +31,7 @@ LL |     one!("hello", "world");
    |
    = note: this error originates in the macro `one` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: second parent: /*«*/ "world" /*»*/
+error: second parent: "world"
   --> $DIR/parent-source-spans.rs:10:5
    |
 LL |     two!($a, $b);
@@ -42,31 +42,31 @@ LL |     one!("hello", "world");
    |
    = note: this error originates in the macro `one` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: first grandparent: /*«*/ "hello" /*»*/
+error: first grandparent: "hello"
   --> $DIR/parent-source-spans.rs:36:5
    |
 LL |     one!("hello", "world");
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
-error: second grandparent: /*«*/ "world" /*»*/
+error: second grandparent: "world"
   --> $DIR/parent-source-spans.rs:36:5
    |
 LL |     one!("hello", "world");
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
-error: first source: /*«*/ "hello" /*»*/
+error: first source: "hello"
   --> $DIR/parent-source-spans.rs:36:5
    |
 LL |     one!("hello", "world");
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
-error: second source: /*«*/ "world" /*»*/
+error: second source: "world"
   --> $DIR/parent-source-spans.rs:36:5
    |
 LL |     one!("hello", "world");
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
-error: first final: /*«*/ "yay" /*»*/
+error: first final: "yay"
   --> $DIR/parent-source-spans.rs:16:12
    |
 LL |     three!($a, $b);
@@ -77,7 +77,7 @@ LL |     two!("yay", "rust");
    |
    = note: this error originates in the macro `two` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: second final: /*«*/ "rust" /*»*/
+error: second final: "rust"
   --> $DIR/parent-source-spans.rs:16:16
    |
 LL |     three!($a, $b);
@@ -88,25 +88,25 @@ LL |     two!("yay", "rust");
    |
    = note: this error originates in the macro `two` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: first parent: /*«*/ "yay" /*»*/
+error: first parent: "yay"
   --> $DIR/parent-source-spans.rs:42:5
    |
 LL |     two!("yay", "rust");
    |     ^^^^^^^^^^^^^^^^^^^
 
-error: second parent: /*«*/ "rust" /*»*/
+error: second parent: "rust"
   --> $DIR/parent-source-spans.rs:42:5
    |
 LL |     two!("yay", "rust");
    |     ^^^^^^^^^^^^^^^^^^^
 
-error: first source: /*«*/ "yay" /*»*/
+error: first source: "yay"
   --> $DIR/parent-source-spans.rs:42:5
    |
 LL |     two!("yay", "rust");
    |     ^^^^^^^^^^^^^^^^^^^
 
-error: second source: /*«*/ "rust" /*»*/
+error: second source: "rust"
   --> $DIR/parent-source-spans.rs:42:5
    |
 LL |     two!("yay", "rust");
index f2adf01531569e4a5de3a7ad92385b47cb3395ba..f6616591a3df223db8782e29ff56dffa662e6991 100644 (file)
@@ -1,5 +1,6 @@
-struct Foo<'a, 'a> { //~ ERROR lifetime name `'a` declared twice
-    x: &'a isize
+struct Foo<'a, 'a> {
+    //~^ ERROR the name `'a` is already used for a generic parameter
+    x: &'a isize,
 }
 
 fn main() {}
index a7e03a61adcf59c10804cac62e8f54cb93b24e29..cef73c18d371e458001501012bd26f34fcab1360 100644 (file)
@@ -1,11 +1,11 @@
-error[E0263]: lifetime name `'a` declared twice in the same scope
+error[E0403]: the name `'a` is already used for a generic parameter in this item's generic parameters
   --> $DIR/regions-name-duplicated.rs:1:16
    |
 LL | struct Foo<'a, 'a> {
-   |            --  ^^ declared twice
+   |            --  ^^ already used
    |            |
-   |            previous declaration here
+   |            first use of `'a`
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0263`.
+For more information about this error, try `rustc --explain E0403`.
index f8d65fec3d12def79add8452fc4cf944570a6f25..00cdd0c58f4ec80c040ec92409667471851da6a2 100644 (file)
@@ -3,12 +3,16 @@ error[E0433]: failed to resolve: maybe a missing crate `nonexistant`?
    |
 LL |     fn global_inner(_: ::nonexistant::Foo) {
    |                          ^^^^^^^^^^^ maybe a missing crate `nonexistant`?
+   |
+   = help: consider adding `extern crate nonexistant` to use the `nonexistant` crate
 
 error[E0433]: failed to resolve: maybe a missing crate `nonexistant`?
   --> $DIR/editions-crate-root-2015.rs:7:30
    |
 LL |     fn crate_inner(_: crate::nonexistant::Foo) {
    |                              ^^^^^^^^^^^ maybe a missing crate `nonexistant`?
+   |
+   = help: consider adding `extern crate nonexistant` to use the `nonexistant` crate
 
 error[E0412]: cannot find type `nonexistant` in the crate root
   --> $DIR/editions-crate-root-2015.rs:11:25
index a59f4c952bb083bba92e37ea9b30d41e6b87e83e..a1591914b4d298878bd6c03be274e603e29f00e6 100644 (file)
@@ -3,12 +3,16 @@ error[E0432]: unresolved import `extern_prelude`
    |
 LL |     use extern_prelude::S;
    |         ^^^^^^^^^^^^^^ maybe a missing crate `extern_prelude`?
+   |
+   = help: consider adding `extern crate extern_prelude` to use the `extern_prelude` crate
 
 error[E0433]: failed to resolve: maybe a missing crate `extern_prelude`?
   --> $DIR/extern-prelude-fail.rs:8:15
    |
 LL |     let s = ::extern_prelude::S;
    |               ^^^^^^^^^^^^^^ maybe a missing crate `extern_prelude`?
+   |
+   = help: consider adding `extern crate extern_prelude` to use the `extern_prelude` crate
 
 error: aborting due to 2 previous errors
 
index 7898c2a360f1241df6b6ead0ebbc916805e34f55..730fd6d602645d9af74dd88af6fc12eb43946845 100644 (file)
@@ -3,6 +3,8 @@ error[E0433]: failed to resolve: maybe a missing crate `x`?
    |
 LL | use x::y::z;
    |     ^ maybe a missing crate `x`?
+   |
+   = help: consider adding `extern crate x` to use the `x` crate
 
 error[E0599]: no function or associated item named `z` found for struct `Box<_, _>` in the current scope
   --> $DIR/issue-82865.rs:8:10
index f475c26f32b8fec5f7f6e893c242684d528e4107..f839dd927db999b883504950badb49cf32a914e8 100644 (file)
@@ -17,7 +17,12 @@ error[E0282]: type annotations needed
   --> $DIR/issue-85348.rs:6:13
    |
 LL |         let mut N;
-   |             ^^^^^ consider giving `N` a type
+   |             ^^^^^
+   |
+help: consider giving `N` an explicit type
+   |
+LL |         let mut N: _;
+   |                  +++
 
 error: aborting due to 3 previous errors
 
index 197ecf0cb003916b08e785074ec7dbaaae87b02e..2ac41b87562e10c1784c18468274accf8cb66971 100644 (file)
@@ -21,12 +21,16 @@ error[E0433]: failed to resolve: maybe a missing crate `nonexistent`?
    |
 LL | pub(in nonexistent) struct G;
    |        ^^^^^^^^^^^ maybe a missing crate `nonexistent`?
+   |
+   = help: consider adding `extern crate nonexistent` to use the `nonexistent` crate
 
 error[E0433]: failed to resolve: maybe a missing crate `too_soon`?
   --> $DIR/resolve-bad-visibility.rs:8:8
    |
 LL | pub(in too_soon) struct H;
    |        ^^^^^^^^ maybe a missing crate `too_soon`?
+   |
+   = help: consider adding `extern crate too_soon` to use the `too_soon` crate
 
 error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/rfc-2011-nicer-assert-messages/feature-gate-generic_assert.rs b/src/test/ui/rfc-2011-nicer-assert-messages/feature-gate-generic_assert.rs
new file mode 100644 (file)
index 0000000..f70ca87
--- /dev/null
@@ -0,0 +1,26 @@
+// compile-flags: --test
+// run-pass
+
+// `generic_assert` is completely unimplemented and doesn't generate any logic, thus the
+// reason why this test currently passes
+#![feature(core_intrinsics, generic_assert, generic_assert_internals)]
+
+use std::fmt::{Debug, Formatter};
+
+#[derive(Clone, Copy, PartialEq)]
+struct CopyDebug(i32);
+
+impl Debug for CopyDebug {
+  fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
+    f.write_str("With great power comes great electricity bills")
+  }
+}
+
+#[test]
+fn test() {
+  let _copy_debug = CopyDebug(1);
+  assert!(_copy_debug == CopyDebug(3));
+}
+
+fn main() {
+}
index 6403b3f55c40ccf714e927b592ae41bd44dfbe12..151659e35c0d610b6af3f3e77e6beb08381eb619 100644 (file)
@@ -7,11 +7,11 @@ fn ffi(
         /// Bar
         //~^ ERROR documentation comments cannot be applied to function
         #[must_use]
-        //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in
+        //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
         /// Baz
         //~^ ERROR documentation comments cannot be applied to function
         #[no_mangle] b: i32,
-        //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in
+        //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
     );
 }
 
@@ -23,11 +23,11 @@ fn ffi(
     /// Bar
     //~^ ERROR documentation comments cannot be applied to function
     #[must_use]
-    //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in
+    //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
     /// Baz
     //~^ ERROR documentation comments cannot be applied to function
     #[no_mangle] b: i32,
-    //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in
+    //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
 );
 
 pub fn foo(
@@ -38,11 +38,11 @@ pub fn foo(
     /// Bar
     //~^ ERROR documentation comments cannot be applied to function
     #[must_use]
-    //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in
+    //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
     /// Baz
     //~^ ERROR documentation comments cannot be applied to function
     #[no_mangle] b: i32,
-    //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in
+    //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
 ) {}
 
 struct SelfStruct {}
@@ -58,11 +58,11 @@ fn foo(
         /// Baz
         //~^ ERROR documentation comments cannot be applied to function
         #[must_use]
-        //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in
+        //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
         /// Qux
         //~^ ERROR documentation comments cannot be applied to function
         #[no_mangle] b: i32,
-        //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in
+        //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
     ) {}
 
     fn issue_64682_associated_fn(
@@ -73,11 +73,11 @@ fn issue_64682_associated_fn(
         /// Baz
         //~^ ERROR documentation comments cannot be applied to function
         #[must_use]
-        //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in
+        //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
         /// Qux
         //~^ ERROR documentation comments cannot be applied to function
         #[no_mangle] b: i32,
-        //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in
+        //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
     ) {}
 }
 
@@ -94,11 +94,11 @@ fn foo(
         /// Baz
         //~^ ERROR documentation comments cannot be applied to function
         #[must_use]
-        //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in
+        //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
         /// Qux
         //~^ ERROR documentation comments cannot be applied to function
         #[no_mangle] b: i32,
-        //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in
+        //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
     ) {}
 }
 trait RefTrait {
@@ -113,11 +113,11 @@ fn foo(
         /// Baz
         //~^ ERROR documentation comments cannot be applied to function
         #[must_use]
-        //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in
+        //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
         /// Qux
         //~^ ERROR documentation comments cannot be applied to function
         #[no_mangle] b: i32,
-        //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in
+        //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
     ) {}
 
     fn issue_64682_associated_fn(
@@ -128,11 +128,11 @@ fn issue_64682_associated_fn(
         /// Baz
         //~^ ERROR documentation comments cannot be applied to function
         #[must_use]
-        //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in
+        //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
         /// Qux
         //~^ ERROR documentation comments cannot be applied to function
         #[no_mangle] b: i32,
-        //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in
+        //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
     ) {}
 }
 
@@ -148,11 +148,11 @@ fn foo(
         /// Baz
         //~^ ERROR documentation comments cannot be applied to function
         #[must_use]
-        //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in
+        //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
         /// Qux
         //~^ ERROR documentation comments cannot be applied to function
         #[no_mangle] b: i32,
-        //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in
+        //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
     ) {}
 }
 
@@ -165,10 +165,10 @@ fn main() {
         /// Bar
         //~^ ERROR documentation comments cannot be applied to function
         #[must_use]
-        //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in
+        //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
         /// Baz
         //~^ ERROR documentation comments cannot be applied to function
         #[no_mangle] b: i32
-        //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in
+        //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
     | {};
 }
index edca8cea68d72a9cc7c8d56d27a8d26b6f5891fe..7573e39d8eb0c8070a210b7be5c0baae7b8c7a7f 100644 (file)
@@ -70,7 +70,7 @@ error: documentation comments cannot be applied to function parameters
 LL |         /// Bar
    |         ^^^^^^^ doc comments are not allowed here
 
-error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
+error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
   --> $DIR/param-attrs-builtin-attrs.rs:9:9
    |
 LL |         #[must_use]
@@ -82,7 +82,7 @@ error: documentation comments cannot be applied to function parameters
 LL |         /// Baz
    |         ^^^^^^^ doc comments are not allowed here
 
-error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
+error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
   --> $DIR/param-attrs-builtin-attrs.rs:13:9
    |
 LL |         #[no_mangle] b: i32,
@@ -100,7 +100,7 @@ error: documentation comments cannot be applied to function parameters
 LL |     /// Bar
    |     ^^^^^^^ doc comments are not allowed here
 
-error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
+error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
   --> $DIR/param-attrs-builtin-attrs.rs:25:5
    |
 LL |     #[must_use]
@@ -112,7 +112,7 @@ error: documentation comments cannot be applied to function parameters
 LL |     /// Baz
    |     ^^^^^^^ doc comments are not allowed here
 
-error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
+error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
   --> $DIR/param-attrs-builtin-attrs.rs:29:5
    |
 LL |     #[no_mangle] b: i32,
@@ -130,7 +130,7 @@ error: documentation comments cannot be applied to function parameters
 LL |     /// Bar
    |     ^^^^^^^ doc comments are not allowed here
 
-error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
+error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
   --> $DIR/param-attrs-builtin-attrs.rs:40:5
    |
 LL |     #[must_use]
@@ -142,7 +142,7 @@ error: documentation comments cannot be applied to function parameters
 LL |     /// Baz
    |     ^^^^^^^ doc comments are not allowed here
 
-error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
+error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
   --> $DIR/param-attrs-builtin-attrs.rs:44:5
    |
 LL |     #[no_mangle] b: i32,
@@ -166,7 +166,7 @@ error: documentation comments cannot be applied to function parameters
 LL |         /// Baz
    |         ^^^^^^^ doc comments are not allowed here
 
-error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
+error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
   --> $DIR/param-attrs-builtin-attrs.rs:60:9
    |
 LL |         #[must_use]
@@ -178,7 +178,7 @@ error: documentation comments cannot be applied to function parameters
 LL |         /// Qux
    |         ^^^^^^^ doc comments are not allowed here
 
-error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
+error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
   --> $DIR/param-attrs-builtin-attrs.rs:64:9
    |
 LL |         #[no_mangle] b: i32,
@@ -196,7 +196,7 @@ error: documentation comments cannot be applied to function parameters
 LL |         /// Baz
    |         ^^^^^^^ doc comments are not allowed here
 
-error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
+error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
   --> $DIR/param-attrs-builtin-attrs.rs:75:9
    |
 LL |         #[must_use]
@@ -208,7 +208,7 @@ error: documentation comments cannot be applied to function parameters
 LL |         /// Qux
    |         ^^^^^^^ doc comments are not allowed here
 
-error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
+error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
   --> $DIR/param-attrs-builtin-attrs.rs:79:9
    |
 LL |         #[no_mangle] b: i32,
@@ -232,7 +232,7 @@ error: documentation comments cannot be applied to function parameters
 LL |         /// Baz
    |         ^^^^^^^ doc comments are not allowed here
 
-error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
+error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
   --> $DIR/param-attrs-builtin-attrs.rs:96:9
    |
 LL |         #[must_use]
@@ -244,7 +244,7 @@ error: documentation comments cannot be applied to function parameters
 LL |         /// Qux
    |         ^^^^^^^ doc comments are not allowed here
 
-error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
+error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
   --> $DIR/param-attrs-builtin-attrs.rs:100:9
    |
 LL |         #[no_mangle] b: i32,
@@ -268,7 +268,7 @@ error: documentation comments cannot be applied to function parameters
 LL |         /// Baz
    |         ^^^^^^^ doc comments are not allowed here
 
-error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
+error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
   --> $DIR/param-attrs-builtin-attrs.rs:115:9
    |
 LL |         #[must_use]
@@ -280,7 +280,7 @@ error: documentation comments cannot be applied to function parameters
 LL |         /// Qux
    |         ^^^^^^^ doc comments are not allowed here
 
-error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
+error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
   --> $DIR/param-attrs-builtin-attrs.rs:119:9
    |
 LL |         #[no_mangle] b: i32,
@@ -298,7 +298,7 @@ error: documentation comments cannot be applied to function parameters
 LL |         /// Baz
    |         ^^^^^^^ doc comments are not allowed here
 
-error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
+error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
   --> $DIR/param-attrs-builtin-attrs.rs:130:9
    |
 LL |         #[must_use]
@@ -310,7 +310,7 @@ error: documentation comments cannot be applied to function parameters
 LL |         /// Qux
    |         ^^^^^^^ doc comments are not allowed here
 
-error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
+error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
   --> $DIR/param-attrs-builtin-attrs.rs:134:9
    |
 LL |         #[no_mangle] b: i32,
@@ -334,7 +334,7 @@ error: documentation comments cannot be applied to function parameters
 LL |         /// Baz
    |         ^^^^^^^ doc comments are not allowed here
 
-error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
+error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
   --> $DIR/param-attrs-builtin-attrs.rs:150:9
    |
 LL |         #[must_use]
@@ -346,7 +346,7 @@ error: documentation comments cannot be applied to function parameters
 LL |         /// Qux
    |         ^^^^^^^ doc comments are not allowed here
 
-error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
+error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
   --> $DIR/param-attrs-builtin-attrs.rs:154:9
    |
 LL |         #[no_mangle] b: i32,
@@ -364,7 +364,7 @@ error: documentation comments cannot be applied to function parameters
 LL |         /// Bar
    |         ^^^^^^^ doc comments are not allowed here
 
-error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
+error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
   --> $DIR/param-attrs-builtin-attrs.rs:167:9
    |
 LL |         #[must_use]
@@ -376,7 +376,7 @@ error: documentation comments cannot be applied to function parameters
 LL |         /// Baz
    |         ^^^^^^^ doc comments are not allowed here
 
-error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
+error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
   --> $DIR/param-attrs-builtin-attrs.rs:171:9
    |
 LL |         #[no_mangle] b: i32
index 2b25882be21f15689cb75975a3e4e777c5a6ff40..650a82a23a981c07263bb906eabe0ea801d730ba 100644 (file)
@@ -1,4 +1,4 @@
-error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
+error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
   --> $DIR/check-doc-alias-attr-location.rs:22:12
    |
 LL |     fn foo(#[doc(alias = "qux")] _x: u32) -> Self::X {
index 570a08cb58768ff9c1fc6ded908cade51d391b22..5b8b9bb68ad1e916c397e2413614d6ad3b6baebd 100644 (file)
@@ -2,9 +2,9 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appea
   --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait-async.rs:8:48
    |
 LL |     async fn f(self: Pin<&Self>) -> impl Clone { self }
-   |                          -                     ^^^^^^^^
+   |                          -----                 ^^^^^^^^
    |                          |
-   |                          hidden type `Pin<&Foo>` captures the lifetime `'_` as defined here
+   |                          hidden type `Pin<&Foo>` captures the anonymous lifetime defined here
    |
 help: to declare that the `impl Trait` captures `'_`, you can add an explicit `'_` lifetime bound
    |
index 7985bf266d8e8e10b30fc7a049b3f11d5c58b4e6..d2106630dfed799deade85311de88b7308030239 100644 (file)
@@ -5,6 +5,12 @@ LL |     async fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
    |                                    ----     ----   ^ ...but data from `f` is returned here
    |                                    |
    |                                    this parameter and the return type are declared with different lifetimes...
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn a<'a>(self: Pin<&'a Foo>, f: &'a Foo) -> &Foo { f }
+   |               ++++            ++           ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:15:82
@@ -13,6 +19,12 @@ LL |     async fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (
    |                                     ----              -----------------          ^ ...but data from `f` is returned here
    |                                     |
    |                                     this parameter and the return type are declared with different lifetimes...
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn c<'a>(self: Pin<&'a Self>, f: &'a Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
+   |               ++++            ++            ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:22:64
index 8a55a7c34d77ba44ef7a4f50b2489cbb14148878..3fd58725d02b7fcf3ba0218e83d8156e794d4c14 100644 (file)
@@ -6,6 +6,11 @@ LL |     async fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
    |                          |         |
    |                          |         let's call the lifetime of this reference `'1`
    |                          let's call the lifetime of this reference `'2`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn a<'a>(self: Pin<&'a Foo>, f: &'a Foo) -> &Foo { f }
+   |               ++++            ++           ++
 
 error: lifetime may not live long enough
   --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:15:75
@@ -15,6 +20,11 @@ LL |     async fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (
    |                          |          |
    |                          |          let's call the lifetime of this reference `'1`
    |                          let's call the lifetime of this reference `'2`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn c<'a>(self: Pin<&'a Self>, f: &'a Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
+   |               ++++            ++            ++
 
 error: lifetime may not live long enough
   --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:22:64
index b43854906149a2b996adbdd6b2f22669680cb713..0e2bbcc3c04db4f5eca744dc41570bba4503ebcb 100644 (file)
@@ -7,6 +7,12 @@ LL |     async fn ref_self(&self, f: &u32) -> &u32 {
    |                                 this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn ref_self<'a>(&'a self, f: &'a u32) -> &u32 {
+   |                      ++++  ++           ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/lt-ref-self-async.rs:24:9
@@ -17,6 +23,12 @@ LL |     async fn ref_Self(self: &Self, f: &u32) -> &u32 {
    |                                       this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn ref_Self<'a>(self: &'a Self, f: &'a u32) -> &u32 {
+   |                      ++++        ++           ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/lt-ref-self-async.rs:30:9
@@ -27,6 +39,12 @@ LL |     async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
    |                                                this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_ref_Self<'a>(self: Box<&'a Self>, f: &'a u32) -> &u32 {
+   |                          ++++            ++            ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/lt-ref-self-async.rs:36:9
@@ -37,6 +55,12 @@ LL |     async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
    |                                                this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn pin_ref_Self<'a>(self: Pin<&'a Self>, f: &'a u32) -> &u32 {
+   |                          ++++            ++            ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/lt-ref-self-async.rs:42:9
@@ -47,6 +71,12 @@ LL |     async fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
    |                                                         this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_box_ref_Self<'a>(self: Box<Box<&'a Self>>, f: &'a u32) -> &u32 {
+   |                              ++++                ++             ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/lt-ref-self-async.rs:48:9
@@ -57,6 +87,12 @@ LL |     async fn box_pin_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
    |                                                     this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_pin_Self<'a>(self: Box<Pin<&'a Self>>, f: &'a u32) -> &u32 {
+   |                          ++++                ++             ++
 
 error: aborting due to 6 previous errors
 
index 2ba9a6596f62d8249e5db98c48b7eae77a806d47..1c889838e7082cabbd3c4f95d18bec503f726fb9 100644 (file)
@@ -7,6 +7,11 @@ LL |     async fn ref_self(&self, f: &u32) -> &u32 {
    |                       let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn ref_self<'a>(&'a self, f: &'a u32) -> &u32 {
+   |                      ++++  ++           ++
 
 error: lifetime may not live long enough
   --> $DIR/lt-ref-self-async.rs:24:9
@@ -17,6 +22,11 @@ LL |     async fn ref_Self(self: &Self, f: &u32) -> &u32 {
    |                             let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn ref_Self<'a>(self: &'a Self, f: &'a u32) -> &u32 {
+   |                      ++++        ++           ++
 
 error: lifetime may not live long enough
   --> $DIR/lt-ref-self-async.rs:30:9
@@ -27,6 +37,11 @@ LL |     async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
    |                                     let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_ref_Self<'a>(self: Box<&'a Self>, f: &'a u32) -> &u32 {
+   |                          ++++            ++            ++
 
 error: lifetime may not live long enough
   --> $DIR/lt-ref-self-async.rs:36:9
@@ -37,6 +52,11 @@ LL |     async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
    |                                     let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn pin_ref_Self<'a>(self: Pin<&'a Self>, f: &'a u32) -> &u32 {
+   |                          ++++            ++            ++
 
 error: lifetime may not live long enough
   --> $DIR/lt-ref-self-async.rs:42:9
@@ -47,6 +67,11 @@ LL |     async fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
    |                                             let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_box_ref_Self<'a>(self: Box<Box<&'a Self>>, f: &'a u32) -> &u32 {
+   |                              ++++                ++             ++
 
 error: lifetime may not live long enough
   --> $DIR/lt-ref-self-async.rs:48:9
@@ -57,6 +82,11 @@ LL |     async fn box_pin_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
    |                                         let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_pin_Self<'a>(self: Box<Pin<&'a Self>>, f: &'a u32) -> &u32 {
+   |                          ++++                ++             ++
 
 error: aborting due to 6 previous errors
 
index 851337552c9ad0890f551b2d9d696b7cf61c4a5e..8ffc0d62242129748939bfb5796ce1ad626bca07 100644 (file)
@@ -7,6 +7,12 @@ LL |     async fn ref_self(&mut self, f: &u32) -> &u32 {
    |                                     this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn ref_self<'a>(&'a mut self, f: &'a u32) -> &u32 {
+   |                      ++++  ++               ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-mut-self-async.rs:24:9
@@ -17,6 +23,12 @@ LL |     async fn ref_Self(self: &mut Self, f: &u32) -> &u32 {
    |                                           this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn ref_Self<'a>(self: &'a mut Self, f: &'a u32) -> &u32 {
+   |                      ++++        ++               ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-mut-self-async.rs:30:9
@@ -27,6 +39,12 @@ LL |     async fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 {
    |                                                    this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_ref_Self<'a>(self: Box<&'a mut Self>, f: &'a u32) -> &u32 {
+   |                          ++++            ++                ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-mut-self-async.rs:36:9
@@ -37,6 +55,12 @@ LL |     async fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 {
    |                                                    this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn pin_ref_Self<'a>(self: Pin<&'a mut Self>, f: &'a u32) -> &u32 {
+   |                          ++++            ++                ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-mut-self-async.rs:42:9
@@ -47,6 +71,12 @@ LL |     async fn box_box_ref_Self(self: Box<Box<&mut Self>>, f: &u32) -> &u32 {
    |                                                             this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_box_ref_Self<'a>(self: Box<Box<&'a mut Self>>, f: &'a u32) -> &u32 {
+   |                              ++++                ++                 ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-mut-self-async.rs:48:9
@@ -57,6 +87,12 @@ LL |     async fn box_pin_ref_Self(self: Box<Pin<&mut Self>>, f: &u32) -> &u32 {
    |                                                             this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_pin_ref_Self<'a>(self: Box<Pin<&'a mut Self>>, f: &'a u32) -> &u32 {
+   |                              ++++                ++                 ++
 
 error: aborting due to 6 previous errors
 
index cdd464039cda0501162c7a8f20439f4e9bebbbf6..9beafcd4ff994c3e000e13dfea4c475eaa474831 100644 (file)
@@ -7,6 +7,11 @@ LL |     async fn ref_self(&mut self, f: &u32) -> &u32 {
    |                       let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn ref_self<'a>(&'a mut self, f: &'a u32) -> &u32 {
+   |                      ++++  ++               ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-mut-self-async.rs:24:9
@@ -17,6 +22,11 @@ LL |     async fn ref_Self(self: &mut Self, f: &u32) -> &u32 {
    |                             let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn ref_Self<'a>(self: &'a mut Self, f: &'a u32) -> &u32 {
+   |                      ++++        ++               ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-mut-self-async.rs:30:9
@@ -27,6 +37,11 @@ LL |     async fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 {
    |                                     let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_ref_Self<'a>(self: Box<&'a mut Self>, f: &'a u32) -> &u32 {
+   |                          ++++            ++                ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-mut-self-async.rs:36:9
@@ -37,6 +52,11 @@ LL |     async fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 {
    |                                     let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn pin_ref_Self<'a>(self: Pin<&'a mut Self>, f: &'a u32) -> &u32 {
+   |                          ++++            ++                ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-mut-self-async.rs:42:9
@@ -47,6 +67,11 @@ LL |     async fn box_box_ref_Self(self: Box<Box<&mut Self>>, f: &u32) -> &u32 {
    |                                             let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_box_ref_Self<'a>(self: Box<Box<&'a mut Self>>, f: &'a u32) -> &u32 {
+   |                              ++++                ++                 ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-mut-self-async.rs:48:9
@@ -57,6 +82,11 @@ LL |     async fn box_pin_ref_Self(self: Box<Pin<&mut Self>>, f: &u32) -> &u32 {
    |                                             let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_pin_ref_Self<'a>(self: Box<Pin<&'a mut Self>>, f: &'a u32) -> &u32 {
+   |                              ++++                ++                 ++
 
 error: aborting due to 6 previous errors
 
index 0de11c248758f711a403ceddf31846add2fd34f9..fefb3fc1944393f057946d08ce43e43f72994e80 100644 (file)
@@ -7,6 +7,12 @@ LL |     async fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 {
    |                                               this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn ref_Struct<'a>(self: &'a mut Struct, f: &'a u32) -> &u32 {
+   |                        ++++        ++                 ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-mut-struct-async.rs:22:9
@@ -17,6 +23,12 @@ LL |     async fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 {
    |                                                        this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_ref_Struct<'a>(self: Box<&'a mut Struct>, f: &'a u32) -> &u32 {
+   |                            ++++            ++                  ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-mut-struct-async.rs:28:9
@@ -27,6 +39,12 @@ LL |     async fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 {
    |                                                        this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn pin_ref_Struct<'a>(self: Pin<&'a mut Struct>, f: &'a u32) -> &u32 {
+   |                            ++++            ++                  ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-mut-struct-async.rs:34:9
@@ -37,6 +55,12 @@ LL |     async fn box_box_ref_Struct(self: Box<Box<&mut Struct>>, f: &u32) -> &u
    |                                                                 this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_box_ref_Struct<'a>(self: Box<Box<&'a mut Struct>>, f: &'a u32) -> &u32 {
+   |                                ++++                ++                   ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-mut-struct-async.rs:40:9
@@ -47,6 +71,12 @@ LL |     async fn box_pin_ref_Struct(self: Box<Pin<&mut Struct>>, f: &u32) -> &u
    |                                                                 this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_pin_ref_Struct<'a>(self: Box<Pin<&'a mut Struct>>, f: &'a u32) -> &u32 {
+   |                                ++++                ++                   ++
 
 error: aborting due to 5 previous errors
 
index 0ef410c8df1eb1c0479b10f3bd543026310e25bf..7fbecbe76a5485f1801321187082d8dbed49a8a5 100644 (file)
@@ -7,6 +7,11 @@ LL |     async fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 {
    |                               let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn ref_Struct<'a>(self: &'a mut Struct, f: &'a u32) -> &u32 {
+   |                        ++++        ++                 ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-mut-struct-async.rs:22:9
@@ -17,6 +22,11 @@ LL |     async fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 {
    |                                       let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_ref_Struct<'a>(self: Box<&'a mut Struct>, f: &'a u32) -> &u32 {
+   |                            ++++            ++                  ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-mut-struct-async.rs:28:9
@@ -27,6 +37,11 @@ LL |     async fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 {
    |                                       let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn pin_ref_Struct<'a>(self: Pin<&'a mut Struct>, f: &'a u32) -> &u32 {
+   |                            ++++            ++                  ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-mut-struct-async.rs:34:9
@@ -37,6 +52,11 @@ LL |     async fn box_box_ref_Struct(self: Box<Box<&mut Struct>>, f: &u32) -> &u
    |                                               let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_box_ref_Struct<'a>(self: Box<Box<&'a mut Struct>>, f: &'a u32) -> &u32 {
+   |                                ++++                ++                   ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-mut-struct-async.rs:40:9
@@ -47,6 +67,11 @@ LL |     async fn box_pin_ref_Struct(self: Box<Pin<&mut Struct>>, f: &u32) -> &u
    |                                               let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_pin_ref_Struct<'a>(self: Box<Pin<&'a mut Struct>>, f: &'a u32) -> &u32 {
+   |                                ++++                ++                   ++
 
 error: aborting due to 5 previous errors
 
index fa13b69bb21a3cdf415e97650efd9298b536dbb6..2b142b089d51b423e19457468791371a08fc5e86 100644 (file)
@@ -7,6 +7,12 @@ LL |     async fn ref_self(&self, f: &u32) -> &u32 {
    |                                 this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn ref_self<'a>(&'a self, f: &'a u32) -> &u32 {
+   |                      ++++  ++           ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-self-async.rs:34:9
@@ -17,6 +23,12 @@ LL |     async fn ref_Self(self: &Self, f: &u32) -> &u32 {
    |                                       this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn ref_Self<'a>(self: &'a Self, f: &'a u32) -> &u32 {
+   |                      ++++        ++           ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-self-async.rs:40:9
@@ -27,6 +39,12 @@ LL |     async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
    |                                                this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_ref_Self<'a>(self: Box<&'a Self>, f: &'a u32) -> &u32 {
+   |                          ++++            ++            ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-self-async.rs:46:9
@@ -37,6 +55,12 @@ LL |     async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
    |                                                this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn pin_ref_Self<'a>(self: Pin<&'a Self>, f: &'a u32) -> &u32 {
+   |                          ++++            ++            ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-self-async.rs:52:9
@@ -47,6 +71,12 @@ LL |     async fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
    |                                                         this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_box_ref_Self<'a>(self: Box<Box<&'a Self>>, f: &'a u32) -> &u32 {
+   |                              ++++                ++             ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-self-async.rs:58:9
@@ -57,6 +87,12 @@ LL |     async fn box_pin_ref_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
    |                                                         this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_pin_ref_Self<'a>(self: Box<Pin<&'a Self>>, f: &'a u32) -> &u32 {
+   |                              ++++                ++             ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-self-async.rs:64:9
@@ -67,6 +103,12 @@ LL |     async fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 {
    |                                                             this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn wrap_ref_Self_Self<'a>(self: Wrap<&'a Self, Self>, f: &'a u8) -> &u8 {
+   |                                ++++             ++                  ++
 
 error: aborting due to 7 previous errors
 
index 77faaa866505fb1ae5d8e74ab9a88faa6390b901..f4e531a817c3d067a8acd0a00240164b3f0414e7 100644 (file)
@@ -7,6 +7,11 @@ LL |     async fn ref_self(&self, f: &u32) -> &u32 {
    |                       let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn ref_self<'a>(&'a self, f: &'a u32) -> &u32 {
+   |                      ++++  ++           ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-self-async.rs:34:9
@@ -17,6 +22,11 @@ LL |     async fn ref_Self(self: &Self, f: &u32) -> &u32 {
    |                             let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn ref_Self<'a>(self: &'a Self, f: &'a u32) -> &u32 {
+   |                      ++++        ++           ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-self-async.rs:40:9
@@ -27,6 +37,11 @@ LL |     async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
    |                                     let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_ref_Self<'a>(self: Box<&'a Self>, f: &'a u32) -> &u32 {
+   |                          ++++            ++            ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-self-async.rs:46:9
@@ -37,6 +52,11 @@ LL |     async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
    |                                     let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn pin_ref_Self<'a>(self: Pin<&'a Self>, f: &'a u32) -> &u32 {
+   |                          ++++            ++            ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-self-async.rs:52:9
@@ -47,6 +67,11 @@ LL |     async fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
    |                                             let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_box_ref_Self<'a>(self: Box<Box<&'a Self>>, f: &'a u32) -> &u32 {
+   |                              ++++                ++             ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-self-async.rs:58:9
@@ -57,6 +82,11 @@ LL |     async fn box_pin_ref_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
    |                                             let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_pin_ref_Self<'a>(self: Box<Pin<&'a Self>>, f: &'a u32) -> &u32 {
+   |                              ++++                ++             ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-self-async.rs:64:9
@@ -67,6 +97,11 @@ LL |     async fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 {
    |                                            let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn wrap_ref_Self_Self<'a>(self: Wrap<&'a Self, Self>, f: &'a u8) -> &u8 {
+   |                                ++++             ++                  ++
 
 error: aborting due to 7 previous errors
 
index 8da673d44354efa940ee5a89613dbf06248234d5..88ddca89804f6833085f233684117a2cde1d009d 100644 (file)
@@ -7,6 +7,12 @@ LL |     async fn ref_Struct(self: &Struct, f: &u32) -> &u32 {
    |                                           this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn ref_Struct<'a>(self: &'a Struct, f: &'a u32) -> &u32 {
+   |                        ++++        ++             ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-struct-async.rs:22:9
@@ -17,6 +23,12 @@ LL |     async fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 {
    |                                                    this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_ref_Struct<'a>(self: Box<&'a Struct>, f: &'a u32) -> &u32 {
+   |                            ++++            ++              ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-struct-async.rs:28:9
@@ -27,6 +39,12 @@ LL |     async fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 {
    |                                                    this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn pin_ref_Struct<'a>(self: Pin<&'a Struct>, f: &'a u32) -> &u32 {
+   |                            ++++            ++              ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-struct-async.rs:34:9
@@ -37,6 +55,12 @@ LL |     async fn box_box_ref_Struct(self: Box<Box<&Struct>>, f: &u32) -> &u32 {
    |                                                             this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_box_ref_Struct<'a>(self: Box<Box<&'a Struct>>, f: &'a u32) -> &u32 {
+   |                                ++++                ++               ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-struct-async.rs:40:9
@@ -47,6 +71,12 @@ LL |     async fn box_pin_Struct(self: Box<Pin<&Struct>>, f: &u32) -> &u32 {
    |                                                         this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_pin_Struct<'a>(self: Box<Pin<&'a Struct>>, f: &'a u32) -> &u32 {
+   |                            ++++                ++               ++
 
 error: aborting due to 5 previous errors
 
index ad07c70df87783e1808328de3eb89e9d4ab6f2ff..83c20329c3dad9601a736bf9069a5ac1fe4aa0fd 100644 (file)
@@ -7,6 +7,11 @@ LL |     async fn ref_Struct(self: &Struct, f: &u32) -> &u32 {
    |                               let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn ref_Struct<'a>(self: &'a Struct, f: &'a u32) -> &u32 {
+   |                        ++++        ++             ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-struct-async.rs:22:9
@@ -17,6 +22,11 @@ LL |     async fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 {
    |                                       let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_ref_Struct<'a>(self: Box<&'a Struct>, f: &'a u32) -> &u32 {
+   |                            ++++            ++              ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-struct-async.rs:28:9
@@ -27,6 +37,11 @@ LL |     async fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 {
    |                                       let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn pin_ref_Struct<'a>(self: Pin<&'a Struct>, f: &'a u32) -> &u32 {
+   |                            ++++            ++              ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-struct-async.rs:34:9
@@ -37,6 +52,11 @@ LL |     async fn box_box_ref_Struct(self: Box<Box<&Struct>>, f: &u32) -> &u32 {
    |                                               let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_box_ref_Struct<'a>(self: Box<Box<&'a Struct>>, f: &'a u32) -> &u32 {
+   |                                ++++                ++               ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-struct-async.rs:40:9
@@ -47,6 +67,11 @@ LL |     async fn box_pin_Struct(self: Box<Pin<&Struct>>, f: &u32) -> &u32 {
    |                                           let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_pin_Struct<'a>(self: Box<Pin<&'a Struct>>, f: &'a u32) -> &u32 {
+   |                            ++++                ++               ++
 
 error: aborting due to 5 previous errors
 
index f568aa04295257a4aa3edbe5b90c9322d5ec352a..870f4064de49b57b311ca937940599ba36013c99 100644 (file)
@@ -3,6 +3,8 @@ error[E0433]: failed to resolve: maybe a missing crate `core`?
    |
 LL | use core::simd::intrinsics;
    |     ^^^^ maybe a missing crate `core`?
+   |
+   = help: consider adding `extern crate core` to use the `core` crate
 
 error[E0432]: unresolved import `std::simd::intrinsics`
   --> $DIR/portable-intrinsics-arent-exposed.rs:5:5
index 278d049224401e336ae581a7371a09fc1df014b2..cd3ffdc6f9d60c0ea1012c9a04e576c918170782 100644 (file)
@@ -1,20 +1,26 @@
-error[E0282]: type annotations needed for `Option<_>`
-  --> $DIR/issue-42234-unknown-receiver-type.rs:10:7
+error[E0282]: type annotations needed
+  --> $DIR/issue-42234-unknown-receiver-type.rs:9:24
    |
 LL |     let x: Option<_> = None;
-   |         - consider giving `x` the explicit type `Option<_>`, where the type parameter `T` is specified
-LL |     x.unwrap().method_that_could_exist_on_some_type();
-   |       ^^^^^^ cannot infer type for type parameter `T`
+   |                        ^^^^ cannot infer type of the type parameter `T` declared on the enum `Option`
    |
    = note: type must be known at this point
+help: consider specifying the generic argument
+   |
+LL |     let x: Option<_> = None::<T>;
+   |                            +++++
 
 error[E0282]: type annotations needed
-  --> $DIR/issue-42234-unknown-receiver-type.rs:16:10
+  --> $DIR/issue-42234-unknown-receiver-type.rs:15:10
    |
 LL |         .sum::<_>()
-   |          ^^^ cannot infer type
+   |          ^^^ cannot infer type of the type parameter `S` declared on the associated function `sum`
    |
    = note: type must be known at this point
+help: consider specifying the generic argument
+   |
+LL |         .sum::<_>()
+   |             ~~~~~
 
 error: aborting due to 2 previous errors
 
index 8d4ed4aea6a6c565a1b9c69774e2dc8b16424bc8..b6a3f07f5715f0a243beb7d3d2d37d3270039392 100644 (file)
@@ -1,20 +1,26 @@
-error[E0282]: type annotations needed for `Option<_>`
-  --> $DIR/issue-42234-unknown-receiver-type.rs:10:7
+error[E0282]: type annotations needed
+  --> $DIR/issue-42234-unknown-receiver-type.rs:9:24
    |
 LL |     let x: Option<_> = None;
-   |         - consider giving `x` the explicit type `Option<_>`, where the type parameter `T` is specified
-LL |     x.unwrap().method_that_could_exist_on_some_type();
-   |       ^^^^^^ cannot infer type for type parameter `T`
+   |                        ^^^^ cannot infer type of the type parameter `T` declared on the enum `Option`
    |
    = note: type must be known at this point
+help: consider specifying the generic argument
+   |
+LL |     let x: Option<_> = None::<T>;
+   |                            +++++
 
 error[E0282]: type annotations needed
-  --> $DIR/issue-42234-unknown-receiver-type.rs:16:16
+  --> $DIR/issue-42234-unknown-receiver-type.rs:15:10
    |
 LL |         .sum::<_>()
-   |                ^ cannot infer type for type parameter `S` declared on the associated function `sum`
+   |          ^^^ cannot infer type of the type parameter `S` declared on the associated function `sum`
    |
    = note: type must be known at this point
+help: consider specifying the generic argument
+   |
+LL |         .sum::<S>()
+   |             ~~~~~
 
 error: aborting due to 2 previous errors
 
index 15b00de44b93395b26a18c090be28268201d0d2a..fd53121204c78733598db7153501766b6456b178 100644 (file)
@@ -6,9 +6,8 @@
 // the fix of which this tests).
 
 fn shines_a_beacon_through_the_darkness() {
-    let x: Option<_> = None;
+    let x: Option<_> = None; //~ ERROR type annotations needed
     x.unwrap().method_that_could_exist_on_some_type();
-    //~^ ERROR type annotations needed
 }
 
 fn courier_to_des_moines_and_points_west(data: &[u32]) -> String {
index a38f07d58e47456695546b45093ba4e0a174c59a..a0f0d8810e5c7c6242d1d330e2248f8934767507 100644 (file)
@@ -2,14 +2,14 @@
 
 fn main() {
     let mut x = Default::default();
-    x.0;
     //~^ ERROR type annotations needed
+    x.0;
     x = 1;
 }
 
 fn foo() {
     let mut x = Default::default();
-    x[0];
     //~^ ERROR type annotations needed
+    x[0];
     x = 1;
 }
index 0ecbe4c136e0045fcf24f4166b5d82bb2aaffffc..2dd650f38ce394b92827a33dc477b14cc3519d82 100644 (file)
@@ -1,22 +1,26 @@
 error[E0282]: type annotations needed
-  --> $DIR/method-and-field-eager-resolution.rs:5:5
+  --> $DIR/method-and-field-eager-resolution.rs:4:9
    |
 LL |     let mut x = Default::default();
-   |         ----- consider giving `x` a type
-LL |     x.0;
-   |     ^ cannot infer type
+   |         ^^^^^
    |
    = note: type must be known at this point
+help: consider giving `x` an explicit type
+   |
+LL |     let mut x: _ = Default::default();
+   |              +++
 
 error[E0282]: type annotations needed
-  --> $DIR/method-and-field-eager-resolution.rs:12:5
+  --> $DIR/method-and-field-eager-resolution.rs:11:9
    |
 LL |     let mut x = Default::default();
-   |         ----- consider giving `x` a type
-LL |     x[0];
-   |     ^ cannot infer type
+   |         ^^^^^
    |
    = note: type must be known at this point
+help: consider giving `x` an explicit type
+   |
+LL |     let mut x: _ = Default::default();
+   |              +++
 
 error: aborting due to 2 previous errors
 
index fbfbefd0782024301154c5d55e874ab701df0db7..e4a8f7464626cd0a14fa39a1e5e8de9f2eff9bb6 100644 (file)
@@ -2,10 +2,10 @@ error[E0282]: type annotations needed
   --> $DIR/type-annotations-needed-expr.rs:2:39
    |
 LL |     let _ = (vec![1,2,3]).into_iter().sum() as f64;
-   |                                       ^^^ cannot infer type for type parameter `S` declared on the associated function `sum`
+   |                                       ^^^ cannot infer type of the type parameter `S` declared on the associated function `sum`
    |
    = note: type must be known at this point
-help: consider specifying the type argument in the method call
+help: consider specifying the generic argument
    |
 LL |     let _ = (vec![1,2,3]).into_iter().sum::<S>() as f64;
    |                                          +++++
index e44a203b7832a70e16fa3dfffd163350edc739e3..f88572f8419c03a1590888658bc41458bb5d6100 100644 (file)
@@ -13,7 +13,7 @@ fn f<T: Tr>() {
     //~^ ERROR expected struct, variant or union type, found associated type
     let z = T::A::<u8> {};
     //~^ ERROR expected struct, variant or union type, found associated type
-    //~| ERROR type arguments are not allowed for this type
+    //~| ERROR type arguments are not allowed on this type
     match S {
         T::A {} => {}
         //~^ ERROR expected struct, variant or union type, found associated type
@@ -22,7 +22,7 @@ fn f<T: Tr>() {
 
 fn g<T: Tr<A = S>>() {
     let s = T::A {}; // OK
-    let z = T::A::<u8> {}; //~ ERROR type arguments are not allowed for this type
+    let z = T::A::<u8> {}; //~ ERROR type arguments are not allowed on this type
     match S {
         T::A {} => {} // OK
     }
index 0b1b6a5e3af280b6e111ff3331bbb4ecaa0730dc..7424ceecbe3b63195ab9f00da7dcae7606ad8ac7 100644 (file)
@@ -4,11 +4,13 @@ error[E0071]: expected struct, variant or union type, found associated type
 LL |     let s = T::A {};
    |             ^^^^ not a struct
 
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
   --> $DIR/struct-path-associated-type.rs:14:20
    |
 LL |     let z = T::A::<u8> {};
-   |                    ^^ type argument not allowed
+   |                -   ^^ type argument not allowed
+   |                |
+   |                not allowed on this
 
 error[E0071]: expected struct, variant or union type, found associated type
   --> $DIR/struct-path-associated-type.rs:14:13
@@ -22,11 +24,13 @@ error[E0071]: expected struct, variant or union type, found associated type
 LL |         T::A {} => {}
    |         ^^^^ not a struct
 
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
   --> $DIR/struct-path-associated-type.rs:25:20
    |
 LL |     let z = T::A::<u8> {};
-   |                    ^^ type argument not allowed
+   |                -   ^^ type argument not allowed
+   |                |
+   |                not allowed on this
 
 error[E0223]: ambiguous associated type
   --> $DIR/struct-path-associated-type.rs:32:13
index c938ce8dad98d69a9beef006d41fb432d1b04d49..6e529c7ed2b70c417fc56fafb4a54f9e01fe1613 100644 (file)
@@ -6,7 +6,7 @@ fn f() {
         //~^ ERROR expected struct, variant or union type, found type parameter
         let z = Self::<u8> {};
         //~^ ERROR expected struct, variant or union type, found type parameter
-        //~| ERROR type arguments are not allowed for this type
+        //~| ERROR type arguments are not allowed on self type
         match s {
             Self { .. } => {}
             //~^ ERROR expected struct, variant or union type, found type parameter
@@ -17,7 +17,7 @@ fn f() {
 impl Tr for S {
     fn f() {
         let s = Self {}; // OK
-        let z = Self::<u8> {}; //~ ERROR type arguments are not allowed for this type
+        let z = Self::<u8> {}; //~ ERROR type arguments are not allowed on self type
         match s {
             Self { .. } => {} // OK
         }
@@ -27,7 +27,7 @@ fn f() {
 impl S {
     fn g() {
         let s = Self {}; // OK
-        let z = Self::<u8> {}; //~ ERROR type arguments are not allowed for this type
+        let z = Self::<u8> {}; //~ ERROR type arguments are not allowed on self type
         match s {
             Self { .. } => {} // OK
         }
index 693ed35cbc9c6f219a971fdc56976a45251f9733..cccdd7b0f023ff938575e152b3e88af51fdd60ec 100644 (file)
@@ -4,11 +4,19 @@ error[E0071]: expected struct, variant or union type, found type parameter `Self
 LL |         let s = Self {};
    |                 ^^^^ not a struct
 
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on self type
   --> $DIR/struct-path-self.rs:7:24
    |
 LL |         let z = Self::<u8> {};
-   |                        ^^ type argument not allowed
+   |                 ----   ^^ type argument not allowed
+   |                 |
+   |                 not allowed on this
+   |
+help: the `Self` type doesn't accept type parameters
+   |
+LL -         let z = Self::<u8> {};
+LL +         let z = Self {};
+   | 
 
 error[E0071]: expected struct, variant or union type, found type parameter `Self`
   --> $DIR/struct-path-self.rs:7:17
@@ -22,17 +30,49 @@ error[E0071]: expected struct, variant or union type, found type parameter `Self
 LL |             Self { .. } => {}
    |             ^^^^ not a struct
 
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on self type
   --> $DIR/struct-path-self.rs:20:24
    |
 LL |         let z = Self::<u8> {};
-   |                        ^^ type argument not allowed
+   |                 ----   ^^ type argument not allowed
+   |                 |
+   |                 not allowed on this
+   |
+note: `Self` is of type `S`
+  --> $DIR/struct-path-self.rs:1:8
+   |
+LL | struct S;
+   |        ^ `Self` corresponds to this type, which doesn't have generic parameters
+...
+LL | impl Tr for S {
+   | ------------- `Self` is on type `S` in this `impl`
+help: the `Self` type doesn't accept type parameters
+   |
+LL -         let z = Self::<u8> {};
+LL +         let z = Self {};
+   | 
 
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on self type
   --> $DIR/struct-path-self.rs:30:24
    |
 LL |         let z = Self::<u8> {};
-   |                        ^^ type argument not allowed
+   |                 ----   ^^ type argument not allowed
+   |                 |
+   |                 not allowed on this
+   |
+note: `Self` is of type `S`
+  --> $DIR/struct-path-self.rs:1:8
+   |
+LL | struct S;
+   |        ^ `Self` corresponds to this type, which doesn't have generic parameters
+...
+LL | impl S {
+   | ------ `Self` is on type `S` in this `impl`
+help: the `Self` type doesn't accept type parameters
+   |
+LL -         let z = Self::<u8> {};
+LL +         let z = Self {};
+   | 
 
 error: aborting due to 6 previous errors
 
diff --git a/src/test/ui/suggestions/enum-method-probe.fixed b/src/test/ui/suggestions/enum-method-probe.fixed
new file mode 100644 (file)
index 0000000..6499c92
--- /dev/null
@@ -0,0 +1,59 @@
+// compile-flags: --edition=2021
+// run-rustfix
+
+#![allow(unused)]
+
+struct Foo;
+
+impl Foo {
+    fn get(&self) -> u8 {
+        42
+    }
+}
+
+fn test_result_in_result() -> Result<(), ()> {
+    let res: Result<_, ()> = Ok(Foo);
+    res?.get();
+    //~^ ERROR no method named `get` found for enum `Result` in the current scope
+    //~| HELP use the `?` operator
+    Ok(())
+}
+
+async fn async_test_result_in_result() -> Result<(), ()> {
+    let res: Result<_, ()> = Ok(Foo);
+    res?.get();
+    //~^ ERROR no method named `get` found for enum `Result` in the current scope
+    //~| HELP use the `?` operator
+    Ok(())
+}
+
+fn test_result_in_unit_return() {
+    let res: Result<_, ()> = Ok(Foo);
+    res.expect("REASON").get();
+    //~^ ERROR no method named `get` found for enum `Result` in the current scope
+    //~| HELP consider using `Result::expect` to unwrap the `Foo` value, panicking if the value is a `Result::Err`
+}
+
+async fn async_test_result_in_unit_return() {
+    let res: Result<_, ()> = Ok(Foo);
+    res.expect("REASON").get();
+    //~^ ERROR no method named `get` found for enum `Result` in the current scope
+    //~| HELP consider using `Result::expect` to unwrap the `Foo` value, panicking if the value is a `Result::Err`
+}
+
+fn test_option_in_option() -> Option<()> {
+    let res: Option<_> = Some(Foo);
+    res?.get();
+    //~^ ERROR no method named `get` found for enum `Option` in the current scope
+    //~| HELP use the `?` operator
+    Some(())
+}
+
+fn test_option_in_unit_return() {
+    let res: Option<_> = Some(Foo);
+    res.expect("REASON").get();
+    //~^ ERROR no method named `get` found for enum `Option` in the current scope
+    //~| HELP consider using `Option::expect` to unwrap the `Foo` value, panicking if the value is an `Option::None`
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/enum-method-probe.rs b/src/test/ui/suggestions/enum-method-probe.rs
new file mode 100644 (file)
index 0000000..18ea8ed
--- /dev/null
@@ -0,0 +1,59 @@
+// compile-flags: --edition=2021
+// run-rustfix
+
+#![allow(unused)]
+
+struct Foo;
+
+impl Foo {
+    fn get(&self) -> u8 {
+        42
+    }
+}
+
+fn test_result_in_result() -> Result<(), ()> {
+    let res: Result<_, ()> = Ok(Foo);
+    res.get();
+    //~^ ERROR no method named `get` found for enum `Result` in the current scope
+    //~| HELP use the `?` operator
+    Ok(())
+}
+
+async fn async_test_result_in_result() -> Result<(), ()> {
+    let res: Result<_, ()> = Ok(Foo);
+    res.get();
+    //~^ ERROR no method named `get` found for enum `Result` in the current scope
+    //~| HELP use the `?` operator
+    Ok(())
+}
+
+fn test_result_in_unit_return() {
+    let res: Result<_, ()> = Ok(Foo);
+    res.get();
+    //~^ ERROR no method named `get` found for enum `Result` in the current scope
+    //~| HELP consider using `Result::expect` to unwrap the `Foo` value, panicking if the value is a `Result::Err`
+}
+
+async fn async_test_result_in_unit_return() {
+    let res: Result<_, ()> = Ok(Foo);
+    res.get();
+    //~^ ERROR no method named `get` found for enum `Result` in the current scope
+    //~| HELP consider using `Result::expect` to unwrap the `Foo` value, panicking if the value is a `Result::Err`
+}
+
+fn test_option_in_option() -> Option<()> {
+    let res: Option<_> = Some(Foo);
+    res.get();
+    //~^ ERROR no method named `get` found for enum `Option` in the current scope
+    //~| HELP use the `?` operator
+    Some(())
+}
+
+fn test_option_in_unit_return() {
+    let res: Option<_> = Some(Foo);
+    res.get();
+    //~^ ERROR no method named `get` found for enum `Option` in the current scope
+    //~| HELP consider using `Option::expect` to unwrap the `Foo` value, panicking if the value is an `Option::None`
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/enum-method-probe.stderr b/src/test/ui/suggestions/enum-method-probe.stderr
new file mode 100644 (file)
index 0000000..6ed1498
--- /dev/null
@@ -0,0 +1,99 @@
+error[E0599]: no method named `get` found for enum `Result` in the current scope
+  --> $DIR/enum-method-probe.rs:24:9
+   |
+LL |     res.get();
+   |         ^^^ method not found in `Result<Foo, ()>`
+   |
+note: the method `get` exists on the type `Foo`
+  --> $DIR/enum-method-probe.rs:9:5
+   |
+LL |     fn get(&self) -> u8 {
+   |     ^^^^^^^^^^^^^^^^^^^
+help: use the `?` operator to extract the `Foo` value, propagating a `Result::Err` value to the caller
+   |
+LL |     res?.get();
+   |        +
+
+error[E0599]: no method named `get` found for enum `Result` in the current scope
+  --> $DIR/enum-method-probe.rs:39:9
+   |
+LL |     res.get();
+   |         ^^^ method not found in `Result<Foo, ()>`
+   |
+note: the method `get` exists on the type `Foo`
+  --> $DIR/enum-method-probe.rs:9:5
+   |
+LL |     fn get(&self) -> u8 {
+   |     ^^^^^^^^^^^^^^^^^^^
+help: consider using `Result::expect` to unwrap the `Foo` value, panicking if the value is a `Result::Err`
+   |
+LL |     res.expect("REASON").get();
+   |        +++++++++++++++++
+
+error[E0599]: no method named `get` found for enum `Result` in the current scope
+  --> $DIR/enum-method-probe.rs:16:9
+   |
+LL |     res.get();
+   |         ^^^ method not found in `Result<Foo, ()>`
+   |
+note: the method `get` exists on the type `Foo`
+  --> $DIR/enum-method-probe.rs:9:5
+   |
+LL |     fn get(&self) -> u8 {
+   |     ^^^^^^^^^^^^^^^^^^^
+help: use the `?` operator to extract the `Foo` value, propagating a `Result::Err` value to the caller
+   |
+LL |     res?.get();
+   |        +
+
+error[E0599]: no method named `get` found for enum `Result` in the current scope
+  --> $DIR/enum-method-probe.rs:32:9
+   |
+LL |     res.get();
+   |         ^^^ method not found in `Result<Foo, ()>`
+   |
+note: the method `get` exists on the type `Foo`
+  --> $DIR/enum-method-probe.rs:9:5
+   |
+LL |     fn get(&self) -> u8 {
+   |     ^^^^^^^^^^^^^^^^^^^
+help: consider using `Result::expect` to unwrap the `Foo` value, panicking if the value is a `Result::Err`
+   |
+LL |     res.expect("REASON").get();
+   |        +++++++++++++++++
+
+error[E0599]: no method named `get` found for enum `Option` in the current scope
+  --> $DIR/enum-method-probe.rs:46:9
+   |
+LL |     res.get();
+   |         ^^^ method not found in `Option<Foo>`
+   |
+note: the method `get` exists on the type `Foo`
+  --> $DIR/enum-method-probe.rs:9:5
+   |
+LL |     fn get(&self) -> u8 {
+   |     ^^^^^^^^^^^^^^^^^^^
+help: use the `?` operator to extract the `Foo` value, propagating an `Option::None` value to the caller
+   |
+LL |     res?.get();
+   |        +
+
+error[E0599]: no method named `get` found for enum `Option` in the current scope
+  --> $DIR/enum-method-probe.rs:54:9
+   |
+LL |     res.get();
+   |         ^^^ method not found in `Option<Foo>`
+   |
+note: the method `get` exists on the type `Foo`
+  --> $DIR/enum-method-probe.rs:9:5
+   |
+LL |     fn get(&self) -> u8 {
+   |     ^^^^^^^^^^^^^^^^^^^
+help: consider using `Option::expect` to unwrap the `Foo` value, panicking if the value is an `Option::None`
+   |
+LL |     res.expect("REASON").get();
+   |        +++++++++++++++++
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0599`.
index 2f140f823afb923707f116ba589670d9c35542ae..bcc91b5cb4c56cba73b007766acbc7aa4656caca 100644 (file)
@@ -1,5 +1,7 @@
 fn f<A>() -> A { unimplemented!() }
 fn foo() {
-    let _ = f; //~ ERROR type annotations needed for `fn() -> A`
+    let _ = f;
+    //~^ ERROR type annotations needed
+    //~| HELP consider specifying the generic argument
 }
 fn main() {}
index a4cfee55633731c2c43a6924a26e3f8e76e294f8..9dea667fb961ed4e45304e40016b519e1a7890d8 100644 (file)
@@ -1,16 +1,13 @@
-error[E0282]: type annotations needed for `fn() -> A`
+error[E0282]: type annotations needed
   --> $DIR/fn-needing-specified-return-type-param.rs:3:13
    |
 LL |     let _ = f;
-   |         -   ^ cannot infer type for type parameter `A` declared on the function `f`
-   |         |
-   |         consider giving this pattern the explicit type `fn() -> A`, where the type parameter `A` is specified
+   |             ^ cannot infer type of the type parameter `A` declared on the function `f`
    |
-help: type parameter declared here
-  --> $DIR/fn-needing-specified-return-type-param.rs:1:6
+help: consider specifying the generic argument
    |
-LL | fn f<A>() -> A { unimplemented!() }
-   |      ^
+LL |     let _ = f::<A>;
+   |              +++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/suggestions/missing-bound-in-derive-copy-impl-2.fixed b/src/test/ui/suggestions/missing-bound-in-derive-copy-impl-2.fixed
new file mode 100644 (file)
index 0000000..ac0b14f
--- /dev/null
@@ -0,0 +1,16 @@
+// run-rustfix
+use std::fmt::Debug;
+
+#[derive(Debug, Copy, Clone)]
+pub struct Vector2<T: Debug + Copy + Clone>{
+    pub x: T,
+    pub y: T
+}
+
+#[derive(Debug, Copy, Clone)]
+pub struct AABB<K: Debug + std::marker::Copy>{
+    pub loc: Vector2<K>, //~ ERROR the trait bound `K: Copy` is not satisfied
+    pub size: Vector2<K>
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/missing-bound-in-derive-copy-impl-2.rs b/src/test/ui/suggestions/missing-bound-in-derive-copy-impl-2.rs
new file mode 100644 (file)
index 0000000..31f8cd6
--- /dev/null
@@ -0,0 +1,16 @@
+// run-rustfix
+use std::fmt::Debug;
+
+#[derive(Debug, Copy, Clone)]
+pub struct Vector2<T: Debug + Copy + Clone>{
+    pub x: T,
+    pub y: T
+}
+
+#[derive(Debug, Copy, Clone)]
+pub struct AABB<K: Debug>{
+    pub loc: Vector2<K>, //~ ERROR the trait bound `K: Copy` is not satisfied
+    pub size: Vector2<K>
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/missing-bound-in-derive-copy-impl-2.stderr b/src/test/ui/suggestions/missing-bound-in-derive-copy-impl-2.stderr
new file mode 100644 (file)
index 0000000..03082be
--- /dev/null
@@ -0,0 +1,19 @@
+error[E0277]: the trait bound `K: Copy` is not satisfied
+  --> $DIR/missing-bound-in-derive-copy-impl-2.rs:12:14
+   |
+LL |     pub loc: Vector2<K>,
+   |              ^^^^^^^^^^ the trait `Copy` is not implemented for `K`
+   |
+note: required by a bound in `Vector2`
+  --> $DIR/missing-bound-in-derive-copy-impl-2.rs:5:31
+   |
+LL | pub struct Vector2<T: Debug + Copy + Clone>{
+   |                               ^^^^ required by this bound in `Vector2`
+help: consider further restricting this bound
+   |
+LL | pub struct AABB<K: Debug + std::marker::Copy>{
+   |                          +++++++++++++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/suggestions/missing-bound-in-derive-copy-impl-3.fixed b/src/test/ui/suggestions/missing-bound-in-derive-copy-impl-3.fixed
new file mode 100644 (file)
index 0000000..304360d
--- /dev/null
@@ -0,0 +1,16 @@
+//run-rustfix
+use std::fmt::Debug;
+
+#[derive(Debug, Copy, Clone)]
+pub struct Vector2<T: Debug + Copy + Clone>{
+    pub x: T,
+    pub y: T
+}
+
+#[derive(Debug, Copy, Clone)] //~ ERROR the trait `Copy` may not be implemented for this type
+pub struct AABB<K: Copy + Debug>{
+    pub loc: Vector2<K>,
+    pub size: Vector2<K>
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/missing-bound-in-derive-copy-impl-3.rs b/src/test/ui/suggestions/missing-bound-in-derive-copy-impl-3.rs
new file mode 100644 (file)
index 0000000..14e1fbb
--- /dev/null
@@ -0,0 +1,16 @@
+//run-rustfix
+use std::fmt::Debug;
+
+#[derive(Debug, Copy, Clone)]
+pub struct Vector2<T: Debug + Copy + Clone>{
+    pub x: T,
+    pub y: T
+}
+
+#[derive(Debug, Copy, Clone)] //~ ERROR the trait `Copy` may not be implemented for this type
+pub struct AABB<K: Copy>{
+    pub loc: Vector2<K>,
+    pub size: Vector2<K>
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/missing-bound-in-derive-copy-impl-3.stderr b/src/test/ui/suggestions/missing-bound-in-derive-copy-impl-3.stderr
new file mode 100644 (file)
index 0000000..faf730a
--- /dev/null
@@ -0,0 +1,27 @@
+error[E0204]: the trait `Copy` may not be implemented for this type
+  --> $DIR/missing-bound-in-derive-copy-impl-3.rs:10:17
+   |
+LL | #[derive(Debug, Copy, Clone)]
+   |                 ^^^^
+LL | pub struct AABB<K: Copy>{
+LL |     pub loc: Vector2<K>,
+   |     ------------------- this field does not implement `Copy`
+LL |     pub size: Vector2<K>
+   |     -------------------- this field does not implement `Copy`
+   |
+note: the `Copy` impl for `Vector2<K>` requires that `K: Debug`
+  --> $DIR/missing-bound-in-derive-copy-impl-3.rs:12:14
+   |
+LL |     pub loc: Vector2<K>,
+   |              ^^^^^^^^^^
+LL |     pub size: Vector2<K>
+   |               ^^^^^^^^^^
+   = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider further restricting this bound
+   |
+LL | pub struct AABB<K: Copy + Debug>{
+   |                         +++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0204`.
diff --git a/src/test/ui/suggestions/missing-bound-in-derive-copy-impl.rs b/src/test/ui/suggestions/missing-bound-in-derive-copy-impl.rs
new file mode 100644 (file)
index 0000000..52163bd
--- /dev/null
@@ -0,0 +1,15 @@
+use std::fmt::Debug;
+
+#[derive(Debug, Copy, Clone)]
+pub struct Vector2<T: Debug + Copy + Clone>{
+    pub x: T,
+    pub y: T
+}
+
+#[derive(Debug, Copy, Clone)] //~ ERROR the trait `Copy` may not be implemented for this type
+pub struct AABB<K>{
+    pub loc: Vector2<K>,
+    pub size: Vector2<K>
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/missing-bound-in-derive-copy-impl.stderr b/src/test/ui/suggestions/missing-bound-in-derive-copy-impl.stderr
new file mode 100644 (file)
index 0000000..11bc540
--- /dev/null
@@ -0,0 +1,27 @@
+error[E0204]: the trait `Copy` may not be implemented for this type
+  --> $DIR/missing-bound-in-derive-copy-impl.rs:9:17
+   |
+LL | #[derive(Debug, Copy, Clone)]
+   |                 ^^^^
+LL | pub struct AABB<K>{
+LL |     pub loc: Vector2<K>,
+   |     ------------------- this field does not implement `Copy`
+LL |     pub size: Vector2<K>
+   |     -------------------- this field does not implement `Copy`
+   |
+note: the `Copy` impl for `Vector2<K>` requires that `K: Debug`
+  --> $DIR/missing-bound-in-derive-copy-impl.rs:11:14
+   |
+LL |     pub loc: Vector2<K>,
+   |              ^^^^^^^^^^
+LL |     pub size: Vector2<K>
+   |               ^^^^^^^^^^
+   = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider restricting type parameter `K`
+   |
+LL | pub struct AABB<K: Debug>{
+   |                  +++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0204`.
index 910f273b9722d01474cc7f8ec6e3b8c3cae7242c..8bb4219039b9392a0da56c9a1a45eff5453d98d1 100644 (file)
@@ -1,3 +1,7 @@
+fn unbound_drop(_: impl Sized) {}
+
 fn main() {
-    let _v = || -> _ { [] }; //~ ERROR type annotations needed for the closure
+    unbound_drop(|| -> _ { [] });
+    //~^ ERROR type annotations needed for `[_; 0]`
+    //~| HELP try giving this closure an explicit return type
 }
index 7161ca3903e613bdc7c7743a46df6f644d88725d..3116211b52c9075307bb2478c166684e2fb0a9ff 100644 (file)
@@ -1,13 +1,13 @@
-error[E0282]: type annotations needed for the closure `fn() -> [_; 0]`
-  --> $DIR/suggest-closure-return-type-1.rs:2:24
+error[E0282]: type annotations needed for `[_; 0]`
+  --> $DIR/suggest-closure-return-type-1.rs:4:18
    |
-LL |     let _v = || -> _ { [] };
-   |                        ^^ cannot infer type
+LL |     unbound_drop(|| -> _ { [] });
+   |                  ^^^^^^^
    |
-help: give this closure an explicit return type without `_` placeholders
+help: try giving this closure an explicit return type
    |
-LL |     let _v = || -> [_; 0] { [] };
-   |                    ~~~~~~
+LL |     unbound_drop(|| -> [_; 0] { [] });
+   |                        ~~~~~~
 
 error: aborting due to previous error
 
index 6955b37ad97e423526043712f4de6b3488b9006a..25ed1882e8d2d1742265104a131f92769bc72019 100644 (file)
@@ -1,3 +1,7 @@
+fn unbound_drop(_: impl Sized) {}
+
 fn main() {
-    let _v = || { [] }; //~ ERROR type annotations needed for the closure
+    unbound_drop(|| { [] })
+    //~^ ERROR type annotations needed for `[_; 0]`
+    //~| HELP try giving this closure an explicit return type
 }
index a7f5b58c4da768f439c4b754101ef59e1df138cc..f368e7de467ca94847bf76348afb3d36604b783b 100644 (file)
@@ -1,13 +1,13 @@
-error[E0282]: type annotations needed for the closure `fn() -> [_; 0]`
-  --> $DIR/suggest-closure-return-type-2.rs:2:19
+error[E0282]: type annotations needed for `[_; 0]`
+  --> $DIR/suggest-closure-return-type-2.rs:4:18
    |
-LL |     let _v = || { [] };
-   |                   ^^ cannot infer type
+LL |     unbound_drop(|| { [] })
+   |                  ^^
    |
-help: give this closure an explicit return type without `_` placeholders
+help: try giving this closure an explicit return type
    |
-LL |     let _v = || -> [_; 0] { [] };
-   |                 +++++++++
+LL |     unbound_drop(|| -> [_; 0] { [] })
+   |                     +++++++++
 
 error: aborting due to previous error
 
index ec6c094027e1e48fdc32f8b2b733b730b187c27f..3de6c55cf1696600667748e6277522e0bfa12401 100644 (file)
@@ -1,3 +1,7 @@
+fn unbound_drop(_: impl Sized) {}
+
 fn main() {
-    let _v = || []; //~ ERROR type annotations needed for the closure
+    unbound_drop(|| []);
+    //~^ ERROR type annotations needed for `[_; 0]`
+    //~| HELP try giving this closure an explicit return type
 }
index eeec23e0da030fd08d52db678a6b94df385f1f2a..417693215335374404536e7a0bd96a42d39fac13 100644 (file)
@@ -1,13 +1,13 @@
-error[E0282]: type annotations needed for the closure `fn() -> [_; 0]`
-  --> $DIR/suggest-closure-return-type-3.rs:2:17
+error[E0282]: type annotations needed for `[_; 0]`
+  --> $DIR/suggest-closure-return-type-3.rs:4:18
    |
-LL |     let _v = || [];
-   |                 ^^ cannot infer type
+LL |     unbound_drop(|| []);
+   |                  ^^
    |
-help: give this closure an explicit return type without `_` placeholders
+help: try giving this closure an explicit return type
    |
-LL |     let _v = || -> [_; 0] { [] };
-   |                 +++++++++++    +
+LL |     unbound_drop(|| -> [_; 0] { [] });
+   |                     +++++++++++    +
 
 error: aborting due to previous error
 
index 0e52420ec43777568f0ea8c9c09157740f904c96..57b2587ae5ccd02a4b3dd2b1e3f9859b530890ed 100644 (file)
@@ -2,19 +2,18 @@ error[E0282]: type annotations needed
   --> $DIR/do-not-mention-type-params-by-name-in-suggestion-issue-96292.rs:17:11
    |
 LL |     thing.method(42);
-   |     ------^^^^^^----
-   |     |     |
-   |     |     cannot infer type for type parameter `T` declared on the trait `Method`
-   |     this method call resolves to `T`
+   |           ^^^^^^
+   |
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <Thing<bool> as Method<T>>::method(thing, 42);
+   |     +++++++++++++++++++++++++++++++++++     ~
 
 error[E0283]: type annotations needed
   --> $DIR/do-not-mention-type-params-by-name-in-suggestion-issue-96292.rs:17:11
    |
 LL |     thing.method(42);
-   |     ------^^^^^^----
-   |     |     |
-   |     |     cannot infer type for type parameter `T` declared on the trait `Method`
-   |     this method call resolves to `T`
+   |           ^^^^^^
    |
 note: multiple `impl`s satisfying `Thing<bool>: Method<_>` found
   --> $DIR/do-not-mention-type-params-by-name-in-suggestion-issue-96292.rs:7:1
@@ -24,12 +23,10 @@ LL | impl<X> Method<i32> for Thing<X> {
 ...
 LL | impl<X> Method<u32> for Thing<X> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: use the fully qualified path for the potential candidates
+help: try using a fully qualified path to specify the expected types
    |
-LL |     <Thing<_> as Method<i32>>::method(thing, 42);
-   |     ++++++++++++++++++++++++++++++++++     ~
-LL |     <Thing<_> as Method<u32>>::method(thing, 42);
-   |     ++++++++++++++++++++++++++++++++++     ~
+LL |     <Thing<bool> as Method<T>>::method(thing, 42);
+   |     +++++++++++++++++++++++++++++++++++     ~
 
 error: aborting due to 2 previous errors
 
index 63c1cb3791edf4144f239cff2393d5918eb86f16..5aa42b5b1d3edeee9eb51ac90d4bee10a7556fa2 100644 (file)
@@ -2,9 +2,7 @@ error[E0283]: type annotations needed
   --> $DIR/issue-77982.rs:8:10
    |
 LL |     opts.get(opt.as_ref());
-   |          ^^^ ------------ this method call resolves to `&T`
-   |          |
-   |          cannot infer type for type parameter `Q` declared on the associated function `get`
+   |          ^^^ cannot infer type of the type parameter `Q` declared on the associated function `get`
    |
    = note: multiple `impl`s satisfying `String: Borrow<_>` found in the following crates: `alloc`, `core`:
            - impl Borrow<str> for String;
@@ -15,44 +13,36 @@ note: required by a bound in `HashMap::<K, V, S>::get`
    |
 LL |         K: Borrow<Q>,
    |            ^^^^^^^^^ required by this bound in `HashMap::<K, V, S>::get`
+help: consider specifying the generic argument
+   |
+LL |     opts.get::<Q>(opt.as_ref());
+   |             +++++
 help: consider specifying the type argument in the function call
    |
 LL |     opts.get::<Q>(opt.as_ref());
    |             +++++
 
 error[E0283]: type annotations needed
-  --> $DIR/issue-77982.rs:8:18
+  --> $DIR/issue-77982.rs:8:10
    |
 LL |     opts.get(opt.as_ref());
-   |              ----^^^^^^--
-   |              |   |
-   |              |   cannot infer type for type parameter `T` declared on the trait `AsRef`
-   |              this method call resolves to `&T`
+   |          ^^^ cannot infer type of the type parameter `Q` declared on the associated function `get`
    |
    = note: multiple `impl`s satisfying `String: AsRef<_>` found in the following crates: `alloc`, `std`:
            - impl AsRef<OsStr> for String;
            - impl AsRef<Path> for String;
            - impl AsRef<[u8]> for String;
            - impl AsRef<str> for String;
-help: use the fully qualified path for the potential candidates
-   |
-LL |     opts.get(<String as AsRef<OsStr>>::as_ref(opt));
-   |              +++++++++++++++++++++++++++++++++   ~
-LL |     opts.get(<String as AsRef<Path>>::as_ref(opt));
-   |              ++++++++++++++++++++++++++++++++   ~
-LL |     opts.get(<String as AsRef<[u8]>>::as_ref(opt));
-   |              ++++++++++++++++++++++++++++++++   ~
-LL |     opts.get(<String as AsRef<str>>::as_ref(opt));
-   |              +++++++++++++++++++++++++++++++   ~
-     and 4 other candidates
+help: consider specifying the generic argument
+   |
+LL |     opts.get::<Q>(opt.as_ref());
+   |             +++++
 
 error[E0283]: type annotations needed
-  --> $DIR/issue-77982.rs:13:44
+  --> $DIR/issue-77982.rs:13:59
    |
 LL |     let ips: Vec<_> = (0..100_000).map(|_| u32::from(0u32.into())).collect();
-   |                                            ^^^^^^^^^ ----------- this method call resolves to `T`
-   |                                            |
-   |                                            cannot infer type for type parameter `T` declared on the trait `From`
+   |                                                           ^^^^
    |
    = note: multiple `impl`s satisfying `u32: From<_>` found in the following crates: `core`, `std`:
            - impl From<Ipv4Addr> for u32;
@@ -60,14 +50,16 @@ LL |     let ips: Vec<_> = (0..100_000).map(|_| u32::from(0u32.into())).collect(
            - impl From<bool> for u32;
            - impl From<char> for u32;
            and 3 more
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     let ips: Vec<_> = (0..100_000).map(|_| u32::from(<u32 as Into<T>>::into(0u32))).collect();
+   |                                                      +++++++++++++++++++++++    ~
 
 error[E0283]: type annotations needed for `Box<T>`
-  --> $DIR/issue-77982.rs:36:16
+  --> $DIR/issue-77982.rs:36:9
    |
 LL |     let _ = ().foo();
-   |         -      ^^^ cannot infer type for type parameter `T` declared on the trait `Foo`
-   |         |
-   |         consider giving this pattern the explicit type `Box<T>`, where the type parameter `T` is specified
+   |         ^
    |
 note: multiple `impl`s satisfying `(): Foo<'_, _>` found
   --> $DIR/issue-77982.rs:29:1
@@ -76,14 +68,16 @@ LL | impl Foo<'static, u32> for () {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 LL | impl<'a> Foo<'a, i16> for () {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider giving this pattern a type, where the type for type parameter `T` is specified
+   |
+LL |     let _: Box<T> = ().foo();
+   |          ++++++++
 
 error[E0283]: type annotations needed for `Box<T>`
-  --> $DIR/issue-77982.rs:40:19
+  --> $DIR/issue-77982.rs:40:9
    |
 LL |     let _ = (&()).bar();
-   |         -         ^^^ cannot infer type for type parameter `T` declared on the trait `Bar`
-   |         |
-   |         consider giving this pattern the explicit type `Box<T>`, where the type parameter `T` is specified
+   |         ^
    |
 note: multiple `impl`s satisfying `&(): Bar<'_, _>` found
   --> $DIR/issue-77982.rs:32:1
@@ -92,6 +86,10 @@ LL | impl<'a> Bar<'static, u32> for &'a () {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 LL | impl<'a> Bar<'a, i16> for &'a () {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider giving this pattern a type, where the type for type parameter `T` is specified
+   |
+LL |     let _: Box<T> = (&()).bar();
+   |          ++++++++
 
 error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/traits/issue-8153.rs b/src/test/ui/traits/issue-8153.rs
new file mode 100644 (file)
index 0000000..81a8f53
--- /dev/null
@@ -0,0 +1,16 @@
+// Test that duplicate methods in impls are not allowed
+
+struct Foo;
+
+trait Bar {
+    fn bar(&self) -> isize;
+}
+
+impl Bar for Foo {
+    fn bar(&self) -> isize {1}
+    fn bar(&self) -> isize {2} //~ ERROR duplicate definitions
+}
+
+fn main() {
+    println!("{}", Foo.bar());
+}
diff --git a/src/test/ui/traits/issue-8153.stderr b/src/test/ui/traits/issue-8153.stderr
new file mode 100644 (file)
index 0000000..4389c3d
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0201]: duplicate definitions with name `bar`:
+  --> $DIR/issue-8153.rs:11:5
+   |
+LL |     fn bar(&self) -> isize {1}
+   |     -------------------------- previous definition of `bar` here
+LL |     fn bar(&self) -> isize {2}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ duplicate definition
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0201`.
diff --git a/src/test/ui/traits/issue-97576.rs b/src/test/ui/traits/issue-97576.rs
new file mode 100644 (file)
index 0000000..fdc85e9
--- /dev/null
@@ -0,0 +1,13 @@
+struct Foo {
+    bar: String,
+}
+
+impl Foo {
+    pub fn new(bar: impl ToString) -> Self {
+        Self {
+            bar: bar.into(), //~ ERROR the trait bound `String: From<impl ToString>` is not satisfied
+        }
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/traits/issue-97576.stderr b/src/test/ui/traits/issue-97576.stderr
new file mode 100644 (file)
index 0000000..bdee073
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0277]: the trait bound `String: From<impl ToString>` is not satisfied
+  --> $DIR/issue-97576.rs:8:22
+   |
+LL |             bar: bar.into(),
+   |                      ^^^^ the trait `From<impl ToString>` is not implemented for `String`
+   |
+   = note: required because of the requirements on the impl of `Into<String>` for `impl ToString`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/traits/issue-97695-double-trivial-bound.rs b/src/test/ui/traits/issue-97695-double-trivial-bound.rs
new file mode 100644 (file)
index 0000000..213605b
--- /dev/null
@@ -0,0 +1,24 @@
+// compile-flags: -Zinline-mir --emit=mir
+// build-pass
+
+pub trait Associate {
+    type Associated;
+}
+
+pub struct Wrap<'a> {
+    pub field: &'a i32,
+}
+
+pub trait Create<T> {
+    fn create() -> Self;
+}
+
+pub fn oh_no<'a, T>()
+where
+    Wrap<'a>: Associate,
+    <Wrap<'a> as Associate>::Associated: Create<T>,
+{
+    <Wrap<'a> as Associate>::Associated::create();
+}
+
+pub fn main() {}
index da7461347106ffa68a2ca0c6b8061bce17aeb9c7..25f8d5383776de0a9cdfd06ea418b2d0ad683756 100644 (file)
@@ -2,25 +2,19 @@ error[E0282]: type annotations needed
   --> $DIR/multidispatch-convert-ambig-dest.rs:26:5
    |
 LL |     test(22, std::default::Default::default());
-   |     ^^^^ cannot infer type for type parameter `U` declared on the function `test`
+   |     ^^^^ cannot infer type of the type parameter `U` declared on the function `test`
    |
-help: type parameter declared here
-  --> $DIR/multidispatch-convert-ambig-dest.rs:20:11
+help: consider specifying the generic arguments
    |
-LL | fn test<T,U>(_: T, _: U)
-   |           ^
+LL |     test::<i32, U>(22, std::default::Default::default());
+   |         ++++++++++
 
 error[E0283]: type annotations needed
   --> $DIR/multidispatch-convert-ambig-dest.rs:26:5
    |
 LL |     test(22, std::default::Default::default());
-   |     ^^^^ cannot infer type for type parameter `U` declared on the function `test`
-   |
-help: type parameter declared here
-  --> $DIR/multidispatch-convert-ambig-dest.rs:20:11
+   |     ^^^^ cannot infer type of the type parameter `U` declared on the function `test`
    |
-LL | fn test<T,U>(_: T, _: U)
-   |           ^
 note: multiple `impl`s satisfying `i32: Convert<_>` found
   --> $DIR/multidispatch-convert-ambig-dest.rs:8:1
    |
@@ -36,6 +30,10 @@ LL | fn test<T,U>(_: T, _: U)
    |    ---- required by a bound in this
 LL | where T : Convert<U>
    |           ^^^^^^^^^^ required by this bound in `test`
+help: consider specifying the generic arguments
+   |
+LL |     test::<i32, U>(22, std::default::Default::default());
+   |         ++++++++++
 help: consider specifying the type arguments in the function call
    |
 LL |     test::<T, U>(22, std::default::Default::default());
index 3c8d7450f96fa1f4bf200399e8c089cce13cd507..75d45d9052b46359f1ca5b06fe33ec3e5bb990ee 100644 (file)
@@ -2,25 +2,19 @@ error[E0282]: type annotations needed
   --> $DIR/not-suggest-non-existing-fully-qualified-path.rs:21:7
    |
 LL |     a.method();
-   |     --^^^^^^--
-   |     | |
-   |     | cannot infer type for type parameter `U` declared on the trait `V`
-   |     this method call resolves to `U`
+   |       ^^^^^^
+   |
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <A<B> as V<U>>::method(a);
+   |     +++++++++++++++++++++++ ~
 
 error[E0283]: type annotations needed
   --> $DIR/not-suggest-non-existing-fully-qualified-path.rs:21:7
    |
 LL |     a.method();
-   |     --^^^^^^--
-   |     | |
-   |     | cannot infer type for type parameter `U`
-   |     this method call resolves to `U`
-   |
-help: type parameter declared here
-  --> $DIR/not-suggest-non-existing-fully-qualified-path.rs:12:9
+   |       ^^^^^^
    |
-LL | impl<T, U> V<U> for A<T>
-   |         ^
 note: multiple `impl`s satisfying `B: I<_>` found
   --> $DIR/not-suggest-non-existing-fully-qualified-path.rs:5:1
    |
@@ -33,6 +27,10 @@ note: required because of the requirements on the impl of `V<_>` for `A<B>`
    |
 LL | impl<T, U> V<U> for A<T>
    |            ^^^^     ^^^^
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <A<B> as V<U>>::method(a);
+   |     +++++++++++++++++++++++ ~
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/traits/suggest-fully-qualified-path-with-adjustment.rs b/src/test/ui/traits/suggest-fully-qualified-path-with-adjustment.rs
new file mode 100644 (file)
index 0000000..9a2cf46
--- /dev/null
@@ -0,0 +1,60 @@
+use std::ops::{Deref, DerefMut};
+
+struct Thing;
+
+trait Method<T> {
+    fn method(&self) -> T;
+    fn mut_method(&mut self) -> T;
+}
+
+impl Method<i32> for Thing {
+    fn method(&self) -> i32 { 0 }
+    fn mut_method(&mut self) -> i32 { 0 }
+}
+
+impl Method<u32> for Thing {
+    fn method(&self) -> u32 { 0 }
+    fn mut_method(&mut self) -> u32 { 0 }
+}
+trait MethodRef<T> {
+    fn by_self(self);
+}
+impl MethodRef<i32> for &Thing {
+    fn by_self(self) {}
+}
+impl MethodRef<u32> for &Thing {
+    fn by_self(self) {}
+}
+
+
+struct DerefsTo<T>(T);
+impl<T> Deref for DerefsTo<T> {
+    type Target = T;
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+impl<T> DerefMut for DerefsTo<T> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.0
+    }
+}
+
+fn main() {
+    let mut thing = Thing;
+    thing.method();
+    //~^ ERROR type annotations needed
+    //~| ERROR type annotations needed
+    thing.mut_method(); //~ ERROR type annotations needed
+    thing.by_self(); //~ ERROR type annotations needed
+
+    let mut deref_to = DerefsTo(Thing);
+    deref_to.method(); //~ ERROR type annotations needed
+    deref_to.mut_method(); //~ ERROR type annotations needed
+    deref_to.by_self(); //~ ERROR type annotations needed
+
+    let mut deref_deref_to = DerefsTo(DerefsTo(Thing));
+    deref_deref_to.method(); //~ ERROR type annotations needed
+    deref_deref_to.mut_method(); //~ ERROR type annotations needed
+    deref_deref_to.by_self(); //~ ERROR type annotations needed
+}
diff --git a/src/test/ui/traits/suggest-fully-qualified-path-with-adjustment.stderr b/src/test/ui/traits/suggest-fully-qualified-path-with-adjustment.stderr
new file mode 100644 (file)
index 0000000..68b31a1
--- /dev/null
@@ -0,0 +1,186 @@
+error[E0282]: type annotations needed
+  --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:45:11
+   |
+LL |     thing.method();
+   |           ^^^^^^
+   |
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <Thing as Method<T>>::method(&thing);
+   |     ++++++++++++++++++++++++++++++     ~
+
+error[E0283]: type annotations needed
+  --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:45:11
+   |
+LL |     thing.method();
+   |           ^^^^^^
+   |
+note: multiple `impl`s satisfying `Thing: Method<_>` found
+  --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:10:1
+   |
+LL | impl Method<i32> for Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl Method<u32> for Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <Thing as Method<T>>::method(&thing);
+   |     ++++++++++++++++++++++++++++++     ~
+
+error[E0283]: type annotations needed
+  --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:48:11
+   |
+LL |     thing.mut_method();
+   |           ^^^^^^^^^^
+   |
+note: multiple `impl`s satisfying `Thing: Method<_>` found
+  --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:10:1
+   |
+LL | impl Method<i32> for Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl Method<u32> for Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <Thing as Method<T>>::mut_method(&mut thing);
+   |     +++++++++++++++++++++++++++++++++++++      ~
+
+error[E0283]: type annotations needed
+  --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:49:11
+   |
+LL |     thing.by_self();
+   |           ^^^^^^^
+   |
+note: multiple `impl`s satisfying `&Thing: MethodRef<_>` found
+  --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:22:1
+   |
+LL | impl MethodRef<i32> for &Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl MethodRef<u32> for &Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <&Thing as MethodRef<T>>::by_self(&thing);
+   |     +++++++++++++++++++++++++++++++++++     ~
+
+error[E0283]: type annotations needed
+  --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:52:14
+   |
+LL |     deref_to.method();
+   |              ^^^^^^
+   |
+note: multiple `impl`s satisfying `Thing: Method<_>` found
+  --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:10:1
+   |
+LL | impl Method<i32> for Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl Method<u32> for Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <Thing as Method<T>>::method(&deref_to);
+   |     ++++++++++++++++++++++++++++++        ~
+
+error[E0283]: type annotations needed
+  --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:53:14
+   |
+LL |     deref_to.mut_method();
+   |              ^^^^^^^^^^
+   |
+note: multiple `impl`s satisfying `Thing: Method<_>` found
+  --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:10:1
+   |
+LL | impl Method<i32> for Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl Method<u32> for Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <Thing as Method<T>>::mut_method(&mut deref_to);
+   |     +++++++++++++++++++++++++++++++++++++         ~
+
+error[E0283]: type annotations needed
+  --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:54:14
+   |
+LL |     deref_to.by_self();
+   |              ^^^^^^^
+   |
+note: multiple `impl`s satisfying `&Thing: MethodRef<_>` found
+  --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:22:1
+   |
+LL | impl MethodRef<i32> for &Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl MethodRef<u32> for &Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <&Thing as MethodRef<T>>::by_self(&deref_to);
+   |     +++++++++++++++++++++++++++++++++++        ~
+
+error[E0283]: type annotations needed
+  --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:57:20
+   |
+LL |     deref_deref_to.method();
+   |                    ^^^^^^
+   |
+note: multiple `impl`s satisfying `Thing: Method<_>` found
+  --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:10:1
+   |
+LL | impl Method<i32> for Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl Method<u32> for Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <Thing as Method<T>>::method(&deref_deref_to);
+   |     ++++++++++++++++++++++++++++++              ~
+
+error[E0283]: type annotations needed
+  --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:58:20
+   |
+LL |     deref_deref_to.mut_method();
+   |                    ^^^^^^^^^^
+   |
+note: multiple `impl`s satisfying `Thing: Method<_>` found
+  --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:10:1
+   |
+LL | impl Method<i32> for Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl Method<u32> for Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <Thing as Method<T>>::mut_method(&mut deref_deref_to);
+   |     +++++++++++++++++++++++++++++++++++++               ~
+
+error[E0283]: type annotations needed
+  --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:59:20
+   |
+LL |     deref_deref_to.by_self();
+   |                    ^^^^^^^
+   |
+note: multiple `impl`s satisfying `&Thing: MethodRef<_>` found
+  --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:22:1
+   |
+LL | impl MethodRef<i32> for &Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl MethodRef<u32> for &Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <&Thing as MethodRef<T>>::by_self(&deref_deref_to);
+   |     +++++++++++++++++++++++++++++++++++              ~
+
+error: aborting due to 10 previous errors
+
+Some errors have detailed explanations: E0282, E0283.
+For more information about an error, try `rustc --explain E0282`.
diff --git a/src/test/ui/traits/suggest-fully-qualified-path-with-appropriate-params.rs b/src/test/ui/traits/suggest-fully-qualified-path-with-appropriate-params.rs
deleted file mode 100644 (file)
index da68b99..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-struct Thing;
-
-trait Method<T> {
-    fn method(&self) -> T;
-    fn mut_method(&mut self) -> T;
-}
-
-impl Method<i32> for Thing {
-    fn method(&self) -> i32 { 0 }
-    fn mut_method(&mut self) -> i32 { 0 }
-}
-
-impl Method<u32> for Thing {
-    fn method(&self) -> u32 { 0 }
-    fn mut_method(&mut self) -> u32 { 0 }
-}
-
-fn main() {
-    let thing = Thing;
-    thing.method();
-    //~^ ERROR type annotations needed
-    //~| ERROR type annotations needed
-    thing.mut_method(); //~ ERROR type annotations needed
-}
diff --git a/src/test/ui/traits/suggest-fully-qualified-path-with-appropriate-params.stderr b/src/test/ui/traits/suggest-fully-qualified-path-with-appropriate-params.stderr
deleted file mode 100644 (file)
index 0c49624..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-error[E0282]: type annotations needed
-  --> $DIR/suggest-fully-qualified-path-with-appropriate-params.rs:20:11
-   |
-LL |     thing.method();
-   |     ------^^^^^^--
-   |     |     |
-   |     |     cannot infer type for type parameter `T` declared on the trait `Method`
-   |     this method call resolves to `T`
-
-error[E0283]: type annotations needed
-  --> $DIR/suggest-fully-qualified-path-with-appropriate-params.rs:20:11
-   |
-LL |     thing.method();
-   |     ------^^^^^^--
-   |     |     |
-   |     |     cannot infer type for type parameter `T` declared on the trait `Method`
-   |     this method call resolves to `T`
-   |
-note: multiple `impl`s satisfying `Thing: Method<_>` found
-  --> $DIR/suggest-fully-qualified-path-with-appropriate-params.rs:8:1
-   |
-LL | impl Method<i32> for Thing {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
-...
-LL | impl Method<u32> for Thing {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: use the fully qualified path for the potential candidates
-   |
-LL |     <Thing as Method<i32>>::method(&thing);
-   |     ++++++++++++++++++++++++++++++++     ~
-LL |     <Thing as Method<u32>>::method(&thing);
-   |     ++++++++++++++++++++++++++++++++     ~
-
-error[E0283]: type annotations needed
-  --> $DIR/suggest-fully-qualified-path-with-appropriate-params.rs:23:11
-   |
-LL |     thing.mut_method();
-   |     ------^^^^^^^^^^--
-   |     |     |
-   |     |     cannot infer type for type parameter `T` declared on the trait `Method`
-   |     this method call resolves to `T`
-   |
-note: multiple `impl`s satisfying `Thing: Method<_>` found
-  --> $DIR/suggest-fully-qualified-path-with-appropriate-params.rs:8:1
-   |
-LL | impl Method<i32> for Thing {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
-...
-LL | impl Method<u32> for Thing {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: use the fully qualified path for the potential candidates
-   |
-LL |     <Thing as Method<i32>>::mut_method(&mut thing);
-   |     +++++++++++++++++++++++++++++++++++++++      ~
-LL |     <Thing as Method<u32>>::mut_method(&mut thing);
-   |     +++++++++++++++++++++++++++++++++++++++      ~
-
-error: aborting due to 3 previous errors
-
-Some errors have detailed explanations: E0282, E0283.
-For more information about an error, try `rustc --explain E0282`.
diff --git a/src/test/ui/traits/suggest-fully-qualified-path-without-adjustment.rs b/src/test/ui/traits/suggest-fully-qualified-path-without-adjustment.rs
new file mode 100644 (file)
index 0000000..da640c8
--- /dev/null
@@ -0,0 +1,64 @@
+use std::ops::{Deref, DerefMut};
+
+struct Thing;
+
+trait Method<T> {
+    fn method(&self) -> T;
+    fn mut_method(&mut self) -> T;
+}
+
+impl Method<i32> for Thing {
+    fn method(&self) -> i32 { 0 }
+    fn mut_method(&mut self) -> i32 { 0 }
+}
+
+impl Method<u32> for Thing {
+    fn method(&self) -> u32 { 0 }
+    fn mut_method(&mut self) -> u32 { 0 }
+}
+
+trait MethodRef<T> {
+    fn by_self(self);
+}
+impl MethodRef<i32> for &Thing {
+    fn by_self(self) {}
+}
+impl MethodRef<u32> for &Thing {
+    fn by_self(self) {}
+}
+
+struct DerefsTo<T>(T);
+impl<T> Deref for DerefsTo<T> {
+    type Target = T;
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+impl<T> DerefMut for DerefsTo<T> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.0
+    }
+}
+
+fn main() {
+    let mut ref_thing = &Thing;
+    ref_thing.method();
+    //~^ ERROR type annotations needed
+    //~| ERROR type annotations needed
+    ref_thing.by_self(); //~ ERROR type annotations needed
+
+    let mut mut_thing = &mut Thing;
+    mut_thing.method(); //~ ERROR type annotations needed
+    mut_thing.mut_method(); //~ ERROR type annotations needed
+    mut_thing.by_self(); //~ ERROR type annotations needed
+
+    let mut deref_to = &DerefsTo(Thing);
+    deref_to.method(); //~ ERROR type annotations needed
+    deref_to.mut_method(); //~ ERROR type annotations needed
+    deref_to.by_self(); //~ ERROR type annotations needed
+
+    let mut deref_deref_to = &DerefsTo(DerefsTo(Thing));
+    deref_deref_to.method(); //~ ERROR type annotations needed
+    deref_deref_to.mut_method(); //~ ERROR type annotations needed
+    deref_deref_to.by_self(); //~ ERROR type annotations needed
+}
diff --git a/src/test/ui/traits/suggest-fully-qualified-path-without-adjustment.stderr b/src/test/ui/traits/suggest-fully-qualified-path-without-adjustment.stderr
new file mode 100644 (file)
index 0000000..27518a5
--- /dev/null
@@ -0,0 +1,224 @@
+error[E0282]: type annotations needed
+  --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:45:15
+   |
+LL |     ref_thing.method();
+   |               ^^^^^^
+   |
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <Thing as Method<T>>::method(ref_thing);
+   |     +++++++++++++++++++++++++++++         ~
+
+error[E0283]: type annotations needed
+  --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:45:15
+   |
+LL |     ref_thing.method();
+   |               ^^^^^^
+   |
+note: multiple `impl`s satisfying `Thing: Method<_>` found
+  --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:10:1
+   |
+LL | impl Method<i32> for Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl Method<u32> for Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <Thing as Method<T>>::method(ref_thing);
+   |     +++++++++++++++++++++++++++++         ~
+
+error[E0283]: type annotations needed
+  --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:48:15
+   |
+LL |     ref_thing.by_self();
+   |               ^^^^^^^
+   |
+note: multiple `impl`s satisfying `&Thing: MethodRef<_>` found
+  --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:23:1
+   |
+LL | impl MethodRef<i32> for &Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl MethodRef<u32> for &Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <&Thing as MethodRef<T>>::by_self(ref_thing);
+   |     ++++++++++++++++++++++++++++++++++         ~
+
+error[E0283]: type annotations needed
+  --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:51:15
+   |
+LL |     mut_thing.method();
+   |               ^^^^^^
+   |
+note: multiple `impl`s satisfying `Thing: Method<_>` found
+  --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:10:1
+   |
+LL | impl Method<i32> for Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl Method<u32> for Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <Thing as Method<T>>::method(mut_thing);
+   |     +++++++++++++++++++++++++++++         ~
+
+error[E0283]: type annotations needed
+  --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:52:15
+   |
+LL |     mut_thing.mut_method();
+   |               ^^^^^^^^^^
+   |
+note: multiple `impl`s satisfying `Thing: Method<_>` found
+  --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:10:1
+   |
+LL | impl Method<i32> for Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl Method<u32> for Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <Thing as Method<T>>::mut_method(mut_thing);
+   |     +++++++++++++++++++++++++++++++++         ~
+
+error[E0283]: type annotations needed
+  --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:53:15
+   |
+LL |     mut_thing.by_self();
+   |               ^^^^^^^
+   |
+note: multiple `impl`s satisfying `&Thing: MethodRef<_>` found
+  --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:23:1
+   |
+LL | impl MethodRef<i32> for &Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl MethodRef<u32> for &Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <&Thing as MethodRef<T>>::by_self(mut_thing);
+   |     ++++++++++++++++++++++++++++++++++         ~
+
+error[E0283]: type annotations needed
+  --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:56:14
+   |
+LL |     deref_to.method();
+   |              ^^^^^^
+   |
+note: multiple `impl`s satisfying `Thing: Method<_>` found
+  --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:10:1
+   |
+LL | impl Method<i32> for Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl Method<u32> for Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <Thing as Method<T>>::method(deref_to);
+   |     +++++++++++++++++++++++++++++        ~
+
+error[E0283]: type annotations needed
+  --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:57:14
+   |
+LL |     deref_to.mut_method();
+   |              ^^^^^^^^^^
+   |
+note: multiple `impl`s satisfying `Thing: Method<_>` found
+  --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:10:1
+   |
+LL | impl Method<i32> for Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl Method<u32> for Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <Thing as Method<T>>::mut_method(deref_to);
+   |     +++++++++++++++++++++++++++++++++        ~
+
+error[E0283]: type annotations needed
+  --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:58:14
+   |
+LL |     deref_to.by_self();
+   |              ^^^^^^^
+   |
+note: multiple `impl`s satisfying `&Thing: MethodRef<_>` found
+  --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:23:1
+   |
+LL | impl MethodRef<i32> for &Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl MethodRef<u32> for &Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <&Thing as MethodRef<T>>::by_self(deref_to);
+   |     ++++++++++++++++++++++++++++++++++        ~
+
+error[E0283]: type annotations needed
+  --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:61:20
+   |
+LL |     deref_deref_to.method();
+   |                    ^^^^^^
+   |
+note: multiple `impl`s satisfying `Thing: Method<_>` found
+  --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:10:1
+   |
+LL | impl Method<i32> for Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl Method<u32> for Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <Thing as Method<T>>::method(deref_deref_to);
+   |     +++++++++++++++++++++++++++++              ~
+
+error[E0283]: type annotations needed
+  --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:62:20
+   |
+LL |     deref_deref_to.mut_method();
+   |                    ^^^^^^^^^^
+   |
+note: multiple `impl`s satisfying `Thing: Method<_>` found
+  --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:10:1
+   |
+LL | impl Method<i32> for Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl Method<u32> for Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <Thing as Method<T>>::mut_method(deref_deref_to);
+   |     +++++++++++++++++++++++++++++++++              ~
+
+error[E0283]: type annotations needed
+  --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:63:20
+   |
+LL |     deref_deref_to.by_self();
+   |                    ^^^^^^^
+   |
+note: multiple `impl`s satisfying `&Thing: MethodRef<_>` found
+  --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:23:1
+   |
+LL | impl MethodRef<i32> for &Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl MethodRef<u32> for &Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <&Thing as MethodRef<T>>::by_self(deref_deref_to);
+   |     ++++++++++++++++++++++++++++++++++              ~
+
+error: aborting due to 12 previous errors
+
+Some errors have detailed explanations: E0282, E0283.
+For more information about an error, try `rustc --explain E0282`.
index 6bc4f528faaf9092f705e0e308c6044f72ecb835..e6f45036f8514fcd8b59e16fcd4674bbdf5577b8 100644 (file)
@@ -13,38 +13,38 @@ fn ts_variant() {
         Self::TSVariant(());
         //~^ ERROR mismatched types [E0308]
         Self::TSVariant::<()>(());
-        //~^ ERROR type arguments are not allowed for this type [E0109]
+        //~^ ERROR type arguments are not allowed on this type [E0109]
         Self::<()>::TSVariant(());
-        //~^ ERROR type arguments are not allowed for this type [E0109]
+        //~^ ERROR type arguments are not allowed on self type [E0109]
         //~| ERROR mismatched types [E0308]
         Self::<()>::TSVariant::<()>(());
-        //~^ ERROR type arguments are not allowed for this type [E0109]
-        //~| ERROR type arguments are not allowed for this type [E0109]
+        //~^ ERROR type arguments are not allowed on self type [E0109]
+        //~| ERROR type arguments are not allowed on this type [E0109]
     }
 
     fn s_variant() {
         Self::SVariant { v: () };
         //~^ ERROR mismatched types [E0308]
         Self::SVariant::<()> { v: () };
-        //~^ ERROR type arguments are not allowed for this type [E0109]
+        //~^ ERROR type arguments are not allowed on this type [E0109]
         //~| ERROR mismatched types [E0308]
         Self::<()>::SVariant { v: () };
-        //~^ ERROR type arguments are not allowed for this type [E0109]
+        //~^ ERROR type arguments are not allowed on self type [E0109]
         //~| ERROR mismatched types [E0308]
         Self::<()>::SVariant::<()> { v: () };
-        //~^ ERROR type arguments are not allowed for this type [E0109]
-        //~| ERROR type arguments are not allowed for this type [E0109]
+        //~^ ERROR type arguments are not allowed on self type [E0109]
+        //~| ERROR type arguments are not allowed on this type [E0109]
         //~| ERROR mismatched types [E0308]
     }
 
     fn u_variant() {
         Self::UVariant::<()>;
-        //~^ ERROR type arguments are not allowed for this type [E0109]
+        //~^ ERROR type arguments are not allowed on this type [E0109]
         Self::<()>::UVariant;
-        //~^ ERROR type arguments are not allowed for this type [E0109]
+        //~^ ERROR type arguments are not allowed on self type [E0109]
         Self::<()>::UVariant::<()>;
-        //~^ ERROR type arguments are not allowed for this type [E0109]
-        //~| ERROR type arguments are not allowed for this type [E0109]
+        //~^ ERROR type arguments are not allowed on self type [E0109]
+        //~| ERROR type arguments are not allowed on this type [E0109]
     }
 }
 
@@ -52,54 +52,54 @@ fn main() {
     // Tuple struct variant
 
     Enum::<()>::TSVariant::<()>(());
-    //~^ ERROR type arguments are not allowed for this type [E0109]
+    //~^ ERROR type arguments are not allowed on this type [E0109]
 
     Alias::TSVariant::<()>(());
-    //~^ ERROR type arguments are not allowed for this type [E0109]
+    //~^ ERROR type arguments are not allowed on this type [E0109]
     Alias::<()>::TSVariant::<()>(());
-    //~^ ERROR type arguments are not allowed for this type [E0109]
+    //~^ ERROR type arguments are not allowed on this type [E0109]
 
     AliasFixed::TSVariant::<()>(());
-    //~^ ERROR type arguments are not allowed for this type [E0109]
+    //~^ ERROR type arguments are not allowed on this type [E0109]
     AliasFixed::<()>::TSVariant(());
     //~^ ERROR this type alias takes 0 generic arguments but 1 generic argument was supplied [E0107]
     AliasFixed::<()>::TSVariant::<()>(());
-    //~^ ERROR type arguments are not allowed for this type [E0109]
+    //~^ ERROR type arguments are not allowed on this type [E0109]
     //~| ERROR this type alias takes 0 generic arguments but 1 generic argument was supplied [E0107]
 
     // Struct variant
 
     Enum::<()>::SVariant::<()> { v: () };
-    //~^ ERROR type arguments are not allowed for this type [E0109]
+    //~^ ERROR type arguments are not allowed on this type [E0109]
 
     Alias::SVariant::<()> { v: () };
-    //~^ ERROR type arguments are not allowed for this type [E0109]
+    //~^ ERROR type arguments are not allowed on this type [E0109]
     Alias::<()>::SVariant::<()> { v: () };
-    //~^ ERROR type arguments are not allowed for this type [E0109]
+    //~^ ERROR type arguments are not allowed on this type [E0109]
 
     AliasFixed::SVariant::<()> { v: () };
-    //~^ ERROR type arguments are not allowed for this type [E0109]
+    //~^ ERROR type arguments are not allowed on this type [E0109]
     AliasFixed::<()>::SVariant { v: () };
     //~^ ERROR this type alias takes 0 generic arguments but 1 generic argument was supplied [E0107]
     AliasFixed::<()>::SVariant::<()> { v: () };
-    //~^ ERROR type arguments are not allowed for this type [E0109]
+    //~^ ERROR type arguments are not allowed on this type [E0109]
     //~| ERROR this type alias takes 0 generic arguments but 1 generic argument was supplied [E0107]
 
     // Unit variant
 
     Enum::<()>::UVariant::<()>;
-    //~^ ERROR type arguments are not allowed for this type [E0109]
+    //~^ ERROR type arguments are not allowed on this type [E0109]
 
     Alias::UVariant::<()>;
-    //~^ ERROR type arguments are not allowed for this type [E0109]
+    //~^ ERROR type arguments are not allowed on this type [E0109]
     Alias::<()>::UVariant::<()>;
-    //~^ ERROR type arguments are not allowed for this type [E0109]
+    //~^ ERROR type arguments are not allowed on this type [E0109]
 
     AliasFixed::UVariant::<()>;
-    //~^ ERROR type arguments are not allowed for this type [E0109]
+    //~^ ERROR type arguments are not allowed on this type [E0109]
     AliasFixed::<()>::UVariant;
     //~^ ERROR this type alias takes 0 generic arguments but 1 generic argument was supplied [E0107]
     AliasFixed::<()>::UVariant::<()>;
-    //~^ ERROR type arguments are not allowed for this type [E0109]
+    //~^ ERROR type arguments are not allowed on this type [E0109]
     //~| ERROR this type alias takes 0 generic arguments but 1 generic argument was supplied [E0107]
 }
index 115ecb013766dd2e9bcd5fd60cd668c9577dfea8..3e60ab108a82fc8fda4488d83150a4b6f1c286fb 100644 (file)
@@ -17,17 +17,34 @@ note: tuple variant defined here
 LL | enum Enum<T> { TSVariant(T), SVariant { v: T }, UVariant }
    |                ^^^^^^^^^
 
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
   --> $DIR/enum-variant-generic-args.rs:15:27
    |
 LL |         Self::TSVariant::<()>(());
-   |                           ^^ type argument not allowed
+   |               ---------   ^^ type argument not allowed
+   |               |
+   |               not allowed on this
 
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on self type
   --> $DIR/enum-variant-generic-args.rs:17:16
    |
 LL |         Self::<()>::TSVariant(());
-   |                ^^ type argument not allowed
+   |         ----   ^^ type argument not allowed
+   |         |
+   |         not allowed on this
+   |
+note: `Self` is of type `Enum<T>`
+  --> $DIR/enum-variant-generic-args.rs:7:6
+   |
+LL | enum Enum<T> { TSVariant(T), SVariant { v: T }, UVariant }
+   |      ^^^^ `Self` corresponds to this type
+...
+LL | impl<T> Enum<T> {
+   | --------------- `Self` is on type `Enum` in this `impl`
+help: the `Self` type doesn't accept type parameters, use the concrete type's name `Enum` instead if you want to specify its type parameters
+   |
+LL |         Enum::<()>::TSVariant(());
+   |         ~~~~
 
 error[E0308]: mismatched types
   --> $DIR/enum-variant-generic-args.rs:17:31
@@ -48,17 +65,34 @@ note: tuple variant defined here
 LL | enum Enum<T> { TSVariant(T), SVariant { v: T }, UVariant }
    |                ^^^^^^^^^
 
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on self type
   --> $DIR/enum-variant-generic-args.rs:20:16
    |
 LL |         Self::<()>::TSVariant::<()>(());
-   |                ^^ type argument not allowed
+   |         ----   ^^ type argument not allowed
+   |         |
+   |         not allowed on this
+   |
+note: `Self` is of type `Enum<T>`
+  --> $DIR/enum-variant-generic-args.rs:7:6
+   |
+LL | enum Enum<T> { TSVariant(T), SVariant { v: T }, UVariant }
+   |      ^^^^ `Self` corresponds to this type
+...
+LL | impl<T> Enum<T> {
+   | --------------- `Self` is on type `Enum` in this `impl`
+help: the `Self` type doesn't accept type parameters, use the concrete type's name `Enum` instead if you want to specify its type parameters
+   |
+LL |         Enum::<()>::TSVariant::<()>(());
+   |         ~~~~
 
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
   --> $DIR/enum-variant-generic-args.rs:20:33
    |
 LL |         Self::<()>::TSVariant::<()>(());
-   |                                 ^^ type argument not allowed
+   |                     ---------   ^^ type argument not allowed
+   |                     |
+   |                     not allowed on this
 
 error[E0308]: mismatched types
   --> $DIR/enum-variant-generic-args.rs:26:29
@@ -72,11 +106,20 @@ LL |         Self::SVariant { v: () };
    = note: expected type parameter `T`
                    found unit type `()`
 
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
   --> $DIR/enum-variant-generic-args.rs:28:26
    |
 LL |         Self::SVariant::<()> { v: () };
-   |                          ^^ type argument not allowed
+   |               --------   ^^ type argument not allowed
+   |               |
+   |               not allowed on this
+   |
+   = note: enum variants can't have type parameters
+help: you might have meant to specity type parameters on enum `Enum`
+   |
+LL -         Self::SVariant::<()> { v: () };
+LL +         Enum::<()>::SVariant { v: () };
+   | 
 
 error[E0308]: mismatched types
   --> $DIR/enum-variant-generic-args.rs:28:35
@@ -90,11 +133,26 @@ LL |         Self::SVariant::<()> { v: () };
    = note: expected type parameter `T`
                    found unit type `()`
 
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on self type
   --> $DIR/enum-variant-generic-args.rs:31:16
    |
 LL |         Self::<()>::SVariant { v: () };
-   |                ^^ type argument not allowed
+   |         ----   ^^ type argument not allowed
+   |         |
+   |         not allowed on this
+   |
+note: `Self` is of type `Enum<T>`
+  --> $DIR/enum-variant-generic-args.rs:7:6
+   |
+LL | enum Enum<T> { TSVariant(T), SVariant { v: T }, UVariant }
+   |      ^^^^ `Self` corresponds to this type
+...
+LL | impl<T> Enum<T> {
+   | --------------- `Self` is on type `Enum` in this `impl`
+help: the `Self` type doesn't accept type parameters, use the concrete type's name `Enum` instead if you want to specify its type parameters
+   |
+LL |         Enum::<()>::SVariant { v: () };
+   |         ~~~~
 
 error[E0308]: mismatched types
   --> $DIR/enum-variant-generic-args.rs:31:35
@@ -108,17 +166,41 @@ LL |         Self::<()>::SVariant { v: () };
    = note: expected type parameter `T`
                    found unit type `()`
 
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on self type
   --> $DIR/enum-variant-generic-args.rs:34:16
    |
 LL |         Self::<()>::SVariant::<()> { v: () };
-   |                ^^ type argument not allowed
+   |         ----   ^^ type argument not allowed
+   |         |
+   |         not allowed on this
+   |
+note: `Self` is of type `Enum<T>`
+  --> $DIR/enum-variant-generic-args.rs:7:6
+   |
+LL | enum Enum<T> { TSVariant(T), SVariant { v: T }, UVariant }
+   |      ^^^^ `Self` corresponds to this type
+...
+LL | impl<T> Enum<T> {
+   | --------------- `Self` is on type `Enum` in this `impl`
+help: the `Self` type doesn't accept type parameters, use the concrete type's name `Enum` instead if you want to specify its type parameters
+   |
+LL |         Enum::<()>::SVariant::<()> { v: () };
+   |         ~~~~
 
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
   --> $DIR/enum-variant-generic-args.rs:34:32
    |
 LL |         Self::<()>::SVariant::<()> { v: () };
-   |                                ^^ type argument not allowed
+   |                     --------   ^^ type argument not allowed
+   |                     |
+   |                     not allowed on this
+   |
+   = note: enum variants can't have type parameters
+help: you might have meant to specity type parameters on enum `Enum`
+   |
+LL -         Self::<()>::SVariant::<()> { v: () };
+LL +         Enum::<()>::SVariant { v: () };
+   | 
 
 error[E0308]: mismatched types
   --> $DIR/enum-variant-generic-args.rs:34:41
@@ -132,53 +214,95 @@ LL |         Self::<()>::SVariant::<()> { v: () };
    = note: expected type parameter `T`
                    found unit type `()`
 
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
   --> $DIR/enum-variant-generic-args.rs:41:26
    |
 LL |         Self::UVariant::<()>;
-   |                          ^^ type argument not allowed
+   |               --------   ^^ type argument not allowed
+   |               |
+   |               not allowed on this
 
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on self type
   --> $DIR/enum-variant-generic-args.rs:43:16
    |
 LL |         Self::<()>::UVariant;
-   |                ^^ type argument not allowed
+   |         ----   ^^ type argument not allowed
+   |         |
+   |         not allowed on this
+   |
+note: `Self` is of type `Enum<T>`
+  --> $DIR/enum-variant-generic-args.rs:7:6
+   |
+LL | enum Enum<T> { TSVariant(T), SVariant { v: T }, UVariant }
+   |      ^^^^ `Self` corresponds to this type
+...
+LL | impl<T> Enum<T> {
+   | --------------- `Self` is on type `Enum` in this `impl`
+help: the `Self` type doesn't accept type parameters, use the concrete type's name `Enum` instead if you want to specify its type parameters
+   |
+LL |         Enum::<()>::UVariant;
+   |         ~~~~
 
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on self type
   --> $DIR/enum-variant-generic-args.rs:45:16
    |
 LL |         Self::<()>::UVariant::<()>;
-   |                ^^ type argument not allowed
+   |         ----   ^^ type argument not allowed
+   |         |
+   |         not allowed on this
+   |
+note: `Self` is of type `Enum<T>`
+  --> $DIR/enum-variant-generic-args.rs:7:6
+   |
+LL | enum Enum<T> { TSVariant(T), SVariant { v: T }, UVariant }
+   |      ^^^^ `Self` corresponds to this type
+...
+LL | impl<T> Enum<T> {
+   | --------------- `Self` is on type `Enum` in this `impl`
+help: the `Self` type doesn't accept type parameters, use the concrete type's name `Enum` instead if you want to specify its type parameters
+   |
+LL |         Enum::<()>::UVariant::<()>;
+   |         ~~~~
 
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
   --> $DIR/enum-variant-generic-args.rs:45:32
    |
 LL |         Self::<()>::UVariant::<()>;
-   |                                ^^ type argument not allowed
+   |                     --------   ^^ type argument not allowed
+   |                     |
+   |                     not allowed on this
 
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
   --> $DIR/enum-variant-generic-args.rs:54:29
    |
 LL |     Enum::<()>::TSVariant::<()>(());
-   |                             ^^ type argument not allowed
+   |                 ---------   ^^ type argument not allowed
+   |                 |
+   |                 not allowed on this
 
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
   --> $DIR/enum-variant-generic-args.rs:57:24
    |
 LL |     Alias::TSVariant::<()>(());
-   |                        ^^ type argument not allowed
+   |            ---------   ^^ type argument not allowed
+   |            |
+   |            not allowed on this
 
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
   --> $DIR/enum-variant-generic-args.rs:59:30
    |
 LL |     Alias::<()>::TSVariant::<()>(());
-   |                              ^^ type argument not allowed
+   |                  ---------   ^^ type argument not allowed
+   |                  |
+   |                  not allowed on this
 
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
   --> $DIR/enum-variant-generic-args.rs:62:29
    |
 LL |     AliasFixed::TSVariant::<()>(());
-   |                             ^^ type argument not allowed
+   |                 ---------   ^^ type argument not allowed
+   |                 |
+   |                 not allowed on this
 
 error[E0107]: this type alias takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/enum-variant-generic-args.rs:64:5
@@ -208,35 +332,68 @@ note: type alias defined here, with 0 generic parameters
 LL | type AliasFixed = Enum<()>;
    |      ^^^^^^^^^^
 
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
   --> $DIR/enum-variant-generic-args.rs:66:35
    |
 LL |     AliasFixed::<()>::TSVariant::<()>(());
-   |                                   ^^ type argument not allowed
+   |                       ---------   ^^ type argument not allowed
+   |                       |
+   |                       not allowed on this
 
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
   --> $DIR/enum-variant-generic-args.rs:72:28
    |
 LL |     Enum::<()>::SVariant::<()> { v: () };
-   |                            ^^ type argument not allowed
+   |                 --------   ^^ type argument not allowed
+   |                 |
+   |                 not allowed on this
+   |
+   = note: enum variants can't have type parameters
 
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
   --> $DIR/enum-variant-generic-args.rs:75:23
    |
 LL |     Alias::SVariant::<()> { v: () };
-   |                       ^^ type argument not allowed
+   |            --------   ^^ type argument not allowed
+   |            |
+   |            not allowed on this
+   |
+   = note: enum variants can't have type parameters
+help: you might have meant to specity type parameters on enum `Enum`
+   |
+LL -     Alias::SVariant::<()> { v: () };
+LL +     Alias::<()>::SVariant { v: () };
+   | 
 
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
   --> $DIR/enum-variant-generic-args.rs:77:29
    |
 LL |     Alias::<()>::SVariant::<()> { v: () };
-   |                             ^^ type argument not allowed
+   |                  --------   ^^ type argument not allowed
+   |                  |
+   |                  not allowed on this
+   |
+   = note: enum variants can't have type parameters
+help: you might have meant to specity type parameters on enum `Enum`
+   |
+LL -     Alias::<()>::SVariant::<()> { v: () };
+LL +     Alias::<()>::SVariant { v: () };
+   | 
 
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
   --> $DIR/enum-variant-generic-args.rs:80:28
    |
 LL |     AliasFixed::SVariant::<()> { v: () };
-   |                            ^^ type argument not allowed
+   |                 --------   ^^ type argument not allowed
+   |                 |
+   |                 not allowed on this
+   |
+   = note: enum variants can't have type parameters
+help: you might have meant to specity type parameters on enum `Enum`
+   |
+LL -     AliasFixed::SVariant::<()> { v: () };
+LL +     AliasFixed::<()>::SVariant { v: () };
+   | 
 
 error[E0107]: this type alias takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/enum-variant-generic-args.rs:82:5
@@ -266,35 +423,52 @@ note: type alias defined here, with 0 generic parameters
 LL | type AliasFixed = Enum<()>;
    |      ^^^^^^^^^^
 
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
   --> $DIR/enum-variant-generic-args.rs:84:34
    |
 LL |     AliasFixed::<()>::SVariant::<()> { v: () };
-   |                                  ^^ type argument not allowed
+   |                       --------   ^^ type argument not allowed
+   |                       |
+   |                       not allowed on this
+   |
+   = note: enum variants can't have type parameters
+help: you might have meant to specity type parameters on enum `Enum`
+   |
+LL -     AliasFixed::<()>::SVariant::<()> { v: () };
+LL +     AliasFixed::<()>::SVariant { v: () };
+   | 
 
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
   --> $DIR/enum-variant-generic-args.rs:90:28
    |
 LL |     Enum::<()>::UVariant::<()>;
-   |                            ^^ type argument not allowed
+   |                 --------   ^^ type argument not allowed
+   |                 |
+   |                 not allowed on this
 
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
   --> $DIR/enum-variant-generic-args.rs:93:23
    |
 LL |     Alias::UVariant::<()>;
-   |                       ^^ type argument not allowed
+   |            --------   ^^ type argument not allowed
+   |            |
+   |            not allowed on this
 
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
   --> $DIR/enum-variant-generic-args.rs:95:29
    |
 LL |     Alias::<()>::UVariant::<()>;
-   |                             ^^ type argument not allowed
+   |                  --------   ^^ type argument not allowed
+   |                  |
+   |                  not allowed on this
 
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
   --> $DIR/enum-variant-generic-args.rs:98:28
    |
 LL |     AliasFixed::UVariant::<()>;
-   |                            ^^ type argument not allowed
+   |                 --------   ^^ type argument not allowed
+   |                 |
+   |                 not allowed on this
 
 error[E0107]: this type alias takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/enum-variant-generic-args.rs:100:5
@@ -324,11 +498,13 @@ note: type alias defined here, with 0 generic parameters
 LL | type AliasFixed = Enum<()>;
    |      ^^^^^^^^^^
 
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
   --> $DIR/enum-variant-generic-args.rs:102:34
    |
 LL |     AliasFixed::<()>::UVariant::<()>;
-   |                                  ^^ type argument not allowed
+   |                       --------   ^^ type argument not allowed
+   |                       |
+   |                       not allowed on this
 
 error: aborting due to 39 previous errors
 
index c1153fa4dc7b4f315b770792992e398ee4bc7d7b..872ece0c0f99e4d1dedd99601c33b995ca7b1848 100644 (file)
@@ -10,5 +10,5 @@ fn main() {
     let _ = Option::<u8>::None; // OK
     let _ = Option::None::<u8>; // OK (Lint in future!)
     let _ = Alias::<u8>::None; // OK
-    let _ = Alias::None::<u8>; //~ ERROR type arguments are not allowed for this type
+    let _ = Alias::None::<u8>; //~ ERROR type arguments are not allowed on this type
 }
index a1064d6925111e726f0adfab0225cf89e64be96d..474548a14a9a6e9e89731a82f10c79f6f7a97055 100644 (file)
@@ -1,8 +1,10 @@
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
   --> $DIR/no-type-application-on-aliased-enum-variant.rs:13:27
    |
 LL |     let _ = Alias::None::<u8>;
-   |                           ^^ type argument not allowed
+   |                    ----   ^^ type argument not allowed
+   |                    |
+   |                    not allowed on this
 
 error: aborting due to previous error
 
index cfa4a4b9d20ba669e9bb6757d93af36f156579a5..b3ca260894bc8e14094fac321a0921974c3298d0 100644 (file)
@@ -2,9 +2,13 @@ error[E0282]: type annotations needed
   --> $DIR/closures_in_branches.rs:21:10
    |
 LL |         |x| x.len()
-   |          ^ consider giving this closure parameter a type
+   |          ^
    |
    = note: type must be known at this point
+help: consider giving this closure parameter an explicit type
+   |
+LL |         |x: _| x.len()
+   |           +++
 
 error: aborting due to previous error
 
index 0cdd4cc8dc3bac32435aa3e1debe2d2d70ca2f35..9a0e71b4eed90d8cfd65f7768fe15688bc3606b1 100644 (file)
@@ -2,7 +2,12 @@ error[E0282]: type annotations needed
   --> $DIR/incomplete-inference.rs:6:5
    |
 LL |     None
-   |     ^^^^ cannot infer type for type parameter `T` declared on the enum `Option`
+   |     ^^^^ cannot infer type of the type parameter `T` declared on the enum `Option`
+   |
+help: consider specifying the generic argument
+   |
+LL |     None::<T>
+   |         +++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/type-alias/issue-14933.rs b/src/test/ui/type-alias/issue-14933.rs
new file mode 100644 (file)
index 0000000..bd95332
--- /dev/null
@@ -0,0 +1,6 @@
+// check-pass
+// pretty-expanded FIXME #23616
+
+pub type BigRat<T = isize> = T;
+
+fn main() {}
index 12a98e4d783e70c50a631337269c1b725db34de7..6ac63a91ee9ac546637a527aa15d071bdcc688fc 100644 (file)
@@ -1,13 +1,13 @@
-error[E0282]: type annotations needed
-  --> $DIR/or_else-multiple-type-params.rs:7:10
+error[E0282]: type annotations needed for `Result<Child, F>`
+  --> $DIR/or_else-multiple-type-params.rs:7:18
    |
 LL |         .or_else(|err| {
-   |          ^^^^^^^ cannot infer type for type parameter `F` declared on the associated function `or_else`
+   |                  ^^^^^
    |
-help: consider specifying the type arguments in the method call
+help: try giving this closure an explicit return type
    |
-LL |         .or_else::<F, O>(|err| {
-   |                 ++++++++
+LL |         .or_else(|err| -> Result<Child, F> {
+   |                        +++++++++++++++++++
 
 error: aborting due to previous error
 
index 78b7386c03e1f6530c3fc9fd4c11d297f132efc0..0a48d5756eb41b8671ad2a604c4ff5d94f019509 100644 (file)
@@ -1,10 +1,10 @@
 error[E0282]: type annotations needed
-  --> $DIR/sort_by_key.rs:3:9
+  --> $DIR/sort_by_key.rs:3:40
    |
 LL |     lst.sort_by_key(|&(v, _)| v.iter().sum());
-   |         ^^^^^^^^^^^ cannot infer type for type parameter `K` declared on the associated function `sort_by_key`
+   |                                        ^^^ cannot infer type of the type parameter `S` declared on the associated function `sum`
    |
-help: consider specifying the type argument in the method call
+help: consider specifying the generic argument
    |
 LL |     lst.sort_by_key(|&(v, _)| v.iter().sum::<S>());
    |                                           +++++
index 19e2bd4513dc51ded1545baf22dfbfca5f8f5c0e..e0fecc72f30928c68bb0e8f6be80b30836123af3 100644 (file)
@@ -1,14 +1,13 @@
 error[E0282]: type annotations needed
-  --> $DIR/unbounded-associated-type.rs:15:5
+  --> $DIR/unbounded-associated-type.rs:15:7
    |
-LL |     type A;
-   |     ------- `<Self as T>::A` defined here
-...
 LL |     S(std::marker::PhantomData).foo();
-   |     ^--------------------------------
-   |     |
-   |     this method call resolves to `<Self as T>::A`
-   |     cannot infer type for type parameter `X` declared on the struct `S`
+   |       ^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `PhantomData`
+   |
+help: consider specifying the generic argument
+   |
+LL |     S(std::marker::PhantomData::<T>).foo();
+   |                               +++++
 
 error: aborting due to previous error
 
index 501fa7c8c67c198adfc54c5abeb899e5dd40fcbb..209abfe5cba49157750464c42ac736caf7b521c5 100644 (file)
@@ -2,13 +2,12 @@ error[E0282]: type annotations needed
   --> $DIR/unbounded-type-param-in-fn-with-assoc-type.rs:8:5
    |
 LL |     foo();
-   |     ^^^ cannot infer type for type parameter `T` declared on the function `foo`
+   |     ^^^ cannot infer type of the type parameter `T` declared on the function `foo`
    |
-help: type parameter declared here
-  --> $DIR/unbounded-type-param-in-fn-with-assoc-type.rs:3:8
+help: consider specifying the generic arguments
    |
-LL | fn foo<T, U = u64>() -> (T, U) {
-   |        ^
+LL |     foo::<T, U>();
+   |        ++++++++
 
 error: aborting due to previous error
 
index d01c3a7d4e220258e1d35aeed2765c4948704dab..d92892eeb84eda01096f4091e8c825897287c92f 100644 (file)
@@ -2,13 +2,12 @@ error[E0282]: type annotations needed
   --> $DIR/unbounded-type-param-in-fn.rs:6:5
    |
 LL |     foo();
-   |     ^^^ cannot infer type for type parameter `T` declared on the function `foo`
+   |     ^^^ cannot infer type of the type parameter `T` declared on the function `foo`
    |
-help: type parameter declared here
-  --> $DIR/unbounded-type-param-in-fn.rs:1:8
+help: consider specifying the generic argument
    |
-LL | fn foo<T>() -> T {
-   |        ^
+LL |     foo::<T>();
+   |        +++++
 
 error: aborting due to previous error
 
index 59b3529272688cca09599f0d39e9713882dc2b3d..b59a73af9f93bb83c2969916045d9911151ed7c7 100644 (file)
@@ -1,4 +1,4 @@
-error: expected type, found `<[_]>::into_vec(box [0, 1])`
+error: expected type, found `<[_]>::into_vec(#[rustc_box] ::alloc::boxed::Box::new([0, 1]))`
   --> $DIR/issue-47666.rs:3:25
    |
 LL |     let _ = Option:Some(vec![0, 1]);
index fd2733c1c545e92fb2e61b33a8c92cfd5877ab36..01ed9ea9e231ff2d73e4996b1cc45b5b2a2b6ec0 100644 (file)
@@ -1,7 +1,7 @@
 // error-pattern: this file contains an unclosed delimiter
 // error-pattern: cannot find type `ţ` in this scope
 // error-pattern: parenthesized type parameters may only be used with a `Fn` trait
-// error-pattern: type arguments are not allowed for this type
+// error-pattern: type arguments are not allowed on this type
 // error-pattern: mismatched types
 // ignore-tidy-trailing-newlines
 // `ţ` must be the last character in this file, it cannot be followed by a newline
index 2fe6ba6248c8d66a17ba482499eaee3f04c4d129..199fd6a23f75550af2c8c6615523b92cc47ef8c6 100644 (file)
@@ -30,11 +30,19 @@ error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
 LL |     0: u8(ţ
    |        ^^^^ only `Fn` traits may use parentheses
 
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
   --> $DIR/issue-91268.rs:9:11
    |
 LL |     0: u8(ţ
-   |           ^ type argument not allowed
+   |        -- ^ type argument not allowed
+   |        |
+   |        not allowed on this
+   |
+help: primitive type `u8` doesn't have generic parameters
+   |
+LL -     0: u8(ţ
+LL +     0: u8
+   | 
 
 error[E0308]: mismatched types
   --> $DIR/issue-91268.rs:9:5
index 64fdbfe7db4c899d1fe8352d268966d7aa01cfcd..7d7890c8b80972fd9924a8ca00ce594dc530cd37 100644 (file)
@@ -2,19 +2,18 @@ error[E0283]: type annotations needed
   --> $DIR/type-annotation-needed.rs:6:5
    |
 LL |     foo(42);
-   |     ^^^ cannot infer type for type parameter `T` declared on the function `foo`
+   |     ^^^ cannot infer type of the type parameter `T` declared on the function `foo`
    |
-help: type parameter declared here
-  --> $DIR/type-annotation-needed.rs:1:8
-   |
-LL | fn foo<T: Into<String>>(x: i32) {}
-   |        ^
    = note: cannot satisfy `_: Into<String>`
 note: required by a bound in `foo`
   --> $DIR/type-annotation-needed.rs:1:11
    |
 LL | fn foo<T: Into<String>>(x: i32) {}
    |           ^^^^^^^^^^^^ required by this bound in `foo`
+help: consider specifying the generic argument
+   |
+LL |     foo::<T>(42);
+   |        +++++
 help: consider specifying the type argument in the function call
    |
 LL |     foo::<T>(42);
index 8edec6e0ea3fd0a662a705e601d15ffae563f783..d68d5e5d40b9e7a7efd4b19e182378823591b685 100644 (file)
@@ -1,10 +1,13 @@
 error[E0282]: type annotations needed for `[_; 0]`
-  --> $DIR/cannot_infer_local_or_array.rs:2:13
+  --> $DIR/cannot_infer_local_or_array.rs:2:9
    |
 LL |     let x = [];
-   |         -   ^^ cannot infer type
-   |         |
-   |         consider giving `x` the explicit type `[_; 0]`, with the type parameters specified
+   |         ^
+   |
+help: consider giving `x` an explicit type, where the placeholders `_` are specified
+   |
+LL |     let x: [_; 0] = [];
+   |          ++++++++
 
 error: aborting due to previous error
 
index 69a4af4672f913e14b059bd7872eb3e004159d48..b63d2a3b61c249db086bace9b1001d83d347573e 100644 (file)
@@ -1,12 +1,13 @@
 error[E0282]: type annotations needed for `Vec<T>`
-  --> $DIR/cannot_infer_local_or_vec.rs:2:13
+  --> $DIR/cannot_infer_local_or_vec.rs:2:9
    |
 LL |     let x = vec![];
-   |         -   ^^^^^^ cannot infer type for type parameter `T`
-   |         |
-   |         consider giving `x` the explicit type `Vec<T>`, where the type parameter `T` is specified
+   |         ^
    |
-   = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider giving `x` an explicit type, where the type for type parameter `T` is specified
+   |
+LL |     let x: Vec<T> = vec![];
+   |          ++++++++
 
 error: aborting due to previous error
 
index af7db43970442d68ad37063620951dafc95703b0..be60cda68b9f0fb0ce1951d6d84934f929f10a1d 100644 (file)
@@ -1,12 +1,13 @@
 error[E0282]: type annotations needed for `(Vec<T>,)`
-  --> $DIR/cannot_infer_local_or_vec_in_tuples.rs:2:18
+  --> $DIR/cannot_infer_local_or_vec_in_tuples.rs:2:9
    |
 LL |     let (x, ) = (vec![], );
-   |         -----    ^^^^^^ cannot infer type for type parameter `T`
-   |         |
-   |         consider giving this pattern the explicit type `(Vec<T>,)`, where the type parameter `T` is specified
+   |         ^^^^^
    |
-   = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider giving this pattern a type, where the type for type parameter `T` is specified
+   |
+LL |     let (x, ): (Vec<T>,) = (vec![], );
+   |              +++++++++++
 
 error: aborting due to previous error
 
index 0089d86e340f141d055b977655452c0706f6f59b..167687c18712910fbac5c86b1ef9636d05f5ef57 100644 (file)
@@ -11,7 +11,7 @@ fn infer_ty() {
 }
 
 fn ambig_return() {
-    let x = || -> Vec<_> { Vec::new() }; //~ ERROR type annotations needed for the closure `fn() -> Vec<_>`
+    let x = || -> Vec<_> { Vec::new() }; //~ ERROR type annotations needed
 }
 
 fn main() {}
index c3accad5f25d9273de7bb8230a39bff568a8d619..9ae97f390d3e4bcb04fb13431c64092f8fc4051e 100644 (file)
@@ -1,31 +1,36 @@
-error[E0282]: type annotations needed for `Vec<_>`
-  --> $DIR/unknown_type_for_closure.rs:2:14
+error[E0282]: type annotations needed
+  --> $DIR/unknown_type_for_closure.rs:2:13
    |
 LL |     let x = |b: Vec<_>| {};
-   |              ^ consider giving this closure parameter a type
+   |             ^^^^^^^^^^^^^^ cannot infer type for struct `Vec<_>`
 
 error[E0282]: type annotations needed
   --> $DIR/unknown_type_for_closure.rs:6:14
    |
 LL |     let x = |_| {};
-   |              ^ consider giving this closure parameter a type
+   |              ^
+   |
+help: consider giving this closure parameter an explicit type
+   |
+LL |     let x = |_: _| {};
+   |               +++
 
 error[E0282]: type annotations needed
   --> $DIR/unknown_type_for_closure.rs:10:14
    |
 LL |     let x = |k: _| {};
-   |              ^ consider giving this closure parameter a type
+   |              ^ cannot infer type
 
-error[E0282]: type annotations needed for the closure `fn() -> Vec<_>`
+error[E0282]: type annotations needed
   --> $DIR/unknown_type_for_closure.rs:14:28
    |
 LL |     let x = || -> Vec<_> { Vec::new() };
-   |                            ^^^^^^^^ cannot infer type for type parameter `T`
+   |                            ^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `Vec`
    |
-help: give this closure an explicit return type without `_` placeholders
+help: consider specifying the generic argument
    |
-LL |     let x = || -> Vec<_> { Vec::new() };
-   |                   ~~~~~~
+LL |     let x = || -> Vec<_> { Vec::<T>::new() };
+   |                               +++++
 
 error: aborting due to 4 previous errors
 
index baf218243c4c87ec878ca2a26dcc537946a60c7d..c1ae10efac4b4e874169caf6729eb77e2e8af666 100644 (file)
@@ -26,7 +26,12 @@ error[E0282]: type annotations needed
   --> $DIR/type-path-err-node-types.rs:23:14
    |
 LL |     let _ = |a, b: _| -> _ { 0 };
-   |              ^ consider giving this closure parameter a type
+   |              ^
+   |
+help: consider giving this closure parameter an explicit type
+   |
+LL |     let _ = |a: _, b: _| -> _ { 0 };
+   |               +++
 
 error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/typeck/issue-13853-2.rs b/src/test/ui/typeck/issue-13853-2.rs
new file mode 100644 (file)
index 0000000..27319c9
--- /dev/null
@@ -0,0 +1,6 @@
+trait FromStructReader<'a> { }
+trait ResponseHook {
+     fn get(&self);
+}
+fn foo(res : Box<dyn ResponseHook>) { res.get } //~ ERROR attempted to take value of method
+fn main() {}
diff --git a/src/test/ui/typeck/issue-13853-2.stderr b/src/test/ui/typeck/issue-13853-2.stderr
new file mode 100644 (file)
index 0000000..92068df
--- /dev/null
@@ -0,0 +1,14 @@
+error[E0615]: attempted to take value of method `get` on type `Box<(dyn ResponseHook + 'static)>`
+  --> $DIR/issue-13853-2.rs:5:43
+   |
+LL | fn foo(res : Box<dyn ResponseHook>) { res.get }
+   |                                           ^^^ method, not a field
+   |
+help: use parentheses to call the method
+   |
+LL | fn foo(res : Box<dyn ResponseHook>) { res.get() }
+   |                                              ++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0615`.
diff --git a/src/test/ui/typeck/issue-13853-5.rs b/src/test/ui/typeck/issue-13853-5.rs
new file mode 100644 (file)
index 0000000..2afdf95
--- /dev/null
@@ -0,0 +1,13 @@
+trait Deserializer<'a> { }
+
+trait Deserializable {
+    fn deserialize_token<'a, D: Deserializer<'a>>(_: D, _: &'a str) -> Self;
+}
+
+impl<'a, T: Deserializable> Deserializable for &'a str {
+    //~^ ERROR type parameter `T` is not constrained
+    fn deserialize_token<D: Deserializer<'a>>(_x: D, _y: &'a str) -> &'a str {
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/typeck/issue-13853-5.stderr b/src/test/ui/typeck/issue-13853-5.stderr
new file mode 100644 (file)
index 0000000..3d8f824
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates
+  --> $DIR/issue-13853-5.rs:7:10
+   |
+LL | impl<'a, T: Deserializable> Deserializable for &'a str {
+   |          ^ unconstrained type parameter
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0207`.
diff --git a/src/test/ui/typeck/issue-13853.rs b/src/test/ui/typeck/issue-13853.rs
new file mode 100644 (file)
index 0000000..ac9886d
--- /dev/null
@@ -0,0 +1,38 @@
+trait Node {
+    fn zomg();
+}
+
+trait Graph<N: Node> {
+    fn nodes<'a, I: Iterator<Item=&'a N>>(&'a self) -> I
+        where N: 'a;
+}
+
+impl<N: Node> Graph<N> for Vec<N> {
+    fn nodes<'a, I: Iterator<Item=&'a N>>(&self) -> I
+        where N: 'a
+    {
+        self.iter() //~ ERROR mismatched types
+    }
+}
+
+struct Stuff;
+
+impl Node for Stuff {
+    fn zomg() {
+        println!("zomg");
+    }
+}
+
+fn iterate<N: Node, G: Graph<N>>(graph: &G) {
+    for node in graph.iter() { //~ ERROR no method named `iter` found
+        node.zomg();
+    }
+}
+
+pub fn main() {
+    let graph = Vec::new();
+
+    graph.push(Stuff);
+
+    iterate(graph); //~ ERROR mismatched types
+}
diff --git a/src/test/ui/typeck/issue-13853.stderr b/src/test/ui/typeck/issue-13853.stderr
new file mode 100644 (file)
index 0000000..657bda5
--- /dev/null
@@ -0,0 +1,40 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-13853.rs:14:9
+   |
+LL |     fn nodes<'a, I: Iterator<Item=&'a N>>(&self) -> I
+   |                  - this type parameter              - expected `I` because of return type
+...
+LL |         self.iter()
+   |         ^^^^^^^^^^^ expected type parameter `I`, found struct `std::slice::Iter`
+   |
+   = note: expected type parameter `I`
+                      found struct `std::slice::Iter<'_, N>`
+
+error[E0599]: no method named `iter` found for reference `&G` in the current scope
+  --> $DIR/issue-13853.rs:27:23
+   |
+LL |     for node in graph.iter() {
+   |                       ^^^^ method not found in `&G`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-13853.rs:37:13
+   |
+LL |     iterate(graph);
+   |     ------- ^^^^^
+   |     |       |
+   |     |       expected reference, found struct `Vec`
+   |     |       help: consider borrowing here: `&graph`
+   |     arguments to this function are incorrect
+   |
+   = note: expected reference `&_`
+                 found struct `Vec<Stuff>`
+note: function defined here
+  --> $DIR/issue-13853.rs:26:4
+   |
+LL | fn iterate<N: Node, G: Graph<N>>(graph: &G) {
+   |    ^^^^^^^                       ---------
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0308, E0599.
+For more information about an error, try `rustc --explain E0308`.
index e3c005a0593f6bdaf1178bd5f928c7f7ed7c4bfe..5f831291a3851542982165e39a246c6330461b73 100644 (file)
@@ -1,11 +1,8 @@
 error[E0282]: type annotations needed
-  --> $DIR/issue-65611.rs:59:20
+  --> $DIR/issue-65611.rs:59:13
    |
 LL |     let x = buffer.last().unwrap().0.clone();
-   |             -------^^^^--
-   |             |      |
-   |             |      cannot infer type for type parameter `T`
-   |             this method call resolves to `Option<&T>`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T`
    |
    = note: type must be known at this point
 
diff --git a/src/test/ui/typeck/prim-with-args.fixed b/src/test/ui/typeck/prim-with-args.fixed
new file mode 100644 (file)
index 0000000..1c5fd75
--- /dev/null
@@ -0,0 +1,28 @@
+// run-rustfix
+fn main() {
+
+let _x: isize; //~ ERROR type arguments are not allowed on this type
+let _x: i8; //~ ERROR type arguments are not allowed on this type
+let _x: i16; //~ ERROR type arguments are not allowed on this type
+let _x: i32; //~ ERROR type arguments are not allowed on this type
+let _x: i64; //~ ERROR type arguments are not allowed on this type
+let _x: usize; //~ ERROR type arguments are not allowed on this type
+let _x: u8; //~ ERROR type arguments are not allowed on this type
+let _x: u16; //~ ERROR type arguments are not allowed on this type
+let _x: u32; //~ ERROR type arguments are not allowed on this type
+let _x: u64; //~ ERROR type arguments are not allowed on this type
+let _x: char; //~ ERROR type arguments are not allowed on this type
+
+let _x: isize; //~ ERROR lifetime arguments are not allowed on this type
+let _x: i8; //~ ERROR lifetime arguments are not allowed on this type
+let _x: i16; //~ ERROR lifetime arguments are not allowed on this type
+let _x: i32; //~ ERROR lifetime arguments are not allowed on this type
+let _x: i64; //~ ERROR lifetime arguments are not allowed on this type
+let _x: usize; //~ ERROR lifetime arguments are not allowed on this type
+let _x: u8; //~ ERROR lifetime arguments are not allowed on this type
+let _x: u16; //~ ERROR lifetime arguments are not allowed on this type
+let _x: u32; //~ ERROR lifetime arguments are not allowed on this type
+let _x: u64; //~ ERROR lifetime arguments are not allowed on this type
+let _x: char; //~ ERROR lifetime arguments are not allowed on this type
+
+}
index e5beaca6abb8c8b54a15da99754d2fb71948709f..b05d6c1cb4e4a4e190ac03fd6116fd3dc4df4815 100644 (file)
@@ -1,27 +1,28 @@
+// run-rustfix
 fn main() {
 
-let x: isize<isize>; //~ ERROR type arguments are not allowed for this type
-let x: i8<isize>; //~ ERROR type arguments are not allowed for this type
-let x: i16<isize>; //~ ERROR type arguments are not allowed for this type
-let x: i32<isize>; //~ ERROR type arguments are not allowed for this type
-let x: i64<isize>; //~ ERROR type arguments are not allowed for this type
-let x: usize<isize>; //~ ERROR type arguments are not allowed for this type
-let x: u8<isize>; //~ ERROR type arguments are not allowed for this type
-let x: u16<isize>; //~ ERROR type arguments are not allowed for this type
-let x: u32<isize>; //~ ERROR type arguments are not allowed for this type
-let x: u64<isize>; //~ ERROR type arguments are not allowed for this type
-let x: char<isize>; //~ ERROR type arguments are not allowed for this type
+let _x: isize<isize>; //~ ERROR type arguments are not allowed on this type
+let _x: i8<isize>; //~ ERROR type arguments are not allowed on this type
+let _x: i16<isize>; //~ ERROR type arguments are not allowed on this type
+let _x: i32<isize>; //~ ERROR type arguments are not allowed on this type
+let _x: i64<isize>; //~ ERROR type arguments are not allowed on this type
+let _x: usize<isize>; //~ ERROR type arguments are not allowed on this type
+let _x: u8<isize>; //~ ERROR type arguments are not allowed on this type
+let _x: u16<isize>; //~ ERROR type arguments are not allowed on this type
+let _x: u32<isize>; //~ ERROR type arguments are not allowed on this type
+let _x: u64<isize>; //~ ERROR type arguments are not allowed on this type
+let _x: char<isize>; //~ ERROR type arguments are not allowed on this type
 
-let x: isize<'static>; //~ ERROR lifetime arguments are not allowed for this type
-let x: i8<'static>; //~ ERROR lifetime arguments are not allowed for this type
-let x: i16<'static>; //~ ERROR lifetime arguments are not allowed for this type
-let x: i32<'static>; //~ ERROR lifetime arguments are not allowed for this type
-let x: i64<'static>; //~ ERROR lifetime arguments are not allowed for this type
-let x: usize<'static>; //~ ERROR lifetime arguments are not allowed for this type
-let x: u8<'static>; //~ ERROR lifetime arguments are not allowed for this type
-let x: u16<'static>; //~ ERROR lifetime arguments are not allowed for this type
-let x: u32<'static>; //~ ERROR lifetime arguments are not allowed for this type
-let x: u64<'static>; //~ ERROR lifetime arguments are not allowed for this type
-let x: char<'static>; //~ ERROR lifetime arguments are not allowed for this type
+let _x: isize<'static>; //~ ERROR lifetime arguments are not allowed on this type
+let _x: i8<'static>; //~ ERROR lifetime arguments are not allowed on this type
+let _x: i16<'static>; //~ ERROR lifetime arguments are not allowed on this type
+let _x: i32<'static>; //~ ERROR lifetime arguments are not allowed on this type
+let _x: i64<'static>; //~ ERROR lifetime arguments are not allowed on this type
+let _x: usize<'static>; //~ ERROR lifetime arguments are not allowed on this type
+let _x: u8<'static>; //~ ERROR lifetime arguments are not allowed on this type
+let _x: u16<'static>; //~ ERROR lifetime arguments are not allowed on this type
+let _x: u32<'static>; //~ ERROR lifetime arguments are not allowed on this type
+let _x: u64<'static>; //~ ERROR lifetime arguments are not allowed on this type
+let _x: char<'static>; //~ ERROR lifetime arguments are not allowed on this type
 
 }
index 4bde981e7f2d4fe0c6b20700efd364c913790ddd..7e7bc580b3b9535b9edb0e8743e8958e218da76a 100644 (file)
-error[E0109]: type arguments are not allowed for this type
-  --> $DIR/prim-with-args.rs:3:14
+error[E0109]: type arguments are not allowed on this type
+  --> $DIR/prim-with-args.rs:4:15
    |
-LL | let x: isize<isize>;
-   |              ^^^^^ type argument not allowed
-
-error[E0109]: type arguments are not allowed for this type
-  --> $DIR/prim-with-args.rs:4:11
+LL | let _x: isize<isize>;
+   |         ----- ^^^^^ type argument not allowed
+   |         |
+   |         not allowed on this
+   |
+help: primitive type `isize` doesn't have generic parameters
    |
-LL | let x: i8<isize>;
-   |           ^^^^^ type argument not allowed
+LL - let _x: isize<isize>;
+LL + let _x: isize;
+   | 
 
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
   --> $DIR/prim-with-args.rs:5:12
    |
-LL | let x: i16<isize>;
-   |            ^^^^^ type argument not allowed
+LL | let _x: i8<isize>;
+   |         -- ^^^^^ type argument not allowed
+   |         |
+   |         not allowed on this
+   |
+help: primitive type `i8` doesn't have generic parameters
+   |
+LL - let _x: i8<isize>;
+LL + let _x: i8;
+   | 
 
-error[E0109]: type arguments are not allowed for this type
-  --> $DIR/prim-with-args.rs:6:12
+error[E0109]: type arguments are not allowed on this type
+  --> $DIR/prim-with-args.rs:6:13
+   |
+LL | let _x: i16<isize>;
+   |         --- ^^^^^ type argument not allowed
+   |         |
+   |         not allowed on this
+   |
+help: primitive type `i16` doesn't have generic parameters
    |
-LL | let x: i32<isize>;
-   |            ^^^^^ type argument not allowed
+LL - let _x: i16<isize>;
+LL + let _x: i16;
+   | 
 
-error[E0109]: type arguments are not allowed for this type
-  --> $DIR/prim-with-args.rs:7:12
+error[E0109]: type arguments are not allowed on this type
+  --> $DIR/prim-with-args.rs:7:13
    |
-LL | let x: i64<isize>;
-   |            ^^^^^ type argument not allowed
+LL | let _x: i32<isize>;
+   |         --- ^^^^^ type argument not allowed
+   |         |
+   |         not allowed on this
+   |
+help: primitive type `i32` doesn't have generic parameters
+   |
+LL - let _x: i32<isize>;
+LL + let _x: i32;
+   | 
 
-error[E0109]: type arguments are not allowed for this type
-  --> $DIR/prim-with-args.rs:8:14
+error[E0109]: type arguments are not allowed on this type
+  --> $DIR/prim-with-args.rs:8:13
+   |
+LL | let _x: i64<isize>;
+   |         --- ^^^^^ type argument not allowed
+   |         |
+   |         not allowed on this
    |
-LL | let x: usize<isize>;
-   |              ^^^^^ type argument not allowed
+help: primitive type `i64` doesn't have generic parameters
+   |
+LL - let _x: i64<isize>;
+LL + let _x: i64;
+   | 
 
-error[E0109]: type arguments are not allowed for this type
-  --> $DIR/prim-with-args.rs:9:11
+error[E0109]: type arguments are not allowed on this type
+  --> $DIR/prim-with-args.rs:9:15
+   |
+LL | let _x: usize<isize>;
+   |         ----- ^^^^^ type argument not allowed
+   |         |
+   |         not allowed on this
+   |
+help: primitive type `usize` doesn't have generic parameters
    |
-LL | let x: u8<isize>;
-   |           ^^^^^ type argument not allowed
+LL - let _x: usize<isize>;
+LL + let _x: usize;
+   | 
 
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
   --> $DIR/prim-with-args.rs:10:12
    |
-LL | let x: u16<isize>;
-   |            ^^^^^ type argument not allowed
+LL | let _x: u8<isize>;
+   |         -- ^^^^^ type argument not allowed
+   |         |
+   |         not allowed on this
+   |
+help: primitive type `u8` doesn't have generic parameters
+   |
+LL - let _x: u8<isize>;
+LL + let _x: u8;
+   | 
 
-error[E0109]: type arguments are not allowed for this type
-  --> $DIR/prim-with-args.rs:11:12
+error[E0109]: type arguments are not allowed on this type
+  --> $DIR/prim-with-args.rs:11:13
+   |
+LL | let _x: u16<isize>;
+   |         --- ^^^^^ type argument not allowed
+   |         |
+   |         not allowed on this
    |
-LL | let x: u32<isize>;
-   |            ^^^^^ type argument not allowed
+help: primitive type `u16` doesn't have generic parameters
+   |
+LL - let _x: u16<isize>;
+LL + let _x: u16;
+   | 
 
-error[E0109]: type arguments are not allowed for this type
-  --> $DIR/prim-with-args.rs:12:12
+error[E0109]: type arguments are not allowed on this type
+  --> $DIR/prim-with-args.rs:12:13
+   |
+LL | let _x: u32<isize>;
+   |         --- ^^^^^ type argument not allowed
+   |         |
+   |         not allowed on this
+   |
+help: primitive type `u32` doesn't have generic parameters
    |
-LL | let x: u64<isize>;
-   |            ^^^^^ type argument not allowed
+LL - let _x: u32<isize>;
+LL + let _x: u32;
+   | 
 
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
   --> $DIR/prim-with-args.rs:13:13
    |
-LL | let x: char<isize>;
-   |             ^^^^^ type argument not allowed
+LL | let _x: u64<isize>;
+   |         --- ^^^^^ type argument not allowed
+   |         |
+   |         not allowed on this
+   |
+help: primitive type `u64` doesn't have generic parameters
+   |
+LL - let _x: u64<isize>;
+LL + let _x: u64;
+   | 
 
-error[E0109]: lifetime arguments are not allowed for this type
-  --> $DIR/prim-with-args.rs:15:14
+error[E0109]: type arguments are not allowed on this type
+  --> $DIR/prim-with-args.rs:14:14
+   |
+LL | let _x: char<isize>;
+   |         ---- ^^^^^ type argument not allowed
+   |         |
+   |         not allowed on this
    |
-LL | let x: isize<'static>;
-   |              ^^^^^^^ lifetime argument not allowed
+help: primitive type `char` doesn't have generic parameters
+   |
+LL - let _x: char<isize>;
+LL + let _x: char;
+   | 
 
-error[E0109]: lifetime arguments are not allowed for this type
-  --> $DIR/prim-with-args.rs:16:11
+error[E0109]: lifetime arguments are not allowed on this type
+  --> $DIR/prim-with-args.rs:16:15
+   |
+LL | let _x: isize<'static>;
+   |         ----- ^^^^^^^ lifetime argument not allowed
+   |         |
+   |         not allowed on this
    |
-LL | let x: i8<'static>;
-   |           ^^^^^^^ lifetime argument not allowed
+help: primitive type `isize` doesn't have generic parameters
+   |
+LL - let _x: isize<'static>;
+LL + let _x: isize;
+   | 
 
-error[E0109]: lifetime arguments are not allowed for this type
+error[E0109]: lifetime arguments are not allowed on this type
   --> $DIR/prim-with-args.rs:17:12
    |
-LL | let x: i16<'static>;
-   |            ^^^^^^^ lifetime argument not allowed
+LL | let _x: i8<'static>;
+   |         -- ^^^^^^^ lifetime argument not allowed
+   |         |
+   |         not allowed on this
+   |
+help: primitive type `i8` doesn't have generic parameters
+   |
+LL - let _x: i8<'static>;
+LL + let _x: i8;
+   | 
 
-error[E0109]: lifetime arguments are not allowed for this type
-  --> $DIR/prim-with-args.rs:18:12
+error[E0109]: lifetime arguments are not allowed on this type
+  --> $DIR/prim-with-args.rs:18:13
    |
-LL | let x: i32<'static>;
-   |            ^^^^^^^ lifetime argument not allowed
+LL | let _x: i16<'static>;
+   |         --- ^^^^^^^ lifetime argument not allowed
+   |         |
+   |         not allowed on this
+   |
+help: primitive type `i16` doesn't have generic parameters
+   |
+LL - let _x: i16<'static>;
+LL + let _x: i16;
+   | 
 
-error[E0109]: lifetime arguments are not allowed for this type
-  --> $DIR/prim-with-args.rs:19:12
+error[E0109]: lifetime arguments are not allowed on this type
+  --> $DIR/prim-with-args.rs:19:13
+   |
+LL | let _x: i32<'static>;
+   |         --- ^^^^^^^ lifetime argument not allowed
+   |         |
+   |         not allowed on this
    |
-LL | let x: i64<'static>;
-   |            ^^^^^^^ lifetime argument not allowed
+help: primitive type `i32` doesn't have generic parameters
+   |
+LL - let _x: i32<'static>;
+LL + let _x: i32;
+   | 
 
-error[E0109]: lifetime arguments are not allowed for this type
-  --> $DIR/prim-with-args.rs:20:14
+error[E0109]: lifetime arguments are not allowed on this type
+  --> $DIR/prim-with-args.rs:20:13
+   |
+LL | let _x: i64<'static>;
+   |         --- ^^^^^^^ lifetime argument not allowed
+   |         |
+   |         not allowed on this
+   |
+help: primitive type `i64` doesn't have generic parameters
    |
-LL | let x: usize<'static>;
-   |              ^^^^^^^ lifetime argument not allowed
+LL - let _x: i64<'static>;
+LL + let _x: i64;
+   | 
 
-error[E0109]: lifetime arguments are not allowed for this type
-  --> $DIR/prim-with-args.rs:21:11
+error[E0109]: lifetime arguments are not allowed on this type
+  --> $DIR/prim-with-args.rs:21:15
    |
-LL | let x: u8<'static>;
-   |           ^^^^^^^ lifetime argument not allowed
+LL | let _x: usize<'static>;
+   |         ----- ^^^^^^^ lifetime argument not allowed
+   |         |
+   |         not allowed on this
+   |
+help: primitive type `usize` doesn't have generic parameters
+   |
+LL - let _x: usize<'static>;
+LL + let _x: usize;
+   | 
 
-error[E0109]: lifetime arguments are not allowed for this type
+error[E0109]: lifetime arguments are not allowed on this type
   --> $DIR/prim-with-args.rs:22:12
    |
-LL | let x: u16<'static>;
-   |            ^^^^^^^ lifetime argument not allowed
+LL | let _x: u8<'static>;
+   |         -- ^^^^^^^ lifetime argument not allowed
+   |         |
+   |         not allowed on this
+   |
+help: primitive type `u8` doesn't have generic parameters
+   |
+LL - let _x: u8<'static>;
+LL + let _x: u8;
+   | 
 
-error[E0109]: lifetime arguments are not allowed for this type
-  --> $DIR/prim-with-args.rs:23:12
+error[E0109]: lifetime arguments are not allowed on this type
+  --> $DIR/prim-with-args.rs:23:13
+   |
+LL | let _x: u16<'static>;
+   |         --- ^^^^^^^ lifetime argument not allowed
+   |         |
+   |         not allowed on this
+   |
+help: primitive type `u16` doesn't have generic parameters
    |
-LL | let x: u32<'static>;
-   |            ^^^^^^^ lifetime argument not allowed
+LL - let _x: u16<'static>;
+LL + let _x: u16;
+   | 
 
-error[E0109]: lifetime arguments are not allowed for this type
-  --> $DIR/prim-with-args.rs:24:12
+error[E0109]: lifetime arguments are not allowed on this type
+  --> $DIR/prim-with-args.rs:24:13
    |
-LL | let x: u64<'static>;
-   |            ^^^^^^^ lifetime argument not allowed
+LL | let _x: u32<'static>;
+   |         --- ^^^^^^^ lifetime argument not allowed
+   |         |
+   |         not allowed on this
+   |
+help: primitive type `u32` doesn't have generic parameters
+   |
+LL - let _x: u32<'static>;
+LL + let _x: u32;
+   | 
 
-error[E0109]: lifetime arguments are not allowed for this type
+error[E0109]: lifetime arguments are not allowed on this type
   --> $DIR/prim-with-args.rs:25:13
    |
-LL | let x: char<'static>;
-   |             ^^^^^^^ lifetime argument not allowed
+LL | let _x: u64<'static>;
+   |         --- ^^^^^^^ lifetime argument not allowed
+   |         |
+   |         not allowed on this
+   |
+help: primitive type `u64` doesn't have generic parameters
+   |
+LL - let _x: u64<'static>;
+LL + let _x: u64;
+   | 
+
+error[E0109]: lifetime arguments are not allowed on this type
+  --> $DIR/prim-with-args.rs:26:14
+   |
+LL | let _x: char<'static>;
+   |         ---- ^^^^^^^ lifetime argument not allowed
+   |         |
+   |         not allowed on this
+   |
+help: primitive type `char` doesn't have generic parameters
+   |
+LL - let _x: char<'static>;
+LL + let _x: char;
+   | 
 
 error: aborting due to 22 previous errors
 
index d03001f523757a3fb14b77e47e1e2e373be24c7f..25c2dbe196fe1105b5c62b2191280d8fddc0ffb7 100644 (file)
@@ -6,6 +6,7 @@
 
 fn a() {
     let mut closure0 = None;
+    //~^ ERROR type annotations needed
     let vec = vec![1, 2, 3];
 
     loop {
@@ -14,7 +15,6 @@ fn a() {
                 match closure0.take() {
                     Some(c) => {
                         return c();
-                        //~^ ERROR type annotations needed
                     }
                     None => { }
                 }
index de20a38c447503db8ea0144a1c33a45afb8f1d73..666ab79b65c32376af95221df43562207f3e063f 100644 (file)
@@ -1,13 +1,14 @@
 error[E0282]: type annotations needed for `Option<T>`
-  --> $DIR/unboxed-closures-failed-recursive-fn-2.rs:16:32
+  --> $DIR/unboxed-closures-failed-recursive-fn-2.rs:8:9
    |
 LL |     let mut closure0 = None;
-   |         ------------ consider giving `closure0` the explicit type `Option<T>`, with the type parameters specified
-...
-LL |                         return c();
-   |                                ^^^ cannot infer type
+   |         ^^^^^^^^^^^^
    |
    = note: type must be known at this point
+help: consider giving `closure0` an explicit type, where the placeholders `_` are specified
+   |
+LL |     let mut closure0: Option<T> = None;
+   |                     +++++++++++
 
 error: aborting due to previous error
 
index fbd71bd091d0b6ed300d9eb4301e6783fac1930b..19ac74fdf58319a4ecc022261919e7a69092380f 100644 (file)
@@ -2,7 +2,12 @@ error[E0282]: type annotations needed
   --> $DIR/unconstrained-none.rs:4:5
    |
 LL |     None;
-   |     ^^^^ cannot infer type for type parameter `T` declared on the enum `Option`
+   |     ^^^^ cannot infer type of the type parameter `T` declared on the enum `Option`
+   |
+help: consider specifying the generic argument
+   |
+LL |     None::<T>;
+   |         +++++
 
 error: aborting due to previous error
 
index eb8ebb5165d180da4b9a3db4afee28e2ab464367..1df6d8b446d5c4029d9ecf053c07954129def4b3 100644 (file)
@@ -2,7 +2,12 @@ error[E0282]: type annotations needed
   --> $DIR/unconstrained-ref.rs:6:5
    |
 LL |     S { o: &None };
-   |     ^ cannot infer type for type parameter `T` declared on the struct `S`
+   |     ^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `S`
+   |
+help: consider specifying the generic argument
+   |
+LL |     S::<T> { o: &None };
+   |      +++++
 
 error: aborting due to previous error
 
index 279808dd55bb4dea18fbaa79ccbbcc66d351fb9b..8ecdafdde204553234cd9748e9d4e3a361aefa05 100644 (file)
@@ -8,10 +8,10 @@ LL | impl Copy for W {}
    |      ^^^^
    |
 note: the `Copy` impl for `ManuallyDrop<String>` requires that `String: Copy`
-  --> $DIR/union-copy.rs:8:5
+  --> $DIR/union-copy.rs:8:8
    |
 LL |     a: std::mem::ManuallyDrop<String>
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
index a789179db65bd68603e093834e3b7663700796a7..8df8eab34a715cb46aa388a93f127248619d35ae 100644 (file)
@@ -3,6 +3,8 @@ error[E0432]: unresolved import `not_existing_crate`
    |
 LL | use not_existing_crate::*;
    |     ^^^^^^^^^^^^^^^^^^ maybe a missing crate `not_existing_crate`?
+   |
+   = help: consider adding `extern crate not_existing_crate` to use the `not_existing_crate` crate
 
 error: aborting due to previous error
 
index b65c3dfb90b4277911aecee662633ecccdf81809..4125c593c747fda6167a93942160f1a6e4c6eda6 100644 (file)
@@ -1,5 +1,6 @@
 use foo::bar; //~ ERROR unresolved import `foo` [E0432]
               //~^ maybe a missing crate `foo`?
+              //~| HELP consider adding `extern crate foo` to use the `foo` crate
 
 use bar::Baz as x; //~ ERROR unresolved import `bar::Baz` [E0432]
                    //~| no `Baz` in `bar`
index d4bfea57809b04b072b4b4dcca88360fba386b0e..0dd928c8b6ffd35f681827c00c91e21733e512f7 100644 (file)
@@ -3,9 +3,11 @@ error[E0432]: unresolved import `foo`
    |
 LL | use foo::bar;
    |     ^^^ maybe a missing crate `foo`?
+   |
+   = help: consider adding `extern crate foo` to use the `foo` crate
 
 error[E0432]: unresolved import `bar::Baz`
-  --> $DIR/unresolved-import.rs:4:5
+  --> $DIR/unresolved-import.rs:5:5
    |
 LL | use bar::Baz as x;
    |     ^^^^^---^^^^^
@@ -14,7 +16,7 @@ LL | use bar::Baz as x;
    |     no `Baz` in `bar`
 
 error[E0432]: unresolved import `food::baz`
-  --> $DIR/unresolved-import.rs:9:5
+  --> $DIR/unresolved-import.rs:10:5
    |
 LL | use food::baz;
    |     ^^^^^^---
@@ -23,7 +25,7 @@ LL | use food::baz;
    |     no `baz` in `food`
 
 error[E0432]: unresolved import `food::beens`
-  --> $DIR/unresolved-import.rs:14:12
+  --> $DIR/unresolved-import.rs:15:12
    |
 LL | use food::{beens as Foo};
    |            -----^^^^^^^
@@ -32,13 +34,13 @@ LL | use food::{beens as Foo};
    |            help: a similar name exists in the module: `beans`
 
 error[E0432]: unresolved import `MyEnum`
-  --> $DIR/unresolved-import.rs:38:9
+  --> $DIR/unresolved-import.rs:39:9
    |
 LL |     use MyEnum::*;
    |         ^^^^^^ help: a similar path exists: `self::MyEnum`
 
 error[E0432]: unresolved import `Enum`
-  --> $DIR/unresolved-import.rs:48:9
+  --> $DIR/unresolved-import.rs:49:9
    |
 LL |     use Enum::*;
    |         ^^^^ help: a similar path exists: `self::Enum`
index 46b06e2b3662a593eb151ae66b6c1ad57fa509a2..6d17ba9b5b26199c599edc7686bfc3c150b36d80 100644 (file)
@@ -1,5 +1,5 @@
 fn foo() {
-    let x: usize<foo>; //~ ERROR const arguments are not allowed for this type
+    let x: usize<foo>; //~ ERROR const arguments are not allowed on this type
 }
 
 fn main() {}
index f1eae3b500840f4d8cdc56a1bd29e98c1987fe04..c657f0faa0b98a64ba2a0252ad8e9d6cf579759a 100644 (file)
@@ -1,8 +1,16 @@
-error[E0109]: const arguments are not allowed for this type
+error[E0109]: const arguments are not allowed on this type
   --> $DIR/usize-generic-argument-parent.rs:2:18
    |
 LL |     let x: usize<foo>;
-   |                  ^^^ const argument not allowed
+   |            ----- ^^^ const argument not allowed
+   |            |
+   |            not allowed on this
+   |
+help: primitive type `usize` doesn't have generic parameters
+   |
+LL -     let x: usize<foo>;
+LL +     let x: usize;
+   | 
 
 error: aborting due to previous error
 
index 39ad1039d9e3e1746177bf5d134af4c164f95528..38472bc19f2f76e245eba54a6e97ee6821b3c1db 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 39ad1039d9e3e1746177bf5d134af4c164f95528
+Subproject commit 38472bc19f2f76e245eba54a6e97ee6821b3c1db
index 51d5b510ab93053e155d1b6ec3cbb0ade5ceb101..070c7e591420d49128fea3160076391425d2c615 100644 (file)
@@ -371,7 +371,7 @@ fn record(&mut self, lifetime: &Option<Lifetime>) {
         if let Some(ref lt) = *lifetime {
             if lt.name == LifetimeName::Static {
                 self.lts.push(RefLt::Static);
-            } else if let LifetimeName::Param(ParamName::Fresh(_)) = lt.name {
+            } else if let LifetimeName::Param(_, ParamName::Fresh) = lt.name {
                 // Fresh lifetimes generated should be ignored.
             } else if lt.is_elided() {
                 self.lts.push(RefLt::Unnamed);
index 548f7b2528b1171acd5fc7877c3ebb6f1591b734..0b96f6ff6835800aec2f42ec9614c88319c8425a 100644 (file)
@@ -343,7 +343,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         use fmt::Write;
         f.write_char('&')?;
         match self.lt {
-            LifetimeName::Param(ParamName::Plain(name)) => {
+            LifetimeName::Param(_, ParamName::Plain(name)) => {
                 name.fmt(f)?;
                 f.write_char(' ')?;
             },
index 5a8677f90be413bbdb9052104a7023242e674909..025dd57e83aa59ccfe8e7da39f19ef6521597c4b 100644 (file)
@@ -187,11 +187,13 @@ fn item_has_safety_comment(cx: &LateContext<'_>, item: &hir::Item<'_>) -> bool {
                 && Lrc::ptr_eq(&unsafe_line.sf, &comment_start_line.sf)
                 && let Some(src) = unsafe_line.sf.src.as_deref()
             {
-                comment_start_line.line < unsafe_line.line && text_has_safety_comment(
-                    src,
-                    &unsafe_line.sf.lines[comment_start_line.line + 1..=unsafe_line.line],
-                    unsafe_line.sf.start_pos.to_usize(),
-                )
+                unsafe_line.sf.lines(|lines| {
+                    comment_start_line.line < unsafe_line.line && text_has_safety_comment(
+                        src,
+                        &lines[comment_start_line.line + 1..=unsafe_line.line],
+                        unsafe_line.sf.start_pos.to_usize(),
+                    )
+                })
             } else {
                 // Problem getting source text. Pretend a comment was found.
                 true
@@ -249,11 +251,13 @@ fn span_from_macro_expansion_has_safety_comment(cx: &LateContext<'_>, span: Span
             && Lrc::ptr_eq(&unsafe_line.sf, &macro_line.sf)
             && let Some(src) = unsafe_line.sf.src.as_deref()
         {
-            macro_line.line < unsafe_line.line && text_has_safety_comment(
-                src,
-                &unsafe_line.sf.lines[macro_line.line + 1..=unsafe_line.line],
-                unsafe_line.sf.start_pos.to_usize(),
-            )
+            unsafe_line.sf.lines(|lines| {
+                macro_line.line < unsafe_line.line && text_has_safety_comment(
+                    src,
+                    &lines[macro_line.line + 1..=unsafe_line.line],
+                    unsafe_line.sf.start_pos.to_usize(),
+                )
+            })
         } else {
             // Problem getting source text. Pretend a comment was found.
             true
@@ -276,11 +280,13 @@ fn span_in_body_has_safety_comment(cx: &LateContext<'_>, span: Span) -> bool {
             // Get the text from the start of function body to the unsafe block.
             //     fn foo() { some_stuff; unsafe { stuff }; other_stuff; }
             //              ^-------------^
-            body_line.line < unsafe_line.line && text_has_safety_comment(
-                src,
-                &unsafe_line.sf.lines[body_line.line + 1..=unsafe_line.line],
-                unsafe_line.sf.start_pos.to_usize(),
-            )
+            unsafe_line.sf.lines(|lines| {
+                body_line.line < unsafe_line.line && text_has_safety_comment(
+                    src,
+                    &lines[body_line.line + 1..=unsafe_line.line],
+                    unsafe_line.sf.start_pos.to_usize(),
+                )
+            })
         } else {
             // Problem getting source text. Pretend a comment was found.
             true
index 4e037d88494d751adefd65449426f1ff09e414dc..39595f589c70be77c832047d11c4e655a8d893a0 100644 (file)
@@ -283,10 +283,10 @@ pub fn span_lint_and_sugg_for_edges(
             {
                 let split_idx = MAX_SUGGESTION_HIGHLIGHT_LINES / 2;
                 let span_upper = sm.span_until_char(
-                    sp.with_hi(line_upper.sf.lines[line_upper.line + split_idx]),
+                    sp.with_hi(line_upper.sf.lines(|lines| lines[line_upper.line + split_idx])),
                     '\n',
                 );
-                let span_bottom = sp.with_lo(line_bottom.sf.lines[line_bottom.line - split_idx]);
+                let span_bottom = sp.with_lo(line_bottom.sf.lines(|lines| lines[line_bottom.line - split_idx]));
 
                 let sugg_lines_vec = sugg.lines().collect::<Vec<&str>>();
                 let sugg_upper = sugg_lines_vec[..split_idx].join("\n");
index c440793b90e0edee2dc8b2442930b80c869ea1e3..fc1a4e1f6025555bb7c472d6c4c0968676bf3a9b 100644 (file)
@@ -902,16 +902,14 @@ pub fn hash_guard(&mut self, g: &Guard<'_>) {
 
     pub fn hash_lifetime(&mut self, lifetime: Lifetime) {
         std::mem::discriminant(&lifetime.name).hash(&mut self.s);
-        if let LifetimeName::Param(ref name) = lifetime.name {
+        if let LifetimeName::Param(param_id, ref name) = lifetime.name {
             std::mem::discriminant(name).hash(&mut self.s);
+            param_id.hash(&mut self.s);
             match name {
                 ParamName::Plain(ref ident) => {
                     ident.name.hash(&mut self.s);
                 },
-                ParamName::Fresh(ref size) => {
-                    size.hash(&mut self.s);
-                },
-                ParamName::Error => {},
+                ParamName::Fresh | ParamName::Error => {},
             }
         }
     }
index adb37cc9d7510bd1d9a58d5fccbdbd8af75c52d2..833f8cde63abaa94d35849a0121ea85bd2f2460b 100644 (file)
@@ -1149,7 +1149,7 @@ fn line_span<T: LintContext>(cx: &T, span: Span) -> Span {
     let span = original_sp(span, DUMMY_SP);
     let source_map_and_line = cx.sess().source_map().lookup_line(span.lo()).unwrap();
     let line_no = source_map_and_line.line;
-    let line_start = source_map_and_line.sf.lines[line_no];
+    let line_start = source_map_and_line.sf.lines(|lines| lines[line_no]);
     span.with_lo(line_start)
 }
 
index 78d8f1e213af0396c81a471e4d0da7aef57f616d..58abef38ea8be9e1cc7505536de596ac62e8d76f 100644 (file)
@@ -125,18 +125,18 @@ fn check_rvalue<'tcx>(
         Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => {
             check_place(tcx, *place, span, body)
         },
-        Rvalue::Cast(CastKind::Misc, operand, cast_ty) => {
-            use rustc_middle::ty::cast::CastTy;
-            let cast_in = CastTy::from_ty(operand.ty(body, tcx)).expect("bad input type for cast");
-            let cast_out = CastTy::from_ty(*cast_ty).expect("bad output type for cast");
-            match (cast_in, cast_out) {
-                (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) => {
-                    Err((span, "casting pointers to ints is unstable in const fn".into()))
-                },
-                _ => check_operand(tcx, operand, span, body),
-            }
+        Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => {
+            Err((span, "casting pointers to ints is unstable in const fn".into()))
+        },
+        Rvalue::Cast(CastKind::Misc, operand, _) => {
+            check_operand(tcx, operand, span, body)
         },
-        Rvalue::Cast(CastKind::Pointer(PointerCast::MutToConstPointer | PointerCast::ArrayToPointer), operand, _) => {
+        Rvalue::Cast(
+            CastKind::PointerFromExposedAddress
+            | CastKind::Pointer(PointerCast::MutToConstPointer | PointerCast::ArrayToPointer),
+            operand,
+            _
+        ) => {
             check_operand(tcx, operand, span, body)
         },
         Rvalue::Cast(
index 065ff89e33b67b3527fcdd56cf8b432e593e32d4..749efd29565a9b8f47afb441aaacfcc10bc145d7 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 065ff89e33b67b3527fcdd56cf8b432e593e32d4
+Subproject commit 749efd29565a9b8f47afb441aaacfcc10bc145d7
index 5d5bbec9b60010dd7389a084c56693baf6bda780..f94fa62d69faf5bd63b3772d3ec4f0c76cf2db57 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 5d5bbec9b60010dd7389a084c56693baf6bda780
+Subproject commit f94fa62d69faf5bd63b3772d3ec4f0c76cf2db57
index cf72dc4bd09a38b8f655e58a17af0cbfe16f333c..135a12b55713a561ebab99c2cc5083afd36c513e 100644 (file)
@@ -7,8 +7,8 @@
 
 const ENTRY_LIMIT: usize = 1000;
 // FIXME: The following limits should be reduced eventually.
-const ROOT_ENTRY_LIMIT: usize = 971;
-const ISSUES_ENTRY_LIMIT: usize = 2234;
+const ROOT_ENTRY_LIMIT: usize = 969;
+const ISSUES_ENTRY_LIMIT: usize = 2211;
 
 fn check_entries(path: &Path, bad: &mut bool) {
     let dirs = walkdir::WalkDir::new(&path.join("test/ui"))
index e161adcd6e0244e002ee2acd7dac15e4a0023c42..25e2c384624e9a89e0b5b3e926edf1cf3e263c1f 100644 (file)
@@ -183,6 +183,16 @@ message_on_add = """\
 """
 message_on_remove = "Issue #{number}'s nomination request has been removed."
 
+[notify-zulip."I-types-nominated"]
+zulip_stream = 326866 # #T-types/nominated
+topic = "#{number}: {title}"
+message_on_add = """\
+@*T-types* issue #{number} "{title}" has been nominated for team discussion.
+"""
+message_on_remove = "Issue #{number}'s nomination has been removed. Thanks all for participating!"
+message_on_close = "Issue #{number} has been closed. Thanks for participating!"
+message_on_reopen = "Issue #{number} has been reopened. Pinging @*T-types*."
+
 [notify-zulip."A-edition-2021"]
 required_labels = ["C-bug"]
 zulip_stream = 268952 # #edition 2021