]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #96280 - lygstate:ffi-fixes, r=joshtriplett
authorbors <bors@rust-lang.org>
Tue, 3 May 2022 17:22:58 +0000 (17:22 +0000)
committerbors <bors@rust-lang.org>
Tue, 3 May 2022 17:22:58 +0000 (17:22 +0000)
library/core: Fixes implement of c_uint, c_long, c_ulong

Fixes: aa670166243 ("make memcmp return a value of c_int_width instead of i32")
Introduce c_num_definition to getting the cfg_if logic easier to maintain
Add newlines for easier code reading

Signed-off-by: Yonggang Luo <luoyonggang@gmail.com>
1181 files changed:
Cargo.lock
compiler/rustc_ast/src/ast.rs
compiler/rustc_ast/src/attr/mod.rs
compiler/rustc_ast/src/mut_visit.rs
compiler/rustc_ast/src/token.rs
compiler/rustc_ast/src/tokenstream.rs
compiler/rustc_ast/src/util/parser.rs
compiler/rustc_ast/src/visit.rs
compiler/rustc_ast_lowering/src/expr.rs
compiler/rustc_ast_lowering/src/index.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_passes/src/feature_gate.rs
compiler/rustc_ast_passes/src/node_count.rs
compiler/rustc_ast_pretty/src/pprust/state.rs
compiler/rustc_ast_pretty/src/pprust/state/expr.rs
compiler/rustc_borrowck/src/constraints/graph.rs
compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
compiler/rustc_borrowck/src/diagnostics/mod.rs
compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
compiler/rustc_borrowck/src/diagnostics/region_errors.rs
compiler/rustc_borrowck/src/type_check/mod.rs
compiler/rustc_builtin_macros/src/asm.rs
compiler/rustc_builtin_macros/src/derive.rs
compiler/rustc_builtin_macros/src/deriving/default.rs
compiler/rustc_codegen_cranelift/Cargo.lock
compiler/rustc_codegen_cranelift/Cargo.toml
compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock
compiler/rustc_codegen_cranelift/example/float-minmax-pass.rs [new file with mode: 0644]
compiler/rustc_codegen_cranelift/example/mini_core.rs
compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
compiler/rustc_codegen_cranelift/example/std_example.rs
compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Disable-unsupported-tests.patch
compiler/rustc_codegen_cranelift/rust-toolchain
compiler/rustc_codegen_cranelift/scripts/filter_profile.rs
compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh
compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
compiler/rustc_codegen_cranelift/scripts/tests.sh
compiler/rustc_codegen_cranelift/src/base.rs
compiler/rustc_codegen_cranelift/src/cast.rs
compiler/rustc_codegen_cranelift/src/config.rs
compiler/rustc_codegen_cranelift/src/discriminant.rs
compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
compiler/rustc_codegen_cranelift/src/lib.rs
compiler/rustc_codegen_cranelift/src/num.rs
compiler/rustc_codegen_gcc/src/lib.rs
compiler/rustc_codegen_llvm/src/back/lto.rs
compiler/rustc_codegen_llvm/src/back/write.rs
compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
compiler/rustc_codegen_llvm/src/lib.rs
compiler/rustc_codegen_llvm/src/llvm/ffi.rs
compiler/rustc_codegen_llvm/src/llvm_util.rs
compiler/rustc_codegen_ssa/src/back/link.rs
compiler/rustc_codegen_ssa/src/back/linker.rs
compiler/rustc_codegen_ssa/src/back/lto.rs
compiler/rustc_codegen_ssa/src/back/metadata.rs
compiler/rustc_codegen_ssa/src/back/symbol_export.rs
compiler/rustc_codegen_ssa/src/back/write.rs
compiler/rustc_codegen_ssa/src/base.rs
compiler/rustc_codegen_ssa/src/common.rs
compiler/rustc_codegen_ssa/src/lib.rs
compiler/rustc_codegen_ssa/src/mir/analyze.rs
compiler/rustc_codegen_ssa/src/mir/block.rs
compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
compiler/rustc_codegen_ssa/src/mir/mod.rs
compiler/rustc_codegen_ssa/src/traits/backend.rs
compiler/rustc_codegen_ssa/src/traits/write.rs
compiler/rustc_const_eval/src/const_eval/eval_queries.rs
compiler/rustc_const_eval/src/const_eval/fn_queries.rs
compiler/rustc_const_eval/src/const_eval/mod.rs
compiler/rustc_const_eval/src/const_eval/valtrees.rs [new file with mode: 0644]
compiler/rustc_const_eval/src/interpret/mod.rs
compiler/rustc_const_eval/src/interpret/operand.rs
compiler/rustc_const_eval/src/interpret/place.rs
compiler/rustc_const_eval/src/lib.rs
compiler/rustc_const_eval/src/transform/promote_consts.rs
compiler/rustc_const_eval/src/transform/validate.rs
compiler/rustc_const_eval/src/util/call_kind.rs
compiler/rustc_error_codes/src/error_codes/E0705.md
compiler/rustc_error_messages/locales/en-US/parser.ftl
compiler/rustc_error_messages/locales/en-US/typeck.ftl
compiler/rustc_errors/src/diagnostic.rs
compiler/rustc_errors/src/diagnostic_builder.rs
compiler/rustc_errors/src/emitter.rs
compiler/rustc_errors/src/json.rs
compiler/rustc_errors/src/lib.rs
compiler/rustc_expand/src/base.rs
compiler/rustc_expand/src/build.rs
compiler/rustc_expand/src/config.rs
compiler/rustc_expand/src/expand.rs
compiler/rustc_expand/src/mbe.rs
compiler/rustc_expand/src/mbe/macro_check.rs
compiler/rustc_expand/src/mbe/macro_rules.rs
compiler/rustc_expand/src/mbe/metavar_expr.rs
compiler/rustc_expand/src/mbe/quoted.rs
compiler/rustc_expand/src/mbe/transcribe.rs
compiler/rustc_expand/src/parse/tests.rs
compiler/rustc_expand/src/placeholders.rs
compiler/rustc_expand/src/proc_macro.rs
compiler/rustc_expand/src/proc_macro_server.rs
compiler/rustc_feature/src/active.rs
compiler/rustc_hir/src/arena.rs
compiler/rustc_hir/src/hir.rs
compiler/rustc_hir/src/intravisit.rs
compiler/rustc_hir/src/itemlikevisit.rs
compiler/rustc_hir/src/lang_items.rs
compiler/rustc_hir_pretty/src/lib.rs
compiler/rustc_incremental/src/assert_dep_graph.rs
compiler/rustc_index/src/bit_set.rs
compiler/rustc_index/src/bit_set/tests.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/find_anon_type.rs
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
compiler/rustc_infer/src/infer/error_reporting/note.rs
compiler/rustc_interface/src/tests.rs
compiler/rustc_lint/src/array_into_iter.rs
compiler/rustc_lint/src/builtin.rs
compiler/rustc_lint/src/context.rs
compiler/rustc_lint/src/non_fmt_panic.rs
compiler/rustc_lint/src/nonstandard_style.rs
compiler/rustc_lint/src/types.rs
compiler/rustc_lint_defs/src/lib.rs
compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
compiler/rustc_macros/src/diagnostics/diagnostic.rs [new file with mode: 0644]
compiler/rustc_macros/src/diagnostics/error.rs [new file with mode: 0644]
compiler/rustc_macros/src/diagnostics/mod.rs [new file with mode: 0644]
compiler/rustc_macros/src/diagnostics/subdiagnostic.rs [new file with mode: 0644]
compiler/rustc_macros/src/diagnostics/utils.rs [new file with mode: 0644]
compiler/rustc_macros/src/lib.rs
compiler/rustc_macros/src/session_diagnostic.rs [deleted file]
compiler/rustc_metadata/src/creader.rs
compiler/rustc_metadata/src/rmeta/decoder.rs
compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
compiler/rustc_metadata/src/rmeta/encoder.rs
compiler/rustc_metadata/src/rmeta/mod.rs
compiler/rustc_middle/src/hir/map/mod.rs
compiler/rustc_middle/src/middle/exported_symbols.rs
compiler/rustc_middle/src/middle/stability.rs
compiler/rustc_middle/src/mir/interpret/allocation.rs
compiler/rustc_middle/src/mir/mod.rs
compiler/rustc_middle/src/mir/patch.rs
compiler/rustc_middle/src/mir/traversal.rs
compiler/rustc_middle/src/query/mod.rs
compiler/rustc_middle/src/thir.rs
compiler/rustc_middle/src/ty/codec.rs
compiler/rustc_middle/src/ty/consts/int.rs
compiler/rustc_middle/src/ty/consts/valtree.rs
compiler/rustc_middle/src/ty/context.rs
compiler/rustc_middle/src/ty/diagnostics.rs
compiler/rustc_middle/src/ty/error.rs
compiler/rustc_middle/src/ty/layout.rs
compiler/rustc_middle/src/ty/list.rs
compiler/rustc_middle/src/ty/mod.rs
compiler/rustc_middle/src/ty/print/mod.rs
compiler/rustc_middle/src/ty/print/pretty.rs
compiler/rustc_middle/src/ty/query.rs
compiler/rustc_middle/src/ty/sty.rs
compiler/rustc_middle/src/ty/util.rs
compiler/rustc_mir_build/src/check_unsafety.rs
compiler/rustc_mir_build/src/thir/pattern/mod.rs
compiler/rustc_mir_dataflow/src/framework/fmt.rs
compiler/rustc_mir_transform/src/add_retag.rs
compiler/rustc_mir_transform/src/check_unsafety.rs
compiler/rustc_mir_transform/src/const_prop.rs
compiler/rustc_mir_transform/src/const_prop_lint.rs
compiler/rustc_mir_transform/src/deref_separator.rs
compiler/rustc_mir_transform/src/early_otherwise_branch.rs
compiler/rustc_mir_transform/src/lib.rs
compiler/rustc_mir_transform/src/pass_manager.rs
compiler/rustc_monomorphize/src/collector.rs
compiler/rustc_monomorphize/src/partitioning/default.rs
compiler/rustc_parse/Cargo.toml
compiler/rustc_parse/src/lexer/mod.rs
compiler/rustc_parse/src/lexer/tokentrees.rs
compiler/rustc_parse/src/lexer/unicode_chars.rs
compiler/rustc_parse/src/parser/attr.rs
compiler/rustc_parse/src/parser/attr_wrapper.rs
compiler/rustc_parse/src/parser/diagnostics.rs
compiler/rustc_parse/src/parser/expr.rs
compiler/rustc_parse/src/parser/generics.rs
compiler/rustc_parse/src/parser/item.rs
compiler/rustc_parse/src/parser/mod.rs
compiler/rustc_parse/src/parser/nonterminal.rs
compiler/rustc_parse/src/parser/pat.rs
compiler/rustc_parse/src/parser/path.rs
compiler/rustc_parse/src/parser/stmt.rs
compiler/rustc_parse/src/parser/ty.rs
compiler/rustc_passes/src/dead.rs
compiler/rustc_passes/src/entry.rs
compiler/rustc_passes/src/hir_stats.rs
compiler/rustc_passes/src/liveness.rs
compiler/rustc_passes/src/reachable.rs
compiler/rustc_passes/src/stability.rs
compiler/rustc_privacy/src/lib.rs
compiler/rustc_query_impl/src/keys.rs
compiler/rustc_resolve/src/build_reduced_graph.rs
compiler/rustc_resolve/src/diagnostics.rs
compiler/rustc_resolve/src/ident.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_save_analysis/src/dump_visitor.rs
compiler/rustc_save_analysis/src/lib.rs
compiler/rustc_save_analysis/src/sig.rs
compiler/rustc_serialize/src/serialize.rs
compiler/rustc_session/src/config.rs
compiler/rustc_session/src/options.rs
compiler/rustc_session/src/parse.rs
compiler/rustc_session/src/session.rs
compiler/rustc_session/src/utils.rs
compiler/rustc_span/src/hygiene.rs
compiler/rustc_span/src/lib.rs
compiler/rustc_span/src/profiling.rs [new file with mode: 0644]
compiler/rustc_span/src/source_map.rs
compiler/rustc_span/src/source_map/tests.rs
compiler/rustc_span/src/symbol.rs
compiler/rustc_target/src/abi/call/mod.rs
compiler/rustc_target/src/abi/call/nvptx64.rs
compiler/rustc_target/src/abi/mod.rs
compiler/rustc_target/src/asm/mips.rs
compiler/rustc_target/src/spec/mod.rs
compiler/rustc_target/src/spec/wasm64_unknown_unknown.rs
compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
compiler/rustc_trait_selection/src/traits/object_safety.rs
compiler/rustc_trait_selection/src/traits/project.rs
compiler/rustc_typeck/src/astconv/generics.rs
compiler/rustc_typeck/src/astconv/mod.rs
compiler/rustc_typeck/src/check/check.rs
compiler/rustc_typeck/src/check/compare_method.rs
compiler/rustc_typeck/src/check/expr.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/generator_interior/drop_ranges/cfg_build.rs
compiler/rustc_typeck/src/check/method/suggest.rs
compiler/rustc_typeck/src/check/mod.rs
compiler/rustc_typeck/src/check/op.rs
compiler/rustc_typeck/src/check/pat.rs
compiler/rustc_typeck/src/check/wfcheck.rs
compiler/rustc_typeck/src/check_unused.rs
compiler/rustc_typeck/src/coherence/orphan.rs
compiler/rustc_typeck/src/collect.rs
compiler/rustc_typeck/src/collect/type_of.rs
compiler/rustc_typeck/src/errors.rs
compiler/rustc_typeck/src/lib.rs
library/alloc/benches/vec_deque.rs
library/alloc/src/borrow.rs
library/alloc/src/collections/binary_heap.rs
library/alloc/src/collections/binary_heap/tests.rs [new file with mode: 0644]
library/alloc/src/collections/linked_list.rs
library/alloc/src/collections/linked_list/tests.rs
library/alloc/src/collections/vec_deque/mod.rs
library/alloc/src/collections/vec_deque/spec_extend.rs [new file with mode: 0644]
library/alloc/src/collections/vec_deque/tests.rs
library/alloc/src/fmt.rs
library/alloc/src/rc.rs
library/alloc/src/string.rs
library/alloc/src/sync.rs
library/alloc/src/vec/into_iter.rs
library/alloc/src/vec/is_zero.rs
library/alloc/src/vec/mod.rs
library/alloc/src/vec/spec_extend.rs
library/alloc/tests/binary_heap.rs [deleted file]
library/alloc/tests/c_str.rs
library/alloc/tests/lib.rs
library/alloc/tests/linked_list.rs
library/core/benches/iter.rs
library/core/benches/lib.rs
library/core/src/internal_macros.rs
library/core/src/iter/adapters/enumerate.rs
library/core/src/iter/adapters/map.rs
library/core/src/iter/adapters/zip.rs
library/core/src/iter/sources/repeat_with.rs
library/core/src/iter/traits/collect.rs
library/core/src/macros/mod.rs
library/core/src/num/f32.rs
library/core/src/num/f64.rs
library/core/src/num/int_macros.rs
library/core/src/num/uint_macros.rs
library/core/src/ops/mod.rs
library/core/src/ops/try_trait.rs
library/core/src/option.rs
library/core/src/panic/location.rs
library/core/src/panic/unwind_safe.rs
library/core/src/result.rs
library/core/src/slice/iter/macros.rs
library/core/src/slice/mod.rs
library/core/tests/num/ops.rs
library/proc_macro/src/lib.rs
library/proc_macro/src/quote.rs
library/std/src/collections/hash/map.rs
library/std/src/ffi/mod.rs
library/std/src/lib.rs
library/std/src/macros.rs
library/std/src/os/unix/process.rs
library/std/src/os/windows/io/handle.rs
library/std/src/path.rs
library/std/src/path/tests.rs
library/std/src/process/tests.rs
library/std/src/sys/unix/fd.rs
library/std/src/sys/unix/fs.rs
library/std/src/sys/unix/mod.rs
library/std/src/sys/unix/process/process_common.rs
library/std/src/sys/unix/thread_parker.rs [new file with mode: 0644]
library/std/src/sys/unix/time.rs
library/std/src/sys/windows/args.rs
library/std/src/sys/windows/c.rs
library/std/src/sys/windows/handle.rs
library/std/src/sys/windows/mod.rs
library/std/src/sys/windows/path.rs
library/std/src/sys/windows/path/tests.rs
library/std/src/sys/windows/pipe.rs
library/std/src/sys/windows/process.rs
library/std/src/sys/windows/process/tests.rs
library/std/src/sys/windows/thread_parker.rs
library/std/src/sys_common/thread_parker/futex.rs
library/std/src/sys_common/thread_parker/generic.rs
library/std/src/sys_common/thread_parker/mod.rs
library/std/src/sys_common/wtf8.rs
library/std/src/thread/local.rs
library/std/src/thread/mod.rs
src/bootstrap/Cargo.toml
src/bootstrap/bin/rustdoc.rs
src/bootstrap/bootstrap.py
src/bootstrap/builder.rs
src/bootstrap/builder/tests.rs
src/bootstrap/check.rs
src/bootstrap/compile.rs
src/bootstrap/config.rs
src/bootstrap/dist.rs
src/bootstrap/doc.rs
src/bootstrap/flags.rs
src/bootstrap/lib.rs
src/bootstrap/native.rs
src/bootstrap/tarball.rs
src/bootstrap/test.rs
src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh
src/ci/docker/host-x86_64/dist-x86_64-linux/build-gcc.sh
src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version
src/doc/book
src/doc/embedded-book
src/doc/rust-by-example
src/doc/rustc-dev-guide
src/doc/rustc/src/command-line-arguments.md
src/doc/unstable-book/src/compiler-flags/cf-protection.md
src/doc/unstable-book/src/language-features/yeet-expr.md [new file with mode: 0644]
src/etc/check_missing_items.py
src/librustdoc/Cargo.toml
src/librustdoc/clean/mod.rs
src/librustdoc/clean/render_macro_matchers.rs
src/librustdoc/clean/types.rs
src/librustdoc/clean/types/tests.rs [new file with mode: 0644]
src/librustdoc/clean/utils.rs
src/librustdoc/config.rs
src/librustdoc/doctest.rs
src/librustdoc/html/format.rs
src/librustdoc/html/markdown.rs
src/librustdoc/html/render/context.rs
src/librustdoc/html/render/mod.rs
src/librustdoc/html/render/span_map.rs
src/librustdoc/html/render/write_shared.rs
src/librustdoc/html/static/COPYRIGHT.txt
src/librustdoc/html/static/css/rustdoc.css
src/librustdoc/html/static/fonts/FiraSans-Medium.woff [deleted file]
src/librustdoc/html/static/fonts/FiraSans-Regular.woff [deleted file]
src/librustdoc/html/static/fonts/NanumBarunGothic.ttf.woff [deleted file]
src/librustdoc/html/static/fonts/SourceCodePro-It.ttf.woff [deleted file]
src/librustdoc/html/static/fonts/SourceCodePro-Regular.ttf.woff [deleted file]
src/librustdoc/html/static/fonts/SourceCodePro-Semibold.ttf.woff [deleted file]
src/librustdoc/html/static/fonts/SourceSerif4-Bold.ttf.woff [deleted file]
src/librustdoc/html/static/fonts/SourceSerif4-It.ttf.woff [deleted file]
src/librustdoc/html/static/fonts/SourceSerif4-Regular.ttf.woff [deleted file]
src/librustdoc/html/static/js/externs.js
src/librustdoc/html/static/js/main.js
src/librustdoc/html/static/js/scrape-examples.js
src/librustdoc/html/static/js/search.js
src/librustdoc/html/static/js/settings.js
src/librustdoc/html/static/js/source-script.js
src/librustdoc/html/static/js/storage.js
src/librustdoc/html/static_files.rs
src/librustdoc/html/templates/page.html
src/librustdoc/lib.rs
src/librustdoc/passes/calculate_doc_coverage.rs
src/librustdoc/passes/collect_intra_doc_links.rs
src/librustdoc/passes/collect_intra_doc_links/early.rs
src/librustdoc/passes/collect_trait_impls.rs
src/librustdoc/passes/mod.rs
src/librustdoc/passes/unindent_comments.rs [deleted file]
src/librustdoc/passes/unindent_comments/tests.rs [deleted file]
src/llvm-project
src/test/assembly/nvptx-kernel-abi/nvptx-kernel-args-abi-v7.rs [new file with mode: 0644]
src/test/codegen/panic-in-drop-abort.rs
src/test/codegen/remap_path_prefix/main.rs
src/test/codegen/vec-calloc.rs [new file with mode: 0644]
src/test/debuginfo/thread.rs
src/test/debuginfo/unit-type.rs [new file with mode: 0644]
src/test/incremental/hashes/enum_defs.rs
src/test/incremental/hashes/inherent_impls.rs
src/test/incremental/hashes/statics.rs
src/test/incremental/hashes/struct_defs.rs
src/test/incremental/hashes/trait_defs.rs
src/test/mir-opt/combine_clone_of_primitives.rs
src/test/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff
src/test/mir-opt/derefer_complex_case.main.Derefer.diff [new file with mode: 0644]
src/test/mir-opt/derefer_complex_case.rs [new file with mode: 0644]
src/test/mir-opt/derefer_terminator_test.main.Derefer.diff [new file with mode: 0644]
src/test/mir-opt/derefer_terminator_test.rs [new file with mode: 0644]
src/test/mir-opt/derefer_test.main.Derefer.diff
src/test/mir-opt/derefer_test_multiple.main.Derefer.diff
src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff
src/test/mir-opt/early_otherwise_branch.rs
src/test/mir-opt/early_otherwise_branch_3_element_tuple.rs
src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyConstCondition-final.after.diff
src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff
src/test/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff
src/test/mir-opt/early_otherwise_branch_noopt.rs
src/test/mir-opt/early_otherwise_branch_soundness.no_deref_ptr.EarlyOtherwiseBranch.diff
src/test/mir-opt/early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff
src/test/mir-opt/early_otherwise_branch_soundness.rs
src/test/mir-opt/if-condition-int.rs
src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir
src/test/mir-opt/lower_array_len.array_bound.NormalizeArrayLen.diff
src/test/mir-opt/lower_array_len.array_bound_mut.NormalizeArrayLen.diff
src/test/mir-opt/lower_array_len.array_len.NormalizeArrayLen.diff
src/test/mir-opt/lower_array_len.array_len_by_value.NormalizeArrayLen.diff
src/test/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.diff
src/test/mir-opt/lower_slice_len.rs
src/test/mir-opt/nrvo-simple.rs
src/test/mir-opt/uninhabited_fallthrough_elimination.eliminate_fallthrough.UninhabitedEnumBranching.diff
src/test/mir-opt/uninhabited_fallthrough_elimination.keep_fallthrough.UninhabitedEnumBranching.diff
src/test/mir-opt/unreachable.main.UnreachablePropagation.diff
src/test/mir-opt/unreachable_diverging.main.UnreachablePropagation.diff
src/test/pretty/dollar-crate.pp
src/test/pretty/hir-pretty-loop.pp
src/test/pretty/issue-4264.pp
src/test/pretty/yeet-expr.rs [new file with mode: 0644]
src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure.txt
src/test/run-make-fulldeps/reproducible-build/linker.rs
src/test/run-make-fulldeps/symbol-visibility/Makefile
src/test/run-make/const_fn_mir/dump.mir
src/test/run-make/emit-shared-files/Makefile
src/test/run-make/issue-47384/Makefile [new file with mode: 0644]
src/test/run-make/issue-47384/lib.rs [new file with mode: 0644]
src/test/run-make/issue-47384/linker.ld [new file with mode: 0644]
src/test/run-make/issue-47384/main.rs [new file with mode: 0644]
src/test/run-make/issue-96498/Makefile [new file with mode: 0644]
src/test/run-make/issue-96498/foo.rs [new file with mode: 0644]
src/test/rustdoc-gui/escape-key.goml
src/test/rustdoc-gui/settings.goml [new file with mode: 0644]
src/test/rustdoc-gui/theme-change.goml
src/test/rustdoc-gui/theme-in-history.goml
src/test/rustdoc-js-std/parser-errors.js
src/test/rustdoc-js-std/parser-ident.js [new file with mode: 0644]
src/test/rustdoc-js-std/parser-returned.js
src/test/rustdoc-ui/intra-doc/macro-rules-error.rs [new file with mode: 0644]
src/test/rustdoc-ui/intra-doc/macro-rules-error.stderr [new file with mode: 0644]
src/test/rustdoc-ui/intra-doc/macro-rules.rs
src/test/rustdoc-ui/issue-91713.stdout
src/test/rustdoc/deref-slice-core.rs [new file with mode: 0644]
src/test/rustdoc/issue-95873.rs [new file with mode: 0644]
src/test/rustdoc/issue-96381.rs [new file with mode: 0644]
src/test/ui-fulldeps/issue-15149.rs
src/test/ui-fulldeps/session-derive-errors.rs [deleted file]
src/test/ui-fulldeps/session-derive-errors.stderr [deleted file]
src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs [new file with mode: 0644]
src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr [new file with mode: 0644]
src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs [new file with mode: 0644]
src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr [new file with mode: 0644]
src/test/ui/argument-suggestions/issue-96638.rs [new file with mode: 0644]
src/test/ui/argument-suggestions/issue-96638.stderr [new file with mode: 0644]
src/test/ui/array-slice-vec/repeat_empty_ok.stderr
src/test/ui/associated-types/impl-trait-return-missing-constraint.rs
src/test/ui/associated-types/impl-trait-return-missing-constraint.stderr
src/test/ui/associated-types/issue-19081.rs [new file with mode: 0644]
src/test/ui/associated-types/issue-25339.rs [new file with mode: 0644]
src/test/ui/associated-types/issue-55846.rs [new file with mode: 0644]
src/test/ui/async-await/async-unsafe-fn-call-in-safe.mir.stderr
src/test/ui/async-await/async-unsafe-fn-call-in-safe.rs
src/test/ui/async-await/async-unsafe-fn-call-in-safe.thir.stderr
src/test/ui/async-await/issue-86507.stderr
src/test/ui/async-await/no-async-const.stderr
src/test/ui/async-await/no-unsafe-async.stderr
src/test/ui/binop/issue-3820.rs [new file with mode: 0644]
src/test/ui/binop/issue-3820.stderr [new file with mode: 0644]
src/test/ui/binop/issue-93927.rs [new file with mode: 0644]
src/test/ui/binop/issue-93927.stderr [new file with mode: 0644]
src/test/ui/builtin-superkinds/builtin-superkinds-self-type.stderr
src/test/ui/closures/coerce-unsafe-closure-to-unsafe-fn-ptr.thir.stderr
src/test/ui/codegen/issue-16602-1.rs [new file with mode: 0644]
src/test/ui/codegen/issue-16602-2.rs [new file with mode: 0644]
src/test/ui/codegen/issue-16602-3.rs [new file with mode: 0644]
src/test/ui/coercion/coerce-issue-49593-box-never-windows.nofallback.stderr [new file with mode: 0644]
src/test/ui/coercion/coerce-issue-49593-box-never-windows.rs [new file with mode: 0644]
src/test/ui/coercion/coerce-issue-49593-box-never.nofallback.stderr
src/test/ui/coercion/coerce-issue-49593-box-never.rs
src/test/ui/coherence/coherence-cow.re_a.stderr
src/test/ui/coherence/coherence-cow.re_b.stderr
src/test/ui/coherence/coherence-cow.re_c.stderr
src/test/ui/coherence/coherence-impls-copy.stderr
src/test/ui/coherence/coherence-orphan.stderr
src/test/ui/coherence/coherence-overlapping-pairs.stderr
src/test/ui/coherence/coherence-pair-covered-uncovered-1.stderr
src/test/ui/coherence/coherence-pair-covered-uncovered.stderr
src/test/ui/coherence/coherence-vec-local-2.stderr
src/test/ui/coherence/coherence-vec-local.stderr
src/test/ui/coherence/coherence_local_err_struct.stderr
src/test/ui/coherence/impl-foreign-for-foreign.stderr
src/test/ui/coherence/impl-foreign-for-foreign[foreign].stderr
src/test/ui/coherence/impl-foreign-for-fundamental[foreign].stderr
src/test/ui/coherence/impl-foreign[foreign]-for-foreign.stderr
src/test/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.stderr
src/test/ui/coherence/impl[t]-foreign-for-foreign[t].stderr
src/test/ui/conservative_impl_trait.rs
src/test/ui/conservative_impl_trait.stderr
src/test/ui/const-generics/const-arg-in-const-arg.min.stderr
src/test/ui/const-generics/const-arg-in-const-arg.rs
src/test/ui/const-generics/defaults/rp_impl_trait_fail.rs
src/test/ui/const-generics/defaults/rp_impl_trait_fail.stderr
src/test/ui/const-generics/issues/issue-56445-1.min.stderr
src/test/ui/const-generics/issues/issue-56445-1.rs
src/test/ui/const-generics/issues/issue-61336-2.stderr
src/test/ui/const-generics/issues/issue-61336.stderr
src/test/ui/consts/const-blocks/fn-call-in-non-const.rs
src/test/ui/consts/const-blocks/fn-call-in-non-const.stderr
src/test/ui/consts/const-blocks/migrate-fail.rs
src/test/ui/consts/const-blocks/migrate-fail.stderr
src/test/ui/consts/const-blocks/nll-fail.rs
src/test/ui/consts/const-blocks/nll-fail.stderr
src/test/ui/consts/const-blocks/trait-error.rs
src/test/ui/consts/const-blocks/trait-error.stderr
src/test/ui/consts/const-eval/issue-50814-2.stderr
src/test/ui/consts/const-eval/issue-50814.stderr
src/test/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr
src/test/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr
src/test/ui/consts/const-eval/validate_uninhabited_zsts.rs
src/test/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.mir.stderr
src/test/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.rs
src/test/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.thir.stderr
src/test/ui/consts/const-float-bits-conv.rs
src/test/ui/consts/const-float-bits-reject-conv.rs [new file with mode: 0644]
src/test/ui/consts/const-float-bits-reject-conv.stderr [new file with mode: 0644]
src/test/ui/consts/const-fn-error.stderr
src/test/ui/consts/const-fn-in-vec.stderr
src/test/ui/consts/const-for.stderr
src/test/ui/consts/issue-19244.rs [new file with mode: 0644]
src/test/ui/did_you_mean/replace-impl-infer-ty-from-trait.fixed [new file with mode: 0644]
src/test/ui/did_you_mean/replace-impl-infer-ty-from-trait.rs [new file with mode: 0644]
src/test/ui/did_you_mean/replace-impl-infer-ty-from-trait.stderr [new file with mode: 0644]
src/test/ui/error-codes/E0117.stderr
src/test/ui/error-codes/E0133.thir.stderr
src/test/ui/error-codes/E0283.stderr
src/test/ui/error-codes/E0771.stderr
src/test/ui/extern-flag/no-nounused.rs [new file with mode: 0644]
src/test/ui/extern-flag/no-nounused.stderr [new file with mode: 0644]
src/test/ui/extern-flag/nounused.rs [new file with mode: 0644]
src/test/ui/extern/extern-type-diag-not-similar.rs [new file with mode: 0644]
src/test/ui/extern/extern-type-diag-not-similar.stderr [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-infer_static_outlives_requirements.stderr
src/test/ui/feature-gates/feature-gate-yeet_expr-in-cfg.rs [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-yeet_expr-in-cfg.stderr [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-yeet_expr.rs [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-yeet_expr.stderr [new file with mode: 0644]
src/test/ui/fn/keyword-order.rs [new file with mode: 0644]
src/test/ui/fn/keyword-order.stderr [new file with mode: 0644]
src/test/ui/foreign-unsafe-fn-called.rs
src/test/ui/foreign-unsafe-fn-called.thir.stderr
src/test/ui/functions-closures/fn-help-with-err.rs
src/test/ui/functions-closures/fn-help-with-err.stderr
src/test/ui/generator/issue-88653.rs
src/test/ui/generator/issue-88653.stderr
src/test/ui/generator/type-mismatch-signature-deduction.rs
src/test/ui/generator/type-mismatch-signature-deduction.stderr
src/test/ui/generic-associated-types/issue-70304.rs
src/test/ui/generic-associated-types/issue-70304.stderr
src/test/ui/generic-associated-types/issue-86483.stderr
src/test/ui/generic-associated-types/issue-91139.migrate.stderr
src/test/ui/generic-associated-types/issue-92096.migrate.stderr
src/test/ui/generic-associated-types/issue-95305.rs [new file with mode: 0644]
src/test/ui/generic-associated-types/issue-95305.stderr [new file with mode: 0644]
src/test/ui/generic-associated-types/missing-bounds.fixed [deleted file]
src/test/ui/generic-associated-types/missing-bounds.rs
src/test/ui/generic-associated-types/missing-bounds.stderr
src/test/ui/generic-associated-types/unsatified-item-lifetime-bound.stderr
src/test/ui/generics/issue-80512-param-reordering-with-defaults.rs [new file with mode: 0644]
src/test/ui/generics/issue-80512-param-reordering-with-defaults.stderr [new file with mode: 0644]
src/test/ui/generics/post_monomorphization_error_backtrace.rs [new file with mode: 0644]
src/test/ui/generics/post_monomorphization_error_backtrace.stderr [new file with mode: 0644]
src/test/ui/hrtb/issue-30786.migrate.stderr
src/test/ui/hrtb/issue-30786.nll.stderr
src/test/ui/impl-trait/bound-normalization-fail.rs
src/test/ui/impl-trait/bound-normalization-fail.stderr
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/equal-hidden-lifetimes.stderr
src/test/ui/impl-trait/fallback_inference.rs [new file with mode: 0644]
src/test/ui/impl-trait/fallback_inference.stderr [new file with mode: 0644]
src/test/ui/impl-trait/issue-72911.rs
src/test/ui/impl-trait/issue-72911.stderr
src/test/ui/impl-trait/issues/issue-67830.stderr
src/test/ui/impl-trait/issues/issue-86800.rs
src/test/ui/impl-trait/issues/issue-88236-2.nll.stderr
src/test/ui/impl-trait/issues/issue-88236-2.stderr
src/test/ui/impl-trait/issues/issue-92305.rs [new file with mode: 0644]
src/test/ui/impl-trait/issues/issue-92305.stderr [new file with mode: 0644]
src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr
src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs
src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr
src/test/ui/impl-trait/nested-return-type2-tait.rs
src/test/ui/impl-trait/nested-return-type2-tait.stderr
src/test/ui/impl-trait/type_parameters_captured.nll.stderr
src/test/ui/impl-trait/type_parameters_captured.rs
src/test/ui/impl-trait/type_parameters_captured.stderr
src/test/ui/impl-trait/where-allowed-2.rs
src/test/ui/impl-trait/where-allowed-2.stderr [new file with mode: 0644]
src/test/ui/inference/question-mark-type-infer.stderr
src/test/ui/intrinsics/unchecked_math_unsafe.thir.stderr
src/test/ui/issues-71798.rs
src/test/ui/issues-71798.stderr
src/test/ui/issues/issue-16602-1.rs [deleted file]
src/test/ui/issues/issue-16602-2.rs [deleted file]
src/test/ui/issues/issue-16602-3.rs [deleted file]
src/test/ui/issues/issue-16922.nll.stderr
src/test/ui/issues/issue-17233.rs [deleted file]
src/test/ui/issues/issue-1866.rs [deleted file]
src/test/ui/issues/issue-1866.stderr [deleted file]
src/test/ui/issues/issue-19081.rs [deleted file]
src/test/ui/issues/issue-19244.rs [deleted file]
src/test/ui/issues/issue-19538.rs [deleted file]
src/test/ui/issues/issue-19538.stderr [deleted file]
src/test/ui/issues/issue-20343.rs [deleted file]
src/test/ui/issues/issue-25339.rs [deleted file]
src/test/ui/issues/issue-26545.rs [deleted file]
src/test/ui/issues/issue-26545.stderr [deleted file]
src/test/ui/issues/issue-28776.thir.stderr
src/test/ui/issues/issue-29124.stderr
src/test/ui/issues/issue-29488.rs [deleted file]
src/test/ui/issues/issue-30438-c.rs
src/test/ui/issues/issue-30438-c.stderr
src/test/ui/issues/issue-3080.thir.stderr
src/test/ui/issues/issue-32709.stderr
src/test/ui/issues/issue-32963.rs [deleted file]
src/test/ui/issues/issue-32963.stderr [deleted file]
src/test/ui/issues/issue-35450.rs [deleted file]
src/test/ui/issues/issue-35450.stderr [deleted file]
src/test/ui/issues/issue-35668.stderr
src/test/ui/issues/issue-37323.rs [deleted file]
src/test/ui/issues/issue-3820.rs [deleted file]
src/test/ui/issues/issue-3820.stderr [deleted file]
src/test/ui/issues/issue-4107.rs [deleted file]
src/test/ui/issues/issue-41776.rs [deleted file]
src/test/ui/issues/issue-41776.stderr [deleted file]
src/test/ui/issues/issue-43132.rs [deleted file]
src/test/ui/issues/issue-44127.rs [deleted file]
src/test/ui/issues/issue-45696-no-variant-box-recur.rs [deleted file]
src/test/ui/issues/issue-47706-trait.rs [deleted file]
src/test/ui/issues/issue-47706-trait.stderr [deleted file]
src/test/ui/issues/issue-47706.rs [deleted file]
src/test/ui/issues/issue-47706.stderr [deleted file]
src/test/ui/issues/issue-52213.nll.stderr [deleted file]
src/test/ui/issues/issue-52213.rs [deleted file]
src/test/ui/issues/issue-52213.stderr [deleted file]
src/test/ui/issues/issue-53692.rs [deleted file]
src/test/ui/issues/issue-53692.stderr [deleted file]
src/test/ui/issues/issue-55846.rs [deleted file]
src/test/ui/issues/issue-57362-1.stderr
src/test/ui/issues/issue-5844.thir.stderr
src/test/ui/issues/issue-61858.rs [deleted file]
src/test/ui/issues/issue-61858.stderr [deleted file]
src/test/ui/issues/issue-71036.rs [deleted file]
src/test/ui/issues/issue-71036.stderr [deleted file]
src/test/ui/issues/issue-72574-1.rs [deleted file]
src/test/ui/issues/issue-72574-1.stderr [deleted file]
src/test/ui/issues/issue-73427.rs [deleted file]
src/test/ui/issues/issue-73427.stderr [deleted file]
src/test/ui/issues/issue-80512-param-reordering-with-defaults.rs [deleted file]
src/test/ui/issues/issue-80512-param-reordering-with-defaults.stderr [deleted file]
src/test/ui/iterators/collect-into-array.rs [new file with mode: 0644]
src/test/ui/iterators/collect-into-array.stderr [new file with mode: 0644]
src/test/ui/iterators/collect-into-slice.rs
src/test/ui/iterators/collect-into-slice.stderr
src/test/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.rs [new file with mode: 0644]
src/test/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr [new file with mode: 0644]
src/test/ui/lifetimes/copy_modulo_regions.rs [new file with mode: 0644]
src/test/ui/lifetimes/copy_modulo_regions.stderr [new file with mode: 0644]
src/test/ui/lifetimes/elided-lifetime-in-path-in-impl-Fn.rs [new file with mode: 0644]
src/test/ui/lifetimes/issue-90170-elision-mismatch.nll.stderr
src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr
src/test/ui/lifetimes/lifetime-elision-return-type-trait.rs
src/test/ui/lifetimes/lifetime-elision-return-type-trait.stderr
src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.nll.stderr
src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-3.nll.stderr
src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.nll.stderr
src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-self-is-anon.nll.stderr
src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-fn-items.nll.stderr
src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-impl-items.nll.stderr
src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.nll.stderr
src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions.nll.stderr
src/test/ui/lifetimes/lifetime-errors/issue_74400.nll.stderr
src/test/ui/lint/issue-1866.rs [new file with mode: 0644]
src/test/ui/lint/issue-1866.stderr [new file with mode: 0644]
src/test/ui/lint/issue-20343.rs [new file with mode: 0644]
src/test/ui/lint/unreachable_pub-pub_crate.rs
src/test/ui/lint/unreachable_pub-pub_crate.stderr
src/test/ui/lint/unreachable_pub.rs
src/test/ui/lint/unreachable_pub.stderr
src/test/ui/macros/issue-35450.rs [new file with mode: 0644]
src/test/ui/macros/issue-35450.stderr [new file with mode: 0644]
src/test/ui/macros/issue-41776.rs [new file with mode: 0644]
src/test/ui/macros/issue-41776.stderr [new file with mode: 0644]
src/test/ui/macros/issue-44127.rs [new file with mode: 0644]
src/test/ui/macros/trace-macro.stderr
src/test/ui/match/issue-82392.stdout
src/test/ui/methods/issues/issue-90315.rs [new file with mode: 0644]
src/test/ui/methods/issues/issue-90315.stderr [new file with mode: 0644]
src/test/ui/mismatched_types/issue-47706-trait.rs [new file with mode: 0644]
src/test/ui/mismatched_types/issue-47706-trait.stderr [new file with mode: 0644]
src/test/ui/mismatched_types/issue-47706.rs [new file with mode: 0644]
src/test/ui/mismatched_types/issue-47706.stderr [new file with mode: 0644]
src/test/ui/moves/use_of_moved_value_copy_suggestions.fixed
src/test/ui/moves/use_of_moved_value_copy_suggestions.rs
src/test/ui/moves/use_of_moved_value_copy_suggestions.stderr
src/test/ui/multiple-reprs.rs [deleted file]
src/test/ui/never_type/issue-52443.stderr
src/test/ui/never_type/issue-96335.rs [new file with mode: 0644]
src/test/ui/never_type/issue-96335.stderr [new file with mode: 0644]
src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr
src/test/ui/nll/issue-45696-no-variant-box-recur.rs [new file with mode: 0644]
src/test/ui/nll/issue-52213.nll.stderr [new file with mode: 0644]
src/test/ui/nll/issue-52213.rs [new file with mode: 0644]
src/test/ui/nll/issue-52213.stderr [new file with mode: 0644]
src/test/ui/nll/mir_check_cast_unsize.stderr
src/test/ui/nll/ty-outlives/impl-trait-outlives.stderr
src/test/ui/nll/ty-outlives/projection-implied-bounds.stderr
src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr
src/test/ui/nll/ty-outlives/projection-no-regions-fn.stderr
src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr
src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr
src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.nll.stderr
src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-lifetime.nll.stderr
src/test/ui/nll/ty-outlives/projection-where-clause-none.stderr
src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr
src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr
src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr
src/test/ui/nll/ty-outlives/ty-param-fn-body.stderr
src/test/ui/nll/ty-outlives/ty-param-fn.stderr
src/test/ui/object-lifetime/object-lifetime-default-from-box-error.nll.stderr
src/test/ui/object-safety/issue-19538.rs [new file with mode: 0644]
src/test/ui/object-safety/issue-19538.stderr [new file with mode: 0644]
src/test/ui/or-patterns/missing-bindings.stderr
src/test/ui/parser/issue-61858.rs [new file with mode: 0644]
src/test/ui/parser/issue-61858.stderr [new file with mode: 0644]
src/test/ui/parser/issues/issue-19398.stderr
src/test/ui/parser/issues/issue-87217-keyword-order/several-kw-jump.rs
src/test/ui/parser/issues/issue-87217-keyword-order/several-kw-jump.stderr
src/test/ui/parser/issues/issue-87217-keyword-order/wrong-async.rs
src/test/ui/parser/issues/issue-87217-keyword-order/wrong-async.stderr
src/test/ui/parser/issues/issue-87217-keyword-order/wrong-const.rs
src/test/ui/parser/issues/issue-87217-keyword-order/wrong-const.stderr
src/test/ui/parser/issues/issue-87217-keyword-order/wrong-unsafe.rs
src/test/ui/parser/issues/issue-87217-keyword-order/wrong-unsafe.stderr
src/test/ui/parser/raw/raw-str-unbalanced.rs
src/test/ui/parser/raw/raw-str-unbalanced.stderr
src/test/ui/pattern/issue-72574-1.rs [new file with mode: 0644]
src/test/ui/pattern/issue-72574-1.stderr [new file with mode: 0644]
src/test/ui/pattern/usefulness/tuple-struct-nonexhaustive.stderr
src/test/ui/polymorphization/generators.stderr
src/test/ui/polymorphization/predicates.stderr
src/test/ui/proc-macro/nodelim-groups.rs
src/test/ui/regions/issue-28848.base.stderr [new file with mode: 0644]
src/test/ui/regions/issue-28848.nll.stderr
src/test/ui/regions/issue-28848.rs
src/test/ui/regions/issue-28848.stderr [deleted file]
src/test/ui/regions/region-invariant-static-error-reporting.base.stderr [new file with mode: 0644]
src/test/ui/regions/region-invariant-static-error-reporting.nll.stderr
src/test/ui/regions/region-invariant-static-error-reporting.rs
src/test/ui/regions/region-invariant-static-error-reporting.stderr [deleted file]
src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.base.stderr [new file with mode: 0644]
src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.nll.stderr
src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.rs
src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.stderr [deleted file]
src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.base.stderr [new file with mode: 0644]
src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.nll.stderr
src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.polonius.stderr [deleted file]
src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.rs
src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.stderr [deleted file]
src/test/ui/regions/region-object-lifetime-2.base.stderr [new file with mode: 0644]
src/test/ui/regions/region-object-lifetime-2.nll.stderr
src/test/ui/regions/region-object-lifetime-2.rs
src/test/ui/regions/region-object-lifetime-2.stderr [deleted file]
src/test/ui/regions/region-object-lifetime-4.base.stderr [new file with mode: 0644]
src/test/ui/regions/region-object-lifetime-4.nll.stderr
src/test/ui/regions/region-object-lifetime-4.rs
src/test/ui/regions/region-object-lifetime-4.stderr [deleted file]
src/test/ui/regions/region-object-lifetime-in-coercion.base.stderr [new file with mode: 0644]
src/test/ui/regions/region-object-lifetime-in-coercion.nll.stderr
src/test/ui/regions/region-object-lifetime-in-coercion.rs
src/test/ui/regions/region-object-lifetime-in-coercion.stderr [deleted file]
src/test/ui/regions/regions-addr-of-self.base.stderr [new file with mode: 0644]
src/test/ui/regions/regions-addr-of-self.nll.stderr
src/test/ui/regions/regions-addr-of-self.rs
src/test/ui/regions/regions-addr-of-self.stderr [deleted file]
src/test/ui/regions/regions-addr-of-upvar-self.base.stderr [new file with mode: 0644]
src/test/ui/regions/regions-addr-of-upvar-self.nll.stderr
src/test/ui/regions/regions-addr-of-upvar-self.rs
src/test/ui/regions/regions-addr-of-upvar-self.stderr [deleted file]
src/test/ui/regions/regions-bounded-by-trait-requiring-static.base.stderr [new file with mode: 0644]
src/test/ui/regions/regions-bounded-by-trait-requiring-static.nll.stderr
src/test/ui/regions/regions-bounded-by-trait-requiring-static.rs
src/test/ui/regions/regions-bounded-by-trait-requiring-static.stderr [deleted file]
src/test/ui/regions/regions-bounded-method-type-parameters-cross-crate.base.stderr [new file with mode: 0644]
src/test/ui/regions/regions-bounded-method-type-parameters-cross-crate.nll.stderr
src/test/ui/regions/regions-bounded-method-type-parameters-cross-crate.rs
src/test/ui/regions/regions-bounded-method-type-parameters-cross-crate.stderr [deleted file]
src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.base.stderr [new file with mode: 0644]
src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.nll.stderr
src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.rs
src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.stderr [deleted file]
src/test/ui/regions/regions-bounded-method-type-parameters.base.stderr [new file with mode: 0644]
src/test/ui/regions/regions-bounded-method-type-parameters.nll.stderr
src/test/ui/regions/regions-bounded-method-type-parameters.rs
src/test/ui/regions/regions-bounded-method-type-parameters.stderr [deleted file]
src/test/ui/regions/regions-bounds.base.stderr [new file with mode: 0644]
src/test/ui/regions/regions-bounds.nll.stderr
src/test/ui/regions/regions-bounds.rs
src/test/ui/regions/regions-bounds.stderr [deleted file]
src/test/ui/regions/regions-close-associated-type-into-object.base.stderr [new file with mode: 0644]
src/test/ui/regions/regions-close-associated-type-into-object.nll.stderr
src/test/ui/regions/regions-close-associated-type-into-object.rs
src/test/ui/regions/regions-close-associated-type-into-object.stderr [deleted file]
src/test/ui/regions/regions-close-object-into-object-2.base.stderr [new file with mode: 0644]
src/test/ui/regions/regions-close-object-into-object-2.nll.stderr
src/test/ui/regions/regions-close-object-into-object-2.rs
src/test/ui/regions/regions-close-object-into-object-2.stderr [deleted file]
src/test/ui/regions/regions-close-object-into-object-4.base.stderr [new file with mode: 0644]
src/test/ui/regions/regions-close-object-into-object-4.nll.stderr
src/test/ui/regions/regions-close-object-into-object-4.rs
src/test/ui/regions/regions-close-object-into-object-4.stderr [deleted file]
src/test/ui/regions/regions-close-object-into-object-5.base.stderr [new file with mode: 0644]
src/test/ui/regions/regions-close-object-into-object-5.nll.stderr
src/test/ui/regions/regions-close-object-into-object-5.rs
src/test/ui/regions/regions-close-object-into-object-5.stderr [deleted file]
src/test/ui/regions/regions-close-over-type-parameter-1.base.stderr [new file with mode: 0644]
src/test/ui/regions/regions-close-over-type-parameter-1.nll.stderr
src/test/ui/regions/regions-close-over-type-parameter-1.rs
src/test/ui/regions/regions-close-over-type-parameter-1.stderr [deleted file]
src/test/ui/regions/regions-close-over-type-parameter-multiple.base.stderr [new file with mode: 0644]
src/test/ui/regions/regions-close-over-type-parameter-multiple.nll.stderr
src/test/ui/regions/regions-close-over-type-parameter-multiple.rs
src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr [deleted file]
src/test/ui/regions/regions-close-param-into-object.base.stderr [new file with mode: 0644]
src/test/ui/regions/regions-close-param-into-object.nll.stderr
src/test/ui/regions/regions-close-param-into-object.rs
src/test/ui/regions/regions-close-param-into-object.stderr [deleted file]
src/test/ui/regions/regions-creating-enums3.base.stderr [new file with mode: 0644]
src/test/ui/regions/regions-creating-enums3.nll.stderr
src/test/ui/regions/regions-creating-enums3.rs
src/test/ui/regions/regions-creating-enums3.stderr [deleted file]
src/test/ui/regions/regions-creating-enums4.base.stderr [new file with mode: 0644]
src/test/ui/regions/regions-creating-enums4.nll.stderr
src/test/ui/regions/regions-creating-enums4.rs
src/test/ui/regions/regions-creating-enums4.stderr [deleted file]
src/test/ui/regions/regions-early-bound-error-method.base.stderr [new file with mode: 0644]
src/test/ui/regions/regions-early-bound-error-method.nll.stderr
src/test/ui/regions/regions-early-bound-error-method.rs
src/test/ui/regions/regions-early-bound-error-method.stderr [deleted file]
src/test/ui/regions/regions-early-bound-error.base.stderr [new file with mode: 0644]
src/test/ui/regions/regions-early-bound-error.nll.stderr
src/test/ui/regions/regions-early-bound-error.rs
src/test/ui/regions/regions-early-bound-error.stderr [deleted file]
src/test/ui/regions/regions-fn-subtyping-return-static-fail.base.stderr [new file with mode: 0644]
src/test/ui/regions/regions-fn-subtyping-return-static-fail.nll.stderr
src/test/ui/regions/regions-fn-subtyping-return-static-fail.rs
src/test/ui/regions/regions-fn-subtyping-return-static-fail.stderr [deleted file]
src/test/ui/regions/regions-free-region-ordering-callee.base.stderr [new file with mode: 0644]
src/test/ui/regions/regions-free-region-ordering-callee.nll.stderr
src/test/ui/regions/regions-free-region-ordering-callee.rs
src/test/ui/regions/regions-free-region-ordering-callee.stderr [deleted file]
src/test/ui/regions/regions-free-region-ordering-incorrect.base.stderr [new file with mode: 0644]
src/test/ui/regions/regions-free-region-ordering-incorrect.nll.stderr
src/test/ui/regions/regions-free-region-ordering-incorrect.rs
src/test/ui/regions/regions-free-region-ordering-incorrect.stderr [deleted file]
src/test/ui/regions/regions-free-region-outlives-static-outlives-free-region.rs
src/test/ui/regions/regions-free-region-outlives-static-outlives-free-region.stderr [new file with mode: 0644]
src/test/ui/regions/regions-implied-bounds-projection-gap-1.base.stderr [new file with mode: 0644]
src/test/ui/regions/regions-implied-bounds-projection-gap-1.nll.stderr
src/test/ui/regions/regions-implied-bounds-projection-gap-1.rs
src/test/ui/regions/regions-implied-bounds-projection-gap-1.stderr [deleted file]
src/test/ui/regions/regions-infer-bound-from-trait-self.base.stderr [new file with mode: 0644]
src/test/ui/regions/regions-infer-bound-from-trait-self.nll.stderr
src/test/ui/regions/regions-infer-bound-from-trait-self.rs
src/test/ui/regions/regions-infer-bound-from-trait-self.stderr [deleted file]
src/test/ui/regions/regions-infer-bound-from-trait.base.stderr [new file with mode: 0644]
src/test/ui/regions/regions-infer-bound-from-trait.nll.stderr
src/test/ui/regions/regions-infer-bound-from-trait.rs
src/test/ui/regions/regions-infer-bound-from-trait.stderr [deleted file]
src/test/ui/regions/regions-infer-contravariance-due-to-decl.base.stderr [new file with mode: 0644]
src/test/ui/regions/regions-infer-contravariance-due-to-decl.nll.stderr
src/test/ui/regions/regions-infer-contravariance-due-to-decl.rs
src/test/ui/regions/regions-infer-contravariance-due-to-decl.stderr [deleted file]
src/test/ui/regions/regions-infer-covariance-due-to-decl.base.stderr [new file with mode: 0644]
src/test/ui/regions/regions-infer-covariance-due-to-decl.nll.stderr
src/test/ui/regions/regions-infer-covariance-due-to-decl.rs
src/test/ui/regions/regions-infer-covariance-due-to-decl.stderr [deleted file]
src/test/ui/regions/regions-infer-invariance-due-to-decl.base.stderr [new file with mode: 0644]
src/test/ui/regions/regions-infer-invariance-due-to-decl.nll.stderr
src/test/ui/regions/regions-infer-invariance-due-to-decl.rs
src/test/ui/regions/regions-infer-invariance-due-to-decl.stderr [deleted file]
src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.base.stderr [new file with mode: 0644]
src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.nll.stderr
src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.rs
src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.stderr [deleted file]
src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.base.stderr [new file with mode: 0644]
src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.nll.stderr
src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.rs
src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.stderr [deleted file]
src/test/ui/regions/regions-infer-not-param.base.stderr [new file with mode: 0644]
src/test/ui/regions/regions-infer-not-param.nll.stderr
src/test/ui/regions/regions-infer-not-param.rs
src/test/ui/regions/regions-infer-not-param.stderr [deleted file]
src/test/ui/regions/regions-infer-paramd-indirect.base.stderr [new file with mode: 0644]
src/test/ui/regions/regions-infer-paramd-indirect.nll.stderr
src/test/ui/regions/regions-infer-paramd-indirect.rs
src/test/ui/regions/regions-infer-paramd-indirect.stderr [deleted file]
src/test/ui/regions/regions-lifetime-bounds-on-fns.base.stderr [new file with mode: 0644]
src/test/ui/regions/regions-lifetime-bounds-on-fns.nll.stderr
src/test/ui/regions/regions-lifetime-bounds-on-fns.rs
src/test/ui/regions/regions-lifetime-bounds-on-fns.stderr [deleted file]
src/test/ui/regions/regions-nested-fns.base.stderr [new file with mode: 0644]
src/test/ui/regions/regions-nested-fns.nll.stderr
src/test/ui/regions/regions-nested-fns.rs
src/test/ui/regions/regions-nested-fns.stderr [deleted file]
src/test/ui/regions/regions-outlives-projection-container.base.stderr [new file with mode: 0644]
src/test/ui/regions/regions-outlives-projection-container.nll.stderr
src/test/ui/regions/regions-outlives-projection-container.rs
src/test/ui/regions/regions-outlives-projection-container.stderr [deleted file]
src/test/ui/regions/regions-proc-bound-capture.base.stderr [new file with mode: 0644]
src/test/ui/regions/regions-proc-bound-capture.nll.stderr
src/test/ui/regions/regions-proc-bound-capture.rs
src/test/ui/regions/regions-proc-bound-capture.stderr [deleted file]
src/test/ui/regions/regions-reborrow-from-shorter-mut-ref-mut-ref.base.stderr [new file with mode: 0644]
src/test/ui/regions/regions-reborrow-from-shorter-mut-ref-mut-ref.nll.stderr
src/test/ui/regions/regions-reborrow-from-shorter-mut-ref-mut-ref.rs
src/test/ui/regions/regions-reborrow-from-shorter-mut-ref-mut-ref.stderr [deleted file]
src/test/ui/regions/regions-reborrow-from-shorter-mut-ref.base.stderr [new file with mode: 0644]
src/test/ui/regions/regions-reborrow-from-shorter-mut-ref.nll.stderr
src/test/ui/regions/regions-reborrow-from-shorter-mut-ref.rs
src/test/ui/regions/regions-reborrow-from-shorter-mut-ref.stderr [deleted file]
src/test/ui/regions/regions-ret-borrowed-1.base.stderr [new file with mode: 0644]
src/test/ui/regions/regions-ret-borrowed-1.nll.stderr
src/test/ui/regions/regions-ret-borrowed-1.rs
src/test/ui/regions/regions-ret-borrowed-1.stderr [deleted file]
src/test/ui/regions/regions-ret-borrowed.base.stderr [new file with mode: 0644]
src/test/ui/regions/regions-ret-borrowed.nll.stderr
src/test/ui/regions/regions-ret-borrowed.rs
src/test/ui/regions/regions-ret-borrowed.stderr [deleted file]
src/test/ui/regions/regions-static-bound-rpass.rs
src/test/ui/regions/regions-static-bound-rpass.stderr [new file with mode: 0644]
src/test/ui/regions/regions-static-bound.base.stderr [new file with mode: 0644]
src/test/ui/regions/regions-static-bound.nll.stderr
src/test/ui/regions/regions-static-bound.rs
src/test/ui/regions/regions-static-bound.stderr [deleted file]
src/test/ui/regions/regions-trait-object-subtyping.base.stderr [new file with mode: 0644]
src/test/ui/regions/regions-trait-object-subtyping.nll.stderr
src/test/ui/regions/regions-trait-object-subtyping.rs
src/test/ui/regions/regions-trait-object-subtyping.stderr [deleted file]
src/test/ui/regions/regions-variance-contravariant-use-covariant-in-second-position.base.stderr [new file with mode: 0644]
src/test/ui/regions/regions-variance-contravariant-use-covariant-in-second-position.nll.stderr
src/test/ui/regions/regions-variance-contravariant-use-covariant-in-second-position.rs
src/test/ui/regions/regions-variance-contravariant-use-covariant-in-second-position.stderr [deleted file]
src/test/ui/regions/regions-variance-contravariant-use-covariant.base.stderr [new file with mode: 0644]
src/test/ui/regions/regions-variance-contravariant-use-covariant.nll.stderr
src/test/ui/regions/regions-variance-contravariant-use-covariant.rs
src/test/ui/regions/regions-variance-contravariant-use-covariant.stderr [deleted file]
src/test/ui/regions/regions-variance-covariant-use-contravariant.base.stderr [new file with mode: 0644]
src/test/ui/regions/regions-variance-covariant-use-contravariant.nll.stderr
src/test/ui/regions/regions-variance-covariant-use-contravariant.rs
src/test/ui/regions/regions-variance-covariant-use-contravariant.stderr [deleted file]
src/test/ui/regions/regions-variance-invariant-use-contravariant.base.stderr [new file with mode: 0644]
src/test/ui/regions/regions-variance-invariant-use-contravariant.nll.stderr
src/test/ui/regions/regions-variance-invariant-use-contravariant.rs
src/test/ui/regions/regions-variance-invariant-use-contravariant.stderr [deleted file]
src/test/ui/regions/regions-variance-invariant-use-covariant.base.stderr [new file with mode: 0644]
src/test/ui/regions/regions-variance-invariant-use-covariant.nll.stderr
src/test/ui/regions/regions-variance-invariant-use-covariant.rs
src/test/ui/regions/regions-variance-invariant-use-covariant.stderr [deleted file]
src/test/ui/repeat-expr-in-static.rs [deleted file]
src/test/ui/repeat-expr/infer.rs [new file with mode: 0644]
src/test/ui/repeat-expr/repeat-expr-in-static.rs [new file with mode: 0644]
src/test/ui/repeat-expr/repeat-to-run-dtor-twice.rs [new file with mode: 0644]
src/test/ui/repeat-expr/repeat-to-run-dtor-twice.stderr [new file with mode: 0644]
src/test/ui/repeat-expr/repeat_count.rs [new file with mode: 0644]
src/test/ui/repeat-expr/repeat_count.stderr [new file with mode: 0644]
src/test/ui/repeat-to-run-dtor-twice.rs [deleted file]
src/test/ui/repeat-to-run-dtor-twice.stderr [deleted file]
src/test/ui/repeat_count.rs [deleted file]
src/test/ui/repeat_count.stderr [deleted file]
src/test/ui/resolve/issue-26545.rs [new file with mode: 0644]
src/test/ui/resolve/issue-26545.stderr [new file with mode: 0644]
src/test/ui/resolve/issue-73427.rs [new file with mode: 0644]
src/test/ui/resolve/issue-73427.stderr [new file with mode: 0644]
src/test/ui/resolve/resolve-inconsistent-names.rs
src/test/ui/resolve/resolve-inconsistent-names.stderr
src/test/ui/rfc-2093-infer-outlives/dont-infer-static.stderr
src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.stderr
src/test/ui/rfc-2093-infer-outlives/regions-struct-not-wf.stderr
src/test/ui/rfc-2632-const-trait-impl/const-and-non-const-impl.rs
src/test/ui/rfc-2632-const-trait-impl/const-and-non-const-impl.stderr
src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.mir.stderr
src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs
src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.thir.stderr
src/test/ui/save-analysis/issue-37323.rs [new file with mode: 0644]
src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.nll.stderr
src/test/ui/self/elision/lt-ref-self.nll.stderr
src/test/ui/self/elision/ref-mut-self.nll.stderr
src/test/ui/self/elision/ref-mut-struct.nll.stderr
src/test/ui/self/elision/ref-self.nll.stderr
src/test/ui/self/elision/ref-struct.nll.stderr
src/test/ui/span/issue-39698.stderr
src/test/ui/static/static-lifetime-bound.stderr
src/test/ui/statics/issue-17233.rs [new file with mode: 0644]
src/test/ui/structs-enums/multiple-reprs.rs [new file with mode: 0644]
src/test/ui/suggest-using-chars.rs [deleted file]
src/test/ui/suggest-using-chars.stderr [deleted file]
src/test/ui/suggestions/bound-suggestions.fixed
src/test/ui/suggestions/bound-suggestions.stderr
src/test/ui/suggestions/field-has-method.rs [new file with mode: 0644]
src/test/ui/suggestions/field-has-method.stderr [new file with mode: 0644]
src/test/ui/suggestions/impl-trait-return-trailing-semicolon.rs
src/test/ui/suggestions/impl-trait-return-trailing-semicolon.stderr
src/test/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.stderr
src/test/ui/suggestions/invalid-bin-op.stderr
src/test/ui/suggestions/issue-21673.stderr
src/test/ui/suggestions/issue-53692.rs [new file with mode: 0644]
src/test/ui/suggestions/issue-53692.stderr [new file with mode: 0644]
src/test/ui/suggestions/issue-81098.rs
src/test/ui/suggestions/issue-81098.stderr
src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.nll.stderr
src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.stderr
src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.nll.stderr
src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs
src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr
src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.nll.stderr
src/test/ui/suggestions/restrict-type-argument.stderr
src/test/ui/suggestions/suggest-impl-trait-lifetime.nll.stderr
src/test/ui/suggestions/suggest-impl-trait-lifetime.stderr
src/test/ui/suggestions/suggest-using-chars.rs [new file with mode: 0644]
src/test/ui/suggestions/suggest-using-chars.stderr [new file with mode: 0644]
src/test/ui/symbol-names/x86-stdcall.rs [new file with mode: 0644]
src/test/ui/threads-sendsync/issue-29488.rs [new file with mode: 0644]
src/test/ui/threads-sendsync/issue-43733.mir.stderr
src/test/ui/threads-sendsync/issue-43733.rs
src/test/ui/threads-sendsync/issue-43733.thir.stderr
src/test/ui/traits/do-not-mention-type-params-by-name-in-suggestion-issue-96292.rs [new file with mode: 0644]
src/test/ui/traits/do-not-mention-type-params-by-name-in-suggestion-issue-96292.stderr [new file with mode: 0644]
src/test/ui/traits/issue-32963.rs [new file with mode: 0644]
src/test/ui/traits/issue-32963.stderr [new file with mode: 0644]
src/test/ui/traits/issue-4107.rs [new file with mode: 0644]
src/test/ui/traits/issue-43132.rs [new file with mode: 0644]
src/test/ui/traits/issue-65284-suggest-generic-trait-bound.stderr
src/test/ui/traits/issue-71036.rs [new file with mode: 0644]
src/test/ui/traits/issue-71036.stderr [new file with mode: 0644]
src/test/ui/traits/issue-77982.stderr
src/test/ui/traits/issue-95898.stderr
src/test/ui/traits/resolution-in-overloaded-op.stderr
src/test/ui/try-trait/bad-interconversion.stderr
src/test/ui/try-trait/option-to-result.stderr
src/test/ui/try-trait/try-on-option.stderr
src/test/ui/try-trait/yeet-for-option.rs [new file with mode: 0644]
src/test/ui/try-trait/yeet-for-result.rs [new file with mode: 0644]
src/test/ui/type-alias-impl-trait/bounds-are-checked.stderr
src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.base.stderr
src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.nll.stderr
src/test/ui/type-alias-impl-trait/issue-60662.stdout
src/test/ui/type-alias-impl-trait/nested-tait-inference.rs
src/test/ui/type-alias-impl-trait/nested-tait-inference.stderr
src/test/ui/type-alias-impl-trait/nested-tait-inference2.rs
src/test/ui/type-alias-impl-trait/nested-tait-inference2.stderr
src/test/ui/type/type-check/missing_trait_impl.stderr
src/test/ui/typeck/issue-87181/empty-tuple-method.rs [new file with mode: 0644]
src/test/ui/typeck/issue-87181/empty-tuple-method.stderr [new file with mode: 0644]
src/test/ui/typeck/issue-87181/enum-variant.rs [new file with mode: 0644]
src/test/ui/typeck/issue-87181/enum-variant.stderr [new file with mode: 0644]
src/test/ui/typeck/issue-87181/tuple-field.rs [new file with mode: 0644]
src/test/ui/typeck/issue-87181/tuple-field.stderr [new file with mode: 0644]
src/test/ui/typeck/issue-87181/tuple-method.rs [new file with mode: 0644]
src/test/ui/typeck/issue-87181/tuple-method.stderr [new file with mode: 0644]
src/test/ui/typeck/remove-extra-argument.fixed [new file with mode: 0644]
src/test/ui/typeck/remove-extra-argument.rs [new file with mode: 0644]
src/test/ui/typeck/remove-extra-argument.stderr [new file with mode: 0644]
src/test/ui/typeck/typeck-default-trait-impl-cross-crate-coherence.stderr
src/test/ui/typeck/typeck_type_placeholder_item.rs
src/test/ui/typeck/typeck_type_placeholder_item.stderr
src/test/ui/unboxed-closures/unboxed-closures-static-call-wrong-trait.stderr
src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr
src/test/ui/underscore-lifetime/underscore-lifetime-elison-mismatch.nll.stderr
src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.mir.stderr
src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs
src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.thir.stderr
src/test/ui/unsafe/unsafe-const-fn.thir.stderr
src/test/ui/unsafe/unsafe-fn-called-from-safe.rs
src/test/ui/unsafe/unsafe-fn-called-from-safe.thir.stderr
src/test/ui/unsafe/unsafe-fn-used-as-value.rs
src/test/ui/unsafe/unsafe-fn-used-as-value.thir.stderr
src/test/ui/unused-crate-deps/deny-attr.rs [new file with mode: 0644]
src/test/ui/unused-crate-deps/deny-attr.stderr [new file with mode: 0644]
src/test/ui/unused-crate-deps/deny-cmdline-json-silent.rs [new file with mode: 0644]
src/test/ui/unused-crate-deps/deny-cmdline-json-silent.stderr [new file with mode: 0644]
src/test/ui/unused-crate-deps/deny-cmdline-json.rs [new file with mode: 0644]
src/test/ui/unused-crate-deps/deny-cmdline-json.stderr [new file with mode: 0644]
src/test/ui/unused-crate-deps/deny-cmdline.rs [new file with mode: 0644]
src/test/ui/unused-crate-deps/deny-cmdline.stderr [new file with mode: 0644]
src/test/ui/unused-crate-deps/warn-cmdline-json.rs [new file with mode: 0644]
src/test/ui/unused-crate-deps/warn-cmdline-json.stderr [new file with mode: 0644]
src/test/ui/weird-exprs.rs
src/test/ui/wf/wf-impl-associated-type-region.stderr
src/test/ui/wf/wf-in-fn-type-static.stderr
src/test/ui/wf/wf-in-obj-type-static.stderr
src/test/ui/wf/wf-outlives-ty-in-fn-or-trait.stderr
src/tools/cargo
src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
src/tools/clippy/clippy_lints/src/enum_variants.rs
src/tools/clippy/clippy_lints/src/exhaustive_items.rs
src/tools/clippy/clippy_lints/src/functions/must_use.rs
src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
src/tools/clippy/clippy_lints/src/functions/too_many_arguments.rs
src/tools/clippy/clippy_lints/src/lifetimes.rs
src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs
src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs
src/tools/clippy/clippy_lints/src/missing_doc.rs
src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
src/tools/clippy/clippy_lints/src/new_without_default.rs
src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs
src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs
src/tools/clippy/clippy_lints/src/serde_api.rs
src/tools/clippy/clippy_lints/src/trait_bounds.rs
src/tools/clippy/clippy_lints/src/types/borrowed_box.rs
src/tools/clippy/clippy_lints/src/unused_async.rs
src/tools/clippy/clippy_lints/src/utils/inspector.rs
src/tools/clippy/clippy_lints/src/wildcard_imports.rs
src/tools/clippy/clippy_utils/src/lib.rs
src/tools/clippy/clippy_utils/src/sugg.rs
src/tools/clippy/tests/ui/extra_unused_lifetimes.stderr
src/tools/clippy/tests/ui/needless_lifetimes.stderr
src/tools/compiletest/src/common.rs
src/tools/compiletest/src/header.rs
src/tools/compiletest/src/header/tests.rs
src/tools/compiletest/src/json.rs
src/tools/compiletest/src/main.rs
src/tools/compiletest/src/runtest.rs
src/tools/miri
src/tools/rust-analyzer
src/tools/rustdoc-gui/tester.js
src/tools/rustdoc-js/tester.js
src/tools/rustfmt/src/expr.rs
src/tools/rustfmt/src/macros.rs
src/tools/rustfmt/src/overflow.rs
src/tools/rustfmt/src/parse/macros/cfg_if.rs
src/tools/rustfmt/src/parse/macros/mod.rs
src/tools/rustfmt/src/utils.rs
src/tools/rustfmt/src/visitor.rs
src/tools/tidy/src/deps.rs
src/tools/tidy/src/ui_tests.rs

index 687fbb24d9fe728fb317611b8e4dcdb1ba0e586d..ef4800a22613682eba1362ac05a718e733424335 100644 (file)
@@ -56,15 +56,13 @@ dependencies = [
 
 [[package]]
 name = "ammonia"
-version = "3.1.3"
+version = "3.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b74b175af97d1aecc1add0878b1cbfcbf3bd4c22d7713eeb6d597da23e29bc0d"
+checksum = "d5ed2509ee88cc023cccee37a6fab35826830fe8b748b3869790e7720c2c4a74"
 dependencies = [
  "html5ever",
- "lazy_static",
  "maplit",
- "markup5ever_rcdom",
- "matches",
+ "once_cell",
  "tendril",
  "url 2.2.2",
 ]
@@ -225,8 +223,10 @@ dependencies = [
  "pretty_assertions",
  "serde",
  "serde_json",
+ "tar",
  "toml",
  "winapi",
+ "xz2",
 ]
 
 [[package]]
@@ -364,7 +364,7 @@ dependencies = [
  "tar",
  "tempfile",
  "termcolor",
- "toml_edit",
+ "toml_edit 0.14.3",
  "unicode-width",
  "unicode-xid",
  "url 2.2.2",
@@ -450,7 +450,7 @@ dependencies = [
  "serde_json",
  "tar",
  "termcolor",
- "toml_edit",
+ "toml_edit 0.13.4",
  "url 2.2.2",
 ]
 
@@ -881,9 +881,9 @@ dependencies = [
 
 [[package]]
 name = "crossbeam-channel"
-version = "0.5.2"
+version = "0.5.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e54ea8bc3fb1ee042f5aace6e3c6e025d3874866da222930f70ce62aceba0bfa"
+checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53"
 dependencies = [
  "cfg-if 1.0.0",
  "crossbeam-utils",
@@ -915,9 +915,9 @@ dependencies = [
 
 [[package]]
 name = "crossbeam-utils"
-version = "0.8.6"
+version = "0.8.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cfcae03edb34f947e64acdb1c33ec169824e20657e9ecb61cef6c8c74dcb8120"
+checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38"
 dependencies = [
  "cfg-if 1.0.0",
  "lazy_static",
@@ -1724,9 +1724,9 @@ dependencies = [
 
 [[package]]
 name = "html5ever"
-version = "0.25.1"
+version = "0.26.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aafcf38a1a36118242d29b92e1b08ef84e67e4a5ed06e0a80be20e6a32bfed6b"
+checksum = "bea68cab48b8459f17cf1c944c67ddc572d272d9f2b274140f223ecb1da4a3b7"
 dependencies = [
  "log",
  "mac",
@@ -2047,6 +2047,15 @@ dependencies = [
  "serde",
 ]
 
+[[package]]
+name = "kstring"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec3066350882a1cd6d950d055997f379ac37fd39f81cd4d8ed186032eb3c5747"
+dependencies = [
+ "static_assertions",
+]
+
 [[package]]
 name = "lazy_static"
 version = "1.4.0"
@@ -2234,9 +2243,9 @@ checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
 
 [[package]]
 name = "markup5ever"
-version = "0.10.1"
+version = "0.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a24f40fb03852d1cdd84330cddcaf98e9ec08a7b7768e952fad3b4cf048ec8fd"
+checksum = "7a2629bb1404f3d34c2e921f21fd34ba00b206124c81f65c50b43b6aaefeb016"
 dependencies = [
  "log",
  "phf",
@@ -2246,18 +2255,6 @@ dependencies = [
  "tendril",
 ]
 
-[[package]]
-name = "markup5ever_rcdom"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f015da43bcd8d4f144559a3423f4591d69b8ce0652c905374da7205df336ae2b"
-dependencies = [
- "html5ever",
- "markup5ever",
- "tendril",
- "xml5ever",
-]
-
 [[package]]
 name = "matchers"
 version = "0.1.0"
@@ -2427,7 +2424,7 @@ dependencies = [
  "libc",
  "log",
  "measureme 9.1.2",
- "rand 0.8.4",
+ "rand 0.8.5",
  "rustc-workspace-hack",
  "rustc_version",
  "shell-escape",
@@ -2531,9 +2528,9 @@ dependencies = [
 
 [[package]]
 name = "once_cell"
-version = "1.7.2"
+version = "1.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3"
+checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
 
 [[package]]
 name = "opaque-debug"
@@ -2573,9 +2570,9 @@ checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de"
 
 [[package]]
 name = "openssl-src"
-version = "111.17.0+1.1.1m"
+version = "111.18.0+1.1.1n"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "05d6a336abd10814198f66e2a91ccd7336611f30334119ca8ce300536666fcf4"
+checksum = "7897a926e1e8d00219127dc020130eca4292e5ca666dd592480d72c3eca2ff6c"
 dependencies = [
  "cc",
 ]
@@ -2783,18 +2780,18 @@ dependencies = [
 
 [[package]]
 name = "phf"
-version = "0.8.0"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12"
+checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259"
 dependencies = [
  "phf_shared",
 ]
 
 [[package]]
 name = "phf_codegen"
-version = "0.8.0"
+version = "0.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815"
+checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd"
 dependencies = [
  "phf_generator",
  "phf_shared",
@@ -2802,19 +2799,19 @@ dependencies = [
 
 [[package]]
 name = "phf_generator"
-version = "0.8.0"
+version = "0.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526"
+checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6"
 dependencies = [
  "phf_shared",
- "rand 0.7.3",
+ "rand 0.8.5",
 ]
 
 [[package]]
 name = "phf_shared"
-version = "0.8.0"
+version = "0.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7"
+checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096"
 dependencies = [
  "siphasher",
 ]
@@ -2923,9 +2920,9 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.30"
+version = "1.0.37"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "edc3358ebc67bc8b7fa0c007f945b0b18226f78437d61bec735a9eb96b61ee70"
+checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1"
 dependencies = [
  "unicode-xid",
 ]
@@ -2993,9 +2990,9 @@ checksum = "07589615d719a60c8dd8a4622e7946465dfef20d1a428f969e3443e7386d5f45"
 
 [[package]]
 name = "quote"
-version = "1.0.7"
+version = "1.0.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
+checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1"
 dependencies = [
  "proc-macro2",
 ]
@@ -3026,20 +3023,18 @@ dependencies = [
  "libc",
  "rand_chacha 0.2.2",
  "rand_core 0.5.1",
- "rand_hc 0.2.0",
- "rand_pcg",
+ "rand_hc",
 ]
 
 [[package]]
 name = "rand"
-version = "0.8.4"
+version = "0.8.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8"
+checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
 dependencies = [
  "libc",
  "rand_chacha 0.3.0",
  "rand_core 0.6.2",
- "rand_hc 0.3.0",
 ]
 
 [[package]]
@@ -3089,24 +3084,6 @@ dependencies = [
  "rand_core 0.5.1",
 ]
 
-[[package]]
-name = "rand_hc"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73"
-dependencies = [
- "rand_core 0.6.2",
-]
-
-[[package]]
-name = "rand_pcg"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429"
-dependencies = [
- "rand_core 0.5.1",
-]
-
 [[package]]
 name = "rand_xorshift"
 version = "0.2.0"
@@ -3245,7 +3222,7 @@ dependencies = [
  "num_cpus",
  "ordslice",
  "racer",
- "rand 0.8.4",
+ "rand 0.8.5",
  "rayon",
  "regex",
  "rls-analysis",
@@ -3266,7 +3243,7 @@ dependencies = [
  "tokio-stream",
  "tokio-util",
  "toml",
- "toml_edit",
+ "toml_edit 0.13.4",
  "url 2.2.2",
  "walkdir",
 ]
@@ -3318,7 +3295,7 @@ dependencies = [
  "env_logger 0.9.0",
  "futures 0.3.19",
  "log",
- "rand 0.8.4",
+ "rand 0.8.5",
  "rls-data",
  "rls-ipc",
  "serde",
@@ -3859,7 +3836,7 @@ dependencies = [
 name = "rustc_incremental"
 version = "0.0.0"
 dependencies = [
- "rand 0.8.4",
+ "rand 0.8.5",
  "rustc_ast",
  "rustc_data_structures",
  "rustc_errors",
@@ -4061,7 +4038,7 @@ dependencies = [
  "either",
  "gsgdt",
  "polonius-engine",
- "rand 0.8.4",
+ "rand 0.8.5",
  "rand_xoshiro 0.6.0",
  "rustc-rayon",
  "rustc-rayon-core",
@@ -4181,6 +4158,7 @@ dependencies = [
  "rustc_errors",
  "rustc_feature",
  "rustc_lexer",
+ "rustc_macros",
  "rustc_session",
  "rustc_span",
  "tracing",
@@ -4536,6 +4514,7 @@ dependencies = [
  "expect-test",
  "itertools",
  "minifier",
+ "once_cell",
  "pulldown-cmark",
  "rayon",
  "regex",
@@ -4923,6 +4902,12 @@ dependencies = [
  "winapi",
 ]
 
+[[package]]
+name = "static_assertions"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
+
 [[package]]
 name = "std"
 version = "0.0.0"
@@ -4962,12 +4947,13 @@ dependencies = [
 
 [[package]]
 name = "string_cache"
-version = "0.8.0"
+version = "0.8.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2940c75beb4e3bf3a494cef919a747a2cb81e52571e212bfbd185074add7208a"
+checksum = "33994d0838dc2d152d17a62adf608a869b5e846b65b389af7f3dbc1de45c5b26"
 dependencies = [
  "lazy_static",
  "new_debug_unreachable",
+ "parking_lot",
  "phf_shared",
  "precomputed-hash",
  "serde",
@@ -4975,9 +4961,9 @@ dependencies = [
 
 [[package]]
 name = "string_cache_codegen"
-version = "0.5.1"
+version = "0.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f24c8e5e19d22a726626f1a5e16fe15b132dcf21d10177fa5a45ce7962996b97"
+checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988"
 dependencies = [
  "phf_generator",
  "phf_shared",
@@ -5050,9 +5036,9 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "1.0.80"
+version = "1.0.91"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d010a1623fbd906d51d650a9916aaefc05ffa0e4053ff7fe601167f3e715d194"
+checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -5090,7 +5076,7 @@ checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22"
 dependencies = [
  "cfg-if 1.0.0",
  "libc",
- "rand 0.8.4",
+ "rand 0.8.5",
  "redox_syscall",
  "remove_dir_all",
  "winapi",
@@ -5339,7 +5325,20 @@ dependencies = [
  "combine",
  "indexmap",
  "itertools",
- "kstring",
+ "kstring 1.0.6",
+ "serde",
+]
+
+[[package]]
+name = "toml_edit"
+version = "0.14.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba98375fd631b83696f87c64e4ed8e29e6a1f3404d6aed95fa95163bad38e705"
+dependencies = [
+ "combine",
+ "indexmap",
+ "itertools",
+ "kstring 2.0.0",
  "serde",
 ]
 
@@ -5804,18 +5803,6 @@ dependencies = [
  "libc",
 ]
 
-[[package]]
-name = "xml5ever"
-version = "0.16.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b1b52e6e8614d4a58b8e70cf51ec0cc21b256ad8206708bcff8139b5bbd6a59"
-dependencies = [
- "log",
- "mac",
- "markup5ever",
- "time",
-]
-
 [[package]]
 name = "xz2"
 version = "0.1.6"
index b7da276fc7e1dc431acd53a999524e3d4e05bb06..1a18d1964c9782edbfb8abff4acb13a1cdc63603 100644 (file)
@@ -23,7 +23,7 @@
 pub use UnsafeSource::*;
 
 use crate::ptr::P;
-use crate::token::{self, CommentKind, DelimToken, Token};
+use crate::token::{self, CommentKind, Delimiter, Token};
 use crate::tokenstream::{DelimSpan, LazyTokenStream, TokenStream, TokenTree};
 
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
@@ -397,6 +397,7 @@ pub struct GenericParam {
     pub bounds: GenericBounds,
     pub is_placeholder: bool,
     pub kind: GenericParamKind,
+    pub colon_span: Option<Span>,
 }
 
 impl GenericParam {
@@ -1274,6 +1275,7 @@ pub fn precedence(&self) -> ExprPrecedence {
             ExprKind::Paren(..) => ExprPrecedence::Paren,
             ExprKind::Try(..) => ExprPrecedence::Try,
             ExprKind::Yield(..) => ExprPrecedence::Yield,
+            ExprKind::Yeet(..) => ExprPrecedence::Yeet,
             ExprKind::Err => ExprPrecedence::Err,
         }
     }
@@ -1461,6 +1463,10 @@ pub enum ExprKind {
     /// A `yield`, with an optional value to be yielded.
     Yield(Option<P<Expr>>),
 
+    /// A `do yeet` (aka `throw`/`fail`/`bail`/`raise`/whatever),
+    /// with an optional value to be returned.
+    Yeet(Option<P<Expr>>),
+
     /// Placeholder for an expression that wasn't syntactically well formed in some way.
     Err,
 }
@@ -1542,10 +1548,10 @@ pub enum MacArgs {
 }
 
 impl MacArgs {
-    pub fn delim(&self) -> DelimToken {
+    pub fn delim(&self) -> Option<Delimiter> {
         match self {
-            MacArgs::Delimited(_, delim, _) => delim.to_token(),
-            MacArgs::Empty | MacArgs::Eq(..) => token::NoDelim,
+            MacArgs::Delimited(_, delim, _) => Some(delim.to_token()),
+            MacArgs::Empty | MacArgs::Eq(..) => None,
         }
     }
 
@@ -1582,20 +1588,20 @@ pub enum MacDelimiter {
 }
 
 impl MacDelimiter {
-    pub fn to_token(self) -> DelimToken {
+    pub fn to_token(self) -> Delimiter {
         match self {
-            MacDelimiter::Parenthesis => DelimToken::Paren,
-            MacDelimiter::Bracket => DelimToken::Bracket,
-            MacDelimiter::Brace => DelimToken::Brace,
+            MacDelimiter::Parenthesis => Delimiter::Parenthesis,
+            MacDelimiter::Bracket => Delimiter::Bracket,
+            MacDelimiter::Brace => Delimiter::Brace,
         }
     }
 
-    pub fn from_token(delim: DelimToken) -> Option<MacDelimiter> {
+    pub fn from_token(delim: Delimiter) -> Option<MacDelimiter> {
         match delim {
-            token::Paren => Some(MacDelimiter::Parenthesis),
-            token::Bracket => Some(MacDelimiter::Bracket),
-            token::Brace => Some(MacDelimiter::Brace),
-            token::NoDelim => None,
+            Delimiter::Parenthesis => Some(MacDelimiter::Parenthesis),
+            Delimiter::Bracket => Some(MacDelimiter::Bracket),
+            Delimiter::Brace => Some(MacDelimiter::Brace),
+            Delimiter::Invisible => None,
         }
     }
 }
index 9a6d12faa605d62bcdf7540aeb1adf28a9dbb8b1..b14367aa1c2c2deb32d109eef53e3939b9035e19 100644 (file)
@@ -5,7 +5,7 @@
 use crate::ast::{Lit, LitKind};
 use crate::ast::{MacArgs, MacDelimiter, MetaItem, MetaItemKind, NestedMetaItem};
 use crate::ast::{Path, PathSegment};
-use crate::token::{self, CommentKind, Token};
+use crate::token::{self, CommentKind, Delimiter, Token};
 use crate::tokenstream::{AttrAnnotatedTokenStream, AttrAnnotatedTokenTree};
 use crate::tokenstream::{DelimSpan, Spacing, TokenTree, TreeAndSpacing};
 use crate::tokenstream::{LazyTokenStream, TokenStream};
@@ -513,7 +513,7 @@ fn token_trees_and_spacings(&self, span: Span) -> Vec<TreeAndSpacing> {
                 vec![
                     TokenTree::Delimited(
                         DelimSpan::from_single(span),
-                        token::Paren,
+                        Delimiter::Parenthesis,
                         TokenStream::new(tokens),
                     )
                     .into(),
@@ -540,7 +540,7 @@ fn name_value_from_tokens(
         tokens: &mut impl Iterator<Item = TokenTree>,
     ) -> Option<MetaItemKind> {
         match tokens.next() {
-            Some(TokenTree::Delimited(_, token::NoDelim, inner_tokens)) => {
+            Some(TokenTree::Delimited(_, Delimiter::Invisible, inner_tokens)) => {
                 MetaItemKind::name_value_from_tokens(&mut inner_tokens.trees())
             }
             Some(TokenTree::Token(token)) => {
@@ -565,7 +565,7 @@ fn from_tokens(
         tokens: &mut iter::Peekable<impl Iterator<Item = TokenTree>>,
     ) -> Option<MetaItemKind> {
         match tokens.peek() {
-            Some(TokenTree::Delimited(_, token::Paren, inner_tokens)) => {
+            Some(TokenTree::Delimited(_, Delimiter::Parenthesis, inner_tokens)) => {
                 let inner_tokens = inner_tokens.clone();
                 tokens.next();
                 MetaItemKind::list_from_tokens(inner_tokens)
@@ -606,7 +606,7 @@ fn from_tokens<I>(tokens: &mut iter::Peekable<I>) -> Option<NestedMetaItem>
                 tokens.next();
                 return Some(NestedMetaItem::Literal(lit));
             }
-            Some(TokenTree::Delimited(_, token::NoDelim, inner_tokens)) => {
+            Some(TokenTree::Delimited(_, Delimiter::Invisible, inner_tokens)) => {
                 let inner_tokens = inner_tokens.clone();
                 tokens.next();
                 return NestedMetaItem::from_tokens(&mut inner_tokens.into_trees().peekable());
index cba49835f69cb45efc0a6be4011ca764790f1b74..4bf3d483f7358f4bb22036df89fd9c14dd362ad0 100644 (file)
@@ -867,9 +867,12 @@ pub fn noop_flat_map_generic_param<T: MutVisitor>(
     mut param: GenericParam,
     vis: &mut T,
 ) -> SmallVec<[GenericParam; 1]> {
-    let GenericParam { id, ident, attrs, bounds, kind, is_placeholder: _ } = &mut param;
+    let GenericParam { id, ident, attrs, bounds, kind, colon_span, is_placeholder: _ } = &mut param;
     vis.visit_id(id);
     vis.visit_ident(ident);
+    if let Some(ref mut colon_span) = colon_span {
+        vis.visit_span(colon_span);
+    }
     visit_thin_attrs(attrs, vis);
     visit_vec(bounds, |bound| noop_visit_param_bound(bound, vis));
     match kind {
@@ -1391,6 +1394,9 @@ pub fn noop_visit_expr<T: MutVisitor>(
         ExprKind::Ret(expr) => {
             visit_opt(expr, |expr| vis.visit_expr(expr));
         }
+        ExprKind::Yeet(expr) => {
+            visit_opt(expr, |expr| vis.visit_expr(expr));
+        }
         ExprKind::InlineAsm(asm) => vis.visit_inline_asm(asm),
         ExprKind::MacCall(mac) => vis.visit_mac_call(mac),
         ExprKind::Struct(se) => {
index 5aa8011ca5eb627a99e24c70ba9b75d085d4e7d5..1589a882f0892c99cbc1f21706797bb3ca493dd0 100644 (file)
@@ -1,5 +1,4 @@
 pub use BinOpToken::*;
-pub use DelimToken::*;
 pub use LitKind::*;
 pub use Nonterminal::*;
 pub use TokenKind::*;
@@ -37,18 +36,26 @@ pub enum BinOpToken {
     Shr,
 }
 
-/// A delimiter token.
-#[derive(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Debug, Copy)]
-#[derive(HashStable_Generic)]
-pub enum DelimToken {
-    /// A round parenthesis (i.e., `(` or `)`).
-    Paren,
-    /// A square bracket (i.e., `[` or `]`).
-    Bracket,
-    /// A curly brace (i.e., `{` or `}`).
+/// Describes how a sequence of token trees is delimited.
+/// Cannot use `proc_macro::Delimiter` directly because this
+/// structure should implement some additional traits.
+/// The `None` variant is also renamed to `Invisible` to be
+/// less confusing and better convey the semantics.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+#[derive(Encodable, Decodable, Hash, HashStable_Generic)]
+pub enum Delimiter {
+    /// `( ... )`
+    Parenthesis,
+    /// `{ ... }`
     Brace,
-    /// An empty delimiter.
-    NoDelim,
+    /// `[ ... ]`
+    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 might not survive roundtrip of a token stream through a string.
+    Invisible,
 }
 
 #[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
@@ -212,9 +219,9 @@ pub enum TokenKind {
     /// Used by proc macros for representing lifetimes, not generated by lexer right now.
     SingleQuote,
     /// An opening delimiter (e.g., `{`).
-    OpenDelim(DelimToken),
+    OpenDelim(Delimiter),
     /// A closing delimiter (e.g., `}`).
-    CloseDelim(DelimToken),
+    CloseDelim(Delimiter),
 
     /* Literals */
     Literal(Lit),
@@ -387,8 +394,8 @@ pub fn can_begin_type(&self) -> bool {
         match self.uninterpolate().kind {
             Ident(name, is_raw)        =>
                 ident_can_begin_type(name, self.span, is_raw), // type name or keyword
-            OpenDelim(Paren)            | // tuple
-            OpenDelim(Bracket)          | // array
+            OpenDelim(Delimiter::Parenthesis) | // tuple
+            OpenDelim(Delimiter::Bracket)     | // array
             Not                         | // never
             BinOp(Star)                 | // raw pointer
             BinOp(And)                  | // reference
@@ -405,7 +412,7 @@ pub fn can_begin_type(&self) -> bool {
     /// Returns `true` if the token can appear at the start of a const param.
     pub fn can_begin_const_arg(&self) -> bool {
         match self.kind {
-            OpenDelim(Brace) => true,
+            OpenDelim(Delimiter::Brace) => true,
             Interpolated(ref nt) => matches!(**nt, NtExpr(..) | NtBlock(..) | NtLiteral(..)),
             _ => self.can_begin_literal_maybe_minus(),
         }
@@ -417,7 +424,7 @@ pub fn can_begin_bound(&self) -> bool {
             || self.is_lifetime()
             || self.is_keyword(kw::For)
             || self == &Question
-            || self == &OpenDelim(Paren)
+            || self == &OpenDelim(Delimiter::Parenthesis)
     }
 
     /// Returns `true` if the token is any literal.
index affb4289cb1b5a4f229a79cdaba90b1d7008f7c3..a8f29f334070e9f4324fdf75e14a1c94818d3d9b 100644 (file)
@@ -13,7 +13,7 @@
 //! and a borrowed `TokenStream` is sufficient to build an owned `TokenStream` without taking
 //! ownership of the original.
 
-use crate::token::{self, DelimToken, Token, TokenKind};
+use crate::token::{self, Delimiter, Token, TokenKind};
 use crate::AttrVec;
 
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
@@ -42,7 +42,7 @@ pub enum TokenTree {
     /// A single token.
     Token(Token),
     /// A delimited sequence of token trees.
-    Delimited(DelimSpan, DelimToken, TokenStream),
+    Delimited(DelimSpan, Delimiter, TokenStream),
 }
 
 #[derive(Copy, Clone)]
@@ -57,7 +57,7 @@ fn _dummy()
 where
     Token: Send + Sync,
     DelimSpan: Send + Sync,
-    DelimToken: Send + Sync,
+    Delimiter: Send + Sync,
     TokenStream: Send + Sync,
 {
 }
@@ -94,16 +94,6 @@ pub fn token(kind: TokenKind, span: Span) -> TokenTree {
         TokenTree::Token(Token::new(kind, span))
     }
 
-    /// Returns the opening delimiter as a token tree.
-    pub fn open_tt(span: DelimSpan, delim: DelimToken) -> TokenTree {
-        TokenTree::token(token::OpenDelim(delim), span.open)
-    }
-
-    /// Returns the closing delimiter as a token tree.
-    pub fn close_tt(span: DelimSpan, delim: DelimToken) -> TokenTree {
-        TokenTree::token(token::CloseDelim(delim), span.close)
-    }
-
     pub fn uninterpolate(self) -> TokenTree {
         match self {
             TokenTree::Token(token) => TokenTree::Token(token.uninterpolate().into_owned()),
@@ -185,7 +175,7 @@ fn hash_stable(&self, _hcx: &mut CTX, _hasher: &mut StableHasher) {
 #[derive(Clone, Debug, Encodable, Decodable)]
 pub enum AttrAnnotatedTokenTree {
     Token(Token),
-    Delimited(DelimSpan, DelimToken, AttrAnnotatedTokenStream),
+    Delimited(DelimSpan, Delimiter, AttrAnnotatedTokenStream),
     /// Stores the attributes for an attribute target,
     /// along with the tokens for that attribute target.
     /// See `AttributesData` for more information
@@ -585,13 +575,20 @@ fn new(stream: TokenStream) -> Self {
         Cursor { stream, index: 0 }
     }
 
+    #[inline]
     pub fn next_with_spacing(&mut self) -> Option<TreeAndSpacing> {
-        if self.index < self.stream.len() {
+        self.stream.0.get(self.index).map(|tree| {
             self.index += 1;
-            Some(self.stream.0[self.index - 1].clone())
-        } else {
-            None
-        }
+            tree.clone()
+        })
+    }
+
+    #[inline]
+    pub fn next_with_spacing_ref(&mut self) -> Option<&TreeAndSpacing> {
+        self.stream.0.get(self.index).map(|tree| {
+            self.index += 1;
+            tree
+        })
     }
 
     pub fn index(&self) -> usize {
index 742a7d1d2df70907fa087b4221fffbf816b835bf..74b7fe9e249552eb3519176f0d8f7b6a045d7d61 100644 (file)
@@ -247,6 +247,7 @@ pub enum ExprPrecedence {
     Continue,
     Ret,
     Yield,
+    Yeet,
 
     Range,
 
@@ -299,7 +300,8 @@ pub fn order(self) -> i8 {
             ExprPrecedence::Break |
             ExprPrecedence::Continue |
             ExprPrecedence::Ret |
-            ExprPrecedence::Yield => PREC_JUMP,
+            ExprPrecedence::Yield |
+            ExprPrecedence::Yeet => PREC_JUMP,
 
             // `Range` claims to have higher precedence than `Assign`, but `x .. x = x` fails to
             // parse, instead of parsing as `(x .. x) = x`.  Giving `Range` a lower precedence
index d925c6dd3549aa5da8b01d7a80858bd1dccaf8d1..fa26716083f86c3436d7631480cf12eef64ecce7 100644 (file)
@@ -32,6 +32,25 @@ pub enum FnCtxt {
     Assoc(AssocCtxt),
 }
 
+#[derive(Copy, Clone, Debug)]
+pub enum BoundKind {
+    /// Trait bounds in generics bounds and type/trait alias.
+    /// E.g., `<T: Bound>`, `type A: Bound`, or `where T: Bound`.
+    Bound,
+
+    /// Trait bounds in `impl` type.
+    /// E.g., `type Foo = impl Bound1 + Bound2 + Bound3`.
+    Impl,
+
+    /// Trait bounds in trait object type.
+    /// E.g., `dyn Bound1 + Bound2 + Bound3`.
+    TraitObject,
+
+    /// Super traits of a trait.
+    /// E.g., `trait A: B`
+    SuperTraits,
+}
+
 #[derive(Copy, Clone, Debug)]
 pub enum FnKind<'a> {
     /// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`.
@@ -139,7 +158,7 @@ fn visit_assoc_item(&mut self, i: &'ast AssocItem, ctxt: AssocCtxt) {
     fn visit_trait_ref(&mut self, t: &'ast TraitRef) {
         walk_trait_ref(self, t)
     }
-    fn visit_param_bound(&mut self, bounds: &'ast GenericBound) {
+    fn visit_param_bound(&mut self, bounds: &'ast GenericBound, _ctxt: BoundKind) {
         walk_param_bound(self, bounds)
     }
     fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef, m: &'ast TraitBoundModifier) {
@@ -311,7 +330,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
         ItemKind::GlobalAsm(ref asm) => walk_inline_asm(visitor, asm),
         ItemKind::TyAlias(box TyAlias { ref generics, ref bounds, ref ty, .. }) => {
             visitor.visit_generics(generics);
-            walk_list!(visitor, visit_param_bound, bounds);
+            walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound);
             walk_list!(visitor, visit_ty, ty);
         }
         ItemKind::Enum(ref enum_definition, ref generics) => {
@@ -346,12 +365,12 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
             ref items,
         }) => {
             visitor.visit_generics(generics);
-            walk_list!(visitor, visit_param_bound, bounds);
+            walk_list!(visitor, visit_param_bound, bounds, BoundKind::SuperTraits);
             walk_list!(visitor, visit_assoc_item, items, AssocCtxt::Trait);
         }
         ItemKind::TraitAlias(ref generics, ref bounds) => {
             visitor.visit_generics(generics);
-            walk_list!(visitor, visit_param_bound, bounds);
+            walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound);
         }
         ItemKind::MacCall(ref mac) => visitor.visit_mac_call(mac),
         ItemKind::MacroDef(ref ts) => visitor.visit_mac_def(ts, item.id),
@@ -416,8 +435,11 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) {
             visitor.visit_ty(ty);
             visitor.visit_anon_const(length)
         }
-        TyKind::TraitObject(ref bounds, ..) | TyKind::ImplTrait(_, ref bounds) => {
-            walk_list!(visitor, visit_param_bound, bounds);
+        TyKind::TraitObject(ref bounds, ..) => {
+            walk_list!(visitor, visit_param_bound, bounds, BoundKind::TraitObject);
+        }
+        TyKind::ImplTrait(_, ref bounds) => {
+            walk_list!(visitor, visit_param_bound, bounds, BoundKind::Impl);
         }
         TyKind::Typeof(ref expression) => visitor.visit_anon_const(expression),
         TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err => {}
@@ -503,7 +525,7 @@ pub fn walk_assoc_constraint<'a, V: Visitor<'a>>(visitor: &mut V, constraint: &'
             Term::Const(c) => visitor.visit_anon_const(c),
         },
         AssocConstraintKind::Bound { ref bounds } => {
-            walk_list!(visitor, visit_param_bound, bounds);
+            walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound);
         }
     }
 }
@@ -566,7 +588,7 @@ pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a ForeignI
         }
         ForeignItemKind::TyAlias(box TyAlias { generics, bounds, ty, .. }) => {
             visitor.visit_generics(generics);
-            walk_list!(visitor, visit_param_bound, bounds);
+            walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound);
             walk_list!(visitor, visit_ty, ty);
         }
         ForeignItemKind::MacCall(mac) => {
@@ -585,7 +607,7 @@ pub fn walk_param_bound<'a, V: Visitor<'a>>(visitor: &mut V, bound: &'a GenericB
 pub fn walk_generic_param<'a, V: Visitor<'a>>(visitor: &mut V, param: &'a GenericParam) {
     visitor.visit_ident(param.ident);
     walk_list!(visitor, visit_attribute, param.attrs.iter());
-    walk_list!(visitor, visit_param_bound, &param.bounds);
+    walk_list!(visitor, visit_param_bound, &param.bounds, BoundKind::Bound);
     match param.kind {
         GenericParamKind::Lifetime => (),
         GenericParamKind::Type { ref default } => walk_list!(visitor, visit_ty, default),
@@ -612,14 +634,14 @@ pub fn walk_where_predicate<'a, V: Visitor<'a>>(visitor: &mut V, predicate: &'a
             ..
         }) => {
             visitor.visit_ty(bounded_ty);
-            walk_list!(visitor, visit_param_bound, bounds);
+            walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound);
             walk_list!(visitor, visit_generic_param, bound_generic_params);
         }
         WherePredicate::RegionPredicate(WhereRegionPredicate {
             ref lifetime, ref bounds, ..
         }) => {
             visitor.visit_lifetime(lifetime);
-            walk_list!(visitor, visit_param_bound, bounds);
+            walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound);
         }
         WherePredicate::EqPredicate(WhereEqPredicate { ref lhs_ty, ref rhs_ty, .. }) => {
             visitor.visit_ty(lhs_ty);
@@ -672,7 +694,7 @@ pub fn walk_assoc_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem,
         }
         AssocItemKind::TyAlias(box TyAlias { generics, bounds, ty, .. }) => {
             visitor.visit_generics(generics);
-            walk_list!(visitor, visit_param_bound, bounds);
+            walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound);
             walk_list!(visitor, visit_ty, ty);
         }
         AssocItemKind::MacCall(mac) => {
@@ -871,6 +893,9 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
         ExprKind::Ret(ref optional_expression) => {
             walk_list!(visitor, visit_expr, optional_expression);
         }
+        ExprKind::Yeet(ref optional_expression) => {
+            walk_list!(visitor, visit_expr, optional_expression);
+        }
         ExprKind::MacCall(ref mac) => visitor.visit_mac_call(mac),
         ExprKind::Paren(ref subexpression) => visitor.visit_expr(subexpression),
         ExprKind::InlineAsm(ref asm) => walk_inline_asm(visitor, asm),
index 9442e0f1a1f3533714c940e8e935000f07aaa533..5c3e3be21167a525df9d53688938e286b7bf4cd0 100644 (file)
@@ -53,7 +53,6 @@ pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
                         e.span,
                         seg,
                         ParamMode::Optional,
-                        0,
                         ParenthesizedGenericArgs::Err,
                         ImplTraitContext::Disallowed(ImplTraitPosition::Path),
                     ));
@@ -222,6 +221,7 @@ pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
                     let e = e.as_ref().map(|x| self.lower_expr(x));
                     hir::ExprKind::Ret(e)
                 }
+                ExprKind::Yeet(ref sub_expr) => self.lower_expr_yeet(e.span, sub_expr.as_deref()),
                 ExprKind::InlineAsm(ref asm) => {
                     hir::ExprKind::InlineAsm(self.lower_inline_asm(e.span, asm))
                 }
@@ -1544,6 +1544,44 @@ fn lower_expr_try(&mut self, span: Span, sub_expr: &Expr) -> hir::ExprKind<'hir>
         )
     }
 
+    /// Desugar `ExprKind::Yeet` from: `do yeet <expr>` into:
+    /// ```rust
+    /// // If there is an enclosing `try {...}`:
+    /// break 'catch_target FromResidual::from_residual(Yeet(residual)),
+    /// // Otherwise:
+    /// return FromResidual::from_residual(Yeet(residual)),
+    /// ```
+    /// But to simplify this, there's a `from_yeet` lang item function which
+    /// handles the combined `FromResidual::from_residual(Yeet(residual))`.
+    fn lower_expr_yeet(&mut self, span: Span, sub_expr: Option<&Expr>) -> hir::ExprKind<'hir> {
+        // The expression (if present) or `()` otherwise.
+        let (yeeted_span, yeeted_expr) = if let Some(sub_expr) = sub_expr {
+            (sub_expr.span, self.lower_expr(sub_expr))
+        } else {
+            (self.mark_span_with_reason(DesugaringKind::YeetExpr, span, None), self.expr_unit(span))
+        };
+
+        let unstable_span = self.mark_span_with_reason(
+            DesugaringKind::YeetExpr,
+            span,
+            self.allow_try_trait.clone(),
+        );
+
+        let from_yeet_expr = self.wrap_in_try_constructor(
+            hir::LangItem::TryTraitFromYeet,
+            unstable_span,
+            yeeted_expr,
+            yeeted_span,
+        );
+
+        if let Some(catch_node) = self.catch_scope {
+            let target_id = Ok(self.lower_node_id(catch_node));
+            hir::ExprKind::Break(hir::Destination { label: None, target_id }, Some(from_yeet_expr))
+        } else {
+            hir::ExprKind::Ret(Some(from_yeet_expr))
+        }
+    }
+
     // =========================================================================
     // Helper methods for building HIR.
     // =========================================================================
index 5eab21bf79a90c9a95b57a41534df927793c3832..c506360aa8a13f55663182138c91d7502a379409 100644 (file)
@@ -30,6 +30,7 @@ pub(super) struct NodeCollector<'a, 'hir> {
     definitions: &'a definitions::Definitions,
 }
 
+#[tracing::instrument(level = "debug", skip(sess, definitions, bodies))]
 pub(super) fn index_hir<'hir>(
     sess: &Session,
     definitions: &definitions::Definitions,
@@ -65,6 +66,7 @@ pub(super) fn index_hir<'hir>(
 }
 
 impl<'a, 'hir> NodeCollector<'a, 'hir> {
+    #[tracing::instrument(level = "debug", skip(self))]
     fn insert(&mut self, span: Span, hir_id: HirId, node: Node<'hir>) {
         debug_assert_eq!(self.owner, hir_id.owner);
         debug_assert_ne!(hir_id.local_id.as_u32(), 0);
@@ -138,8 +140,8 @@ fn visit_param(&mut self, param: &'hir Param<'hir>) {
         });
     }
 
+    #[tracing::instrument(level = "debug", skip(self))]
     fn visit_item(&mut self, i: &'hir Item<'hir>) {
-        debug!("visit_item: {:?}", i);
         debug_assert_eq!(i.def_id, self.owner);
         self.with_parent(i.hir_id(), |this| {
             if let ItemKind::Struct(ref struct_def, _) = i.kind {
@@ -152,6 +154,7 @@ fn visit_item(&mut self, i: &'hir Item<'hir>) {
         });
     }
 
+    #[tracing::instrument(level = "debug", skip(self))]
     fn visit_foreign_item(&mut self, fi: &'hir ForeignItem<'hir>) {
         debug_assert_eq!(fi.def_id, self.owner);
         self.with_parent(fi.hir_id(), |this| {
@@ -170,6 +173,7 @@ fn visit_const_param_default(&mut self, param: HirId, ct: &'hir AnonConst) {
         })
     }
 
+    #[tracing::instrument(level = "debug", skip(self))]
     fn visit_trait_item(&mut self, ti: &'hir TraitItem<'hir>) {
         debug_assert_eq!(ti.def_id, self.owner);
         self.with_parent(ti.hir_id(), |this| {
@@ -177,6 +181,7 @@ fn visit_trait_item(&mut self, ti: &'hir TraitItem<'hir>) {
         });
     }
 
+    #[tracing::instrument(level = "debug", skip(self))]
     fn visit_impl_item(&mut self, ii: &'hir ImplItem<'hir>) {
         debug_assert_eq!(ii.def_id, self.owner);
         self.with_parent(ii.hir_id(), |this| {
@@ -290,18 +295,6 @@ fn visit_lifetime(&mut self, lifetime: &'hir Lifetime) {
         self.insert(lifetime.span, lifetime.hir_id, Node::Lifetime(lifetime));
     }
 
-    fn visit_vis(&mut self, visibility: &'hir Visibility<'hir>) {
-        match visibility.node {
-            VisibilityKind::Public | VisibilityKind::Crate(_) | VisibilityKind::Inherited => {}
-            VisibilityKind::Restricted { hir_id, .. } => {
-                self.insert(visibility.span, hir_id, Node::Visibility(visibility));
-                self.with_parent(hir_id, |this| {
-                    intravisit::walk_vis(this, visibility);
-                });
-            }
-        }
-    }
-
     fn visit_variant(&mut self, v: &'hir Variant<'hir>, g: &'hir Generics<'hir>, item_id: HirId) {
         self.insert(v.span, v.id, Node::Variant(v));
         self.with_parent(v.id, |this| {
index a8bd8c92a41c47b54d45329720f092185260300f..5a95e5b084ad42b8ab9daf89c70527bde997dbae 100644 (file)
@@ -1,11 +1,11 @@
-use super::{AnonymousLifetimeMode, LoweringContext, ParamMode};
 use super::{AstOwner, ImplTraitContext, ImplTraitPosition, ResolverAstLowering};
+use super::{LoweringContext, ParamMode};
 use crate::{Arena, FnDeclKind};
 
 use rustc_ast::ptr::P;
 use rustc_ast::visit::AssocCtxt;
 use rustc_ast::*;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sorted_map::SortedMap;
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
@@ -14,7 +14,7 @@
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_session::utils::NtToTokenstream;
 use rustc_session::Session;
-use rustc_span::source_map::{respan, DesugaringKind};
+use rustc_span::source_map::DesugaringKind;
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::Span;
 use rustc_target::spec::abi;
@@ -81,14 +81,11 @@ fn with_lctx(
             is_in_loop_condition: false,
             is_in_trait_impl: false,
             is_in_dyn_type: false,
-            anonymous_lifetime_mode: AnonymousLifetimeMode::PassThrough,
             generator_kind: None,
             task_context: None,
             current_item: None,
-            lifetimes_to_define: Vec::new(),
-            is_collecting_anonymous_lifetimes: None,
-            in_scope_lifetimes: Vec::new(),
-            allow_try_trait: Some([sym::try_trait_v2][..].into()),
+            captured_lifetimes: None,
+            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()),
         };
@@ -143,32 +140,14 @@ fn lower_assoc_item(&mut self, item: &AssocItem, ctxt: AssocCtxt) {
             LocalDefId { local_def_index }
         };
 
-        let parent_hir = self.lower_node(parent_id).unwrap().node().expect_item();
+        let parent_hir = self.lower_node(parent_id).unwrap();
         self.with_lctx(item.id, |lctx| {
             // Evaluate with the lifetimes in `params` in-scope.
             // This is used to track which lifetimes have already been defined,
             // and which need to be replicated when lowering an async fn.
-            match parent_hir.kind {
-                hir::ItemKind::Impl(hir::Impl { ref of_trait, ref generics, .. }) => {
+            match parent_hir.node().expect_item().kind {
+                hir::ItemKind::Impl(hir::Impl { ref of_trait, .. }) => {
                     lctx.is_in_trait_impl = of_trait.is_some();
-                    lctx.in_scope_lifetimes = generics
-                        .params
-                        .iter()
-                        .filter(|param| {
-                            matches!(param.kind, hir::GenericParamKind::Lifetime { .. })
-                        })
-                        .map(|param| param.name)
-                        .collect();
-                }
-                hir::ItemKind::Trait(_, _, ref generics, ..) => {
-                    lctx.in_scope_lifetimes = generics
-                        .params
-                        .iter()
-                        .filter(|param| {
-                            matches!(param.kind, hir::GenericParamKind::Lifetime { .. })
-                        })
-                        .map(|param| param.name)
-                        .collect();
                 }
                 _ => {}
             };
@@ -230,15 +209,15 @@ fn lower_item_id_use_tree(
 
     fn lower_item(&mut self, i: &Item) -> &'hir hir::Item<'hir> {
         let mut ident = i.ident;
-        let mut vis = self.lower_visibility(&i.vis);
+        let vis_span = self.lower_span(i.vis.span);
         let hir_id = self.lower_node_id(i.id);
         let attrs = self.lower_attrs(hir_id, &i.attrs);
-        let kind = self.lower_item_kind(i.span, i.id, hir_id, &mut ident, attrs, &mut vis, &i.kind);
+        let kind = self.lower_item_kind(i.span, i.id, hir_id, &mut ident, attrs, vis_span, &i.kind);
         let item = hir::Item {
             def_id: hir_id.expect_owner(),
             ident: self.lower_ident(ident),
             kind,
-            vis,
+            vis_span,
             span: self.lower_span(i.span),
         };
         self.arena.alloc(item)
@@ -251,7 +230,7 @@ fn lower_item_kind(
         hir_id: hir::HirId,
         ident: &mut Ident,
         attrs: Option<&'hir [Attribute]>,
-        vis: &mut hir::Visibility<'hir>,
+        vis_span: Span,
         i: &ItemKind,
     ) -> hir::ItemKind<'hir> {
         match *i {
@@ -260,7 +239,7 @@ fn lower_item_kind(
                 // Start with an empty prefix.
                 let prefix = Path { segments: vec![], span: use_tree.span, tokens: None };
 
-                self.lower_use_tree(use_tree, &prefix, id, vis, ident, attrs)
+                self.lower_use_tree(use_tree, &prefix, id, vis_span, ident, attrs)
             }
             ItemKind::Static(ref t, m, ref e) => {
                 let (ty, body_id) = self.lower_const_item(t, span, e.as_deref());
@@ -276,7 +255,6 @@ fn lower_item_kind(
                 ref body,
                 ..
             }) => {
-                let fn_def_id = self.resolver.local_def_id(id);
                 self.with_new_scopes(|this| {
                     this.current_item = Some(ident.span);
 
@@ -288,20 +266,16 @@ fn lower_item_kind(
                     let body_id =
                         this.lower_maybe_async_body(span, &decl, asyncness, body.as_deref());
 
-                    let (generics, decl) = this.add_in_band_defs(
-                        generics,
-                        fn_def_id,
-                        AnonymousLifetimeMode::PassThrough,
-                        |this, idty| {
+                    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((fn_def_id, idty)),
+                                Some((id, idty, idpb)),
                                 FnDeclKind::Fn,
                                 ret_id,
                             )
-                        },
-                    );
+                        });
                     let sig = hir::FnSig {
                         decl,
                         header: this.lower_fn_header(header),
@@ -339,12 +313,7 @@ fn lower_item_kind(
                 //
                 // type Foo = Foo1
                 // opaque type Foo1: Trait
-                let ty = self.lower_ty(
-                    ty,
-                    ImplTraitContext::TypeAliasesOpaqueTy {
-                        capturable_lifetimes: &mut FxHashSet::default(),
-                    },
-                );
+                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(
@@ -419,12 +388,8 @@ 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 lowered_trait_def_id = hir_id.expect_owner();
-                let (generics, (trait_ref, lowered_ty)) = self.add_in_band_defs(
-                    ast_generics,
-                    lowered_trait_def_id,
-                    AnonymousLifetimeMode::CreateParameter,
-                    |this, _| {
+                let (generics, (trait_ref, lowered_ty)) =
+                    self.add_implicit_generics(ast_generics, id, |this, _, _| {
                         let trait_ref = trait_ref.as_ref().map(|trait_ref| {
                             this.lower_trait_ref(
                                 trait_ref,
@@ -436,16 +401,12 @@ fn lower_item_kind(
                             .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
 
                         (trait_ref, lowered_ty)
-                    },
-                );
-
-                let new_impl_items =
-                    self.with_in_scope_lifetime_defs(&ast_generics.params, |this| {
-                        this.arena.alloc_from_iter(
-                            impl_items.iter().map(|item| this.lower_impl_item_ref(item)),
-                        )
                     });
 
+                let new_impl_items = self
+                    .arena
+                    .alloc_from_iter(impl_items.iter().map(|item| self.lower_impl_item_ref(item)));
+
                 // `defaultness.has_value()` is never called for an `impl`, always `true` in order
                 // to not cause an assertion failure inside the `lower_defaultness` function.
                 let has_val = true;
@@ -454,7 +415,7 @@ fn lower_item_kind(
                     ImplPolarity::Positive => ImplPolarity::Positive,
                     ImplPolarity::Negative(s) => ImplPolarity::Negative(self.lower_span(s)),
                 };
-                hir::ItemKind::Impl(hir::Impl {
+                hir::ItemKind::Impl(self.arena.alloc(hir::Impl {
                     unsafety: self.lower_unsafety(unsafety),
                     polarity,
                     defaultness,
@@ -464,7 +425,7 @@ fn lower_item_kind(
                     of_trait: trait_ref,
                     self_ty: lowered_ty,
                     items: new_impl_items,
-                })
+                }))
             }
             ItemKind::Trait(box Trait {
                 is_auto,
@@ -527,12 +488,11 @@ fn lower_use_tree(
         tree: &UseTree,
         prefix: &Path,
         id: NodeId,
-        vis: &mut hir::Visibility<'hir>,
+        vis_span: Span,
         ident: &mut Ident,
         attrs: Option<&'hir [Attribute]>,
     ) -> hir::ItemKind<'hir> {
         debug!("lower_use_tree(tree={:?})", tree);
-        debug!("lower_use_tree: vis = {:?}", vis);
 
         let path = &tree.prefix;
         let segments = prefix.segments.iter().chain(path.segments.iter()).cloned().collect();
@@ -586,7 +546,6 @@ fn lower_use_tree(
                         let res = this.lower_res(res);
                         let path = this.lower_path_extra(res, &path, ParamMode::Explicit);
                         let kind = hir::ItemKind::Use(path, hir::UseKind::Single);
-                        let vis = this.rebuild_vis(&vis);
                         if let Some(attrs) = attrs {
                             this.attrs.insert(hir::ItemLocalId::new(0), attrs);
                         }
@@ -595,7 +554,7 @@ fn lower_use_tree(
                             def_id: new_id,
                             ident: this.lower_ident(ident),
                             kind,
-                            vis,
+                            vis_span,
                             span: this.lower_span(span),
                         };
                         hir::OwnerNode::Item(this.arena.alloc(item))
@@ -657,11 +616,10 @@ fn lower_use_tree(
                     // own its own names, we have to adjust the owner before
                     // lowering the rest of the import.
                     self.with_hir_id_owner(id, |this| {
-                        let mut vis = this.rebuild_vis(&vis);
                         let mut ident = *ident;
 
                         let kind =
-                            this.lower_use_tree(use_tree, &prefix, id, &mut vis, &mut ident, attrs);
+                            this.lower_use_tree(use_tree, &prefix, id, vis_span, &mut ident, attrs);
                         if let Some(attrs) = attrs {
                             this.attrs.insert(hir::ItemLocalId::new(0), attrs);
                         }
@@ -670,37 +628,13 @@ fn lower_use_tree(
                             def_id: new_hir_id,
                             ident: this.lower_ident(ident),
                             kind,
-                            vis,
+                            vis_span,
                             span: this.lower_span(use_tree.span),
                         };
                         hir::OwnerNode::Item(this.arena.alloc(item))
                     });
                 }
 
-                // Subtle and a bit hacky: we lower the privacy level
-                // of the list stem to "private" most of the time, but
-                // not for "restricted" paths. The key thing is that
-                // we don't want it to stay as `pub` (with no caveats)
-                // because that affects rustdoc and also the lints
-                // about `pub` items. But we can't *always* make it
-                // private -- particularly not for restricted paths --
-                // because it contains node-ids that would then be
-                // unused, failing the check that HirIds are "densely
-                // assigned".
-                match vis.node {
-                    hir::VisibilityKind::Public
-                    | hir::VisibilityKind::Crate(_)
-                    | hir::VisibilityKind::Inherited => {
-                        *vis = respan(
-                            self.lower_span(prefix.span.shrink_to_lo()),
-                            hir::VisibilityKind::Inherited,
-                        );
-                    }
-                    hir::VisibilityKind::Restricted { .. } => {
-                        // Do nothing here, as described in the comment on the match.
-                    }
-                }
-
                 let res = self.expect_full_res_from_use(id).next().unwrap_or(Res::Err);
                 let res = self.lower_res(res);
                 let path = self.lower_path_extra(res, &prefix, ParamMode::Explicit);
@@ -709,37 +643,6 @@ fn lower_use_tree(
         }
     }
 
-    /// Paths like the visibility path in `pub(super) use foo::{bar, baz}` are repeated
-    /// many times in the HIR tree; for each occurrence, we need to assign distinct
-    /// `NodeId`s. (See, e.g., #56128.)
-    fn rebuild_use_path(&mut self, path: &hir::Path<'hir>) -> &'hir hir::Path<'hir> {
-        debug!("rebuild_use_path(path = {:?})", path);
-        let segments =
-            self.arena.alloc_from_iter(path.segments.iter().map(|seg| hir::PathSegment {
-                ident: seg.ident,
-                hir_id: seg.hir_id.map(|_| self.next_id()),
-                res: seg.res,
-                args: None,
-                infer_args: seg.infer_args,
-            }));
-        self.arena.alloc(hir::Path { span: path.span, res: path.res, segments })
-    }
-
-    fn rebuild_vis(&mut self, vis: &hir::Visibility<'hir>) -> hir::Visibility<'hir> {
-        let vis_kind = match vis.node {
-            hir::VisibilityKind::Public => hir::VisibilityKind::Public,
-            hir::VisibilityKind::Crate(sugar) => hir::VisibilityKind::Crate(sugar),
-            hir::VisibilityKind::Inherited => hir::VisibilityKind::Inherited,
-            hir::VisibilityKind::Restricted { ref path, hir_id: _ } => {
-                hir::VisibilityKind::Restricted {
-                    path: self.rebuild_use_path(path),
-                    hir_id: self.next_id(),
-                }
-            }
-        };
-        respan(self.lower_span(vis.span), vis_kind)
-    }
-
     fn lower_foreign_item(&mut self, i: &ForeignItem) -> &'hir hir::ForeignItem<'hir> {
         let hir_id = self.lower_node_id(i.id);
         let def_id = hir_id.expect_owner();
@@ -750,18 +653,14 @@ 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 (generics, (fn_dec, fn_args)) = self.add_in_band_defs(
-                        generics,
-                        def_id,
-                        AnonymousLifetimeMode::PassThrough,
-                        |this, _| {
+                    let (generics, (fn_dec, fn_args)) =
+                        self.add_implicit_generics(generics, i.id, |this, _, _| {
                             (
                                 // Disallow `impl Trait` in foreign items.
                                 this.lower_fn_decl(fdec, None, FnDeclKind::ExternFn, None),
                                 this.lower_fn_params_to_names(fdec),
                             )
-                        },
-                    );
+                        });
 
                     hir::ForeignItemKind::Fn(fn_dec, fn_args, generics)
                 }
@@ -773,7 +672,7 @@ fn lower_foreign_item(&mut self, i: &ForeignItem) -> &'hir hir::ForeignItem<'hir
                 ForeignItemKind::TyAlias(..) => hir::ForeignItemKind::Type,
                 ForeignItemKind::MacCall(_) => panic!("macro shouldn't exist here"),
             },
-            vis: self.lower_visibility(&i.vis),
+            vis_span: self.lower_span(i.vis.span),
             span: self.lower_span(i.span),
         };
         self.arena.alloc(item)
@@ -851,7 +750,7 @@ fn lower_field_def(&mut self, (index, f): (usize, &FieldDef)) -> hir::FieldDef<'
                 // FIXME(jseyfried): positional field hygiene.
                 None => Ident::new(sym::integer(index), self.lower_span(f.span)),
             },
-            vis: self.lower_visibility(&f.vis),
+            vis_span: self.lower_span(f.vis.span),
             ty,
         }
     }
@@ -868,13 +767,8 @@ fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> {
             }
             AssocItemKind::Fn(box Fn { ref sig, ref generics, body: None, .. }) => {
                 let names = self.lower_fn_params_to_names(&sig.decl);
-                let (generics, sig) = self.lower_method_sig(
-                    generics,
-                    sig,
-                    trait_item_def_id,
-                    FnDeclKind::Trait,
-                    None,
-                );
+                let (generics, sig) =
+                    self.lower_method_sig(generics, sig, i.id, FnDeclKind::Trait, None);
                 (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names)))
             }
             AssocItemKind::Fn(box Fn { ref sig, ref generics, body: Some(ref body), .. }) => {
@@ -884,7 +778,7 @@ fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> {
                 let (generics, sig) = self.lower_method_sig(
                     generics,
                     sig,
-                    trait_item_def_id,
+                    i.id,
                     FnDeclKind::Trait,
                     asyncness.opt_return_id(),
                 );
@@ -958,8 +852,6 @@ fn lower_trait_item_ref(&mut self, i: &AssocItem) -> hir::TraitItemRef {
     }
 
     fn lower_impl_item(&mut self, i: &AssocItem) -> &'hir hir::ImplItem<'hir> {
-        let impl_item_def_id = self.resolver.local_def_id(i.id);
-
         let (generics, kind) = match &i.kind {
             AssocItemKind::Const(_, ty, expr) => {
                 let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
@@ -976,7 +868,7 @@ fn lower_impl_item(&mut self, i: &AssocItem) -> &'hir hir::ImplItem<'hir> {
                 let (generics, sig) = self.lower_method_sig(
                     generics,
                     sig,
-                    impl_item_def_id,
+                    i.id,
                     if self.is_in_trait_impl { FnDeclKind::Impl } else { FnDeclKind::Inherent },
                     asyncness.opt_return_id(),
                 );
@@ -996,12 +888,7 @@ fn lower_impl_item(&mut self, i: &AssocItem) -> &'hir hir::ImplItem<'hir> {
                         hir::ImplItemKind::TyAlias(ty)
                     }
                     Some(ty) => {
-                        let ty = self.lower_ty(
-                            ty,
-                            ImplTraitContext::TypeAliasesOpaqueTy {
-                                capturable_lifetimes: &mut FxHashSet::default(),
-                            },
-                        );
+                        let ty = self.lower_ty(ty, ImplTraitContext::TypeAliasesOpaqueTy);
                         hir::ImplItemKind::TyAlias(ty)
                     }
                 };
@@ -1016,8 +903,8 @@ fn lower_impl_item(&mut self, i: &AssocItem) -> &'hir hir::ImplItem<'hir> {
             def_id: hir_id.expect_owner(),
             ident: self.lower_ident(i.ident),
             generics,
-            vis: self.lower_visibility(&i.vis),
             kind,
+            vis_span: self.lower_span(i.vis.span),
             span: self.lower_span(i.span),
         };
         self.arena.alloc(item)
@@ -1044,28 +931,6 @@ fn lower_impl_item_ref(&mut self, i: &AssocItem) -> hir::ImplItemRef {
         }
     }
 
-    /// If an `explicit_owner` is given, this method allocates the `HirId` in
-    /// the address space of that item instead of the item currently being
-    /// lowered. This can happen during `lower_impl_item_ref()` where we need to
-    /// lower a `Visibility` value although we haven't lowered the owning
-    /// `ImplItem` in question yet.
-    fn lower_visibility(&mut self, v: &Visibility) -> hir::Visibility<'hir> {
-        let node = match v.kind {
-            VisibilityKind::Public => hir::VisibilityKind::Public,
-            VisibilityKind::Crate(sugar) => hir::VisibilityKind::Crate(sugar),
-            VisibilityKind::Restricted { ref path, id } => {
-                debug!("lower_visibility: restricted path id = {:?}", id);
-                let lowered_id = self.lower_node_id(id);
-                hir::VisibilityKind::Restricted {
-                    path: self.lower_path(id, path, ParamMode::Explicit),
-                    hir_id: lowered_id,
-                }
-            }
-            VisibilityKind::Inherited => hir::VisibilityKind::Inherited,
-        };
-        respan(self.lower_span(v.span), node)
-    }
-
     fn lower_defaultness(
         &self,
         d: Defaultness,
@@ -1363,17 +1228,14 @@ fn lower_method_sig(
         &mut self,
         generics: &Generics,
         sig: &FnSig,
-        fn_def_id: LocalDefId,
+        id: NodeId,
         kind: FnDeclKind,
         is_async: Option<NodeId>,
-    ) -> (hir::Generics<'hir>, hir::FnSig<'hir>) {
+    ) -> (&'hir hir::Generics<'hir>, hir::FnSig<'hir>) {
         let header = self.lower_fn_header(sig.header);
-        let (generics, decl) = self.add_in_band_defs(
-            generics,
-            fn_def_id,
-            AnonymousLifetimeMode::PassThrough,
-            |this, idty| this.lower_fn_decl(&sig.decl, Some((fn_def_id, idty)), kind, is_async),
-        );
+        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)
+        });
         (generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) })
     }
 
@@ -1432,7 +1294,7 @@ pub(super) fn lower_unsafety(&mut self, u: Unsafe) -> hir::Unsafety {
     pub(super) fn lower_generics_mut(
         &mut self,
         generics: &Generics,
-        itctx: ImplTraitContext<'_, 'hir>,
+        mut itctx: ImplTraitContext<'_, 'hir>,
     ) -> GenericsCtor<'hir> {
         // 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
@@ -1481,9 +1343,24 @@ pub(super) fn lower_generics_mut(
             }
         }
 
+        let mut predicates = SmallVec::new();
+        predicates.extend(generics.params.iter().filter_map(|param| {
+            let bounds = self.lower_param_bounds(&param.bounds, itctx.reborrow());
+            self.lower_generic_bound_predicate(param.ident, param.id, &param.kind, bounds)
+        }));
+        predicates.extend(
+            generics
+                .where_clause
+                .predicates
+                .iter()
+                .map(|predicate| self.lower_where_predicate(predicate)),
+        );
+
         GenericsCtor {
-            params: self.lower_generic_params_mut(&generics.params, itctx).collect(),
-            where_clause: self.lower_where_clause(&generics.where_clause),
+            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),
         }
     }
@@ -1492,20 +1369,75 @@ pub(super) fn lower_generics(
         &mut self,
         generics: &Generics,
         itctx: ImplTraitContext<'_, 'hir>,
-    ) -> hir::Generics<'hir> {
+    ) -> &'hir hir::Generics<'hir> {
         let generics_ctor = self.lower_generics_mut(generics, itctx);
         generics_ctor.into_generics(self.arena)
     }
 
-    fn lower_where_clause(&mut self, wc: &WhereClause) -> hir::WhereClause<'hir> {
-        self.with_anonymous_lifetime_mode(AnonymousLifetimeMode::ReportError, |this| {
-            hir::WhereClause {
-                predicates: this.arena.alloc_from_iter(
-                    wc.predicates.iter().map(|predicate| this.lower_where_predicate(predicate)),
-                ),
-                span: this.lower_span(wc.span),
+    pub(super) fn lower_generic_bound_predicate(
+        &mut self,
+        ident: Ident,
+        id: NodeId,
+        kind: &GenericParamKind,
+        bounds: &'hir [hir::GenericBound<'hir>],
+    ) -> Option<hir::WherePredicate<'hir>> {
+        // Do not create a clause if we do not have anything inside it.
+        if bounds.is_empty() {
+            return None;
+        }
+        let ident = self.lower_ident(ident);
+        let param_span = ident.span;
+        let span = bounds
+            .iter()
+            .fold(Some(param_span.shrink_to_hi()), |span: Option<Span>, bound| {
+                let bound_span = bound.span();
+                // We include bounds that come from a `#[derive(_)]` but point at the user's code,
+                // as we use this method to get a span appropriate for suggestions.
+                if !bound_span.can_be_used_for_suggestions() {
+                    None
+                } else if let Some(span) = span {
+                    Some(span.to(bound_span))
+                } else {
+                    Some(bound_span)
+                }
+            })
+            .unwrap_or(param_span.shrink_to_hi());
+        match kind {
+            GenericParamKind::Const { .. } => None,
+            GenericParamKind::Type { .. } => {
+                let def_id = self.resolver.local_def_id(id).to_def_id();
+                let ty_path = self.arena.alloc(hir::Path {
+                    span: param_span,
+                    res: Res::Def(DefKind::TyParam, def_id),
+                    segments: self.arena.alloc_from_iter([hir::PathSegment::from_ident(ident)]),
+                });
+                let ty_id = self.next_id();
+                let bounded_ty =
+                    self.ty_path(ty_id, param_span, hir::QPath::Resolved(None, ty_path));
+                Some(hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
+                    bounded_ty: self.arena.alloc(bounded_ty),
+                    bounds,
+                    span,
+                    bound_generic_params: &[],
+                    in_where_clause: false,
+                }))
             }
-        })
+            GenericParamKind::Lifetime => {
+                let ident_span = self.lower_span(ident.span);
+                let ident = self.lower_ident(ident);
+                let res = self.resolver.get_lifetime_res(id).unwrap_or_else(|| {
+                    panic!("Missing resolution for lifetime {:?} at {:?}", id, ident.span)
+                });
+                let lt_id = self.resolver.next_node_id();
+                let lifetime = self.new_named_lifetime_with_res(lt_id, ident_span, ident, res);
+                Some(hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate {
+                    lifetime,
+                    span,
+                    bounds,
+                    in_where_clause: false,
+                }))
+            }
+        }
     }
 
     fn lower_where_predicate(&mut self, pred: &WherePredicate) -> hir::WherePredicate<'hir> {
@@ -1515,24 +1447,18 @@ fn lower_where_predicate(&mut self, pred: &WherePredicate) -> hir::WherePredicat
                 ref bounded_ty,
                 ref bounds,
                 span,
-            }) => self.with_in_scope_lifetime_defs(&bound_generic_params, |this| {
-                hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
-                    bound_generic_params: this.lower_generic_params(
-                        bound_generic_params,
-                        ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
-                    ),
-                    bounded_ty: this.lower_ty(
-                        bounded_ty,
-                        ImplTraitContext::Disallowed(ImplTraitPosition::Type),
-                    ),
-                    bounds: this.arena.alloc_from_iter(bounds.iter().map(|bound| {
-                        this.lower_param_bound(
-                            bound,
-                            ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
-                        )
-                    })),
-                    span: this.lower_span(span),
-                })
+            }) => hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
+                bound_generic_params: self.lower_generic_params(bound_generic_params),
+                bounded_ty: self
+                    .lower_ty(bounded_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)),
+                bounds: self.arena.alloc_from_iter(bounds.iter().map(|bound| {
+                    self.lower_param_bound(
+                        bound,
+                        ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
+                    )
+                })),
+                span: self.lower_span(span),
+                in_where_clause: true,
             }),
             WherePredicate::RegionPredicate(WhereRegionPredicate {
                 ref lifetime,
@@ -1545,6 +1471,7 @@ fn lower_where_predicate(&mut self, pred: &WherePredicate) -> hir::WherePredicat
                     bounds,
                     ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
                 ),
+                in_where_clause: true,
             }),
             WherePredicate::EqPredicate(WhereEqPredicate { id, ref lhs_ty, ref rhs_ty, span }) => {
                 hir::WherePredicate::EqPredicate(hir::WhereEqPredicate {
@@ -1563,16 +1490,20 @@ 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]>,
-    where_clause: hir::WhereClause<'hir>,
+    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::Generics<'hir> {
-        hir::Generics {
+    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),
-            where_clause: self.where_clause,
+            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 9cb205074e7eaf6b9a81413042c3127e991a14bd..d433775f85cf3eeae2670ae182b19c7b096bdf2a 100644 (file)
 
 #![feature(crate_visibility_modifier)]
 #![feature(box_patterns)]
+#![feature(let_chains)]
 #![feature(let_else)]
 #![feature(never_type)]
 #![recursion_limit = "256"]
 #![allow(rustc::potential_query_instability)]
 
-use rustc_ast::token::{self, Token};
+use rustc_ast::token::{Delimiter, Token};
 use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream, TokenTree};
 use rustc_ast::visit;
 use rustc_ast::{self as ast, *};
@@ -53,7 +54,6 @@
 use rustc_hir::def::{DefKind, Namespace, PartialRes, PerNS, Res};
 use rustc_hir::def_id::{DefId, DefPathHash, LocalDefId, CRATE_DEF_ID};
 use rustc_hir::definitions::{DefKey, DefPathData, Definitions};
-use rustc_hir::intravisit;
 use rustc_hir::{ConstArg, GenericArg, ItemLocalId, ParamName, TraitCandidate};
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_query_system::ich::StableHashingContext;
@@ -61,7 +61,7 @@
 use rustc_session::utils::{FlattenNonterminals, NtToTokenstream};
 use rustc_session::Session;
 use rustc_span::hygiene::{ExpnId, MacroKind};
-use rustc_span::source_map::{respan, DesugaringKind};
+use rustc_span::source_map::DesugaringKind;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
 
@@ -122,27 +122,8 @@ struct LoweringContext<'a, 'hir: 'a> {
     is_in_trait_impl: bool,
     is_in_dyn_type: bool,
 
-    /// What to do when we encounter an "anonymous lifetime
-    /// reference". The term "anonymous" is meant to encompass both
-    /// `'_` lifetimes as well as fully elided cases where nothing is
-    /// written at all (e.g., `&T` or `std::cell::Ref<T>`).
-    anonymous_lifetime_mode: AnonymousLifetimeMode,
-
-    /// Used to create lifetime definitions for anonymous lifetimes.
-    /// When an anonymous lifetime is encountered in a function or impl header and
-    /// requires to create a fresh lifetime parameter, it is added
-    /// to this list. The results of this list are then added to the list of
-    /// lifetime definitions in the corresponding impl or function generics.
-    lifetimes_to_define: Vec<(Span, NodeId)>,
-
-    /// If anonymous lifetimes are being collected, this field holds the parent
-    /// `LocalDefId` to create the fresh lifetime parameters' `LocalDefId`.
-    is_collecting_anonymous_lifetimes: Option<LocalDefId>,
-
-    /// Currently in-scope lifetimes defined in impl headers, fn headers, or HRTB.
-    /// We always store a `normalize_to_macros_2_0()` version of the param-name in this
-    /// vector.
-    in_scope_lifetimes: Vec<ParamName>,
+    /// Used to handle lifetimes appearing in impl-traits.
+    captured_lifetimes: Option<LifetimeCaptureContext>,
 
     current_hir_id_owner: LocalDefId,
     item_local_id_counter: hir::ItemLocalId,
@@ -157,6 +138,68 @@ struct LoweringContext<'a, 'hir: 'a> {
     allow_into_future: Option<Lrc<[Symbol]>>,
 }
 
+/// Resolution for a lifetime appearing in a type.
+#[derive(Copy, Clone, Debug)]
+pub enum LifetimeRes {
+    /// Successfully linked the lifetime to a generic parameter.
+    Param {
+        /// Id of the generic parameter that introduced it.
+        param: LocalDefId,
+        /// Id of the introducing place. That can be:
+        /// - an item's id, for the item's generic parameters;
+        /// - a TraitRef's ref_id, identifying the `for<...>` binder;
+        /// - a BareFn type's id;
+        /// - a Path's id when this path has parenthesized generic args.
+        ///
+        /// This information is used for impl-trait lifetime captures, to know when to or not to
+        /// capture any given lifetime.
+        binder: NodeId,
+    },
+    /// Created a generic parameter for an anonymous lifetime.
+    Fresh {
+        /// Id of the generic parameter that introduced it.
+        param: LocalDefId,
+        /// Id of the introducing place. See `Param`.
+        binder: NodeId,
+    },
+    /// This variant is used for anonymous lifetimes that we did not resolve during
+    /// late resolution.  Shifting the work to the HIR lifetime resolver.
+    Anonymous {
+        /// Id of the introducing place. See `Param`.
+        binder: NodeId,
+        /// Whether this lifetime was spelled or elided.
+        elided: bool,
+    },
+    /// Explicit `'static` lifetime.
+    Static,
+    /// Resolution failure.
+    Error,
+    /// HACK: This is used to recover the NodeId of an elided lifetime.
+    ElidedAnchor { start: NodeId, end: NodeId },
+}
+
+/// When we lower a lifetime, it is inserted in `captures`, and the resolution is modified so
+/// to point to the lifetime parameter impl-trait will generate.
+/// When traversing `for<...>` binders, they are inserted in `binders_to_ignore` so we know *not*
+/// to rebind the introduced lifetimes.
+#[derive(Debug)]
+struct LifetimeCaptureContext {
+    /// parent def_id for new definitions
+    parent_def_id: LocalDefId,
+    /// Set of lifetimes to rebind.
+    captures: FxHashMap<
+        LocalDefId, // original parameter id
+        (
+            Span,        // Span
+            NodeId,      // synthetized parameter id
+            ParamName,   // parameter name
+            LifetimeRes, // original resolution
+        ),
+    >,
+    /// Traversed binders.  The ids in this set should *not* be rebound.
+    binders_to_ignore: FxHashSet<NodeId>,
+}
+
 pub trait ResolverAstLowering {
     fn def_key(&self, id: DefId) -> DefKey;
 
@@ -175,6 +218,12 @@ pub trait ResolverAstLowering {
     /// Obtains resolution for a label with the given `NodeId`.
     fn get_label_res(&self, id: NodeId) -> Option<NodeId>;
 
+    /// Obtains resolution for a lifetime with the given `NodeId`.
+    fn get_lifetime_res(&self, id: NodeId) -> Option<LifetimeRes>;
+
+    /// Obtain the list of lifetimes parameters to add to an item.
+    fn take_extra_lifetime_params(&mut self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)>;
+
     fn create_stable_hashing_context(&self) -> StableHashingContext<'_>;
 
     fn definitions(&self) -> &Definitions;
@@ -210,36 +259,18 @@ enum ImplTraitContext<'b, 'a> {
     /// 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>>, LocalDefId),
+    Universal(&'b mut Vec<hir::GenericParam<'a>>, &'b mut Vec<hir::WherePredicate<'a>>, LocalDefId),
 
     /// Treat `impl Trait` as shorthand for a new opaque type.
     /// Example: `fn foo() -> impl Debug`, where `impl Debug` is conceptually
     /// equivalent to a new opaque type like `type T = impl Debug; fn foo() -> T`.
     ///
     ReturnPositionOpaqueTy {
-        /// `DefId` for the parent function, used to look up necessary
-        /// information later.
-        fn_def_id: LocalDefId,
         /// Origin: Either OpaqueTyOrigin::FnReturn or OpaqueTyOrigin::AsyncFn,
         origin: hir::OpaqueTyOrigin,
     },
     /// Impl trait in type aliases.
-    TypeAliasesOpaqueTy {
-        /// Set of lifetimes that this opaque type can capture, if it uses
-        /// them. This includes lifetimes bound since we entered this context.
-        /// For example:
-        ///
-        /// ```
-        /// type A<'b> = impl for<'a> Trait<'a, Out = impl Sized + 'a>;
-        /// ```
-        ///
-        /// Here the inner opaque type captures `'a` because it uses it. It doesn't
-        /// need to capture `'b` because it already inherits the lifetime
-        /// parameter from `A`.
-        // FIXME(impl_trait): but `required_region_bounds` will ICE later
-        // anyway.
-        capturable_lifetimes: &'b mut FxHashSet<hir::LifetimeName>,
-    },
+    TypeAliasesOpaqueTy,
     /// `impl Trait` is not accepted in this position.
     Disallowed(ImplTraitPosition),
 }
@@ -272,13 +303,9 @@ impl<'a> ImplTraitContext<'_, 'a> {
     fn reborrow<'this>(&'this mut self) -> ImplTraitContext<'this, 'a> {
         use self::ImplTraitContext::*;
         match self {
-            Universal(params, parent) => Universal(params, *parent),
-            ReturnPositionOpaqueTy { fn_def_id, origin } => {
-                ReturnPositionOpaqueTy { fn_def_id: *fn_def_id, origin: *origin }
-            }
-            TypeAliasesOpaqueTy { capturable_lifetimes } => {
-                TypeAliasesOpaqueTy { capturable_lifetimes }
-            }
+            Universal(params, bounds, parent) => Universal(params, bounds, *parent),
+            ReturnPositionOpaqueTy { origin } => ReturnPositionOpaqueTy { origin: *origin },
+            TypeAliasesOpaqueTy => TypeAliasesOpaqueTy,
             Disallowed(pos) => Disallowed(*pos),
         }
     }
@@ -453,56 +480,6 @@ enum ParenthesizedGenericArgs {
     Err,
 }
 
-/// What to do when we encounter an **anonymous** lifetime
-/// reference. Anonymous lifetime references come in two flavors. You
-/// have implicit, or fully elided, references to lifetimes, like the
-/// one in `&T` or `Ref<T>`, and you have `'_` lifetimes, like `&'_ T`
-/// or `Ref<'_, T>`. These often behave the same, but not always:
-///
-/// - certain usages of implicit references are deprecated, like
-///   `Ref<T>`, and we sometimes just give hard errors in those cases
-///   as well.
-/// - for object bounds there is a difference: `Box<dyn Foo>` is not
-///   the same as `Box<dyn Foo + '_>`.
-///
-/// We describe the effects of the various modes in terms of three cases:
-///
-/// - **Modern** -- includes all uses of `'_`, but also the lifetime arg
-///   of a `&` (e.g., the missing lifetime in something like `&T`)
-/// - **Dyn Bound** -- if you have something like `Box<dyn Foo>`,
-///   there is an elided lifetime bound (`Box<dyn Foo + 'X>`). These
-///   elided bounds follow special rules. Note that this only covers
-///   cases where *nothing* is written; the `'_` in `Box<dyn Foo +
-///   '_>` is a case of "modern" elision.
-/// - **Deprecated** -- this covers cases like `Ref<T>`, where the lifetime
-///   parameter to ref is completely elided. `Ref<'_, T>` would be the modern,
-///   non-deprecated equivalent.
-///
-/// Currently, the handling of lifetime elision is somewhat spread out
-/// between HIR lowering and -- as described below -- the
-/// `resolve_lifetime` module. Often we "fallthrough" to that code by generating
-/// an "elided" or "underscore" lifetime name. In the future, we probably want to move
-/// everything into HIR lowering.
-#[derive(Copy, Clone, Debug)]
-pub enum AnonymousLifetimeMode {
-    /// For **Modern** cases, create a new anonymous region parameter
-    /// and reference that.
-    ///
-    /// For **Dyn Bound** cases, pass responsibility to
-    /// `resolve_lifetime` code.
-    ///
-    /// For **Deprecated** cases, report an error.
-    CreateParameter,
-
-    /// Give a hard error when either `&` or `'_` is written. Used to
-    /// rule out things like `where T: Foo<'_>`. Does not imply an
-    /// error on default object bounds (e.g., `Box<dyn Foo>`).
-    ReportError,
-
-    /// Pass responsibility to `resolve_lifetime` code for all cases.
-    PassThrough,
-}
-
 impl<'a, 'hir> LoweringContext<'a, 'hir> {
     fn with_hir_id_owner(
         &mut self,
@@ -688,26 +665,6 @@ fn mark_span_with_reason(
         )
     }
 
-    fn with_anonymous_lifetime_mode<R>(
-        &mut self,
-        anonymous_lifetime_mode: AnonymousLifetimeMode,
-        op: impl FnOnce(&mut Self) -> R,
-    ) -> R {
-        debug!(
-            "with_anonymous_lifetime_mode(anonymous_lifetime_mode={:?})",
-            anonymous_lifetime_mode,
-        );
-        let old_anonymous_lifetime_mode = self.anonymous_lifetime_mode;
-        self.anonymous_lifetime_mode = anonymous_lifetime_mode;
-        let result = op(self);
-        self.anonymous_lifetime_mode = old_anonymous_lifetime_mode;
-        debug!(
-            "with_anonymous_lifetime_mode: restoring anonymous_lifetime_mode={:?}",
-            old_anonymous_lifetime_mode
-        );
-        result
-    }
-
     /// Intercept all spans entering HIR.
     /// Mark a span as relative to the current owning item.
     fn lower_span(&self, span: Span) -> Span {
@@ -723,140 +680,114 @@ fn lower_ident(&self, ident: Ident) -> Ident {
         Ident::new(ident.name, self.lower_span(ident.span))
     }
 
-    /// Creates a new `hir::GenericParam` for every new lifetime and
-    /// type parameter encountered while evaluating `f`. Definitions
-    /// are created with the parent provided. If no `parent_id` is
-    /// provided, no definitions will be returned.
-    ///
-    /// Presuming that in-band lifetimes are enabled, then
-    /// `self.anonymous_lifetime_mode` will be updated to match the
-    /// parameter while `f` is running (and restored afterwards).
-    fn collect_in_band_defs<T>(
-        &mut self,
-        parent_def_id: LocalDefId,
-        f: impl FnOnce(&mut Self) -> T,
-    ) -> (Vec<(Span, NodeId)>, T) {
-        let was_collecting =
-            std::mem::replace(&mut self.is_collecting_anonymous_lifetimes, Some(parent_def_id));
-        let len = self.lifetimes_to_define.len();
-
-        let res = f(self);
-
-        let lifetimes_to_define = self.lifetimes_to_define.split_off(len);
-        self.is_collecting_anonymous_lifetimes = was_collecting;
-        (lifetimes_to_define, res)
-    }
-
     /// Converts a lifetime into a new generic parameter.
-    fn fresh_lifetime_to_generic_param(
+    fn lifetime_res_to_generic_param(
         &mut self,
-        span: Span,
+        ident: Ident,
         node_id: NodeId,
-    ) -> hir::GenericParam<'hir> {
+        res: LifetimeRes,
+    ) -> Option<hir::GenericParam<'hir>> {
+        let (name, kind) = match res {
+            LifetimeRes::Param { .. } => {
+                (hir::ParamName::Plain(ident), hir::LifetimeParamKind::Explicit)
+            }
+            LifetimeRes::Fresh { param, .. } => {
+                (hir::ParamName::Fresh(param), hir::LifetimeParamKind::Elided)
+            }
+            LifetimeRes::Static | LifetimeRes::Error => return None,
+            res => panic!(
+                "Unexpected lifetime resolution {:?} for {:?} at {:?}",
+                res, ident, ident.span
+            ),
+        };
         let hir_id = self.lower_node_id(node_id);
-        let def_id = self.resolver.local_def_id(node_id);
-        hir::GenericParam {
+        Some(hir::GenericParam {
             hir_id,
-            name: hir::ParamName::Fresh(def_id),
-            bounds: &[],
-            span: self.lower_span(span),
+            name,
+            span: self.lower_span(ident.span),
             pure_wrt_drop: false,
-            kind: hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Elided },
-        }
+            kind: hir::GenericParamKind::Lifetime { kind },
+            colon_span: None,
+        })
     }
 
-    /// When we have either an elided or `'_` lifetime in an impl
-    /// header, we convert it to an in-band lifetime.
-    fn collect_fresh_anonymous_lifetime(&mut self, span: Span) -> ParamName {
-        let Some(parent_def_id) = self.is_collecting_anonymous_lifetimes else { panic!() };
-
-        let node_id = self.resolver.next_node_id();
+    /// 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);
 
-        // Add a definition for the in-band lifetime def.
-        let param_def_id = self.resolver.create_def(
-            parent_def_id,
-            node_id,
-            DefPathData::LifetimeNs(kw::UnderscoreLifetime),
-            ExpnId::root(),
-            span.with_parent(None),
+        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 hir_name = ParamName::Fresh(param_def_id);
-        self.lifetimes_to_define.push((span, node_id));
-        hir_name
+        let lowered_generics = lowered_generics.into_generics(self.arena);
+        (lowered_generics, res)
     }
 
-    // Evaluates `f` with the lifetimes in `params` in-scope.
-    // This is used to track which lifetimes have already been defined, and
-    // which are new in-band lifetimes that need to have a definition created
-    // for them.
-    fn with_in_scope_lifetime_defs<T>(
+    /// Setup lifetime capture for and impl-trait.
+    /// The captures will be added to `captures`.
+    fn while_capturing_lifetimes<T>(
         &mut self,
-        params: &[GenericParam],
+        parent_def_id: LocalDefId,
+        captures: &mut FxHashMap<LocalDefId, (Span, NodeId, ParamName, LifetimeRes)>,
         f: impl FnOnce(&mut Self) -> T,
     ) -> T {
-        let old_len = self.in_scope_lifetimes.len();
-        let lt_def_names = params.iter().filter_map(|param| match param.kind {
-            GenericParamKind::Lifetime { .. } => {
-                Some(ParamName::Plain(param.ident.normalize_to_macros_2_0()))
-            }
-            _ => None,
-        });
-        self.in_scope_lifetimes.extend(lt_def_names);
-
-        let res = f(self);
+        let lifetime_stash = std::mem::replace(
+            &mut self.captured_lifetimes,
+            Some(LifetimeCaptureContext {
+                parent_def_id,
+                captures: std::mem::take(captures),
+                binders_to_ignore: Default::default(),
+            }),
+        );
 
-        self.in_scope_lifetimes.truncate(old_len);
-        res
-    }
+        let ret = f(self);
 
-    /// Appends in-band lifetime defs and argument-position `impl
-    /// Trait` defs to the existing set of generics.
-    ///
-    /// Presuming that in-band lifetimes are enabled, then
-    /// `self.anonymous_lifetime_mode` will be updated to match the
-    /// parameter while `f` is running (and restored afterwards).
-    fn add_in_band_defs<T>(
-        &mut self,
-        generics: &Generics,
-        parent_def_id: LocalDefId,
-        anonymous_lifetime_mode: AnonymousLifetimeMode,
-        f: impl FnOnce(&mut Self, &mut Vec<hir::GenericParam<'hir>>) -> T,
-    ) -> (hir::Generics<'hir>, T) {
-        let (lifetimes_to_define, (mut lowered_generics, impl_trait_defs, res)) = self
-            .collect_in_band_defs(parent_def_id, |this| {
-                this.with_anonymous_lifetime_mode(anonymous_lifetime_mode, |this| {
-                    this.with_in_scope_lifetime_defs(&generics.params, |this| {
-                        let mut impl_trait_defs = Vec::new();
-                        // Note: it is necessary to lower generics *before* calling `f`.
-                        // When lowering `async fn`, there's a final step when lowering
-                        // the return type that assumes that all in-scope lifetimes have
-                        // already been added to either `in_scope_lifetimes` or
-                        // `lifetimes_to_define`. If we swapped the order of these two,
-                        // in-band-lifetimes introduced by generics or where-clauses
-                        // wouldn't have been added yet.
-                        let generics = this.lower_generics_mut(
-                            generics,
-                            ImplTraitContext::Universal(
-                                &mut impl_trait_defs,
-                                this.current_hir_id_owner,
-                            ),
-                        );
-                        let res = f(this, &mut impl_trait_defs);
-                        (generics, impl_trait_defs, res)
-                    })
-                })
-            });
+        let ctxt = std::mem::replace(&mut self.captured_lifetimes, lifetime_stash).unwrap();
+        *captures = ctxt.captures;
 
-        lowered_generics.params.extend(
-            lifetimes_to_define
-                .into_iter()
-                .map(|(span, node_id)| self.fresh_lifetime_to_generic_param(span, node_id))
-                .chain(impl_trait_defs),
-        );
+        ret
+    }
 
-        let lowered_generics = lowered_generics.into_generics(self.arena);
-        (lowered_generics, res)
+    /// Register a binder to be ignored for lifetime capture.
+    #[tracing::instrument(level = "debug", skip(self, f))]
+    #[inline]
+    fn with_lifetime_binder<T>(&mut self, binder: NodeId, f: impl FnOnce(&mut Self) -> T) -> T {
+        if let Some(ctxt) = &mut self.captured_lifetimes {
+            ctxt.binders_to_ignore.insert(binder);
+        }
+        let ret = f(self);
+        if let Some(ctxt) = &mut self.captured_lifetimes {
+            ctxt.binders_to_ignore.remove(&binder);
+        }
+        ret
     }
 
     fn with_dyn_type_scope<T>(&mut self, in_scope: bool, f: impl FnOnce(&mut Self) -> T) -> T {
@@ -965,7 +896,7 @@ fn unwrap_single_token(sess: &Session, tokens: TokenStream, span: Span) -> Token
                     match tokens.into_trees().next() {
                         Some(TokenTree::Token(token)) => token,
                         Some(TokenTree::Delimited(_, delim, tokens)) => {
-                            if delim != token::NoDelim {
+                            if delim != Delimiter::Invisible {
                                 sess.diagnostic().delay_span_bug(
                                     span,
                                     "unexpected delimiter in key-value attribute's value",
@@ -1058,7 +989,6 @@ fn lower_assoc_ty_constraint(
                 hir::TypeBindingKind::Equality { term }
             }
             AssocConstraintKind::Bound { ref bounds } => {
-                let mut capturable_lifetimes;
                 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 {
@@ -1079,7 +1009,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 => {
+                    ImplTraitContext::Universal(_, _, parent) if self.is_in_dyn_type => {
                         parent_def_id = parent;
                         (true, itctx)
                     }
@@ -1091,13 +1021,7 @@ fn lower_assoc_ty_constraint(
                     //
                     // FIXME: this is only needed until `impl Trait` is allowed in type aliases.
                     ImplTraitContext::Disallowed(_) if self.is_in_dyn_type => {
-                        capturable_lifetimes = FxHashSet::default();
-                        (
-                            true,
-                            ImplTraitContext::TypeAliasesOpaqueTy {
-                                capturable_lifetimes: &mut capturable_lifetimes,
-                            },
-                        )
+                        (true, ImplTraitContext::TypeAliasesOpaqueTy)
                     }
 
                     // We are in the parameter position, but not within a dyn type:
@@ -1258,26 +1182,28 @@ fn lower_ty_direct(&mut self, t: &Ty, mut itctx: ImplTraitContext<'_, 'hir>) ->
             TyKind::Slice(ref ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)),
             TyKind::Ptr(ref mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)),
             TyKind::Rptr(ref region, ref mt) => {
-                let span = self.sess.source_map().next_point(t.span.shrink_to_lo());
-                let lifetime = match *region {
-                    Some(ref lt) => self.lower_lifetime(lt),
-                    None => self.elided_ref_lifetime(span),
-                };
+                let region = region.unwrap_or_else(|| {
+                    let Some(LifetimeRes::ElidedAnchor { start, end }) = self.resolver.get_lifetime_res(t.id) else {
+                        panic!()
+                    };
+                    debug_assert_eq!(start.plus(1), end);
+                    let span = self.sess.source_map().next_point(t.span.shrink_to_lo());
+                    Lifetime {
+                        ident: Ident::new(kw::UnderscoreLifetime, span),
+                        id: start,
+                    }
+                });
+                let lifetime = self.lower_lifetime(&region);
                 hir::TyKind::Rptr(lifetime, self.lower_mt(mt, itctx))
             }
-            TyKind::BareFn(ref f) => self.with_in_scope_lifetime_defs(&f.generic_params, |this| {
-                this.with_anonymous_lifetime_mode(AnonymousLifetimeMode::PassThrough, |this| {
-                    hir::TyKind::BareFn(this.arena.alloc(hir::BareFnTy {
-                        generic_params: this.lower_generic_params(
-                            &f.generic_params,
-                            ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
-                        ),
-                        unsafety: this.lower_unsafety(f.unsafety),
-                        abi: this.lower_extern(f.ext),
-                        decl: this.lower_fn_decl(&f.decl, None, FnDeclKind::Pointer, None),
-                        param_names: this.lower_fn_params_to_names(&f.decl),
-                    }))
-                })
+            TyKind::BareFn(ref f) => self.with_lifetime_binder(t.id, |this| {
+                hir::TyKind::BareFn(this.arena.alloc(hir::BareFnTy {
+                    generic_params: this.lower_generic_params(&f.generic_params),
+                    unsafety: this.lower_unsafety(f.unsafety),
+                    abi: this.lower_extern(f.ext),
+                    decl: this.lower_fn_decl(&f.decl, None, FnDeclKind::Pointer, None),
+                    param_names: this.lower_fn_params_to_names(&f.decl),
+                }))
             }),
             TyKind::Never => hir::TyKind::Never,
             TyKind::Tup(ref tys) => {
@@ -1342,38 +1268,34 @@ fn lower_ty_direct(&mut self, t: &Ty, mut itctx: ImplTraitContext<'_, 'hir>) ->
             TyKind::ImplTrait(def_node_id, ref bounds) => {
                 let span = t.span;
                 match itctx {
-                    ImplTraitContext::ReturnPositionOpaqueTy { fn_def_id, origin } => self
-                        .lower_opaque_impl_trait(
-                            span,
-                            Some(fn_def_id),
-                            origin,
-                            def_node_id,
-                            None,
-                            |this| this.lower_param_bounds(bounds, itctx),
-                        ),
-                    ImplTraitContext::TypeAliasesOpaqueTy { ref capturable_lifetimes } => {
-                        // Reset capturable lifetimes, any nested impl trait
-                        // types will inherit lifetimes from this opaque type,
-                        // so don't need to capture them again.
-                        let nested_itctx = ImplTraitContext::TypeAliasesOpaqueTy {
-                            capturable_lifetimes: &mut FxHashSet::default(),
-                        };
+                    ImplTraitContext::ReturnPositionOpaqueTy { origin } => self
+                        .lower_opaque_impl_trait(span, origin, def_node_id, |this| {
+                            this.lower_param_bounds(bounds, itctx)
+                        }),
+                    ImplTraitContext::TypeAliasesOpaqueTy => {
+                        let nested_itctx = ImplTraitContext::TypeAliasesOpaqueTy;
                         self.lower_opaque_impl_trait(
                             span,
-                            None,
                             hir::OpaqueTyOrigin::TyAlias,
                             def_node_id,
-                            Some(capturable_lifetimes),
                             |this| this.lower_param_bounds(bounds, nested_itctx),
                         )
                     }
-                    ImplTraitContext::Universal(in_band_ty_params, parent_def_id) => {
+                    ImplTraitContext::Universal(
+                        in_band_ty_params,
+                        in_band_ty_bounds,
+                        parent_def_id,
+                    ) => {
                         // 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, parent_def_id),
+                            ImplTraitContext::Universal(
+                                in_band_ty_params,
+                                in_band_ty_bounds,
+                                parent_def_id,
+                            ),
                         );
                         // Set the name to `impl Bound1 + Bound2`.
                         let ident = Ident::from_str_and_span(&pprust::ty_to_string(t), span);
@@ -1381,10 +1303,18 @@ fn lower_ty_direct(&mut self, t: &Ty, mut itctx: ImplTraitContext<'_, 'hir>) ->
                             hir_id: self.lower_node_id(def_node_id),
                             name: ParamName::Plain(self.lower_ident(ident)),
                             pure_wrt_drop: false,
-                            bounds: hir_bounds,
                             span: self.lower_span(span),
                             kind: hir::GenericParamKind::Type { default: None, synthetic: true },
+                            colon_span: None,
                         });
+                        if let Some(preds) = self.lower_generic_bound_predicate(
+                            ident,
+                            def_node_id,
+                            &GenericParamKind::Type { default: None },
+                            hir_bounds,
+                        ) {
+                            in_band_ty_bounds.push(preds)
+                        }
 
                         hir::TyKind::Path(hir::QPath::Resolved(
                             None,
@@ -1421,20 +1351,14 @@ fn lower_ty_direct(&mut self, t: &Ty, mut itctx: ImplTraitContext<'_, 'hir>) ->
         hir::Ty { kind, span: self.lower_span(t.span), hir_id: self.lower_node_id(t.id) }
     }
 
+    #[tracing::instrument(level = "debug", skip(self, lower_bounds))]
     fn lower_opaque_impl_trait(
         &mut self,
         span: Span,
-        fn_def_id: Option<LocalDefId>,
         origin: hir::OpaqueTyOrigin,
         opaque_ty_node_id: NodeId,
-        capturable_lifetimes: Option<&FxHashSet<hir::LifetimeName>>,
         lower_bounds: impl FnOnce(&mut Self) -> hir::GenericBounds<'hir>,
     ) -> hir::TyKind<'hir> {
-        debug!(
-            "lower_opaque_impl_trait(fn_def_id={:?}, opaque_ty_node_id={:?}, span={:?})",
-            fn_def_id, opaque_ty_node_id, span,
-        );
-
         // Make sure we know that some funky desugaring has been going on here.
         // This is a first: there is code in other places like for loop
         // desugaring that explicitly states that we don't want to track that.
@@ -1444,57 +1368,51 @@ fn lower_opaque_impl_trait(
 
         let opaque_ty_def_id = self.resolver.local_def_id(opaque_ty_node_id);
 
-        let mut collected_lifetimes = Vec::new();
+        let mut collected_lifetimes = FxHashMap::default();
         self.with_hir_id_owner(opaque_ty_node_id, |lctx| {
-            let hir_bounds = lower_bounds(lctx);
+            let hir_bounds = if origin == hir::OpaqueTyOrigin::TyAlias {
+                lower_bounds(lctx)
+            } else {
+                lctx.while_capturing_lifetimes(
+                    opaque_ty_def_id,
+                    &mut collected_lifetimes,
+                    lower_bounds,
+                )
+            };
+            debug!(?collected_lifetimes);
 
-            collected_lifetimes = lifetimes_from_impl_trait_bounds(
-                opaque_ty_node_id,
-                &hir_bounds,
-                capturable_lifetimes,
-            );
+            let lifetime_defs = lctx.arena.alloc_from_iter(collected_lifetimes.iter().map(
+                |(_, &(span, p_id, p_name, _))| {
+                    let hir_id = lctx.lower_node_id(p_id);
+                    debug_assert_ne!(lctx.resolver.opt_local_def_id(p_id), None);
 
-            let lifetime_defs =
-                lctx.arena.alloc_from_iter(collected_lifetimes.iter().map(|&(name, span)| {
-                    let def_node_id = lctx.resolver.next_node_id();
-                    lctx.resolver.create_def(
-                        opaque_ty_def_id,
-                        def_node_id,
-                        DefPathData::LifetimeNs(name.ident().name),
-                        ExpnId::root(),
-                        span.with_parent(None),
-                    );
-                    let hir_id = lctx.lower_node_id(def_node_id);
-
-                    let (name, kind) = match name {
-                        hir::LifetimeName::Underscore => (
-                            hir::ParamName::Plain(Ident::with_dummy_span(kw::UnderscoreLifetime)),
-                            hir::LifetimeParamKind::Elided,
-                        ),
-                        hir::LifetimeName::Param(param_name) => {
-                            (param_name, hir::LifetimeParamKind::Explicit)
-                        }
-                        _ => panic!("expected `LifetimeName::Param` or `ParamName::Plain`"),
+                    let kind = if p_name.ident().name == kw::UnderscoreLifetime {
+                        hir::LifetimeParamKind::Elided
+                    } else {
+                        hir::LifetimeParamKind::Explicit
                     };
 
                     hir::GenericParam {
                         hir_id,
-                        name,
+                        name: p_name,
                         span,
                         pure_wrt_drop: false,
-                        bounds: &[],
                         kind: hir::GenericParamKind::Lifetime { kind },
+                        colon_span: None,
                     }
-                }));
+                },
+            ));
 
             debug!("lower_opaque_impl_trait: lifetime_defs={:#?}", lifetime_defs);
 
             let opaque_ty_item = hir::OpaqueTy {
-                generics: hir::Generics {
+                generics: self.arena.alloc(hir::Generics {
                     params: lifetime_defs,
-                    where_clause: hir::WhereClause { predicates: &[], span: lctx.lower_span(span) },
+                    predicates: &[],
+                    has_where_clause: false,
+                    where_clause_span: lctx.lower_span(span),
                     span: lctx.lower_span(span),
-                },
+                }),
                 bounds: hir_bounds,
                 origin,
             };
@@ -1503,10 +1421,14 @@ fn lower_opaque_impl_trait(
             lctx.generate_opaque_type(opaque_ty_def_id, opaque_ty_item, span, opaque_ty_span)
         });
 
-        let lifetimes =
-            self.arena.alloc_from_iter(collected_lifetimes.into_iter().map(|(name, span)| {
-                hir::GenericArg::Lifetime(hir::Lifetime { hir_id: self.next_id(), span, name })
-            }));
+        let lifetimes = self.arena.alloc_from_iter(collected_lifetimes.into_iter().map(
+            |(_, (span, _, p_name, res))| {
+                let id = self.resolver.next_node_id();
+                let ident = Ident::new(p_name.ident().name, span);
+                let l = self.new_named_lifetime_with_res(id, span, ident, res);
+                hir::GenericArg::Lifetime(l)
+            },
+        ));
 
         debug!("lower_opaque_impl_trait: lifetimes={:#?}", lifetimes);
 
@@ -1530,7 +1452,7 @@ fn generate_opaque_type(
             def_id: opaque_ty_id,
             ident: Ident::empty(),
             kind: opaque_ty_item_kind,
-            vis: respan(self.lower_span(span.shrink_to_lo()), hir::VisibilityKind::Inherited),
+            vis_span: self.lower_span(span.shrink_to_lo()),
             span: self.lower_span(opaque_ty_span),
         };
         hir::OwnerNode::Item(self.arena.alloc(opaque_ty_item))
@@ -1565,7 +1487,11 @@ fn lower_fn_params_to_names(&mut self, decl: &FnDecl) -> &'hir [Ident] {
     fn lower_fn_decl(
         &mut self,
         decl: &FnDecl,
-        mut in_band_ty_params: Option<(LocalDefId, &mut Vec<hir::GenericParam<'hir>>)>,
+        mut in_band_ty_params: Option<(
+            NodeId,
+            &mut Vec<hir::GenericParam<'hir>>,
+            &mut Vec<hir::WherePredicate<'hir>>,
+        )>,
         kind: FnDeclKind,
         make_ret_async: Option<NodeId>,
     ) -> &'hir hir::FnDecl<'hir> {
@@ -1577,50 +1503,38 @@ fn lower_fn_decl(
             make_ret_async: {:?})",
             decl, in_band_ty_params, kind, make_ret_async,
         );
-        let lt_mode = if make_ret_async.is_some() {
-            // In `async fn`, argument-position elided lifetimes
-            // must be transformed into fresh generic parameters so that
-            // they can be applied to the opaque `impl Trait` return type.
-            AnonymousLifetimeMode::CreateParameter
-        } else {
-            self.anonymous_lifetime_mode
-        };
 
         let c_variadic = decl.c_variadic();
 
-        // Remember how many lifetimes were already around so that we can
-        // only look at the lifetime parameters introduced by the arguments.
-        let inputs = self.with_anonymous_lifetime_mode(lt_mode, |this| {
-            // Skip the `...` (`CVarArgs`) trailing arguments from the AST,
-            // as they are not explicit in HIR/Ty function signatures.
-            // (instead, the `c_variadic` flag is set to `true`)
-            let mut inputs = &decl.inputs[..];
-            if c_variadic {
-                inputs = &inputs[..inputs.len() - 1];
+        // Skip the `...` (`CVarArgs`) trailing arguments from the AST,
+        // as they are not explicit in HIR/Ty function signatures.
+        // (instead, the `c_variadic` flag is set to `true`)
+        let mut inputs = &decl.inputs[..];
+        if c_variadic {
+            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),
+                )
+            } else {
+                self.lower_ty_direct(
+                    &param.ty,
+                    ImplTraitContext::Disallowed(match kind {
+                        FnDeclKind::Fn | FnDeclKind::Inherent => {
+                            unreachable!("fn should allow in-band lifetimes")
+                        }
+                        FnDeclKind::ExternFn => ImplTraitPosition::ExternFnParam,
+                        FnDeclKind::Closure => ImplTraitPosition::ClosureParam,
+                        FnDeclKind::Pointer => ImplTraitPosition::PointerParam,
+                        FnDeclKind::Trait => ImplTraitPosition::TraitParam,
+                        FnDeclKind::Impl => ImplTraitPosition::ImplParam,
+                    }),
+                )
             }
-            this.arena.alloc_from_iter(inputs.iter().map(|param| {
-                if let Some((_, ibty)) = &mut in_band_ty_params {
-                    this.lower_ty_direct(
-                        &param.ty,
-                        ImplTraitContext::Universal(ibty, this.current_hir_id_owner),
-                    )
-                } else {
-                    this.lower_ty_direct(
-                        &param.ty,
-                        ImplTraitContext::Disallowed(match kind {
-                            FnDeclKind::Fn | FnDeclKind::Inherent => {
-                                unreachable!("fn should allow in-band lifetimes")
-                            }
-                            FnDeclKind::ExternFn => ImplTraitPosition::ExternFnParam,
-                            FnDeclKind::Closure => ImplTraitPosition::ClosureParam,
-                            FnDeclKind::Pointer => ImplTraitPosition::PointerParam,
-                            FnDeclKind::Trait => ImplTraitPosition::TraitParam,
-                            FnDeclKind::Impl => ImplTraitPosition::ImplParam,
-                        }),
-                    )
-                }
-            }))
-        });
+        }));
 
         let output = if let Some(ret_id) = make_ret_async {
             self.lower_async_fn_ret_ty(
@@ -1632,10 +1546,10 @@ fn lower_fn_decl(
             match decl.output {
                 FnRetTy::Ty(ref ty) => {
                     let context = match in_band_ty_params {
-                        Some((def_id, _)) if kind.impl_trait_return_allowed() => {
+                        Some((node_id, _, _)) if kind.impl_trait_return_allowed() => {
+                            let fn_def_id = self.resolver.local_def_id(node_id);
                             ImplTraitContext::ReturnPositionOpaqueTy {
-                                fn_def_id: def_id,
-                                origin: hir::OpaqueTyOrigin::FnReturn(def_id),
+                                origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
                             }
                         }
                         _ => ImplTraitContext::Disallowed(match kind {
@@ -1696,25 +1610,19 @@ fn lower_fn_decl(
     // `fn_def_id`: `DefId` of the parent function (used to create child impl trait definition)
     // `opaque_ty_node_id`: `NodeId` of the opaque `impl Trait` type that should be created
     // `elided_lt_replacement`: replacement for elided lifetimes in the return type
+    #[tracing::instrument(level = "debug", skip(self))]
     fn lower_async_fn_ret_ty(
         &mut self,
         output: &FnRetTy,
-        fn_def_id: LocalDefId,
+        fn_node_id: NodeId,
         opaque_ty_node_id: NodeId,
     ) -> hir::FnRetTy<'hir> {
-        debug!(
-            "lower_async_fn_ret_ty(\
-             output={:?}, \
-             fn_def_id={:?}, \
-             opaque_ty_node_id={:?})",
-            output, fn_def_id, opaque_ty_node_id,
-        );
-
         let span = output.span();
 
         let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::Async, span, None);
 
         let opaque_ty_def_id = self.resolver.local_def_id(opaque_ty_node_id);
+        let fn_def_id = self.resolver.local_def_id(fn_node_id);
 
         // When we create the opaque type for this async fn, it is going to have
         // to capture all the lifetimes involved in the signature (including in the
@@ -1754,100 +1662,95 @@ fn lower_async_fn_ret_ty(
         // should be figured out using the ordinary elision rules, and
         // this desugaring achieves that.
 
-        debug!("lower_async_fn_ret_ty: in_scope_lifetimes={:#?}", self.in_scope_lifetimes);
-        debug!("lower_async_fn_ret_ty: lifetimes_to_define={:#?}", self.lifetimes_to_define);
-
         // Calculate all the lifetimes that should be captured
         // by the opaque type. This should include all in-scope
         // lifetime parameters, including those defined in-band.
-        //
-        // `lifetime_params` is a vector of tuple (span, parameter name, lifetime name).
-
-        // Input lifetime like `'a` or `'1`:
-        let mut lifetime_params: Vec<_> = self
-            .in_scope_lifetimes
-            .iter()
-            .cloned()
-            .map(|name| (name.ident().span, hir::LifetimeName::Param(name)))
-            .chain(self.lifetimes_to_define.iter().map(|&(span, node_id)| {
-                let def_id = self.resolver.local_def_id(node_id);
-                let name = hir::ParamName::Fresh(def_id);
-                (span, hir::LifetimeName::Param(name))
-            }))
-            .collect();
+
+        let mut captures = FxHashMap::default();
+
+        let extra_lifetime_params = self.resolver.take_extra_lifetime_params(opaque_ty_node_id);
+        debug!(?extra_lifetime_params);
+        for (ident, outer_node_id, outer_res) in extra_lifetime_params {
+            let Ident { name, span } = ident;
+            let outer_def_id = self.resolver.local_def_id(outer_node_id);
+            let inner_node_id = self.resolver.next_node_id();
+
+            // Add a definition for the in scope lifetime def.
+            self.resolver.create_def(
+                opaque_ty_def_id,
+                inner_node_id,
+                DefPathData::LifetimeNs(name),
+                ExpnId::root(),
+                span.with_parent(None),
+            );
+
+            let (p_name, inner_res) = match outer_res {
+                // Input lifetime like `'a`:
+                LifetimeRes::Param { param, .. } => {
+                    (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::Static | LifetimeRes::Error => continue,
+                res => {
+                    panic!("Unexpected lifetime resolution {:?} for {:?} at {:?}", res, ident, span)
+                }
+            };
+
+            captures.insert(outer_def_id, (span, inner_node_id, p_name, inner_res));
+        }
+
+        debug!(?captures);
 
         self.with_hir_id_owner(opaque_ty_node_id, |this| {
-            let mut generic_params: Vec<_> = lifetime_params
-                .iter()
-                .map(|&(span, name)| {
-                    // We can only get lifetime names from the outside.
-                    let hir::LifetimeName::Param(hir_name) = name else { panic!() };
-
-                    let node_id = this.resolver.next_node_id();
-
-                    // Add a definition for the in-band lifetime def.
-                    let def_id = this.resolver.create_def(
-                        opaque_ty_def_id,
-                        node_id,
-                        DefPathData::LifetimeNs(hir_name.ident().name),
-                        ExpnId::root(),
-                        span.with_parent(None),
-                    );
+            let future_bound =
+                this.while_capturing_lifetimes(opaque_ty_def_id, &mut captures, |this| {
+                    // We have to be careful to get elision right here. The
+                    // idea is that we create a lifetime parameter for each
+                    // lifetime in the return type.  So, given a return type
+                    // like `async fn foo(..) -> &[&u32]`, we lower to `impl
+                    // Future<Output = &'1 [ &'2 u32 ]>`.
+                    //
+                    // Then, we will create `fn foo(..) -> Foo<'_, '_>`, and
+                    // hence the elision takes place at the fn site.
+                    this.lower_async_fn_output_type_to_future_bound(output, fn_def_id, span)
+                });
+            debug!("lower_async_fn_ret_ty: future_bound={:#?}", future_bound);
+            debug!("lower_async_fn_ret_ty: captures={:#?}", captures);
 
-                    let (kind, name) = match hir_name {
-                        ParamName::Plain(ident) => {
-                            (hir::LifetimeParamKind::Explicit, hir::ParamName::Plain(ident))
-                        }
-                        ParamName::Fresh(_) => {
-                            (hir::LifetimeParamKind::Elided, hir::ParamName::Fresh(def_id))
-                        }
-                        ParamName::Error => (hir::LifetimeParamKind::Error, hir::ParamName::Error),
+            let generic_params =
+                this.arena.alloc_from_iter(captures.iter().map(|(_, &(span, p_id, p_name, _))| {
+                    let hir_id = this.lower_node_id(p_id);
+                    debug_assert_ne!(this.resolver.opt_local_def_id(p_id), None);
+
+                    let kind = if p_name.ident().name == kw::UnderscoreLifetime {
+                        hir::LifetimeParamKind::Elided
+                    } else {
+                        hir::LifetimeParamKind::Explicit
                     };
 
                     hir::GenericParam {
-                        hir_id: this.lower_node_id(node_id),
-                        name,
-                        bounds: &[],
-                        span: this.lower_span(span),
+                        hir_id,
+                        name: p_name,
+                        span,
                         pure_wrt_drop: false,
                         kind: hir::GenericParamKind::Lifetime { kind },
+                        colon_span: None,
                     }
-                })
-                .collect();
-
-            // We have to be careful to get elision right here. The
-            // idea is that we create a lifetime parameter for each
-            // lifetime in the return type.  So, given a return type
-            // like `async fn foo(..) -> &[&u32]`, we lower to `impl
-            // Future<Output = &'1 [ &'2 u32 ]>`.
-            //
-            // Then, we will create `fn foo(..) -> Foo<'_, '_>`, and
-            // hence the elision takes place at the fn site.
-            let (lifetimes_to_define, future_bound) =
-                this.with_anonymous_lifetime_mode(AnonymousLifetimeMode::CreateParameter, |this| {
-                    this.collect_in_band_defs(opaque_ty_def_id, |this| {
-                        this.lower_async_fn_output_type_to_future_bound(output, fn_def_id, span)
-                    })
-                });
-            debug!("lower_async_fn_ret_ty: future_bound={:#?}", future_bound);
-            debug!("lower_async_fn_ret_ty: lifetimes_to_define={:#?}", lifetimes_to_define);
-
-            // Output lifetime like `'_`:
-            for (span, node_id) in lifetimes_to_define {
-                let param = this.fresh_lifetime_to_generic_param(span, node_id);
-                lifetime_params.push((span, hir::LifetimeName::Implicit));
-                generic_params.push(param);
-            }
-            let generic_params = this.arena.alloc_from_iter(generic_params);
-            debug!("lower_async_fn_ret_ty: lifetime_params={:#?}", lifetime_params);
+                }));
             debug!("lower_async_fn_ret_ty: generic_params={:#?}", generic_params);
 
             let opaque_ty_item = hir::OpaqueTy {
-                generics: hir::Generics {
+                generics: this.arena.alloc(hir::Generics {
                     params: generic_params,
-                    where_clause: hir::WhereClause { predicates: &[], span: this.lower_span(span) },
+                    predicates: &[],
+                    has_where_clause: false,
+                    where_clause_span: this.lower_span(span),
                     span: this.lower_span(span),
-                },
+                }),
                 bounds: arena_vec![this; future_bound],
                 origin: hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
             };
@@ -1856,8 +1759,7 @@ fn lower_async_fn_ret_ty(
             this.generate_opaque_type(opaque_ty_def_id, opaque_ty_item, span, opaque_ty_span)
         });
 
-        // As documented above on the variable
-        // `input_lifetimes_count`, we need to create the lifetime
+        // As documented above, we need to create the lifetime
         // arguments to our opaque type. Continuing with our example,
         // we're creating the type arguments for the return type:
         //
@@ -1873,12 +1775,11 @@ fn lower_async_fn_ret_ty(
         // For the "output" lifetime parameters, we just want to
         // generate `'_`.
         let generic_args =
-            self.arena.alloc_from_iter(lifetime_params.into_iter().map(|(span, name)| {
-                GenericArg::Lifetime(hir::Lifetime {
-                    hir_id: self.next_id(),
-                    span: self.lower_span(span),
-                    name,
-                })
+            self.arena.alloc_from_iter(captures.into_iter().map(|(_, (span, _, p_name, res))| {
+                let id = self.resolver.next_node_id();
+                let ident = Ident::new(p_name.ident().name, span);
+                let l = self.new_named_lifetime_with_res(id, span, ident, res);
+                hir::GenericArg::Lifetime(l)
             }));
 
         // Create the `Foo<...>` reference itself. Note that the `type
@@ -1905,7 +1806,6 @@ fn lower_async_fn_output_type_to_future_bound(
                 // `impl Future` opaque type that `async fn` implicitly
                 // generates.
                 let context = ImplTraitContext::ReturnPositionOpaqueTy {
-                    fn_def_id,
                     origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
                 };
                 self.lower_ty(ty, context)
@@ -1948,92 +1848,134 @@ fn lower_param_bound(
 
     fn lower_lifetime(&mut self, l: &Lifetime) -> hir::Lifetime {
         let span = self.lower_span(l.ident.span);
-        match l.ident {
-            ident if ident.name == kw::StaticLifetime => {
-                self.new_named_lifetime(l.id, span, hir::LifetimeName::Static)
-            }
-            ident if ident.name == kw::UnderscoreLifetime => match self.anonymous_lifetime_mode {
-                AnonymousLifetimeMode::CreateParameter => {
-                    let fresh_name = self.collect_fresh_anonymous_lifetime(span);
-                    self.new_named_lifetime(l.id, span, hir::LifetimeName::Param(fresh_name))
-                }
-
-                AnonymousLifetimeMode::PassThrough => {
-                    self.new_named_lifetime(l.id, span, hir::LifetimeName::Underscore)
-                }
-
-                AnonymousLifetimeMode::ReportError => self.new_error_lifetime(Some(l.id), span),
-            },
-            ident => {
-                let param_name = ParamName::Plain(self.lower_ident(ident));
-                self.new_named_lifetime(l.id, span, hir::LifetimeName::Param(param_name))
-            }
-        }
+        let ident = self.lower_ident(l.ident);
+        let res = self
+            .resolver
+            .get_lifetime_res(l.id)
+            .unwrap_or_else(|| panic!("Missing resolution for lifetime {:?} at {:?}", l, span));
+        self.new_named_lifetime_with_res(l.id, span, ident, res)
     }
 
-    fn new_named_lifetime(
+    #[tracing::instrument(level = "debug", skip(self))]
+    fn new_named_lifetime_with_res(
         &mut self,
         id: NodeId,
         span: Span,
-        name: hir::LifetimeName,
+        ident: Ident,
+        res: LifetimeRes,
     ) -> hir::Lifetime {
+        debug!(?self.captured_lifetimes);
+        let name = match res {
+            LifetimeRes::Param { 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 }) =
+                    &mut self.captured_lifetimes
+                    && !binders_to_ignore.contains(&binder)
+                {
+                    match captures.entry(param) {
+                        Entry::Occupied(_) => {}
+                        Entry::Vacant(v) => {
+                            let p_id = self.resolver.next_node_id();
+                            self.resolver.create_def(
+                                *parent_def_id,
+                                p_id,
+                                DefPathData::LifetimeNs(p_name.ident().name),
+                                ExpnId::root(),
+                                span.with_parent(None),
+                            );
+
+                            v.insert((span, p_id, p_name, res));
+                        }
+                    }
+                }
+                hir::LifetimeName::Param(p_name)
+            }
+            LifetimeRes::Fresh { mut param, binder } => {
+                debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
+                if let Some(LifetimeCaptureContext { parent_def_id, captures, binders_to_ignore }) =
+                    &mut self.captured_lifetimes
+                    && !binders_to_ignore.contains(&binder)
+                {
+                    match captures.entry(param) {
+                        Entry::Occupied(o) => param = self.resolver.local_def_id(o.get().1),
+                        Entry::Vacant(v) => {
+                            let p_id = self.resolver.next_node_id();
+                            let p_def_id = self.resolver.create_def(
+                                *parent_def_id,
+                                p_id,
+                                DefPathData::LifetimeNs(kw::UnderscoreLifetime),
+                                ExpnId::root(),
+                                span.with_parent(None),
+                            );
+
+                            let p_name = ParamName::Fresh(param);
+                            v.insert((span, p_id, p_name, res));
+                            param = p_def_id;
+                        }
+                    }
+                }
+                let p_name = ParamName::Fresh(param);
+                hir::LifetimeName::Param(p_name)
+            }
+            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)
+                {
+                    let p_id = self.resolver.next_node_id();
+                    let p_def_id = self.resolver.create_def(
+                        *parent_def_id,
+                        p_id,
+                        DefPathData::LifetimeNs(kw::UnderscoreLifetime),
+                        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)
+                } else {
+                    l_name
+                }
+            }
+            LifetimeRes::Static => hir::LifetimeName::Static,
+            LifetimeRes::Error => hir::LifetimeName::Error,
+            res => panic!("Unexpected lifetime resolution {:?} for {:?} at {:?}", res, ident, span),
+        };
+        debug!(?self.captured_lifetimes);
         hir::Lifetime { hir_id: self.lower_node_id(id), span: self.lower_span(span), name }
     }
 
     fn lower_generic_params_mut<'s>(
         &'s mut self,
         params: &'s [GenericParam],
-        mut itctx: ImplTraitContext<'s, 'hir>,
     ) -> impl Iterator<Item = hir::GenericParam<'hir>> + Captures<'a> + Captures<'s> {
-        params.iter().map(move |param| self.lower_generic_param(param, itctx.reborrow()))
+        params.iter().map(move |param| self.lower_generic_param(param))
     }
 
-    fn lower_generic_params(
-        &mut self,
-        params: &[GenericParam],
-        itctx: ImplTraitContext<'_, 'hir>,
-    ) -> &'hir [hir::GenericParam<'hir>] {
-        self.arena.alloc_from_iter(self.lower_generic_params_mut(params, itctx))
+    fn lower_generic_params(&mut self, params: &[GenericParam]) -> &'hir [hir::GenericParam<'hir>] {
+        self.arena.alloc_from_iter(self.lower_generic_params_mut(params))
     }
 
-    fn lower_generic_param(
-        &mut self,
-        param: &GenericParam,
-        mut itctx: ImplTraitContext<'_, 'hir>,
-    ) -> hir::GenericParam<'hir> {
-        let bounds: Vec<_> = self
-            .with_anonymous_lifetime_mode(AnonymousLifetimeMode::ReportError, |this| {
-                this.lower_param_bounds_mut(&param.bounds, itctx.reborrow()).collect()
-            });
-
+    fn lower_generic_param(&mut self, param: &GenericParam) -> hir::GenericParam<'hir> {
         let (name, kind) = match param.kind {
             GenericParamKind::Lifetime => {
-                let was_collecting_in_band = self.is_collecting_anonymous_lifetimes;
-                self.is_collecting_anonymous_lifetimes = None;
-
-                let lt = self
-                    .with_anonymous_lifetime_mode(AnonymousLifetimeMode::ReportError, |this| {
-                        this.lower_lifetime(&Lifetime { id: param.id, ident: param.ident })
-                    });
-                let param_name = match lt.name {
-                    hir::LifetimeName::Param(param_name) => param_name,
-                    hir::LifetimeName::Implicit | hir::LifetimeName::Underscore => {
-                        hir::ParamName::Plain(lt.name.ident())
-                    }
-                    hir::LifetimeName::ImplicitObjectLifetimeDefault => {
-                        self.sess.diagnostic().span_bug(
-                            param.ident.span,
-                            "object-lifetime-default should not occur here",
-                        );
-                    }
-                    hir::LifetimeName::Static | hir::LifetimeName::Error => ParamName::Error,
+                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)
                 };
-
                 let kind =
                     hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit };
 
-                self.is_collecting_anonymous_lifetimes = was_collecting_in_band;
-
                 (param_name, kind)
             }
             GenericParamKind::Type { ref default, .. } => {
@@ -2047,10 +1989,7 @@ fn lower_generic_param(
                 (hir::ParamName::Plain(self.lower_ident(param.ident)), kind)
             }
             GenericParamKind::Const { ref ty, kw_span: _, ref default } => {
-                let ty =
-                    self.with_anonymous_lifetime_mode(AnonymousLifetimeMode::ReportError, |this| {
-                        this.lower_ty(&ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type))
-                    });
+                let ty = self.lower_ty(&ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
                 let default = default.as_ref().map(|def| self.lower_anon_const(def));
                 (
                     hir::ParamName::Plain(self.lower_ident(param.ident)),
@@ -2070,8 +2009,8 @@ fn lower_generic_param(
             name,
             span: self.lower_span(param.span()),
             pure_wrt_drop: self.sess.contains_name(&param.attrs, sym::may_dangle),
-            bounds: self.arena.alloc_from_iter(bounds),
             kind,
+            colon_span: param.colon_span.map(|s| self.lower_span(s)),
         }
     }
 
@@ -2087,35 +2026,16 @@ fn lower_trait_ref(
         hir::TraitRef { path, hir_ref_id: self.lower_node_id(p.ref_id) }
     }
 
+    #[tracing::instrument(level = "debug", skip(self))]
     fn lower_poly_trait_ref(
         &mut self,
         p: &PolyTraitRef,
         mut itctx: ImplTraitContext<'_, 'hir>,
     ) -> hir::PolyTraitRef<'hir> {
-        let bound_generic_params =
-            self.lower_generic_params(&p.bound_generic_params, itctx.reborrow());
-
-        let trait_ref = self.with_in_scope_lifetime_defs(&p.bound_generic_params, |this| {
-            // Any impl Trait types defined within this scope can capture
-            // lifetimes bound on this predicate.
-            let lt_def_names = p.bound_generic_params.iter().filter_map(|param| match param.kind {
-                GenericParamKind::Lifetime { .. } => Some(hir::LifetimeName::Param(
-                    ParamName::Plain(param.ident.normalize_to_macros_2_0()),
-                )),
-                _ => None,
-            });
-            if let ImplTraitContext::TypeAliasesOpaqueTy { ref mut capturable_lifetimes } = itctx {
-                capturable_lifetimes.extend(lt_def_names.clone());
-            }
-
-            let res = this.lower_trait_ref(&p.trait_ref, itctx.reborrow());
+        let bound_generic_params = self.lower_generic_params(&p.bound_generic_params);
 
-            if let ImplTraitContext::TypeAliasesOpaqueTy { ref mut capturable_lifetimes } = itctx {
-                for param in lt_def_names {
-                    capturable_lifetimes.remove(&param);
-                }
-            }
-            res
+        let trait_ref = self.with_lifetime_binder(p.trait_ref.ref_id, |this| {
+            this.lower_trait_ref(&p.trait_ref, itctx.reborrow())
         });
 
         hir::PolyTraitRef { bound_generic_params, trait_ref, span: self.lower_span(p.span) }
@@ -2378,98 +2298,11 @@ fn ty_path(
         hir::Ty { hir_id, kind, span: self.lower_span(span) }
     }
 
-    /// Invoked to create the lifetime argument for a type `&T`
-    /// with no explicit lifetime.
-    fn elided_ref_lifetime(&mut self, span: Span) -> hir::Lifetime {
-        match self.anonymous_lifetime_mode {
-            // Intercept when we are in an impl header or async fn and introduce an in-band
-            // lifetime.
-            // Hence `impl Foo for &u32` becomes `impl<'f> Foo for &'f u32` for some fresh
-            // `'f`.
-            AnonymousLifetimeMode::CreateParameter => {
-                let fresh_name = self.collect_fresh_anonymous_lifetime(span);
-                hir::Lifetime {
-                    hir_id: self.next_id(),
-                    span: self.lower_span(span),
-                    name: hir::LifetimeName::Param(fresh_name),
-                }
-            }
-
-            AnonymousLifetimeMode::ReportError => self.new_error_lifetime(None, span),
-
-            AnonymousLifetimeMode::PassThrough => self.new_implicit_lifetime(span),
-        }
-    }
-
-    /// Report an error on illegal use of `'_` or a `&T` with no explicit lifetime;
-    /// return an "error lifetime".
-    fn new_error_lifetime(&mut self, id: Option<NodeId>, span: Span) -> hir::Lifetime {
-        let id = id.unwrap_or_else(|| self.resolver.next_node_id());
-        self.new_named_lifetime(id, span, hir::LifetimeName::Error)
-    }
-
-    /// Invoked to create the lifetime argument(s) for a path like
-    /// `std::cell::Ref<T>`; note that implicit lifetimes in these
-    /// sorts of cases are deprecated. This may therefore report a warning or an
-    /// error, depending on the mode.
-    fn elided_path_lifetimes<'s>(
-        &'s mut self,
-        span: Span,
-        count: usize,
-    ) -> impl Iterator<Item = hir::Lifetime> + Captures<'a> + Captures<'s> + Captures<'hir> {
-        (0..count).map(move |_| self.elided_path_lifetime(span))
-    }
-
-    fn elided_path_lifetime(&mut self, span: Span) -> hir::Lifetime {
-        match self.anonymous_lifetime_mode {
-            AnonymousLifetimeMode::CreateParameter => {
-                // We should have emitted E0726 when processing this path above
-                self.sess
-                    .delay_span_bug(span, "expected 'implicit elided lifetime not allowed' error");
-                let id = self.resolver.next_node_id();
-                self.new_named_lifetime(id, span, hir::LifetimeName::Error)
-            }
-            // `PassThrough` is the normal case.
-            // `new_error_lifetime`, which would usually be used in the case of `ReportError`,
-            // is unsuitable here, as these can occur from missing lifetime parameters in a
-            // `PathSegment`, for which there is no associated `'_` or `&T` with no explicit
-            // lifetime. Instead, we simply create an implicit lifetime, which will be checked
-            // later, at which point a suitable error will be emitted.
-            AnonymousLifetimeMode::PassThrough | AnonymousLifetimeMode::ReportError => {
-                self.new_implicit_lifetime(span)
-            }
-        }
-    }
-
     /// Invoked to create the lifetime argument(s) for an elided trait object
     /// bound, like the bound in `Box<dyn Debug>`. This method is not invoked
     /// when the bound is written, even if it is written with `'_` like in
     /// `Box<dyn Debug + '_>`. In those cases, `lower_lifetime` is invoked.
     fn elided_dyn_bound(&mut self, span: Span) -> hir::Lifetime {
-        match self.anonymous_lifetime_mode {
-            // NB. We intentionally ignore the create-parameter mode here.
-            // and instead "pass through" to resolve-lifetimes, which will apply
-            // the object-lifetime-defaulting rules. Elided object lifetime defaults
-            // do not act like other elided lifetimes. In other words, given this:
-            //
-            //     impl Foo for Box<dyn Debug>
-            //
-            // we do not introduce a fresh `'_` to serve as the bound, but instead
-            // ultimately translate to the equivalent of:
-            //
-            //     impl Foo for Box<dyn Debug + 'static>
-            //
-            // `resolve_lifetime` has the code to make that happen.
-            AnonymousLifetimeMode::CreateParameter => {}
-
-            AnonymousLifetimeMode::ReportError => {
-                // ReportError applies to explicit use of `'_`.
-            }
-
-            // This is the normal case.
-            AnonymousLifetimeMode::PassThrough => {}
-        }
-
         let r = hir::Lifetime {
             hir_id: self.next_id(),
             span: self.lower_span(span),
@@ -2478,14 +2311,6 @@ fn elided_dyn_bound(&mut self, span: Span) -> hir::Lifetime {
         debug!("elided_dyn_bound: r={:?}", r);
         r
     }
-
-    fn new_implicit_lifetime(&mut self, span: Span) -> hir::Lifetime {
-        hir::Lifetime {
-            hir_id: self.next_id(),
-            span: self.lower_span(span),
-            name: hir::LifetimeName::Implicit,
-        }
-    }
 }
 
 /// Helper struct for delayed construction of GenericArgs.
@@ -2511,121 +2336,3 @@ fn into_generic_args(self, this: &LoweringContext<'_, 'hir>) -> &'hir hir::Gener
         this.arena.alloc(ga)
     }
 }
-
-#[tracing::instrument(level = "debug")]
-fn lifetimes_from_impl_trait_bounds(
-    opaque_ty_id: NodeId,
-    bounds: hir::GenericBounds<'_>,
-    lifetimes_to_include: Option<&FxHashSet<hir::LifetimeName>>,
-) -> Vec<(hir::LifetimeName, Span)> {
-    // This visitor walks over `impl Trait` bounds and creates defs for all lifetimes that
-    // appear in the bounds, excluding lifetimes that are created within the bounds.
-    // E.g., `'a`, `'b`, but not `'c` in `impl for<'c> SomeTrait<'a, 'b, 'c>`.
-    struct ImplTraitLifetimeCollector<'r> {
-        collect_elided_lifetimes: bool,
-        currently_bound_lifetimes: Vec<hir::LifetimeName>,
-        already_defined_lifetimes: FxHashSet<hir::LifetimeName>,
-        lifetimes: Vec<(hir::LifetimeName, Span)>,
-        lifetimes_to_include: Option<&'r FxHashSet<hir::LifetimeName>>,
-    }
-
-    impl<'r, 'v> intravisit::Visitor<'v> for ImplTraitLifetimeCollector<'r> {
-        fn visit_generic_args(&mut self, span: Span, parameters: &'v hir::GenericArgs<'v>) {
-            // Don't collect elided lifetimes used inside of `Fn()` syntax.
-            if parameters.parenthesized {
-                let old_collect_elided_lifetimes = self.collect_elided_lifetimes;
-                self.collect_elided_lifetimes = false;
-                intravisit::walk_generic_args(self, span, parameters);
-                self.collect_elided_lifetimes = old_collect_elided_lifetimes;
-            } else {
-                intravisit::walk_generic_args(self, span, parameters);
-            }
-        }
-
-        fn visit_ty(&mut self, t: &'v hir::Ty<'v>) {
-            // Don't collect elided lifetimes used inside of `fn()` syntax.
-            if let hir::TyKind::BareFn(_) = t.kind {
-                let old_collect_elided_lifetimes = self.collect_elided_lifetimes;
-                self.collect_elided_lifetimes = false;
-
-                // Record the "stack height" of `for<'a>` lifetime bindings
-                // to be able to later fully undo their introduction.
-                let old_len = self.currently_bound_lifetimes.len();
-                intravisit::walk_ty(self, t);
-                self.currently_bound_lifetimes.truncate(old_len);
-
-                self.collect_elided_lifetimes = old_collect_elided_lifetimes;
-            } else {
-                intravisit::walk_ty(self, t)
-            }
-        }
-
-        fn visit_poly_trait_ref(
-            &mut self,
-            trait_ref: &'v hir::PolyTraitRef<'v>,
-            modifier: hir::TraitBoundModifier,
-        ) {
-            // Record the "stack height" of `for<'a>` lifetime bindings
-            // to be able to later fully undo their introduction.
-            let old_len = self.currently_bound_lifetimes.len();
-            intravisit::walk_poly_trait_ref(self, trait_ref, modifier);
-            self.currently_bound_lifetimes.truncate(old_len);
-        }
-
-        fn visit_generic_param(&mut self, param: &'v hir::GenericParam<'v>) {
-            // Record the introduction of 'a in `for<'a> ...`.
-            if let hir::GenericParamKind::Lifetime { .. } = param.kind {
-                // Introduce lifetimes one at a time so that we can handle
-                // cases like `fn foo<'d>() -> impl for<'a, 'b: 'a, 'c: 'b + 'd>`.
-                let lt_name = hir::LifetimeName::Param(param.name);
-                self.currently_bound_lifetimes.push(lt_name);
-            }
-
-            intravisit::walk_generic_param(self, param);
-        }
-
-        fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) {
-            let name = match lifetime.name {
-                hir::LifetimeName::Implicit | hir::LifetimeName::Underscore => {
-                    if self.collect_elided_lifetimes {
-                        // Use `'_` for both implicit and underscore lifetimes in
-                        // `type Foo<'_> = impl SomeTrait<'_>;`.
-                        hir::LifetimeName::Underscore
-                    } else {
-                        return;
-                    }
-                }
-                hir::LifetimeName::Param(_) => lifetime.name,
-
-                // Refers to some other lifetime that is "in
-                // scope" within the type.
-                hir::LifetimeName::ImplicitObjectLifetimeDefault => return,
-
-                hir::LifetimeName::Error | hir::LifetimeName::Static => return,
-            };
-
-            if !self.currently_bound_lifetimes.contains(&name)
-                && !self.already_defined_lifetimes.contains(&name)
-                && self.lifetimes_to_include.map_or(true, |lifetimes| lifetimes.contains(&name))
-            {
-                self.already_defined_lifetimes.insert(name);
-
-                self.lifetimes.push((name, lifetime.span));
-            }
-        }
-    }
-
-    let mut lifetime_collector = ImplTraitLifetimeCollector {
-        collect_elided_lifetimes: true,
-        currently_bound_lifetimes: Vec::new(),
-        already_defined_lifetimes: FxHashSet::default(),
-        lifetimes: Vec::new(),
-        lifetimes_to_include,
-    };
-
-    for bound in bounds {
-        intravisit::walk_param_bound(&mut lifetime_collector, &bound);
-    }
-
-    lifetime_collector.lifetimes
-}
index 8bf4b8fcc3975347c926a41373d56f359fb65b97..3c9399c1fdf80af168b4e5eacea26519addfb1d0 100644 (file)
@@ -1,15 +1,14 @@
 use crate::ImplTraitPosition;
 
-use super::{AnonymousLifetimeMode, ImplTraitContext, LoweringContext, ParamMode};
-use super::{GenericArgsCtor, ParenthesizedGenericArgs};
+use super::{GenericArgsCtor, LifetimeRes, ParenthesizedGenericArgs};
+use super::{ImplTraitContext, LoweringContext, ParamMode};
 
 use rustc_ast::{self as ast, *};
 use rustc_errors::{struct_span_err, Applicability};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, PartialRes, Res};
-use rustc_hir::def_id::DefId;
 use rustc_hir::GenericArg;
-use rustc_span::symbol::Ident;
+use rustc_span::symbol::{kw, Ident};
 use rustc_span::{BytePos, Span, DUMMY_SP};
 
 use smallvec::smallvec;
@@ -47,30 +46,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         _ => param_mode,
                     };
 
-                    // Figure out if this is a type/trait segment,
-                    // which may need lifetime elision performed.
-                    let parent_def_id = |this: &mut Self, def_id: DefId| DefId {
-                        krate: def_id.krate,
-                        index: this.resolver.def_key(def_id).parent.expect("missing parent"),
-                    };
-                    let type_def_id = match partial_res.base_res() {
-                        Res::Def(DefKind::AssocTy, def_id) if i + 2 == proj_start => {
-                            Some(parent_def_id(self, def_id))
-                        }
-                        Res::Def(DefKind::Variant, def_id) if i + 1 == proj_start => {
-                            Some(parent_def_id(self, def_id))
-                        }
-                        Res::Def(DefKind::Struct, def_id)
-                        | Res::Def(DefKind::Union, def_id)
-                        | Res::Def(DefKind::Enum, def_id)
-                        | Res::Def(DefKind::TyAlias, def_id)
-                        | Res::Def(DefKind::Trait, def_id)
-                            if i + 1 == proj_start =>
-                        {
-                            Some(def_id)
-                        }
-                        _ => None,
-                    };
                     let parenthesized_generic_args = match partial_res.base_res() {
                         // `a::b::Trait(Args)`
                         Res::Def(DefKind::Trait, _) if i + 1 == proj_start => {
@@ -90,13 +65,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         _ => ParenthesizedGenericArgs::Err,
                     };
 
-                    let num_lifetimes = type_def_id
-                        .map_or(0, |def_id| self.resolver.item_generics_num_lifetimes(def_id));
                     self.lower_path_segment(
                         p.span,
                         segment,
                         param_mode,
-                        num_lifetimes,
                         parenthesized_generic_args,
                         itctx.reborrow(),
                     )
@@ -143,7 +115,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 p.span,
                 segment,
                 param_mode,
-                0,
                 ParenthesizedGenericArgs::Err,
                 itctx.reborrow(),
             ));
@@ -184,7 +155,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     p.span,
                     segment,
                     param_mode,
-                    0,
                     ParenthesizedGenericArgs::Err,
                     ImplTraitContext::Disallowed(ImplTraitPosition::Path),
                 )
@@ -209,14 +179,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         path_span: Span,
         segment: &PathSegment,
         param_mode: ParamMode,
-        expected_lifetimes: usize,
         parenthesized_generic_args: ParenthesizedGenericArgs,
         itctx: ImplTraitContext<'_, 'hir>,
     ) -> hir::PathSegment<'hir> {
-        debug!(
-            "path_span: {:?}, lower_path_segment(segment: {:?}, expected_lifetimes: {:?})",
-            path_span, segment, expected_lifetimes
-        );
+        debug!("path_span: {:?}, lower_path_segment(segment: {:?})", path_span, segment,);
         let (mut generic_args, infer_args) = if let Some(ref generic_args) = segment.args {
             let msg = "parenthesized type parameters may only be used with a `Fn` trait";
             match **generic_args {
@@ -224,7 +190,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     self.lower_angle_bracketed_parameter_data(data, param_mode, itctx)
                 }
                 GenericArgs::Parenthesized(ref data) => match parenthesized_generic_args {
-                    ParenthesizedGenericArgs::Ok => self.lower_parenthesized_parameter_data(data),
+                    ParenthesizedGenericArgs::Ok => {
+                        self.lower_parenthesized_parameter_data(segment.id, data)
+                    }
                     ParenthesizedGenericArgs::Err => {
                         let mut err = struct_span_err!(self.sess, data.span, E0214, "{}", msg);
                         err.span_label(data.span, "only `Fn` traits may use parentheses");
@@ -274,33 +242,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
 
         let has_lifetimes =
             generic_args.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_)));
-        if !generic_args.parenthesized && !has_lifetimes && expected_lifetimes > 0 {
-            // Note: these spans are used for diagnostics when they can't be inferred.
-            // See rustc_resolve::late::lifetimes::LifetimeContext::add_missing_lifetime_specifiers_label
-            let elided_lifetime_span = if generic_args.span.is_empty() {
-                // If there are no brackets, use the identifier span.
-                // HACK: we use find_ancestor_inside to properly suggest elided spans in paths
-                // originating from macros, since the segment's span might be from a macro arg.
-                segment.ident.span.find_ancestor_inside(path_span).unwrap_or(path_span)
-            } else if generic_args.is_empty() {
-                // If there are brackets, but not generic arguments, then use the opening bracket
-                generic_args.span.with_hi(generic_args.span.lo() + BytePos(1))
-            } else {
-                // Else use an empty span right after the opening bracket.
-                generic_args.span.with_lo(generic_args.span.lo() + BytePos(1)).shrink_to_lo()
-            };
-            generic_args.args = self
-                .elided_path_lifetimes(elided_lifetime_span, expected_lifetimes)
-                .map(GenericArg::Lifetime)
-                .chain(generic_args.args.into_iter())
-                .collect();
-            if let (ParamMode::Explicit, AnonymousLifetimeMode::CreateParameter) =
-                (param_mode, self.anonymous_lifetime_mode)
-            {
-                // Late resolver should have issued the error.
-                self.sess
-                    .delay_span_bug(elided_lifetime_span, "implicit lifetime not allowed here");
-            }
+        if !generic_args.parenthesized && !has_lifetimes {
+            self.maybe_insert_elided_lifetimes_in_path(
+                path_span,
+                segment.id,
+                segment.ident.span,
+                &mut generic_args,
+            );
         }
 
         let res = self.expect_full_res(segment.id);
@@ -323,6 +271,49 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         }
     }
 
+    fn maybe_insert_elided_lifetimes_in_path(
+        &mut self,
+        path_span: Span,
+        segment_id: NodeId,
+        segment_ident_span: Span,
+        generic_args: &mut GenericArgsCtor<'hir>,
+    ) {
+        let (start, end) = match self.resolver.get_lifetime_res(segment_id) {
+            Some(LifetimeRes::ElidedAnchor { start, end }) => (start, end),
+            None => return,
+            Some(_) => panic!(),
+        };
+        let expected_lifetimes = end.as_usize() - start.as_usize();
+        debug!(expected_lifetimes);
+
+        // Note: these spans are used for diagnostics when they can't be inferred.
+        // See rustc_resolve::late::lifetimes::LifetimeContext::add_missing_lifetime_specifiers_label
+        let elided_lifetime_span = if generic_args.span.is_empty() {
+            // If there are no brackets, use the identifier span.
+            // HACK: we use find_ancestor_inside to properly suggest elided spans in paths
+            // originating from macros, since the segment's span might be from a macro arg.
+            segment_ident_span.find_ancestor_inside(path_span).unwrap_or(path_span)
+        } else if generic_args.is_empty() {
+            // If there are brackets, but not generic arguments, then use the opening bracket
+            generic_args.span.with_hi(generic_args.span.lo() + BytePos(1))
+        } else {
+            // Else use an empty span right after the opening bracket.
+            generic_args.span.with_lo(generic_args.span.lo() + BytePos(1)).shrink_to_lo()
+        };
+
+        generic_args.args.insert_many(
+            0,
+            (start.as_u32()..end.as_u32()).map(|i| {
+                let id = NodeId::from_u32(i);
+                let l = self.lower_lifetime(&Lifetime {
+                    id,
+                    ident: Ident::new(kw::UnderscoreLifetime, elided_lifetime_span),
+                });
+                GenericArg::Lifetime(l)
+            }),
+        );
+    }
+
     pub(crate) fn lower_angle_bracketed_parameter_data(
         &mut self,
         data: &AngleBracketedArgs,
@@ -354,6 +345,7 @@ pub(crate) fn lower_angle_bracketed_parameter_data(
 
     fn lower_parenthesized_parameter_data(
         &mut self,
+        id: NodeId,
         data: &ParenthesizedArgs,
     ) -> (GenericArgsCtor<'hir>, bool) {
         // Switch to `PassThrough` mode for anonymous lifetimes; this
@@ -361,7 +353,7 @@ fn lower_parenthesized_parameter_data(
         // a hidden lifetime parameter. This is needed for backwards
         // compatibility, even in contexts like an impl header where
         // we generally don't permit such things (see #51008).
-        self.with_anonymous_lifetime_mode(AnonymousLifetimeMode::PassThrough, |this| {
+        self.with_lifetime_binder(id, |this| {
             let ParenthesizedArgs { span, inputs, inputs_span, output } = data;
             let inputs = this.arena.alloc_from_iter(inputs.iter().map(|ty| {
                 this.lower_ty_direct(
index 8d815e95528825a269a56f88619e9102631d5cc4..058a0f975a7b39be565f61803af4c906740057fd 100644 (file)
@@ -8,7 +8,7 @@
 
 use itertools::{Either, Itertools};
 use rustc_ast::ptr::P;
-use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
+use rustc_ast::visit::{self, AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor};
 use rustc_ast::walk_list;
 use rustc_ast::*;
 use rustc_ast_pretty::pprust::{self, State};
@@ -345,23 +345,6 @@ fn check_trait_fn_not_const(&self, constness: Const) {
         }
     }
 
-    // FIXME(ecstaticmorse): Instead, use `bound_context` to check this in `visit_param_bound`.
-    fn no_questions_in_bounds(&self, bounds: &GenericBounds, where_: &str, is_trait: bool) {
-        for bound in bounds {
-            if let GenericBound::Trait(ref poly, TraitBoundModifier::Maybe) = *bound {
-                let mut err = self.err_handler().struct_span_err(
-                    poly.span,
-                    &format!("`?Trait` is not permitted in {}", where_),
-                );
-                if is_trait {
-                    let path_str = pprust::path_to_string(&poly.trait_ref.path);
-                    err.note(&format!("traits are `?{}` by default", path_str));
-                }
-                err.emit();
-            }
-        }
-    }
-
     fn check_late_bound_lifetime_defs(&self, params: &[GenericParam]) {
         // Check only lifetime parameters are present and that the lifetime
         // parameters that are present have no bounds.
@@ -873,7 +856,6 @@ fn visit_ty_common(&mut self, ty: &'a Ty) {
                         any_lifetime_bounds = true;
                     }
                 }
-                self.no_questions_in_bounds(bounds, "trait object types", false);
             }
             TyKind::ImplTrait(_, ref bounds) => {
                 if self.is_impl_trait_banned {
@@ -1242,14 +1224,15 @@ fn visit_item(&mut self, item: &'a Item) {
                     self.deny_where_clause(&generics.where_clause, item.ident.span);
                     self.deny_items(items, item.ident.span);
                 }
-                self.no_questions_in_bounds(bounds, "supertraits", true);
 
                 // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound
                 // context for the supertraits.
                 self.visit_vis(&item.vis);
                 self.visit_ident(item.ident);
                 self.visit_generics(generics);
-                self.with_banned_tilde_const(|this| walk_list!(this, visit_param_bound, bounds));
+                self.with_banned_tilde_const(|this| {
+                    walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits)
+                });
                 walk_list!(self, visit_assoc_item, items, AssocCtxt::Trait);
                 walk_list!(self, visit_attribute, &item.attrs);
                 return;
@@ -1476,23 +1459,39 @@ fn visit_generic_param(&mut self, param: &'a GenericParam) {
         visit::walk_generic_param(self, param);
     }
 
-    fn visit_param_bound(&mut self, bound: &'a GenericBound) {
-        match bound {
-            GenericBound::Trait(_, TraitBoundModifier::MaybeConst) => {
-                if !self.is_tilde_const_allowed {
+    fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind) {
+        if let GenericBound::Trait(ref poly, modify) = *bound {
+            match (ctxt, modify) {
+                (BoundKind::SuperTraits, TraitBoundModifier::Maybe) => {
+                    let mut err = self.err_handler().struct_span_err(
+                        poly.span,
+                        &format!("`?Trait` is not permitted in supertraits"),
+                    );
+                    let path_str = pprust::path_to_string(&poly.trait_ref.path);
+                    err.note(&format!("traits are `?{}` by default", path_str));
+                    err.emit();
+                }
+                (BoundKind::TraitObject, TraitBoundModifier::Maybe) => {
+                    let mut err = self.err_handler().struct_span_err(
+                        poly.span,
+                        &format!("`?Trait` is not permitted in trait object types"),
+                    );
+                    err.emit();
+                }
+                (_, TraitBoundModifier::MaybeConst) => {
+                    if !self.is_tilde_const_allowed {
+                        self.err_handler()
+                            .struct_span_err(bound.span(), "`~const` is not allowed here")
+                            .note("only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions")
+                            .emit();
+                    }
+                }
+                (_, TraitBoundModifier::MaybeConstMaybe) => {
                     self.err_handler()
-                        .struct_span_err(bound.span(), "`~const` is not allowed here")
-                        .note("only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions")
-                        .emit();
+                        .span_err(bound.span(), "`~const` and `?` are mutually exclusive");
                 }
+                _ => {}
             }
-
-            GenericBound::Trait(_, TraitBoundModifier::MaybeConstMaybe) => {
-                self.err_handler()
-                    .span_err(bound.span(), "`~const` and `?` are mutually exclusive");
-            }
-
-            _ => {}
         }
 
         visit::walk_param_bound(self, bound)
@@ -1662,7 +1661,7 @@ fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
                 walk_list!(self, visit_attribute, &item.attrs);
                 self.with_tilde_const_allowed(|this| {
                     this.visit_generics(generics);
-                    walk_list!(this, visit_param_bound, bounds);
+                    walk_list!(this, visit_param_bound, bounds, BoundKind::Bound);
                 });
                 walk_list!(self, visit_ty, ty);
             }
index 649af48e48adf624311ba4f4e37a6ef2c69c6783..0e8af549692fc2f9e42e85125e936edce4cd2e8a 100644 (file)
@@ -783,6 +783,7 @@ macro_rules! gate_all {
     gate_all!(inline_const, "inline-const is experimental");
     gate_all!(inline_const_pat, "inline-const in pattern position is experimental");
     gate_all!(associated_const_equality, "associated const equality is incomplete");
+    gate_all!(yeet_expr, "`do yeet` expression is experimental");
 
     // All uses of `gate_all!` below this point were added in #65742,
     // and subsequently disabled (with the non-early gating readded).
index a4a48cc8e8a7f1d279cadb2dc2daf4953865134f..48b79809c1b97b0711aa34043902dfff7f239fa6 100644 (file)
@@ -76,7 +76,7 @@ fn visit_trait_ref(&mut self, t: &TraitRef) {
         self.count += 1;
         walk_trait_ref(self, t)
     }
-    fn visit_param_bound(&mut self, bounds: &GenericBound) {
+    fn visit_param_bound(&mut self, bounds: &GenericBound, _ctxt: BoundKind) {
         self.count += 1;
         walk_param_bound(self, bounds)
     }
index 3c9bb81bedb1c64aec042148a23823b03ccd1ef0..a2ebe3048ceee91a1426eae54ab7199f2a5bbd12 100644 (file)
@@ -6,7 +6,7 @@
 use crate::pp::{self, Breaks};
 
 use rustc_ast::ptr::P;
-use rustc_ast::token::{self, BinOpToken, CommentKind, DelimToken, Nonterminal, Token, TokenKind};
+use rustc_ast::token::{self, BinOpToken, CommentKind, Delimiter, Nonterminal, Token, TokenKind};
 use rustc_ast::tokenstream::{TokenStream, TokenTree};
 use rustc_ast::util::classify;
 use rustc_ast::util::comments::{gather_comments, Comment, CommentStyle};
@@ -155,10 +155,10 @@ fn tt_prepend_space(tt: &TokenTree, prev: &TokenTree) -> bool {
     }
     match tt {
         TokenTree::Token(token) => !matches!(token.kind, token::Comma | token::Not | token::Dot),
-        TokenTree::Delimited(_, DelimToken::Paren, _) => {
+        TokenTree::Delimited(_, Delimiter::Parenthesis, _) => {
             !matches!(prev, TokenTree::Token(Token { kind: token::Ident(..), .. }))
         }
-        TokenTree::Delimited(_, DelimToken::Bracket, _) => {
+        TokenTree::Delimited(_, Delimiter::Bracket, _) => {
             !matches!(prev, TokenTree::Token(Token { kind: token::Pound, .. }))
         }
         TokenTree::Delimited(..) => true,
@@ -464,7 +464,7 @@ fn print_attr_item(&mut self, item: &ast::AttrItem, span: Span) {
                 Some(MacHeader::Path(&item.path)),
                 false,
                 None,
-                delim.to_token(),
+                Some(delim.to_token()),
                 tokens,
                 true,
                 span,
@@ -530,7 +530,7 @@ fn print_tt(&mut self, tt: &TokenTree, convert_dollar_crate: bool) {
                     None,
                     false,
                     None,
-                    *delim,
+                    Some(*delim),
                     tts,
                     convert_dollar_crate,
                     dspan.entire(),
@@ -556,12 +556,12 @@ fn print_mac_common(
         header: Option<MacHeader<'_>>,
         has_bang: bool,
         ident: Option<Ident>,
-        delim: DelimToken,
+        delim: Option<Delimiter>,
         tts: &TokenStream,
         convert_dollar_crate: bool,
         span: Span,
     ) {
-        if delim == DelimToken::Brace {
+        if delim == Some(Delimiter::Brace) {
             self.cbox(INDENT_UNIT);
         }
         match header {
@@ -577,7 +577,7 @@ fn print_mac_common(
             self.print_ident(ident);
         }
         match delim {
-            DelimToken::Brace => {
+            Some(Delimiter::Brace) => {
                 if header.is_some() || has_bang || ident.is_some() {
                     self.nbsp();
                 }
@@ -585,23 +585,25 @@ fn print_mac_common(
                 if !tts.is_empty() {
                     self.space();
                 }
-            }
-            _ => {
-                let token_str = self.token_kind_to_string(&token::OpenDelim(delim));
-                self.word(token_str)
-            }
-        }
-        self.ibox(0);
-        self.print_tts(tts, convert_dollar_crate);
-        self.end();
-        match delim {
-            DelimToken::Brace => {
+                self.ibox(0);
+                self.print_tts(tts, convert_dollar_crate);
+                self.end();
                 let empty = tts.is_empty();
                 self.bclose(span, empty);
             }
-            _ => {
+            Some(delim) => {
+                let token_str = self.token_kind_to_string(&token::OpenDelim(delim));
+                self.word(token_str);
+                self.ibox(0);
+                self.print_tts(tts, convert_dollar_crate);
+                self.end();
                 let token_str = self.token_kind_to_string(&token::CloseDelim(delim));
-                self.word(token_str)
+                self.word(token_str);
+            }
+            None => {
+                self.ibox(0);
+                self.print_tts(tts, convert_dollar_crate);
+                self.end();
             }
         }
     }
@@ -756,13 +758,15 @@ fn token_kind_to_string_ext(
             token::RArrow => "->".into(),
             token::LArrow => "<-".into(),
             token::FatArrow => "=>".into(),
-            token::OpenDelim(token::Paren) => "(".into(),
-            token::CloseDelim(token::Paren) => ")".into(),
-            token::OpenDelim(token::Bracket) => "[".into(),
-            token::CloseDelim(token::Bracket) => "]".into(),
-            token::OpenDelim(token::Brace) => "{".into(),
-            token::CloseDelim(token::Brace) => "}".into(),
-            token::OpenDelim(token::NoDelim) | token::CloseDelim(token::NoDelim) => "".into(),
+            token::OpenDelim(Delimiter::Parenthesis) => "(".into(),
+            token::CloseDelim(Delimiter::Parenthesis) => ")".into(),
+            token::OpenDelim(Delimiter::Bracket) => "[".into(),
+            token::CloseDelim(Delimiter::Bracket) => "]".into(),
+            token::OpenDelim(Delimiter::Brace) => "{".into(),
+            token::CloseDelim(Delimiter::Brace) => "}".into(),
+            token::OpenDelim(Delimiter::Invisible) | token::CloseDelim(Delimiter::Invisible) => {
+                "".into()
+            }
             token::Pound => "#".into(),
             token::Dollar => "$".into(),
             token::Question => "?".into(),
index 9de4cbbee13f068e483d0fa0ae26d055358f4e1a..9f44f1b6cc205f927d7825490aff4b69cbd9469c 100644 (file)
@@ -64,7 +64,10 @@ fn print_expr_as_cond(&mut self, expr: &ast::Expr) {
     // parses as the erroneous construct `if (return {})`, not `if (return) {}`.
     pub(super) fn cond_needs_par(expr: &ast::Expr) -> bool {
         match expr.kind {
-            ast::ExprKind::Break(..) | ast::ExprKind::Closure(..) | ast::ExprKind::Ret(..) => true,
+            ast::ExprKind::Break(..)
+            | ast::ExprKind::Closure(..)
+            | ast::ExprKind::Ret(..)
+            | ast::ExprKind::Yeet(..) => true,
             _ => parser::contains_exterior_struct_lit(expr),
         }
     }
@@ -502,6 +505,15 @@ pub(super) fn print_expr_outer_attr_style(&mut self, expr: &ast::Expr, is_inline
                     self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
                 }
             }
+            ast::ExprKind::Yeet(ref result) => {
+                self.word("do");
+                self.word(" ");
+                self.word("yeet");
+                if let Some(ref expr) = *result {
+                    self.word(" ");
+                    self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
+                }
+            }
             ast::ExprKind::InlineAsm(ref a) => {
                 self.word("asm!");
                 self.print_inline_asm(a);
index 4ceca60e23cee736bcbaebfc71f050ef4fe978e9..c19a39c393f799f3c926d4ac3aa8e5c6f0c447d1 100644 (file)
@@ -190,7 +190,7 @@ impl<'s, 'tcx, D: ConstraintGraphDirecton> RegionGraph<'s, 'tcx, D> {
 
     /// Given a region `R`, iterate over all regions `R1` such that
     /// there exists a constraint `R: R1`.
-    crate fn outgoing_regions(&self, region_sup: RegionVid) -> Successors<'_, 'tcx, D> {
+    crate fn outgoing_regions(&self, region_sup: RegionVid) -> Successors<'s, 'tcx, D> {
         Successors {
             edges: self.constraint_graph.outgoing_edges(region_sup, self.set, self.static_region),
         }
@@ -225,10 +225,7 @@ fn successors(&self, node: Self::Node) -> <Self as graph::GraphSuccessors<'_>>::
     }
 }
 
-impl<'s, 'graph, 'tcx, D: ConstraintGraphDirecton> graph::GraphSuccessors<'graph>
-    for RegionGraph<'s, 'tcx, D>
-{
+impl<'s, 'tcx, D: ConstraintGraphDirecton> graph::GraphSuccessors<'_> for RegionGraph<'s, 'tcx, D> {
     type Item = RegionVid;
-    // FIXME - why can't this be `'graph, 'tcx`
-    type Iter = Successors<'graph, 'graph, D>;
+    type Iter = Successors<'s, 'tcx, D>;
 }
index 9e5fb674772d5f0d7c9c525c40dbe886c13e784e..3b4e9e95b0e9108db5086f244888b4bce63e041b 100644 (file)
@@ -7,6 +7,7 @@
 use rustc_hir::{AsyncGeneratorKind, GeneratorKind};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_infer::traits::ObligationCause;
+use rustc_middle::mir::tcx::PlaceTy;
 use rustc_middle::mir::{
     self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory,
     FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef,
@@ -22,6 +23,7 @@
 use crate::borrow_set::TwoPhaseActivation;
 use crate::borrowck_errors;
 
+use crate::diagnostics::conflict_errors::StorageDeadOrDrop::LocalStorageDead;
 use crate::diagnostics::find_all_local_uses;
 use crate::{
     borrow_set::BorrowData, diagnostics::Instance, prefixes::IsPrefixOf,
@@ -1484,7 +1486,7 @@ fn try_report_cannot_return_reference_to_local(
                         err.span_suggestion_hidden(
                             return_span,
                             "use `.collect()` to allocate the iterator",
-                            format!("{}{}", snippet, ".collect::<Vec<_>>()"),
+                            format!("{snippet}.collect::<Vec<_>>()"),
                             Applicability::MaybeIncorrect,
                         );
                     }
@@ -1956,45 +1958,46 @@ pub(crate) fn report_illegal_reassignment(
 
     fn classify_drop_access_kind(&self, place: PlaceRef<'tcx>) -> StorageDeadOrDrop<'tcx> {
         let tcx = self.infcx.tcx;
-        match place.last_projection() {
-            None => StorageDeadOrDrop::LocalStorageDead,
-            Some((place_base, elem)) => {
-                // FIXME(spastorino) make this iterate
-                let base_access = self.classify_drop_access_kind(place_base);
-                match elem {
-                    ProjectionElem::Deref => match base_access {
-                        StorageDeadOrDrop::LocalStorageDead
-                        | StorageDeadOrDrop::BoxedStorageDead => {
-                            assert!(
-                                place_base.ty(self.body, tcx).ty.is_box(),
-                                "Drop of value behind a reference or raw pointer"
-                            );
-                            StorageDeadOrDrop::BoxedStorageDead
-                        }
-                        StorageDeadOrDrop::Destructor(_) => base_access,
-                    },
-                    ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => {
-                        let base_ty = place_base.ty(self.body, tcx).ty;
-                        match base_ty.kind() {
-                            ty::Adt(def, _) if def.has_dtor(tcx) => {
-                                // Report the outermost adt with a destructor
-                                match base_access {
-                                    StorageDeadOrDrop::Destructor(_) => base_access,
-                                    StorageDeadOrDrop::LocalStorageDead
-                                    | StorageDeadOrDrop::BoxedStorageDead => {
-                                        StorageDeadOrDrop::Destructor(base_ty)
+        let (kind, _place_ty) = place.projection.iter().fold(
+            (LocalStorageDead, PlaceTy::from_ty(self.body.local_decls[place.local].ty)),
+            |(kind, place_ty), &elem| {
+                (
+                    match elem {
+                        ProjectionElem::Deref => match kind {
+                            StorageDeadOrDrop::LocalStorageDead
+                            | StorageDeadOrDrop::BoxedStorageDead => {
+                                assert!(
+                                    place_ty.ty.is_box(),
+                                    "Drop of value behind a reference or raw pointer"
+                                );
+                                StorageDeadOrDrop::BoxedStorageDead
+                            }
+                            StorageDeadOrDrop::Destructor(_) => kind,
+                        },
+                        ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => {
+                            match place_ty.ty.kind() {
+                                ty::Adt(def, _) if def.has_dtor(tcx) => {
+                                    // Report the outermost adt with a destructor
+                                    match kind {
+                                        StorageDeadOrDrop::Destructor(_) => kind,
+                                        StorageDeadOrDrop::LocalStorageDead
+                                        | StorageDeadOrDrop::BoxedStorageDead => {
+                                            StorageDeadOrDrop::Destructor(place_ty.ty)
+                                        }
                                     }
                                 }
+                                _ => kind,
                             }
-                            _ => base_access,
                         }
-                    }
-                    ProjectionElem::ConstantIndex { .. }
-                    | ProjectionElem::Subslice { .. }
-                    | ProjectionElem::Index(_) => base_access,
-                }
-            }
-        }
+                        ProjectionElem::ConstantIndex { .. }
+                        | ProjectionElem::Subslice { .. }
+                        | ProjectionElem::Index(_) => kind,
+                    },
+                    place_ty.projection_ty(tcx, elem),
+                )
+            },
+        );
+        kind
     }
 
     /// Describe the reason for the fake borrow that was assigned to `place`.
index c2b5c16517af56312d4a41aaf99992da200e8f18..368c0be794bccd317dbf0696d95fe09d15f93dbc 100644 (file)
@@ -40,6 +40,7 @@
 crate use region_errors::{ErrorConstraintInfo, RegionErrorKind, RegionErrors};
 crate use region_name::{RegionName, RegionNameSource};
 crate use rustc_const_eval::util::CallKind;
+use rustc_middle::mir::tcx::PlaceTy;
 
 pub(super) struct IncludingDowncast(pub(super) bool);
 
@@ -89,7 +90,7 @@ pub(super) fn add_moved_or_invoked_closure_note(
         {
             if let ty::FnDef(id, _) = *literal.ty().kind() {
                 debug!("add_moved_or_invoked_closure_note: id={:?}", id);
-                if self.infcx.tcx.parent(id) == self.infcx.tcx.lang_items().fn_once_trait() {
+                if Some(self.infcx.tcx.parent(id)) == self.infcx.tcx.lang_items().fn_once_trait() {
                     let closure = match args.first() {
                         Some(Operand::Copy(ref place)) | Some(Operand::Move(ref place))
                             if target == place.local_or_deref_local() =>
@@ -329,30 +330,20 @@ fn append_local_to_string(&self, local: Local, buf: &mut String) -> Result<(), (
 
     /// End-user visible description of the `field`nth field of `base`
     fn describe_field(&self, place: PlaceRef<'tcx>, field: Field) -> String {
-        // FIXME Place2 Make this work iteratively
-        match place {
-            PlaceRef { local, projection: [] } => {
-                let local = &self.body.local_decls[local];
-                self.describe_field_from_ty(local.ty, field, None)
-            }
+        let place_ty = match place {
+            PlaceRef { local, projection: [] } => PlaceTy::from_ty(self.body.local_decls[local].ty),
             PlaceRef { local, projection: [proj_base @ .., elem] } => match elem {
-                ProjectionElem::Deref => {
-                    self.describe_field(PlaceRef { local, projection: proj_base }, field)
-                }
-                ProjectionElem::Downcast(_, variant_index) => {
-                    let base_ty = place.ty(self.body, self.infcx.tcx).ty;
-                    self.describe_field_from_ty(base_ty, field, Some(*variant_index))
-                }
-                ProjectionElem::Field(_, field_type) => {
-                    self.describe_field_from_ty(*field_type, field, None)
-                }
-                ProjectionElem::Index(..)
+                ProjectionElem::Deref
+                | ProjectionElem::Index(..)
                 | ProjectionElem::ConstantIndex { .. }
                 | ProjectionElem::Subslice { .. } => {
-                    self.describe_field(PlaceRef { local, projection: proj_base }, field)
+                    PlaceRef { local, projection: proj_base }.ty(self.body, self.infcx.tcx)
                 }
+                ProjectionElem::Downcast(..) => place.ty(self.body, self.infcx.tcx),
+                ProjectionElem::Field(_, field_type) => PlaceTy::from_ty(*field_type),
             },
-        }
+        };
+        self.describe_field_from_ty(place_ty.ty, field, place_ty.variant_index)
     }
 
     /// End-user visible description of the `field_index`nth field of `ty`
index 8b12db071b6ac255a210b215a181b0d12b25169b..fe5e3c5a81b61dda07296fe4e8f9a249bf75cabc 100644 (file)
@@ -237,7 +237,7 @@ pub(crate) fn report_mutability_error(
                     err.span_suggestion_verbose(
                         span,
                         "consider changing this to be mutable",
-                        " mut ".into(),
+                        " mut ",
                         Applicability::MaybeIncorrect,
                     );
                 }
index 5fd9ecf4513661c4301705d5d0db35c7950a122d..30fe4ea8662eb909d4fda73aeccff5d2ec769702 100644 (file)
@@ -1,16 +1,20 @@
 //! Error reporting machinery for lifetime errors.
 
-use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
+use rustc_errors::{Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
 use rustc_infer::infer::{
-    error_reporting::nice_region_error::NiceRegionError,
-    error_reporting::unexpected_hidden_region_diagnostic, NllRegionVariableOrigin,
+    error_reporting::nice_region_error::{
+        self, find_anon_type, find_param_with_region, suggest_adding_lifetime_params,
+        NiceRegionError,
+    },
+    error_reporting::unexpected_hidden_region_diagnostic,
+    NllRegionVariableOrigin, RelateParamBound,
 };
 use rustc_middle::hir::place::PlaceBase;
 use rustc_middle::mir::{ConstraintCategory, ReturnConstraint};
-use rustc_middle::ty::subst::{InternalSubsts, Subst};
+use rustc_middle::ty::subst::InternalSubsts;
 use rustc_middle::ty::{self, RegionVid, Ty};
-use rustc_span::symbol::{kw, sym};
-use rustc_span::{BytePos, Span};
+use rustc_span::symbol::sym;
+use rustc_span::Span;
 
 use crate::borrowck_errors;
 
@@ -166,11 +170,14 @@ pub(crate) fn report_region_errors(&mut self, nll_errors: RegionErrors<'tcx>) {
                     let type_test_span = type_test.locations.span(&self.body);
 
                     if let Some(lower_bound_region) = lower_bound_region {
+                        let generic_ty = type_test.generic_kind.to_ty(self.infcx.tcx);
+                        let origin = RelateParamBound(type_test_span, generic_ty, None);
                         self.buffer_error(self.infcx.construct_generic_bound_failure(
                             type_test_span,
-                            None,
+                            Some(origin),
                             type_test.generic_kind,
                             lower_bound_region,
+                            self.body.source.def_id().as_local(),
                         ));
                     } else {
                         // FIXME. We should handle this case better. It
@@ -626,6 +633,7 @@ fn report_general_error(
         }
 
         self.add_static_impl_trait_suggestion(&mut diag, *fr, fr_name, *outlived_fr);
+        self.suggest_adding_lifetime_params(&mut diag, *fr, *outlived_fr);
 
         diag
     }
@@ -647,82 +655,76 @@ fn add_static_impl_trait_suggestion(
         fr_name: RegionName,
         outlived_fr: RegionVid,
     ) {
-        if let (Some(f), Some(ty::ReStatic)) =
-            (self.to_error_region(fr), self.to_error_region(outlived_fr).as_deref())
+        if let (Some(f), Some(outlived_f)) =
+            (self.to_error_region(fr), self.to_error_region(outlived_fr))
         {
-            if let Some(&ty::Opaque(did, substs)) = self
+            if *outlived_f != ty::ReStatic {
+                return;
+            }
+
+            let fn_returns = self
                 .infcx
                 .tcx
                 .is_suitable_region(f)
-                .map(|r| r.def_id)
-                .and_then(|id| self.infcx.tcx.return_type_impl_trait(id))
-                .map(|(ty, _)| ty.kind())
-            {
-                // Check whether or not the impl trait return type is intended to capture
-                // data with the static lifetime.
-                //
-                // eg. check for `impl Trait + 'static` instead of `impl Trait`.
-                let has_static_predicate = {
-                    let bounds = self.infcx.tcx.explicit_item_bounds(did);
-
-                    let mut found = false;
-                    for (bound, _) in bounds {
-                        if let ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(_, r)) =
-                            bound.kind().skip_binder()
-                        {
-                            let r = r.subst(self.infcx.tcx, substs);
-                            if r.is_static() {
-                                found = true;
-                                break;
-                            } else {
-                                // If there's already a lifetime bound, don't
-                                // suggest anything.
-                                return;
-                            }
-                        }
-                    }
+                .map(|r| self.infcx.tcx.return_type_impl_or_dyn_traits(r.def_id))
+                .unwrap_or_default();
 
-                    found
-                };
-
-                debug!(
-                    "add_static_impl_trait_suggestion: has_static_predicate={:?}",
-                    has_static_predicate
-                );
-                let static_str = kw::StaticLifetime;
-                // If there is a static predicate, then the only sensible suggestion is to replace
-                // fr with `'static`.
-                if has_static_predicate {
-                    diag.help(&format!("consider replacing `{fr_name}` with `{static_str}`"));
-                } else {
-                    // Otherwise, we should suggest adding a constraint on the return type.
-                    let span = self.infcx.tcx.def_span(did);
-                    if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) {
-                        let suggestable_fr_name = if fr_name.was_named() {
-                            fr_name.to_string()
-                        } else {
-                            "'_".to_string()
-                        };
-                        let span = if snippet.ends_with(';') {
-                            // `type X = impl Trait;`
-                            span.with_hi(span.hi() - BytePos(1))
-                        } else {
-                            span
-                        };
-                        let suggestion = format!(" + {suggestable_fr_name}");
-                        let span = span.shrink_to_hi();
-                        diag.span_suggestion(
-                            span,
-                            &format!(
-                                "to allow this `impl Trait` to capture borrowed data with lifetime \
-                                 `{fr_name}`, add `{suggestable_fr_name}` as a bound",
-                            ),
-                            suggestion,
-                            Applicability::MachineApplicable,
-                        );
-                    }
-                }
+            if fn_returns.is_empty() {
+                return;
             }
+
+            let param = if let Some(param) = find_param_with_region(self.infcx.tcx, f, outlived_f) {
+                param
+            } else {
+                return;
+            };
+
+            let lifetime = if f.has_name() { fr_name.to_string() } else { "'_".to_string() };
+
+            let arg = match param.param.pat.simple_ident() {
+                Some(simple_ident) => format!("argument `{}`", simple_ident),
+                None => "the argument".to_string(),
+            };
+            let captures = format!("captures data from {}", arg);
+
+            return nice_region_error::suggest_new_region_bound(
+                self.infcx.tcx,
+                diag,
+                fn_returns,
+                lifetime,
+                Some(arg),
+                captures,
+                Some((param.param_ty_span, param.param_ty.to_string())),
+            );
         }
     }
+
+    fn suggest_adding_lifetime_params(
+        &self,
+        diag: &mut Diagnostic,
+        sub: RegionVid,
+        sup: RegionVid,
+    ) {
+        let (Some(sub), Some(sup)) = (self.to_error_region(sub), self.to_error_region(sup)) else {
+            return
+        };
+
+        let Some((ty_sub, _)) = self
+            .infcx
+            .tcx
+            .is_suitable_region(sub)
+            .and_then(|anon_reg| find_anon_type(self.infcx.tcx, sub, &anon_reg.boundregion)) else {
+            return
+        };
+
+        let Some((ty_sup, _)) = self
+            .infcx
+            .tcx
+            .is_suitable_region(sup)
+            .and_then(|anon_reg| find_anon_type(self.infcx.tcx, sup, &anon_reg.boundregion)) else {
+            return
+        };
+
+        suggest_adding_lifetime_params(self.infcx.tcx, sub, ty_sup, ty_sub, diag);
+    }
 }
index 6dcdd46816e0dbea5a284ec8a88ffa306cbde90a..c4a190b44cbd4816c10bb732e84ab62f4b5a5680 100644 (file)
 use rustc_span::def_id::CRATE_DEF_ID;
 use rustc_span::{Span, DUMMY_SP};
 use rustc_target::abi::VariantIdx;
-use rustc_trait_selection::infer::InferCtxtExt as _;
-use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
 use rustc_trait_selection::traits::query::type_op;
 use rustc_trait_selection::traits::query::type_op::custom::scrape_region_constraints;
 use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
 use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
 use rustc_trait_selection::traits::query::Fallible;
-use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligation};
+use rustc_trait_selection::traits::PredicateObligation;
 
-use rustc_const_eval::transform::{
-    check_consts::ConstCx, promote_consts::is_const_fn_in_array_repeat_expression,
-};
 use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
 use rustc_mir_dataflow::move_paths::MoveData;
 use rustc_mir_dataflow::ResultsCursor;
@@ -1868,41 +1863,17 @@ fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: L
                         Operand::Move(place) => {
                             // Make sure that repeated elements implement `Copy`.
                             let span = body.source_info(location).span;
-                            let ty = operand.ty(body, tcx);
-                            if !self.infcx.type_is_copy_modulo_regions(self.param_env, ty, span) {
-                                let ccx = ConstCx::new_with_param_env(tcx, body, self.param_env);
-                                let is_const_fn =
-                                    is_const_fn_in_array_repeat_expression(&ccx, &place, &body);
-
-                                debug!("check_rvalue: is_const_fn={:?}", is_const_fn);
-
-                                let def_id = body.source.def_id().expect_local();
-                                let obligation = traits::Obligation::new(
-                                    ObligationCause::new(
-                                        span,
-                                        self.tcx().hir().local_def_id_to_hir_id(def_id),
-                                        traits::ObligationCauseCode::RepeatElementCopy {
-                                            is_const_fn,
-                                        },
-                                    ),
-                                    self.param_env,
-                                    ty::Binder::dummy(ty::TraitRef::new(
-                                        self.tcx().require_lang_item(
-                                            LangItem::Copy,
-                                            Some(self.last_span),
-                                        ),
-                                        tcx.mk_substs_trait(ty, &[]),
-                                    ))
-                                    .without_const()
-                                    .to_predicate(self.tcx()),
-                                );
-                                self.infcx.report_selection_error(
-                                    obligation.clone(),
-                                    &obligation,
-                                    &traits::SelectionError::Unimplemented,
-                                    false,
-                                );
-                            }
+                            let ty = place.ty(body, tcx).ty;
+                            let trait_ref = ty::TraitRef::new(
+                                tcx.require_lang_item(LangItem::Copy, Some(span)),
+                                tcx.mk_substs_trait(ty, &[]),
+                            );
+
+                            self.prove_trait_ref(
+                                trait_ref,
+                                Locations::Single(location),
+                                ConstraintCategory::CopyBound,
+                            );
                         }
                     }
                 }
index 030295d3d8dc382e296c1b01dc7f7ecfeeb35c2e..e9e3307ca95dac89f377ba83f0cb894baf27a025 100644 (file)
@@ -1,6 +1,6 @@
 use rustc_ast as ast;
 use rustc_ast::ptr::P;
-use rustc_ast::token;
+use rustc_ast::token::{self, Delimiter};
 use rustc_ast::tokenstream::TokenStream;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::{Applicability, PResult};
@@ -395,9 +395,9 @@ fn parse_options<'a>(
 ) -> PResult<'a, ()> {
     let span_start = p.prev_token.span;
 
-    p.expect(&token::OpenDelim(token::DelimToken::Paren))?;
+    p.expect(&token::OpenDelim(Delimiter::Parenthesis))?;
 
-    while !p.eat(&token::CloseDelim(token::DelimToken::Paren)) {
+    while !p.eat(&token::CloseDelim(Delimiter::Parenthesis)) {
         if !is_global_asm && p.eat_keyword(sym::pure) {
             try_set_option(p, args, sym::pure, ast::InlineAsmOptions::PURE);
         } else if !is_global_asm && p.eat_keyword(sym::nomem) {
@@ -421,7 +421,7 @@ fn parse_options<'a>(
         }
 
         // Allow trailing commas
-        if p.eat(&token::CloseDelim(token::DelimToken::Paren)) {
+        if p.eat(&token::CloseDelim(Delimiter::Parenthesis)) {
             break;
         }
         p.expect(&token::Comma)?;
@@ -436,9 +436,9 @@ fn parse_options<'a>(
 fn parse_clobber_abi<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> PResult<'a, ()> {
     let span_start = p.prev_token.span;
 
-    p.expect(&token::OpenDelim(token::DelimToken::Paren))?;
+    p.expect(&token::OpenDelim(Delimiter::Parenthesis))?;
 
-    if p.eat(&token::CloseDelim(token::DelimToken::Paren)) {
+    if p.eat(&token::CloseDelim(Delimiter::Parenthesis)) {
         let err = p.sess.span_diagnostic.struct_span_err(
             p.token.span,
             "at least one abi must be provided as an argument to `clobber_abi`",
@@ -454,7 +454,7 @@ fn parse_clobber_abi<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> PResult<'a,
             }
             Err(opt_lit) => {
                 // If the non-string literal is a closing paren then it's the end of the list and is fine
-                if p.eat(&token::CloseDelim(token::DelimToken::Paren)) {
+                if p.eat(&token::CloseDelim(Delimiter::Parenthesis)) {
                     break;
                 }
                 let span = opt_lit.map_or(p.token.span, |lit| lit.span);
@@ -466,7 +466,7 @@ fn parse_clobber_abi<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> PResult<'a,
         };
 
         // Allow trailing commas
-        if p.eat(&token::CloseDelim(token::DelimToken::Paren)) {
+        if p.eat(&token::CloseDelim(Delimiter::Parenthesis)) {
             break;
         }
         p.expect(&token::Comma)?;
@@ -501,7 +501,7 @@ fn parse_reg<'a>(
     p: &mut Parser<'a>,
     explicit_reg: &mut bool,
 ) -> PResult<'a, ast::InlineAsmRegOrRegClass> {
-    p.expect(&token::OpenDelim(token::DelimToken::Paren))?;
+    p.expect(&token::OpenDelim(Delimiter::Parenthesis))?;
     let result = match p.token.uninterpolate().kind {
         token::Ident(name, false) => ast::InlineAsmRegOrRegClass::RegClass(name),
         token::Literal(token::Lit { kind: token::LitKind::Str, symbol, suffix: _ }) => {
@@ -515,7 +515,7 @@ fn parse_reg<'a>(
         }
     };
     p.bump();
-    p.expect(&token::CloseDelim(token::DelimToken::Paren))?;
+    p.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
     Ok(result)
 }
 
index 61681ec66a48dfdea63284c47f358021af72b9bb..391c46d18132feb7d1ff29fdee3d1e72fcb3d29b 100644 (file)
@@ -95,6 +95,7 @@ fn dummy_annotatable() -> Annotatable {
         bounds: Default::default(),
         is_placeholder: false,
         kind: GenericParamKind::Lifetime,
+        colon_span: None,
     })
 }
 
index 2c5260616c7da398c6bce5a84e25e4691333aeec..b49331e28753db194fcfa5cc1470473d866382f5 100644 (file)
@@ -235,7 +235,7 @@ fn validate_default_attribute(
             .span_suggestion_hidden(
                 attr.span,
                 "try using `#[default]`",
-                "#[default]".into(),
+                "#[default]",
                 Applicability::MaybeIncorrect,
             )
             .emit();
index 30e9627c48d749f17324ba2dab559af13ba4e956..7b8e43b639f993f97aec41c1da60d8775fdb613a 100644 (file)
@@ -33,18 +33,18 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "cranelift-bforest"
-version = "0.82.1"
+version = "0.83.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d16922317bd7dd104d509a373887822caa0242fc1def00de66abb538db221db4"
+checksum = "ed44413e7e2fe3260d0ed73e6956ab188b69c10ee92b892e401e0f4f6808c68b"
 dependencies = [
  "cranelift-entity",
 ]
 
 [[package]]
 name = "cranelift-codegen"
-version = "0.82.1"
+version = "0.83.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8b80bf40380256307b68a3dcbe1b91cac92a533e212b5b635abc3e4525781a0a"
+checksum = "0b5d83f0f26bf213f971f45589d17e5b65e4861f9ed22392b0cbb6eaa5bd329c"
 dependencies = [
  "cranelift-bforest",
  "cranelift-codegen-meta",
@@ -59,30 +59,30 @@ dependencies = [
 
 [[package]]
 name = "cranelift-codegen-meta"
-version = "0.82.1"
+version = "0.83.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "703d0ed7d3bc6c7a814ca12858175bf4e93167a3584127858c686e4b5dd6e432"
+checksum = "6800dc386177df6ecc5a32680607ed8ba1fa0d31a2a59c8c61fbf44826b8191d"
 dependencies = [
  "cranelift-codegen-shared",
 ]
 
 [[package]]
 name = "cranelift-codegen-shared"
-version = "0.82.1"
+version = "0.83.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "80f52311e1c90de12dcf8c4b9999c6ebfd1ed360373e88c357160936844511f6"
+checksum = "c961f85070985ebc8fcdb81b838a5cf842294d1e6ed4852446161c7e246fd455"
 
 [[package]]
 name = "cranelift-entity"
-version = "0.82.1"
+version = "0.83.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "66bc82ef522c1f643baf7d4d40b7c52643ee4549d8960b0e6a047daacb83f897"
+checksum = "2347b2b8d1d5429213668f2a8e36c85ee3c73984a2f6a79007e365d3e575e7ed"
 
 [[package]]
 name = "cranelift-frontend"
-version = "0.82.1"
+version = "0.83.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3cc35e4251864b17515845ba47447bca88fec9ca1a4186b19fe42526e36140e8"
+checksum = "4cbcdbf7bed29e363568b778649b69dabc3d727256d5d25236096ef693757654"
 dependencies = [
  "cranelift-codegen",
  "log",
@@ -92,9 +92,9 @@ dependencies = [
 
 [[package]]
 name = "cranelift-jit"
-version = "0.82.1"
+version = "0.83.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "93c66d594ad3bfe4e58b1fbd8d17877a7c6564a5f2d6f78cbbf4b0182af1927f"
+checksum = "7c769d4e0d76f59c8b2a3bf0477d89ee149bb0731b53fbb245ee081d49063095"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -110,9 +110,9 @@ dependencies = [
 
 [[package]]
 name = "cranelift-module"
-version = "0.82.1"
+version = "0.83.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf356697c40232aa09e1e3fb8a350ee894e849ccecc4eac56ff0570a4575c325"
+checksum = "0ab57d399a2401074bb0cc40b3031e420f3d66d46ec0cf21eeae53ac04bd73e2"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -120,9 +120,9 @@ dependencies = [
 
 [[package]]
 name = "cranelift-native"
-version = "0.82.1"
+version = "0.83.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b882b2251c9845d509d92aebfdb6c8bb3b3b48e207ac951f21fbd20cfe7f90b3"
+checksum = "8f4cdf93552e5ceb2e3c042829ebb4de4378492705f769eadc6a7c6c5251624c"
 dependencies = [
  "cranelift-codegen",
  "libc",
@@ -131,9 +131,9 @@ dependencies = [
 
 [[package]]
 name = "cranelift-object"
-version = "0.82.1"
+version = "0.83.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2d3f1a88e654e567d2591169239ed157ab290811a729a6468f53999c01001263"
+checksum = "cf8e65f4839c26e6237fc0744911d79b0a2ac5e76b4e4eebd14db2b8d849fd31"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
index 70c03da3f29fa9808169e415ae6417cb99e3eefd..74f50808a980a7de298a943e74ac3c4301f07473 100644 (file)
@@ -8,12 +8,12 @@ crate-type = ["dylib"]
 
 [dependencies]
 # These have to be in sync with each other
-cranelift-codegen = { version = "0.82.1", features = ["unwind", "all-arch"] }
-cranelift-frontend = "0.82.1"
-cranelift-module = "0.82.1"
-cranelift-native = "0.82.1"
-cranelift-jit = { version = "0.82.1", optional = true }
-cranelift-object = "0.82.1"
+cranelift-codegen = { version = "0.83.0", features = ["unwind", "all-arch"] }
+cranelift-frontend = "0.83.0"
+cranelift-module = "0.83.0"
+cranelift-native = "0.83.0"
+cranelift-jit = { version = "0.83.0", optional = true }
+cranelift-object = "0.83.0"
 target-lexicon = "0.12.0"
 gimli = { version = "0.26.0", default-features = false, features = ["write"]}
 object = { version = "0.27.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
index f584f54e106ac060900e01924f65d5e0a17804df..51ba0dbfcc7920e2868531cc897bd70c48a9909b 100644 (file)
@@ -56,9 +56,9 @@ dependencies = [
 
 [[package]]
 name = "compiler_builtins"
-version = "0.1.71"
+version = "0.1.72"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "163437f05ca8f29d7e9128ea728dedf5eb620e445fbca273641d3a3050305f23"
+checksum = "afdbb35d279238cf77f0c9e8d90ad50d6c7bff476ab342baafa29440f0f10bff"
 dependencies = [
  "rustc-std-workspace-core",
 ]
@@ -134,9 +134,9 @@ dependencies = [
 
 [[package]]
 name = "libc"
-version = "0.2.121"
+version = "0.2.124"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "efaa7b300f3b5fe8eb6bf21ce3895e1751d9665086af2d64b42f19701015ff4f"
+checksum = "21a41fed9d98f27ab1c6d161da622a4fa35e8a54a8adc24bbf3ddd0ef70b0e50"
 dependencies = [
  "rustc-std-workspace-core",
 ]
@@ -203,6 +203,7 @@ dependencies = [
 name = "proc_macro"
 version = "0.0.0"
 dependencies = [
+ "core",
  "std",
 ]
 
diff --git a/compiler/rustc_codegen_cranelift/example/float-minmax-pass.rs b/compiler/rustc_codegen_cranelift/example/float-minmax-pass.rs
new file mode 100644 (file)
index 0000000..b8f901d
--- /dev/null
@@ -0,0 +1,53 @@
+// Copied from https://github.com/rust-lang/rust/blob/3fe3b89cd57229343eeca753fdd8c63d9b03c65c/src/test/ui/simd/intrinsic/float-minmax-pass.rs
+// run-pass
+// ignore-emscripten
+
+// Test that the simd_f{min,max} intrinsics produce the correct results.
+
+#![feature(repr_simd, platform_intrinsics)]
+#![allow(non_camel_case_types)]
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+struct f32x4(pub f32, pub f32, pub f32, pub f32);
+
+extern "platform-intrinsic" {
+    fn simd_fmin<T>(x: T, y: T) -> T;
+    fn simd_fmax<T>(x: T, y: T) -> T;
+}
+
+fn main() {
+    let x = f32x4(1.0, 2.0, 3.0, 4.0);
+    let y = f32x4(2.0, 1.0, 4.0, 3.0);
+
+    #[cfg(not(any(target_arch = "mips", target_arch = "mips64")))]
+    let nan = f32::NAN;
+    // MIPS hardware treats f32::NAN as SNAN. Clear the signaling bit.
+    // See https://github.com/rust-lang/rust/issues/52746.
+    #[cfg(any(target_arch = "mips", target_arch = "mips64"))]
+    let nan = f32::from_bits(f32::NAN.to_bits() - 1);
+
+    let n = f32x4(nan, nan, nan, nan);
+
+    unsafe {
+        let min0 = simd_fmin(x, y);
+        let min1 = simd_fmin(y, x);
+        assert_eq!(min0, min1);
+        let e = f32x4(1.0, 1.0, 3.0, 3.0);
+        assert_eq!(min0, e);
+        let minn = simd_fmin(x, n);
+        assert_eq!(minn, x);
+        let minn = simd_fmin(y, n);
+        assert_eq!(minn, y);
+
+        let max0 = simd_fmax(x, y);
+        let max1 = simd_fmax(y, x);
+        assert_eq!(max0, max1);
+        let e = f32x4(2.0, 2.0, 4.0, 4.0);
+        assert_eq!(max0, e);
+        let maxn = simd_fmax(x, n);
+        assert_eq!(maxn, x);
+        let maxn = simd_fmax(y, n);
+        assert_eq!(maxn, y);
+    }
+}
index 7efc8dc785a1912476b3d6e93e9f3f5896d6e39c..8da705e0cb06dbf7f0232bdad8e9ab6f899636d8 100644 (file)
@@ -16,6 +16,9 @@
 #[lang = "sized"]
 pub trait Sized {}
 
+#[lang = "destruct"]
+pub trait Destruct {}
+
 #[lang = "unsize"]
 pub trait Unsize<T: ?Sized> {}
 
@@ -491,13 +494,20 @@ pub trait Deref {
     fn deref(&self) -> &Self::Target;
 }
 
+#[repr(transparent)]
+#[rustc_layout_scalar_valid_range_start(1)]
+#[rustc_nonnull_optimization_guaranteed]
+pub struct NonNull<T: ?Sized>(pub *mut T);
+
+impl<T: ?Sized, U: ?Sized> CoerceUnsized<NonNull<U>> for NonNull<T> where T: Unsize<U> {}
+impl<T: ?Sized, U: ?Sized> DispatchFromDyn<NonNull<U>> for NonNull<T> where T: Unsize<U> {}
+
 pub struct Unique<T: ?Sized> {
-    pub pointer: *const T,
+    pub pointer: NonNull<T>,
     pub _marker: PhantomData<T>,
 }
 
 impl<T: ?Sized, U: ?Sized> CoerceUnsized<Unique<U>> for Unique<T> where T: Unsize<U> {}
-
 impl<T: ?Sized, U: ?Sized> DispatchFromDyn<Unique<U>> for Unique<T> where T: Unsize<U> {}
 
 #[lang = "owned_box"]
@@ -526,7 +536,7 @@ unsafe fn allocate(size: usize, _align: usize) -> *mut u8 {
 
 #[lang = "box_free"]
 unsafe fn box_free<T: ?Sized>(ptr: Unique<T>, alloc: ()) {
-    libc::free(ptr.pointer as *mut u8);
+    libc::free(ptr.pointer.0 as *mut u8);
 }
 
 #[lang = "drop"]
index c4730581335ecbffa29d3c58fc1cfc187b052b86..85ca908d0a266f2e1012ea4d166d1068d7e538dc 100644 (file)
@@ -122,7 +122,7 @@ fn call_return_u128_pair() {
 #[allow(unreachable_code)] // FIXME false positive
 fn main() {
     take_unique(Unique {
-        pointer: 0 as *const (),
+        pointer: unsafe { NonNull(1 as *mut ()) },
         _marker: PhantomData,
     });
     take_f32(0.1);
@@ -173,7 +173,7 @@ fn main() {
         assert!(intrinsics::needs_drop::<NoisyDrop>());
 
         Unique {
-            pointer: 0 as *const &str,
+            pointer: NonNull(1 as *mut &str),
             _marker: PhantomData,
         } as Unique<dyn SomeTrait>;
 
index 5bc51a541b58c7d63b0939976ab2d8869983d24b..0a2bce2621d963f1e6d68e173c5f65522c108a89 100644 (file)
@@ -1,7 +1,8 @@
-#![feature(core_intrinsics, generators, generator_trait, is_sorted)]
+#![feature(core_intrinsics, generators, generator_trait, is_sorted, bench_black_box)]
 
 #[cfg(target_arch = "x86_64")]
 use std::arch::x86_64::*;
+use std::hint::black_box;
 use std::io::Write;
 use std::ops::Generator;
 
@@ -86,6 +87,9 @@ fn main() {
     assert_eq!(houndred_f64 as i128, 100);
     assert_eq!(1u128.rotate_left(2), 4);
 
+    assert_eq!(black_box(f32::NAN) as i128, 0);
+    assert_eq!(black_box(f32::NAN) as u128, 0);
+
     // Test signed 128bit comparing
     let max = usize::MAX as i128;
     if 100i128 < 0i128 || 100i128 > max {
index c13259086917b9c8e996dd8b88d7a142137a0bc5..54e13b090abda43a8d66147207b16c09c27dae64 100644 (file)
@@ -102,42 +102,6 @@ index 6a8ecd3..68fcb49 100644
          }
      }
  }
-diff --git a/crates/core_simd/tests/ops_macros.rs b/crates/core_simd/tests/ops_macros.rs
-index 31b7ee2..bd04b3c 100644
---- a/crates/core_simd/tests/ops_macros.rs
-+++ b/crates/core_simd/tests/ops_macros.rs
-@@ -567,6 +567,7 @@ macro_rules! impl_float_tests {
-                     });
-                 }
-+                /*
-                 fn horizontal_max<const LANES: usize>() {
-                     test_helpers::test_1(&|x| {
-                         let vmax = Vector::<LANES>::from_array(x).horizontal_max();
-@@ -590,6 +591,7 @@ macro_rules! impl_float_tests {
-                         Ok(())
-                     });
-                 }
-+                */
-             }
-             #[cfg(feature = "std")]
-@@ -604,6 +606,7 @@ macro_rules! impl_float_tests {
-                         )
-                     }
-+                    /*
-                     fn mul_add<const LANES: usize>() {
-                         test_helpers::test_ternary_elementwise(
-                             &Vector::<LANES>::mul_add,
-@@ -611,6 +614,7 @@ macro_rules! impl_float_tests {
-                             &|_, _, _| true,
-                         )
-                     }
-+                    */
-                 }
-             }
-         }
 -- 
 2.26.2.7.g19db9cfb68
 
index 84d90e5db02539c3edcc72c5fed578f41368e06c..966097c248b6f6c98d6d250a369f5df0b8d797c9 100644 (file)
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2022-03-19"
+channel = "nightly-2022-04-21"
 components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
index a0e99267c2b705771b9c9cfee2e11a41c12a5cf1..f4e863e5494b51f34154bfc0730cd9758e73b999 100755 (executable)
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
 #![forbid(unsafe_code)]/* This line is ignored by bash
 # This block is ignored by rustc
 pushd $(dirname "$0")/../
index 85c0109c6f61eb6932889a6cd667e0c31cd4f352..cabbaaa8922517351dc70eeb3bb0730f752b0c17 100644 (file)
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
 set -e
 
 ./y.rs build --no-unstable-features
index a32e6df220832847efaef3e86f5dd1b402dc3d5f..4cf24c02235df731a81e36def7900d4c9e390afd 100755 (executable)
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
 set -e
 
 cd $(dirname "$0")/../
@@ -11,7 +11,7 @@ pushd rust
 command -v rg >/dev/null 2>&1 || cargo install ripgrep
 
 rm -r src/test/ui/{extern/,unsized-locals/,lto/,linkage*} || true
-for test in $(rg --files-with-matches "asm!|lto|// needs-asm-support|// needs-unwind" src/test/{ui,incremental}); do
+for test in $(rg --files-with-matches "lto|// needs-asm-support|// needs-unwind" src/test/{ui,incremental}); do
   rm $test
 done
 
@@ -25,14 +25,8 @@ git checkout -- src/test/ui/issues/auxiliary/issue-3136-a.rs # contains //~ERROR
 # ================
 
 # requires stack unwinding
-rm src/test/ui/backtrace.rs
-rm src/test/ui/process/multi-panic.rs
-rm src/test/ui/numbers-arithmetic/issue-8460.rs
 rm src/test/incremental/change_crate_dep_kind.rs
 rm src/test/incremental/issue-80691-bad-eval-cache.rs # -Cpanic=abort causes abort instead of exit(101)
-rm src/test/ui/panic-while-printing.rs
-rm src/test/ui/test-attrs/test-panic-while-printing.rs
-rm src/test/ui/test-attrs/test-type.rs
 
 # requires compiling with -Cpanic=unwind
 rm src/test/ui/test-attrs/test-fn-signature-verification-for-explicit-return-type.rs # "Cannot run dynamic test fn out-of-process"
@@ -85,8 +79,6 @@ rm src/test/ui/abi/stack-protector.rs # requires stack protector support
 
 # giving different but possibly correct results
 # =============================================
-rm src/test/ui/numbers-arithmetic/saturating-float-casts.rs # intrinsic gives different but valid result
-rm src/test/ui/simd/intrinsic/float-minmax-pass.rs # same
 rm src/test/ui/mir/mir_misc_casts.rs # depends on deduplication of constants
 rm src/test/ui/mir/mir_raw_fat_ptr.rs # same
 rm src/test/ui/consts/issue-33537.rs # same
@@ -112,9 +104,14 @@ rm src/test/ui/mir/ssa-analysis-regression-50041.rs # produces ICE
 
 rm src/test/ui/simd/intrinsic/generic-reduction-pass.rs # simd_reduce_add_unordered doesn't accept an accumulator for integer vectors
 
+rm src/test/ui/rfc-2091-track-caller/intrinsic-wrapper.rs # wrong result from `Location::caller()`
+
 # bugs in the test suite
 # ======================
-rm src/test/ui/unsafe/union.rs # has UB caught by cg_clif. see rust-lang/rust#95075
+rm src/test/ui/backtrace.rs # TODO warning
+rm src/test/ui/empty_global_asm.rs # TODO add needs-asm-support
+rm src/test/ui/simple_global_asm.rs # TODO add needs-asm-support
+rm src/test/ui/test-attrs/test-type.rs # TODO panic message on stderr. correct stdout
 
 echo "[TEST] rustc test suite"
 RUST_TEST_NOCAPTURE=1 COMPILETEST_FORCE_STAGE0=1 ./x.py test --stage 0 src/test/{codegen-units,run-make,run-pass-valgrind,ui,incremental}
index fee1012c8f1dc4196df3f6e8293c75f24faa315d..aae626081f62be5c93b3e7d92c08c811105c4d8f 100755 (executable)
@@ -72,6 +72,10 @@ function base_sysroot_tests() {
     $MY_RUSTC example/track-caller-attribute.rs --crate-type bin -Cpanic=abort --target "$TARGET_TRIPLE"
     $RUN_WRAPPER ./target/out/track-caller-attribute
 
+    echo "[AOT] float-minmax-pass"
+    $MY_RUSTC example/float-minmax-pass.rs --crate-type bin -Cpanic=abort --target "$TARGET_TRIPLE"
+    $RUN_WRAPPER ./target/out/float-minmax-pass
+
     echo "[AOT] mod_bench"
     $MY_RUSTC example/mod_bench.rs --crate-type bin --target "$TARGET_TRIPLE"
     $RUN_WRAPPER ./target/out/mod_bench
index 8c45993a8b76bf7e4a171be65c81def5e6e6025c..65346cb39622aa0e7bc2a7de747820af62b3d519 100644 (file)
@@ -821,7 +821,8 @@ pub(crate) fn codegen_place<'tcx>(
                 if cplace.layout().ty.is_box() {
                     cplace = cplace
                         .place_field(fx, Field::new(0)) // Box<T> -> Unique<T>
-                        .place_field(fx, Field::new(0)) // Unique<T> -> *const T
+                        .place_field(fx, Field::new(0)) // Unique<T> -> NonNull<T>
+                        .place_field(fx, Field::new(0)) // NonNull<T> -> *mut T
                         .place_deref(fx);
                 } else {
                     cplace = cplace.place_deref(fx);
index e7e6afeb865bb005bf436b7ec6e2802930dc7fe2..e19070774c6e0c246662f55ed06e4cf5a53f17e0 100644 (file)
@@ -84,7 +84,7 @@ pub(crate) fn clif_int_or_float_cast(
             fx.bcx.ins().fcvt_from_uint(to_ty, from)
         }
     } else if from_ty.is_float() && to_ty.is_int() {
-        if to_ty == types::I128 {
+        let val = if to_ty == types::I128 {
             // _____sssf___
             // __fix   sfti: f32 -> i128
             // __fix   dfti: f64 -> i128
@@ -109,13 +109,9 @@ pub(crate) fn clif_int_or_float_cast(
 
             let to_rust_ty = if to_signed { fx.tcx.types.i128 } else { fx.tcx.types.u128 };
 
-            return fx
-                .easy_call(&name, &[CValue::by_val(from, fx.layout_of(from_rust_ty))], to_rust_ty)
-                .load_scalar(fx);
-        }
-
-        // float -> int-like
-        if to_ty == types::I8 || to_ty == types::I16 {
+            fx.easy_call(&name, &[CValue::by_val(from, fx.layout_of(from_rust_ty))], to_rust_ty)
+                .load_scalar(fx)
+        } else if to_ty == types::I8 || to_ty == types::I16 {
             // FIXME implement fcvt_to_*int_sat.i8/i16
             let val = if to_signed {
                 fx.bcx.ins().fcvt_to_sint_sat(types::I32, from)
@@ -146,6 +142,23 @@ pub(crate) fn clif_int_or_float_cast(
             fx.bcx.ins().fcvt_to_sint_sat(to_ty, from)
         } else {
             fx.bcx.ins().fcvt_to_uint_sat(to_ty, from)
+        };
+
+        if let Some(false) = fx.tcx.sess.opts.debugging_opts.saturating_float_casts {
+            return val;
+        }
+
+        let is_not_nan = fx.bcx.ins().fcmp(FloatCC::Equal, from, from);
+        if to_ty == types::I128 {
+            // FIXME(bytecodealliance/wasmtime#3963): select.i128 on fcmp eq miscompiles
+            let (lsb, msb) = fx.bcx.ins().isplit(val);
+            let zero = fx.bcx.ins().iconst(types::I64, 0);
+            let lsb = fx.bcx.ins().select(is_not_nan, lsb, zero);
+            let msb = fx.bcx.ins().select(is_not_nan, msb, zero);
+            fx.bcx.ins().iconcat(lsb, msb)
+        } else {
+            let zero = fx.bcx.ins().iconst(to_ty, 0);
+            fx.bcx.ins().select(is_not_nan, val, zero)
         }
     } else if from_ty.is_float() && to_ty.is_float() {
         // float -> float
index eef3c8c8d6e2b38170209854f34c5c441ad59b5b..e59a0cb0a23237bfe0b4fd0164909db4d8a98e49 100644 (file)
@@ -48,12 +48,6 @@ pub struct BackendConfig {
     /// Can be set using `-Cllvm-args=display_cg_time=...`.
     pub display_cg_time: bool,
 
-    /// The register allocator to use.
-    ///
-    /// Defaults to the value of `CG_CLIF_REGALLOC` or `backtracking` otherwise. Can be set using
-    /// `-Cllvm-args=regalloc=...`.
-    pub regalloc: String,
-
     /// Enable the Cranelift ir verifier for all compilation passes. If not set it will only run
     /// once before passing the clif ir to Cranelift for compilation.
     ///
@@ -80,8 +74,6 @@ fn default() -> Self {
                 args.split(' ').map(|arg| arg.to_string()).collect()
             },
             display_cg_time: bool_env_var("CG_CLIF_DISPLAY_CG_TIME"),
-            regalloc: std::env::var("CG_CLIF_REGALLOC")
-                .unwrap_or_else(|_| "backtracking".to_string()),
             enable_verifier: cfg!(debug_assertions) || bool_env_var("CG_CLIF_ENABLE_VERIFIER"),
             disable_incr_cache: bool_env_var("CG_CLIF_DISABLE_INCR_CACHE"),
         }
@@ -101,7 +93,6 @@ fn parse_bool(name: &str, value: &str) -> Result<bool, String> {
                 match name {
                     "mode" => config.codegen_mode = value.parse()?,
                     "display_cg_time" => config.display_cg_time = parse_bool(name, value)?,
-                    "regalloc" => config.regalloc = value.to_string(),
                     "enable_verifier" => config.enable_verifier = parse_bool(name, value)?,
                     "disable_incr_cache" => config.disable_incr_cache = parse_bool(name, value)?,
                     _ => return Err(format!("Unknown option `{}`", name)),
index 357cb4a6d246fa451a1b42ff3413df5455ef3f81..f619bb5ed5e586ae33f5b7711095613bdad14472 100644 (file)
@@ -128,8 +128,16 @@ pub(crate) fn codegen_get_discriminant<'tcx>(
             let relative_discr = if niche_start == 0 {
                 tag
             } else {
-                // FIXME handle niche_start > i64::MAX
-                fx.bcx.ins().iadd_imm(tag, -i64::try_from(niche_start).unwrap())
+                let niche_start = match fx.bcx.func.dfg.value_type(tag) {
+                    types::I128 => {
+                        let lsb = fx.bcx.ins().iconst(types::I64, niche_start as u64 as i64);
+                        let msb =
+                            fx.bcx.ins().iconst(types::I64, (niche_start >> 64) as u64 as i64);
+                        fx.bcx.ins().iconcat(lsb, msb)
+                    }
+                    ty => fx.bcx.ins().iconst(ty, niche_start as i64),
+                };
+                fx.bcx.ins().isub(tag, niche_start)
             };
             let relative_max = niche_variants.end().as_u32() - niche_variants.start().as_u32();
             let is_niche = {
index 310d27c6decf6c87e66bd21a5148912eb0c9f070..d76dfca7960c4a220871c57b8fc1f020f5cab588 100644 (file)
@@ -1019,39 +1019,23 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
             ret.write_cvalue(fx, old);
         };
 
-        // In Rust floating point min and max don't propagate NaN. In Cranelift they do however.
-        // For this reason it is necessary to use `a.is_nan() ? b : (a >= b ? b : a)` for `minnumf*`
-        // and `a.is_nan() ? b : (a <= b ? b : a)` for `maxnumf*`. NaN checks are done by comparing
-        // a float against itself. Only in case of NaN is it not equal to itself.
         minnumf32, (v a, v b) {
-            let a_is_nan = fx.bcx.ins().fcmp(FloatCC::NotEqual, a, a);
-            let a_ge_b = fx.bcx.ins().fcmp(FloatCC::GreaterThanOrEqual, a, b);
-            let temp = fx.bcx.ins().select(a_ge_b, b, a);
-            let val = fx.bcx.ins().select(a_is_nan, b, temp);
+            let val = crate::num::codegen_float_min(fx, a, b);
             let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f32));
             ret.write_cvalue(fx, val);
         };
         minnumf64, (v a, v b) {
-            let a_is_nan = fx.bcx.ins().fcmp(FloatCC::NotEqual, a, a);
-            let a_ge_b = fx.bcx.ins().fcmp(FloatCC::GreaterThanOrEqual, a, b);
-            let temp = fx.bcx.ins().select(a_ge_b, b, a);
-            let val = fx.bcx.ins().select(a_is_nan, b, temp);
+            let val = crate::num::codegen_float_min(fx, a, b);
             let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f64));
             ret.write_cvalue(fx, val);
         };
         maxnumf32, (v a, v b) {
-            let a_is_nan = fx.bcx.ins().fcmp(FloatCC::NotEqual, a, a);
-            let a_le_b = fx.bcx.ins().fcmp(FloatCC::LessThanOrEqual, a, b);
-            let temp = fx.bcx.ins().select(a_le_b, b, a);
-            let val = fx.bcx.ins().select(a_is_nan, b, temp);
+            let val = crate::num::codegen_float_max(fx, a, b);
             let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f32));
             ret.write_cvalue(fx, val);
         };
         maxnumf64, (v a, v b) {
-            let a_is_nan = fx.bcx.ins().fcmp(FloatCC::NotEqual, a, a);
-            let a_le_b = fx.bcx.ins().fcmp(FloatCC::LessThanOrEqual, a, b);
-            let temp = fx.bcx.ins().select(a_le_b, b, a);
-            let val = fx.bcx.ins().select(a_is_nan, b, temp);
+            let val = crate::num::codegen_float_max(fx, a, b);
             let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f64));
             ret.write_cvalue(fx, val);
         };
index bc21d736166277ce3f664fe926b17adb34841578..d1ca9edf2e0f1bb578889566bc8384c5bf5bfc1c 100644 (file)
@@ -322,20 +322,21 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
             }
             assert_eq!(a.layout(), b.layout());
             assert_eq!(a.layout(), c.layout());
-            let layout = a.layout();
+            assert_eq!(a.layout(), ret.layout());
 
-            let (lane_count, _lane_ty) = layout.ty.simd_size_and_type(fx.tcx);
-            let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx);
-            assert_eq!(lane_count, ret_lane_count);
-            let ret_lane_layout = fx.layout_of(ret_lane_ty);
+            let layout = a.layout();
+            let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx);
 
             for lane in 0..lane_count {
-                let a_lane = a.value_lane(fx, lane).load_scalar(fx);
-                let b_lane = b.value_lane(fx, lane).load_scalar(fx);
-                let c_lane = c.value_lane(fx, lane).load_scalar(fx);
+                let a_lane = a.value_lane(fx, lane);
+                let b_lane = b.value_lane(fx, lane);
+                let c_lane = c.value_lane(fx, lane);
 
-                let mul_lane = fx.bcx.ins().fmul(a_lane, b_lane);
-                let res_lane = CValue::by_val(fx.bcx.ins().fadd(mul_lane, c_lane), ret_lane_layout);
+                let res_lane = match lane_ty.kind() {
+                    ty::Float(FloatTy::F32) => fx.easy_call("fmaf", &[a_lane, b_lane, c_lane], lane_ty),
+                    ty::Float(FloatTy::F64) => fx.easy_call("fma", &[a_lane, b_lane, c_lane], lane_ty),
+                    _ => unreachable!(),
+                };
 
                 ret.place_lane(fx, lane).write_cvalue(fx, res_lane);
             }
@@ -354,8 +355,8 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
                     _ => unreachable!("{:?}", lane_ty),
                 }
                 match intrinsic {
-                    sym::simd_fmin => fx.bcx.ins().fmin(x_lane, y_lane),
-                    sym::simd_fmax => fx.bcx.ins().fmax(x_lane, y_lane),
+                    sym::simd_fmin => crate::num::codegen_float_min(fx, x_lane, y_lane),
+                    sym::simd_fmax => crate::num::codegen_float_max(fx, x_lane, y_lane),
                     _ => unreachable!(),
                 }
             });
@@ -495,7 +496,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
                 let lt = match ty.kind() {
                     ty::Int(_) => fx.bcx.ins().icmp(IntCC::SignedLessThan, a, b),
                     ty::Uint(_) => fx.bcx.ins().icmp(IntCC::UnsignedLessThan, a, b),
-                    ty::Float(_) => fx.bcx.ins().fcmp(FloatCC::LessThan, a, b),
+                    ty::Float(_) => return crate::num::codegen_float_min(fx, a, b),
                     _ => unreachable!(),
                 };
                 fx.bcx.ins().select(lt, a, b)
@@ -512,7 +513,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
                 let gt = match ty.kind() {
                     ty::Int(_) => fx.bcx.ins().icmp(IntCC::SignedGreaterThan, a, b),
                     ty::Uint(_) => fx.bcx.ins().icmp(IntCC::UnsignedGreaterThan, a, b),
-                    ty::Float(_) => fx.bcx.ins().fcmp(FloatCC::GreaterThan, a, b),
+                    ty::Float(_) => return crate::num::codegen_float_max(fx, a, b),
                     _ => unreachable!(),
                 };
                 fx.bcx.ins().select(gt, a, b)
index 878b9390e1318c6c650cf56fb0ed6a3b1c132682..9d2e12f98984ae366b37472015543a0adcee4559 100644 (file)
@@ -256,8 +256,6 @@ fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Box<dyn isa::Tar
 
     flags_builder.set("enable_llvm_abi_extensions", "true").unwrap();
 
-    flags_builder.set("regalloc", &backend_config.regalloc).unwrap();
-
     use rustc_session::config::OptLevel;
     match sess.opts.optimize {
         OptLevel::No => {
index 545d390e269957f1ef94c48b83d2c1e10b5f953f..4ce8adb182e0fab68756d06f3fad196f1bf5a770 100644 (file)
@@ -420,3 +420,21 @@ pub(crate) fn codegen_ptr_binop<'tcx>(
         CValue::by_val(fx.bcx.ins().bint(types::I8, res), fx.layout_of(fx.tcx.types.bool))
     }
 }
+
+// In Rust floating point min and max don't propagate NaN. In Cranelift they do however.
+// For this reason it is necessary to use `a.is_nan() ? b : (a >= b ? b : a)` for `minnumf*`
+// and `a.is_nan() ? b : (a <= b ? b : a)` for `maxnumf*`. NaN checks are done by comparing
+// a float against itself. Only in case of NaN is it not equal to itself.
+pub(crate) fn codegen_float_min(fx: &mut FunctionCx<'_, '_, '_>, a: Value, b: Value) -> Value {
+    let a_is_nan = fx.bcx.ins().fcmp(FloatCC::NotEqual, a, a);
+    let a_ge_b = fx.bcx.ins().fcmp(FloatCC::GreaterThanOrEqual, a, b);
+    let temp = fx.bcx.ins().select(a_ge_b, b, a);
+    fx.bcx.ins().select(a_is_nan, b, temp)
+}
+
+pub(crate) fn codegen_float_max(fx: &mut FunctionCx<'_, '_, '_>, a: Value, b: Value) -> Value {
+    let a_is_nan = fx.bcx.ins().fcmp(FloatCC::NotEqual, a, a);
+    let a_le_b = fx.bcx.ins().fcmp(FloatCC::LessThanOrEqual, a, b);
+    let temp = fx.bcx.ins().select(a_le_b, b, a);
+    fx.bcx.ins().select(a_is_nan, b, temp)
+}
index 497a28354d813b837c378a3ae87b857c02768908..58996a9db78ad4e0dfbd315ea85af833e7137413 100644 (file)
@@ -139,14 +139,12 @@ fn target_features(&self, sess: &Session) -> Vec<Symbol> {
 }
 
 impl ExtraBackendMethods for GccCodegenBackend {
-    fn new_metadata<'tcx>(&self, _tcx: TyCtxt<'tcx>, _mod_name: &str) -> Self::Module {
-        GccContext {
+    fn codegen_allocator<'tcx>(&self, tcx: TyCtxt<'tcx>, module_name: &str, kind: AllocatorKind, has_alloc_error_handler: bool) -> Self::Module {
+        let mut mods = GccContext {
             context: Context::default(),
-        }
-    }
-
-    fn codegen_allocator<'tcx>(&self, tcx: TyCtxt<'tcx>, mods: &mut Self::Module, module_name: &str, kind: AllocatorKind, has_alloc_error_handler: bool) {
-        unsafe { allocator::codegen(tcx, mods, module_name, kind, has_alloc_error_handler) }
+        };
+        unsafe { allocator::codegen(tcx, &mut mods, module_name, kind, has_alloc_error_handler); }
+        mods
     }
 
     fn compile_codegen_unit<'tcx>(&self, tcx: TyCtxt<'tcx>, cgu_name: Symbol) -> (ModuleCodegen<Self::Module>, u64) {
@@ -213,7 +211,7 @@ fn run_fat_lto(_cgcx: &CodegenContext<Self>, mut modules: Vec<FatLTOInput<Self>>
                     unimplemented!();
                 }
             };
-        Ok(LtoModuleCodegen::Fat { module: Some(module), _serialized_bitcode: vec![] })
+        Ok(LtoModuleCodegen::Fat { module, _serialized_bitcode: vec![] })
     }
 
     fn run_thin_lto(_cgcx: &CodegenContext<Self>, _modules: Vec<(String, Self::ThinBuffer)>, _cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>) -> Result<(Vec<LtoModuleCodegen<Self>>, Vec<WorkProduct>), FatalError> {
@@ -229,7 +227,12 @@ unsafe fn optimize(_cgcx: &CodegenContext<Self>, _diag_handler: &Handler, module
         Ok(())
     }
 
-    unsafe fn optimize_thin(_cgcx: &CodegenContext<Self>, _thin: &mut ThinModule<Self>) -> Result<ModuleCodegen<Self::Module>, FatalError> {
+    fn optimize_fat(_cgcx: &CodegenContext<Self>, _module: &mut ModuleCodegen<Self::Module>) -> Result<(), FatalError> {
+        // TODO(antoyo)
+        Ok(())
+    }
+
+    unsafe fn optimize_thin(_cgcx: &CodegenContext<Self>, _thin: ThinModule<Self>) -> Result<ModuleCodegen<Self::Module>, FatalError> {
         unimplemented!();
     }
 
@@ -245,11 +248,6 @@ fn serialize_module(_module: ModuleCodegen<Self::Module>) -> (String, Self::Modu
         unimplemented!();
     }
 
-    fn run_lto_pass_manager(_cgcx: &CodegenContext<Self>, _module: &ModuleCodegen<Self::Module>, _config: &ModuleConfig, _thin: bool) -> Result<(), FatalError> {
-        // TODO(antoyo)
-        Ok(())
-    }
-
     fn run_link(cgcx: &CodegenContext<Self>, diag_handler: &Handler, modules: Vec<ModuleCodegen<Self::Module>>) -> Result<ModuleCodegen<Self::Module>, FatalError> {
         back::write::link(cgcx, diag_handler, modules)
     }
index 7a747a9cdee4ead49b6894f5dc730a0ac94e729e..b5b2a27d2378da7bd7271d263739726253aa7cc4 100644 (file)
@@ -6,9 +6,7 @@
 use crate::{llvm_util, LlvmCodegenBackend, ModuleLlvm};
 use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule, ThinShared};
 use rustc_codegen_ssa::back::symbol_export;
-use rustc_codegen_ssa::back::write::{
-    CodegenContext, FatLTOInput, ModuleConfig, TargetMachineFactoryConfig,
-};
+use rustc_codegen_ssa::back::write::{CodegenContext, FatLTOInput, TargetMachineFactoryConfig};
 use rustc_codegen_ssa::traits::*;
 use rustc_codegen_ssa::{looks_like_rust_object_file, ModuleCodegen, ModuleKind};
 use rustc_data_structures::fx::FxHashMap;
@@ -16,7 +14,7 @@
 use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_middle::bug;
 use rustc_middle::dep_graph::WorkProduct;
-use rustc_middle::middle::exported_symbols::SymbolExportLevel;
+use rustc_middle::middle::exported_symbols::{SymbolExportInfo, SymbolExportLevel};
 use rustc_session::cgu_reuse_tracker::CguReuse;
 use rustc_session::config::{self, CrateType, Lto};
 use tracing::{debug, info};
@@ -55,8 +53,8 @@ fn prepare_lto(
         Lto::No => panic!("didn't request LTO but we're doing LTO"),
     };
 
-    let symbol_filter = &|&(ref name, level): &(String, SymbolExportLevel)| {
-        if level.is_below_threshold(export_threshold) {
+    let symbol_filter = &|&(ref name, info): &(String, SymbolExportInfo)| {
+        if info.level.is_below_threshold(export_threshold) || info.used {
             Some(CString::new(name.as_str()).unwrap())
         } else {
             None
@@ -353,7 +351,7 @@ fn fat_lto(
         }
     }
 
-    Ok(LtoModuleCodegen::Fat { module: Some(module), _serialized_bitcode: serialized_bitcode })
+    Ok(LtoModuleCodegen::Fat { module, _serialized_bitcode: serialized_bitcode })
 }
 
 crate struct Linker<'a>(&'a mut llvm::Linker<'a>);
@@ -578,11 +576,11 @@ fn thin_lto(
 pub(crate) fn run_pass_manager(
     cgcx: &CodegenContext<LlvmCodegenBackend>,
     diag_handler: &Handler,
-    module: &ModuleCodegen<ModuleLlvm>,
-    config: &ModuleConfig,
+    module: &mut ModuleCodegen<ModuleLlvm>,
     thin: bool,
 ) -> Result<(), FatalError> {
     let _timer = cgcx.prof.extra_verbose_generic_activity("LLVM_lto_optimize", &*module.name);
+    let config = cgcx.config(module.kind);
 
     // Now we have one massive module inside of llmod. Time to run the
     // LTO-specific optimization passes that LLVM provides.
@@ -625,7 +623,7 @@ pub(crate) fn run_pass_manager(
             if thin {
                 llvm::LLVMRustPassManagerBuilderPopulateThinLTOPassManager(b, pm);
             } else {
-                llvm::LLVMPassManagerBuilderPopulateLTOPassManager(
+                llvm::LLVMRustPassManagerBuilderPopulateLTOPassManager(
                     b, pm, /* Internalize = */ False, /* RunInliner = */ True,
                 );
             }
@@ -726,7 +724,7 @@ fn drop(&mut self) {
 }
 
 pub unsafe fn optimize_thin_module(
-    thin_module: &mut ThinModule<LlvmCodegenBackend>,
+    thin_module: ThinModule<LlvmCodegenBackend>,
     cgcx: &CodegenContext<LlvmCodegenBackend>,
 ) -> Result<ModuleCodegen<ModuleLlvm>, FatalError> {
     let diag_handler = cgcx.create_diag_handler();
@@ -743,7 +741,7 @@ pub unsafe fn optimize_thin_module(
     // that LLVM Context and Module.
     let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names);
     let llmod_raw = parse_module(llcx, module_name, thin_module.data(), &diag_handler)? as *const _;
-    let module = ModuleCodegen {
+    let mut module = ModuleCodegen {
         module_llvm: ModuleLlvm { llmod_raw, llcx, tm },
         name: thin_module.name().to_string(),
         kind: ModuleKind::Regular,
@@ -859,8 +857,7 @@ pub unsafe fn optimize_thin_module(
         // little differently.
         {
             info!("running thin lto passes over {}", module.name);
-            let config = cgcx.config(module.kind);
-            run_pass_manager(cgcx, &diag_handler, &module, config, true)?;
+            run_pass_manager(cgcx, &diag_handler, &mut module, true)?;
             save_temp_bitcode(cgcx, &module, "thin-lto-after-pm");
         }
     }
index 7ef3b12cd08dab5c5a2b7f71ca1ceb70668c388d..99e30531c226f0aa5d3dd08c6d8b05943f311887 100644 (file)
@@ -523,6 +523,12 @@ pub(crate) unsafe fn optimize(
     let module_name = module.name.clone();
     let module_name = Some(&module_name[..]);
 
+    if let Some(false) = config.new_llvm_pass_manager && llvm_util::get_version() >= (15, 0, 0) {
+        diag_handler.warn(
+            "ignoring `-Z new-llvm-pass-manager=no`, which is no longer supported with LLVM 15",
+        );
+    }
+
     if config.emit_no_opt_bc {
         let out = cgcx.output_filenames.temp_path_ext("no-opt.bc", module_name);
         let out = path_to_c_string(&out);
@@ -628,8 +634,8 @@ pub(crate) unsafe fn optimize(
                         extra_passes.as_ptr(),
                         extra_passes.len() as size_t,
                     );
-                    llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(b, fpm);
-                    llvm::LLVMPassManagerBuilderPopulateModulePassManager(b, mpm);
+                    llvm::LLVMRustPassManagerBuilderPopulateFunctionPassManager(b, fpm);
+                    llvm::LLVMRustPassManagerBuilderPopulateModulePassManager(b, mpm);
                 });
 
                 have_name_anon_globals_pass = have_name_anon_globals_pass || prepare_for_thin_lto;
@@ -1085,7 +1091,7 @@ pub unsafe fn with_llvm_pmb(
     // Create the PassManagerBuilder for LLVM. We configure it with
     // reasonable defaults and prepare it to actually populate the pass
     // manager.
-    let builder = llvm::LLVMPassManagerBuilderCreate();
+    let builder = llvm::LLVMRustPassManagerBuilderCreate();
     let opt_size = config.opt_size.map_or(llvm::CodeGenOptSizeNone, |x| to_llvm_opt_settings(x).1);
     let inline_threshold = config.inline_threshold;
     let pgo_gen_path = get_pgo_gen_path(config);
@@ -1102,14 +1108,9 @@ pub unsafe fn with_llvm_pmb(
         pgo_gen_path.as_ref().map_or(ptr::null(), |s| s.as_ptr()),
         pgo_use_path.as_ref().map_or(ptr::null(), |s| s.as_ptr()),
         pgo_sample_use_path.as_ref().map_or(ptr::null(), |s| s.as_ptr()),
+        opt_size as c_int,
     );
 
-    llvm::LLVMPassManagerBuilderSetSizeLevel(builder, opt_size as u32);
-
-    if opt_size != llvm::CodeGenOptSizeNone {
-        llvm::LLVMPassManagerBuilderSetDisableUnrollLoops(builder, 1);
-    }
-
     llvm::LLVMRustAddBuilderLibraryInfo(builder, llmod, config.no_builtins);
 
     // Here we match what clang does (kinda). For O0 we only inline
@@ -1118,16 +1119,16 @@ pub unsafe fn with_llvm_pmb(
     // thresholds copied from clang.
     match (opt_level, opt_size, inline_threshold) {
         (.., Some(t)) => {
-            llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, t);
+            llvm::LLVMRustPassManagerBuilderUseInlinerWithThreshold(builder, t);
         }
         (llvm::CodeGenOptLevel::Aggressive, ..) => {
-            llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 275);
+            llvm::LLVMRustPassManagerBuilderUseInlinerWithThreshold(builder, 275);
         }
         (_, llvm::CodeGenOptSizeDefault, _) => {
-            llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 75);
+            llvm::LLVMRustPassManagerBuilderUseInlinerWithThreshold(builder, 75);
         }
         (_, llvm::CodeGenOptSizeAggressive, _) => {
-            llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 25);
+            llvm::LLVMRustPassManagerBuilderUseInlinerWithThreshold(builder, 25);
         }
         (llvm::CodeGenOptLevel::None, ..) => {
             llvm::LLVMRustAddAlwaysInlinePass(builder, config.emit_lifetime_markers);
@@ -1136,12 +1137,12 @@ pub unsafe fn with_llvm_pmb(
             llvm::LLVMRustAddAlwaysInlinePass(builder, config.emit_lifetime_markers);
         }
         (llvm::CodeGenOptLevel::Default, ..) => {
-            llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 225);
+            llvm::LLVMRustPassManagerBuilderUseInlinerWithThreshold(builder, 225);
         }
     }
 
     f(builder);
-    llvm::LLVMPassManagerBuilderDispose(builder);
+    llvm::LLVMRustPassManagerBuilderDispose(builder);
 }
 
 // Create a `__imp_<symbol> = &symbol` global for every public static `symbol`.
index 76caa3ceaafae81e741973af657b401a9bcf5447..99e4ded62f1a7f3ae75997b134c8677173182e76 100644 (file)
@@ -20,7 +20,6 @@ pub fn compute_mir_scopes<'ll, 'tcx>(
     cx: &CodegenCx<'ll, 'tcx>,
     instance: Instance<'tcx>,
     mir: &Body<'tcx>,
-    fn_dbg_scope: &'ll DIScope,
     debug_context: &mut FunctionDebugContext<&'ll DIScope, &'ll DILocation>,
 ) {
     // Find all scopes with variables defined in them.
@@ -38,40 +37,41 @@ pub fn compute_mir_scopes<'ll, 'tcx>(
         // Nothing to emit, of course.
         None
     };
-
+    let mut instantiated = BitSet::new_empty(mir.source_scopes.len());
     // Instantiate all scopes.
     for idx in 0..mir.source_scopes.len() {
         let scope = SourceScope::new(idx);
-        make_mir_scope(cx, instance, mir, fn_dbg_scope, &variables, debug_context, scope);
+        make_mir_scope(cx, instance, mir, &variables, debug_context, &mut instantiated, scope);
     }
+    assert!(instantiated.count() == mir.source_scopes.len());
 }
 
 fn make_mir_scope<'ll, 'tcx>(
     cx: &CodegenCx<'ll, 'tcx>,
     instance: Instance<'tcx>,
     mir: &Body<'tcx>,
-    fn_dbg_scope: &'ll DIScope,
     variables: &Option<BitSet<SourceScope>>,
     debug_context: &mut FunctionDebugContext<&'ll DIScope, &'ll DILocation>,
+    instantiated: &mut BitSet<SourceScope>,
     scope: SourceScope,
 ) {
-    if debug_context.scopes[scope].dbg_scope.is_some() {
+    if instantiated.contains(scope) {
         return;
     }
 
     let scope_data = &mir.source_scopes[scope];
     let parent_scope = if let Some(parent) = scope_data.parent_scope {
-        make_mir_scope(cx, instance, mir, fn_dbg_scope, variables, debug_context, parent);
+        make_mir_scope(cx, instance, mir, variables, debug_context, instantiated, parent);
         debug_context.scopes[parent]
     } else {
         // The root is the function itself.
         let loc = cx.lookup_debug_loc(mir.span.lo());
         debug_context.scopes[scope] = DebugScope {
-            dbg_scope: Some(fn_dbg_scope),
-            inlined_at: None,
             file_start_pos: loc.file.start_pos,
             file_end_pos: loc.file.end_pos,
+            ..debug_context.scopes[scope]
         };
+        instantiated.insert(scope);
         return;
     };
 
@@ -79,6 +79,7 @@ fn make_mir_scope<'ll, 'tcx>(
         // Do not create a DIScope if there are no variables defined in this
         // MIR `SourceScope`, and it's not `inlined`, to avoid debuginfo bloat.
         debug_context.scopes[scope] = parent_scope;
+        instantiated.insert(scope);
         return;
     }
 
@@ -100,7 +101,7 @@ fn make_mir_scope<'ll, 'tcx>(
         None => unsafe {
             llvm::LLVMRustDIBuilderCreateLexicalBlock(
                 DIB(cx),
-                parent_scope.dbg_scope.unwrap(),
+                parent_scope.dbg_scope,
                 file_metadata,
                 loc.line,
                 loc.col,
@@ -116,9 +117,10 @@ fn make_mir_scope<'ll, 'tcx>(
     });
 
     debug_context.scopes[scope] = DebugScope {
-        dbg_scope: Some(dbg_scope),
+        dbg_scope,
         inlined_at: inlined_at.or(parent_scope.inlined_at),
         file_start_pos: loc.file.start_pos,
         file_end_pos: loc.file.end_pos,
     };
+    instantiated.insert(scope);
 }
index 74e194750faddffe269347358d223140586a3bfc..f2cf3b1ef5c1eea396fdd208024118f7a9b7deb6 100644 (file)
@@ -437,11 +437,9 @@ pub fn type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll D
 
     let DINodeCreationResult { di_node, already_stored_in_typemap } = match *t.kind() {
         ty::Never | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) => {
-            DINodeCreationResult::new(build_basic_type_di_node(cx, t), false)
-        }
-        ty::Tuple(elements) if elements.is_empty() => {
-            DINodeCreationResult::new(build_basic_type_di_node(cx, t), false)
+            build_basic_type_di_node(cx, t)
         }
+        ty::Tuple(elements) if elements.is_empty() => build_basic_type_di_node(cx, t),
         ty::Array(..) => build_fixed_size_array_di_node(cx, unique_type_id, t),
         ty::Slice(_) | ty::Str => build_slice_type_di_node(cx, t, unique_type_id),
         ty::Dynamic(..) => build_dyn_type_di_node(cx, t, unique_type_id),
@@ -640,7 +638,10 @@ fn msvc_basic_name(self) -> &'static str {
     }
 }
 
-fn build_basic_type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType {
+fn build_basic_type_di_node<'ll, 'tcx>(
+    cx: &CodegenCx<'ll, 'tcx>,
+    t: Ty<'tcx>,
+) -> DINodeCreationResult<'ll> {
     debug!("build_basic_type_di_node: {:?}", t);
 
     // When targeting MSVC, emit MSVC style type names for compatibility with
@@ -649,7 +650,13 @@ fn build_basic_type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -
 
     let (name, encoding) = match t.kind() {
         ty::Never => ("!", DW_ATE_unsigned),
-        ty::Tuple(elements) if elements.is_empty() => ("()", DW_ATE_unsigned),
+        ty::Tuple(elements) if elements.is_empty() => {
+            if cpp_like_debuginfo {
+                return build_tuple_type_di_node(cx, UniqueTypeId::for_ty(cx.tcx, t));
+            } else {
+                ("()", DW_ATE_unsigned)
+            }
+        }
         ty::Bool => ("bool", DW_ATE_boolean),
         ty::Char => ("char", DW_ATE_UTF),
         ty::Int(int_ty) if cpp_like_debuginfo => (int_ty.msvc_basic_name(), DW_ATE_signed),
@@ -672,14 +679,14 @@ fn build_basic_type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -
     };
 
     if !cpp_like_debuginfo {
-        return ty_di_node;
+        return DINodeCreationResult::new(ty_di_node, false);
     }
 
     let typedef_name = match t.kind() {
         ty::Int(int_ty) => int_ty.name_str(),
         ty::Uint(uint_ty) => uint_ty.name_str(),
         ty::Float(float_ty) => float_ty.name_str(),
-        _ => return ty_di_node,
+        _ => return DINodeCreationResult::new(ty_di_node, false),
     };
 
     let typedef_di_node = unsafe {
@@ -694,7 +701,7 @@ fn build_basic_type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -
         )
     };
 
-    typedef_di_node
+    DINodeCreationResult::new(typedef_di_node, false)
 }
 
 fn build_foreign_type_di_node<'ll, 'tcx>(
index 4e6d3f88e67196ae2abf24ffb6d63ce367f39127..6a164557a4719ae97fac9a1bbe98610d8242d6f4 100644 (file)
@@ -286,9 +286,8 @@ fn create_function_debug_context(
         }
 
         // Initialize fn debug context (including scopes).
-        // FIXME(eddyb) figure out a way to not need `Option` for `dbg_scope`.
         let empty_scope = DebugScope {
-            dbg_scope: None,
+            dbg_scope: self.dbg_scope_fn(instance, fn_abi, Some(llfn)),
             inlined_at: None,
             file_start_pos: BytePos(0),
             file_end_pos: BytePos(0),
@@ -297,13 +296,7 @@ fn create_function_debug_context(
             FunctionDebugContext { scopes: IndexVec::from_elem(empty_scope, &mir.source_scopes) };
 
         // Fill in all the scopes, with the information from the MIR body.
-        compute_mir_scopes(
-            self,
-            instance,
-            mir,
-            self.dbg_scope_fn(instance, fn_abi, Some(llfn)),
-            &mut fn_debug_context,
-        );
+        compute_mir_scopes(self, instance, mir, &mut fn_debug_context);
 
         Some(fn_debug_context)
     }
index fe9851cfa561218c93b2247a39684578aa095af5..8f24367390775e1a8b43cac1024b7d093b17e4d3 100644 (file)
@@ -46,7 +46,7 @@ pub fn DIB<'a, 'll>(cx: &'a CodegenCx<'ll, '_>) -> &'a DIBuilder<'ll> {
 }
 
 pub fn get_namespace_for_item<'ll>(cx: &CodegenCx<'ll, '_>, def_id: DefId) -> &'ll DIScope {
-    item_namespace(cx, cx.tcx.parent(def_id).expect("get_namespace_for_item: missing parent?"))
+    item_namespace(cx, cx.tcx.parent(def_id))
 }
 
 #[derive(Debug, PartialEq, Eq)]
index 3152c505af0e5488bd74a926d4a2b769e19a3615..b0359239569549b460d26dadca79c0e0396a65c2 100644 (file)
@@ -104,19 +104,18 @@ fn drop(&mut self) {
 }
 
 impl ExtraBackendMethods for LlvmCodegenBackend {
-    fn new_metadata(&self, tcx: TyCtxt<'_>, mod_name: &str) -> ModuleLlvm {
-        ModuleLlvm::new_metadata(tcx, mod_name)
-    }
-
     fn codegen_allocator<'tcx>(
         &self,
         tcx: TyCtxt<'tcx>,
-        module_llvm: &mut ModuleLlvm,
         module_name: &str,
         kind: AllocatorKind,
         has_alloc_error_handler: bool,
-    ) {
-        unsafe { allocator::codegen(tcx, module_llvm, module_name, kind, has_alloc_error_handler) }
+    ) -> ModuleLlvm {
+        let mut module_llvm = ModuleLlvm::new_metadata(tcx, module_name);
+        unsafe {
+            allocator::codegen(tcx, &mut module_llvm, module_name, kind, has_alloc_error_handler);
+        }
+        module_llvm
     }
     fn compile_codegen_unit(
         &self,
@@ -210,9 +209,16 @@ unsafe fn optimize(
     ) -> Result<(), FatalError> {
         back::write::optimize(cgcx, diag_handler, module, config)
     }
+    fn optimize_fat(
+        cgcx: &CodegenContext<Self>,
+        module: &mut ModuleCodegen<Self::Module>,
+    ) -> Result<(), FatalError> {
+        let diag_handler = cgcx.create_diag_handler();
+        back::lto::run_pass_manager(cgcx, &diag_handler, module, false)
+    }
     unsafe fn optimize_thin(
         cgcx: &CodegenContext<Self>,
-        thin: &mut ThinModule<Self>,
+        thin: ThinModule<Self>,
     ) -> Result<ModuleCodegen<Self::Module>, FatalError> {
         back::lto::optimize_thin_module(thin, cgcx)
     }
@@ -230,15 +236,6 @@ fn prepare_thin(module: ModuleCodegen<Self::Module>) -> (String, Self::ThinBuffe
     fn serialize_module(module: ModuleCodegen<Self::Module>) -> (String, Self::ModuleBuffer) {
         (module.name, back::lto::ModuleBuffer::new(module.module_llvm.llmod()))
     }
-    fn run_lto_pass_manager(
-        cgcx: &CodegenContext<Self>,
-        module: &ModuleCodegen<Self::Module>,
-        config: &ModuleConfig,
-        thin: bool,
-    ) -> Result<(), FatalError> {
-        let diag_handler = cgcx.create_diag_handler();
-        back::lto::run_pass_manager(cgcx, &diag_handler, module, config, thin)
-    }
 }
 
 unsafe impl Send for LlvmCodegenBackend {} // Llvm is on a per-thread basis
index 7f533b0552a5de2d884be0b1a312a66faca174f5..13baaddccd4df5be8bf9d37d83b2ed37c5489fe2 100644 (file)
@@ -1825,24 +1825,22 @@ pub fn LLVMRustBuildAtomicFence(
 
     pub fn LLVMAddAnalysisPasses<'a>(T: &'a TargetMachine, PM: &PassManager<'a>);
 
-    pub fn LLVMPassManagerBuilderCreate() -> &'static mut PassManagerBuilder;
-    pub fn LLVMPassManagerBuilderDispose(PMB: &'static mut PassManagerBuilder);
-    pub fn LLVMPassManagerBuilderSetSizeLevel(PMB: &PassManagerBuilder, Value: Bool);
-    pub fn LLVMPassManagerBuilderSetDisableUnrollLoops(PMB: &PassManagerBuilder, Value: Bool);
-    pub fn LLVMPassManagerBuilderUseInlinerWithThreshold(
+    pub fn LLVMRustPassManagerBuilderCreate() -> &'static mut PassManagerBuilder;
+    pub fn LLVMRustPassManagerBuilderDispose(PMB: &'static mut PassManagerBuilder);
+    pub fn LLVMRustPassManagerBuilderUseInlinerWithThreshold(
         PMB: &PassManagerBuilder,
         threshold: c_uint,
     );
-    pub fn LLVMPassManagerBuilderPopulateModulePassManager(
+    pub fn LLVMRustPassManagerBuilderPopulateModulePassManager(
         PMB: &PassManagerBuilder,
         PM: &PassManager<'_>,
     );
 
-    pub fn LLVMPassManagerBuilderPopulateFunctionPassManager(
+    pub fn LLVMRustPassManagerBuilderPopulateFunctionPassManager(
         PMB: &PassManagerBuilder,
         PM: &PassManager<'_>,
     );
-    pub fn LLVMPassManagerBuilderPopulateLTOPassManager(
+    pub fn LLVMRustPassManagerBuilderPopulateLTOPassManager(
         PMB: &PassManagerBuilder,
         PM: &PassManager<'_>,
         Internalize: Bool,
@@ -2308,6 +2306,7 @@ pub fn LLVMRustConfigurePassManagerBuilder(
         PGOGenPath: *const c_char,
         PGOUsePath: *const c_char,
         PGOSampleUsePath: *const c_char,
+        SizeLevel: c_int,
     );
     pub fn LLVMRustAddLibraryInfo<'a>(
         PM: &PassManager<'a>,
index c24e369ae7284ab26b44eaca7aaad446a25db824..7b407c94e7b066e8e9c6b30aa98b42b29ba3451d 100644 (file)
@@ -542,6 +542,11 @@ pub(crate) fn should_use_new_llvm_pass_manager(user_opt: &Option<bool>, target_a
     // The new pass manager is enabled by default for LLVM >= 13.
     // This matches Clang, which also enables it since Clang 13.
 
+    // Since LLVM 15, the legacy pass manager is no longer supported.
+    if llvm_util::get_version() >= (15, 0, 0) {
+        return true;
+    }
+
     // There are some perf issues with the new pass manager when targeting
     // s390x with LLVM 13, so enable the new pass manager only with LLVM 14.
     // See https://github.com/rust-lang/rust/issues/89609.
index 4d20ed841d47c502bd0b17d39c9f557ac91904b2..6887f0666a4b037399c4ed022fe27fcd7ff095aa 100644 (file)
@@ -7,6 +7,7 @@
 use rustc_fs_util::fix_windows_verbatim_for_gcc;
 use rustc_hir::def_id::CrateNum;
 use rustc_middle::middle::dependency_format::Linkage;
+use rustc_middle::middle::exported_symbols::SymbolExportKind;
 use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Strip};
 use rustc_session::config::{OutputFilenames, OutputType, PrintRequest, SplitDwarfKind};
 use rustc_session::cstore::DllImport;
@@ -1655,6 +1656,100 @@ fn add_post_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor
     }
 }
 
+/// Add a synthetic object file that contains reference to all symbols that we want to expose to
+/// the linker.
+///
+/// Background: we implement rlibs as static library (archives). Linkers treat archives
+/// differently from object files: all object files participate in linking, while archives will
+/// only participate in linking if they can satisfy at least one undefined reference (version
+/// scripts doesn't count). This causes `#[no_mangle]` or `#[used]` items to be ignored by the
+/// linker, and since they never participate in the linking, using `KEEP` in the linker scripts
+/// can't keep them either. This causes #47384.
+///
+/// To keep them around, we could use `--whole-archive` and equivalents to force rlib to
+/// participate in linking like object files, but this proves to be expensive (#93791). Therefore
+/// we instead just introduce an undefined reference to them. This could be done by `-u` command
+/// line option to the linker or `EXTERN(...)` in linker scripts, however they does not only
+/// introduce an undefined reference, but also make them the GC roots, preventing `--gc-sections`
+/// from removing them, and this is especially problematic for embedded programming where every
+/// byte counts.
+///
+/// This method creates a synthetic object file, which contains undefined references to all symbols
+/// that are necessary for the linking. They are only present in symbol table but not actually
+/// used in any sections, so the linker will therefore pick relevant rlibs for linking, but
+/// unused `#[no_mangle]` or `#[used]` can still be discard by GC sections.
+fn add_linked_symbol_object(
+    cmd: &mut dyn Linker,
+    sess: &Session,
+    tmpdir: &Path,
+    symbols: &[(String, SymbolExportKind)],
+) {
+    if symbols.is_empty() {
+        return;
+    }
+
+    let Some(mut file) = super::metadata::create_object_file(sess) else {
+        return;
+    };
+
+    // NOTE(nbdd0121): MSVC will hang if the input object file contains no sections,
+    // so add an empty section.
+    if file.format() == object::BinaryFormat::Coff {
+        file.add_section(Vec::new(), ".text".into(), object::SectionKind::Text);
+
+        // We handle the name decoration of COFF targets in `symbol_export.rs`, so disable the
+        // default mangler in `object` crate.
+        file.set_mangling(object::write::Mangling::None);
+
+        // Add feature flags to the object file. On MSVC this is optional but LLD will complain if
+        // not present.
+        let mut feature = 0;
+
+        if file.architecture() == object::Architecture::I386 {
+            // Indicate that all SEH handlers are registered in .sxdata section.
+            // We don't have generate any code, so we don't need .sxdata section but LLD still
+            // expects us to set this bit (see #96498).
+            // Reference: https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
+            feature |= 1;
+        }
+
+        file.add_symbol(object::write::Symbol {
+            name: "@feat.00".into(),
+            value: feature,
+            size: 0,
+            kind: object::SymbolKind::Data,
+            scope: object::SymbolScope::Compilation,
+            weak: false,
+            section: object::write::SymbolSection::Absolute,
+            flags: object::SymbolFlags::None,
+        });
+    }
+
+    for (sym, kind) in symbols.iter() {
+        file.add_symbol(object::write::Symbol {
+            name: sym.clone().into(),
+            value: 0,
+            size: 0,
+            kind: match kind {
+                SymbolExportKind::Text => object::SymbolKind::Text,
+                SymbolExportKind::Data => object::SymbolKind::Data,
+                SymbolExportKind::Tls => object::SymbolKind::Tls,
+            },
+            scope: object::SymbolScope::Unknown,
+            weak: false,
+            section: object::write::SymbolSection::Undefined,
+            flags: object::SymbolFlags::None,
+        });
+    }
+
+    let path = tmpdir.join("symbols.o");
+    let result = std::fs::write(&path, file.write().unwrap());
+    if let Err(e) = result {
+        sess.fatal(&format!("failed to write {}: {}", path.display(), e));
+    }
+    cmd.add_object(&path);
+}
+
 /// Add object files containing code from the current crate.
 fn add_local_crate_regular_objects(cmd: &mut dyn Linker, codegen_results: &CodegenResults) {
     for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) {
@@ -1795,6 +1890,13 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
     // Pre-link CRT objects.
     add_pre_link_objects(cmd, sess, link_output_kind, crt_objects_fallback);
 
+    add_linked_symbol_object(
+        cmd,
+        sess,
+        tmpdir,
+        &codegen_results.crate_info.linked_symbols[&crate_type],
+    );
+
     // Sanitizer libraries.
     add_sanitizer_libraries(sess, crate_type, cmd);
 
@@ -1845,7 +1947,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
     // This change is somewhat breaking in practice due to local static libraries being linked
     // as whole-archive (#85144), so removing whole-archive may be a pre-requisite.
     if sess.opts.debugging_opts.link_native_libraries {
-        add_local_native_libraries(cmd, sess, codegen_results, crate_type);
+        add_local_native_libraries(cmd, sess, codegen_results);
     }
 
     // Upstream rust libraries and their nobundle static libraries
@@ -2017,16 +2119,6 @@ fn add_order_independent_options(
     add_rpath_args(cmd, sess, codegen_results, out_filename);
 }
 
-// A dylib may reexport symbols from the linked rlib or native static library.
-// Even if some symbol is reexported it's still not necessarily counted as used and may be
-// dropped, at least with `ld`-like ELF linkers. So we have to link some rlibs and static
-// libraries as whole-archive to avoid losing reexported symbols.
-// FIXME: Find a way to mark reexported symbols as used and avoid this use of whole-archive.
-fn default_to_whole_archive(sess: &Session, crate_type: CrateType, cmd: &dyn Linker) -> bool {
-    crate_type == CrateType::Dylib
-        && !(sess.target.limit_rdylib_exports && cmd.exported_symbol_means_used_symbol())
-}
-
 /// # Native library linking
 ///
 /// User-supplied library search paths (-L on the command line). These are the same paths used to
@@ -2040,7 +2132,6 @@ fn add_local_native_libraries(
     cmd: &mut dyn Linker,
     sess: &Session,
     codegen_results: &CodegenResults,
-    crate_type: CrateType,
 ) {
     let filesearch = sess.target_filesearch(PathKind::All);
     for search_path in filesearch.search_paths() {
@@ -2082,7 +2173,6 @@ fn add_local_native_libraries(
             }
             NativeLibKind::Static { whole_archive, bundle, .. } => {
                 if whole_archive == Some(true)
-                    || (whole_archive == None && default_to_whole_archive(sess, crate_type, cmd))
                     // Backward compatibility case: this can be a rlib (so `+whole-archive` cannot
                     // be added explicitly if necessary, see the error in `fn link_rlib`) compiled
                     // as an executable due to `--test`. Use whole-archive implicitly, like before
@@ -2201,7 +2291,7 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>(
         let src = &codegen_results.crate_info.used_crate_source[&cnum];
         match data[cnum.as_usize() - 1] {
             _ if codegen_results.crate_info.profiler_runtime == Some(cnum) => {
-                add_static_crate::<B>(cmd, sess, codegen_results, tmpdir, crate_type, cnum);
+                add_static_crate::<B>(cmd, sess, codegen_results, tmpdir, cnum);
             }
             // compiler-builtins are always placed last to ensure that they're
             // linked correctly.
@@ -2211,7 +2301,7 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>(
             }
             Linkage::NotLinked | Linkage::IncludedFromDylib => {}
             Linkage::Static => {
-                add_static_crate::<B>(cmd, sess, codegen_results, tmpdir, crate_type, cnum);
+                add_static_crate::<B>(cmd, sess, codegen_results, tmpdir, cnum);
 
                 // Link static native libs with "-bundle" modifier only if the crate they originate from
                 // is being linked statically to the current crate.  If it's linked dynamically
@@ -2242,10 +2332,7 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>(
                             lib.kind
                         {
                             let verbatim = lib.verbatim.unwrap_or(false);
-                            if whole_archive == Some(true)
-                                || (whole_archive == None
-                                    && default_to_whole_archive(sess, crate_type, cmd))
-                            {
+                            if whole_archive == Some(true) {
                                 cmd.link_whole_staticlib(
                                     name,
                                     verbatim,
@@ -2272,7 +2359,7 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>(
     // was already "included" in a dylib (e.g., `libstd` when `-C prefer-dynamic`
     // is used)
     if let Some(cnum) = compiler_builtins {
-        add_static_crate::<B>(cmd, sess, codegen_results, tmpdir, crate_type, cnum);
+        add_static_crate::<B>(cmd, sess, codegen_results, tmpdir, cnum);
     }
 
     // Converts a library file-stem into a cc -l argument
@@ -2303,23 +2390,13 @@ fn add_static_crate<'a, B: ArchiveBuilder<'a>>(
         sess: &'a Session,
         codegen_results: &CodegenResults,
         tmpdir: &Path,
-        crate_type: CrateType,
         cnum: CrateNum,
     ) {
         let src = &codegen_results.crate_info.used_crate_source[&cnum];
         let cratepath = &src.rlib.as_ref().unwrap().0;
 
         let mut link_upstream = |path: &Path| {
-            // We don't want to include the whole compiler-builtins crate (e.g., compiler-rt)
-            // regardless of the default because it'll get repeatedly linked anyway.
-            let path = fix_windows_verbatim_for_gcc(path);
-            if default_to_whole_archive(sess, crate_type, cmd)
-                && codegen_results.crate_info.compiler_builtins != Some(cnum)
-            {
-                cmd.link_whole_rlib(&path);
-            } else {
-                cmd.link_rlib(&path);
-            }
+            cmd.link_rlib(&fix_windows_verbatim_for_gcc(path));
         };
 
         // See the comment above in `link_staticlib` and `link_rlib` for why if
index 2c15ed831670ceefe65dd6eb93bd93c12f5373ca..50db2c22ae625aff807225c65b792a805eefa71a 100644 (file)
@@ -12,6 +12,7 @@
 
 use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
 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};
@@ -186,9 +187,6 @@ pub trait Linker {
     fn no_crt_objects(&mut self);
     fn no_default_libraries(&mut self);
     fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]);
-    fn exported_symbol_means_used_symbol(&self) -> bool {
-        true
-    }
     fn subsystem(&mut self, subsystem: &str);
     fn group_start(&mut self);
     fn group_end(&mut self);
@@ -727,10 +725,6 @@ fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[St
         }
     }
 
-    fn exported_symbol_means_used_symbol(&self) -> bool {
-        self.sess.target.is_like_windows || self.sess.target.is_like_osx
-    }
-
     fn subsystem(&mut self, subsystem: &str) {
         self.linker_arg("--subsystem");
         self.linker_arg(&subsystem);
@@ -1478,10 +1472,6 @@ fn export_symbols(&mut self, _: &Path, _: CrateType, _: &[String]) {
         return;
     }
 
-    fn exported_symbol_means_used_symbol(&self) -> bool {
-        false
-    }
-
     fn subsystem(&mut self, subsystem: &str) {
         self.cmd.arg(&format!("--subsystem {}", subsystem));
     }
@@ -1518,6 +1508,29 @@ fn hint_static(&mut self) {
     }
 }
 
+fn for_each_exported_symbols_include_dep<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    crate_type: CrateType,
+    mut callback: impl FnMut(ExportedSymbol<'tcx>, SymbolExportInfo, CrateNum),
+) {
+    for &(symbol, info) in tcx.exported_symbols(LOCAL_CRATE).iter() {
+        callback(symbol, info, LOCAL_CRATE);
+    }
+
+    let formats = tcx.dependency_formats(());
+    let deps = formats.iter().find_map(|(t, list)| (*t == crate_type).then_some(list)).unwrap();
+
+    for (index, dep_format) in deps.iter().enumerate() {
+        let cnum = CrateNum::new(index + 1);
+        // For each dependency that we are linking to statically ...
+        if *dep_format == Linkage::Static {
+            for &(symbol, info) in tcx.exported_symbols(cnum).iter() {
+                callback(symbol, info, cnum);
+            }
+        }
+    }
+}
+
 pub(crate) fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<String> {
     if let Some(ref exports) = tcx.sess.target.override_export_symbols {
         return exports.iter().map(ToString::to_string).collect();
@@ -1526,34 +1539,38 @@ pub(crate) fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<St
     let mut symbols = Vec::new();
 
     let export_threshold = symbol_export::crates_export_threshold(&[crate_type]);
-    for &(symbol, level) in tcx.exported_symbols(LOCAL_CRATE).iter() {
-        if level.is_below_threshold(export_threshold) {
-            symbols.push(symbol_export::symbol_name_for_instance_in_crate(
-                tcx,
-                symbol,
-                LOCAL_CRATE,
-            ));
+    for_each_exported_symbols_include_dep(tcx, crate_type, |symbol, info, cnum| {
+        if info.level.is_below_threshold(export_threshold) {
+            symbols.push(symbol_export::symbol_name_for_instance_in_crate(tcx, symbol, cnum));
         }
-    }
-
-    let formats = tcx.dependency_formats(());
-    let deps = formats.iter().find_map(|(t, list)| (*t == crate_type).then_some(list)).unwrap();
+    });
 
-    for (index, dep_format) in deps.iter().enumerate() {
-        let cnum = CrateNum::new(index + 1);
-        // For each dependency that we are linking to statically ...
-        if *dep_format == Linkage::Static {
-            // ... we add its symbol list to our export list.
-            for &(symbol, level) in tcx.exported_symbols(cnum).iter() {
-                if !level.is_below_threshold(export_threshold) {
-                    continue;
-                }
+    symbols
+}
 
-                symbols.push(symbol_export::symbol_name_for_instance_in_crate(tcx, symbol, cnum));
-            }
+pub(crate) fn linked_symbols(
+    tcx: TyCtxt<'_>,
+    crate_type: CrateType,
+) -> Vec<(String, SymbolExportKind)> {
+    match crate_type {
+        CrateType::Executable | CrateType::Cdylib | CrateType::Dylib => (),
+        CrateType::Staticlib | CrateType::ProcMacro | CrateType::Rlib => {
+            return Vec::new();
         }
     }
 
+    let mut symbols = Vec::new();
+
+    let export_threshold = symbol_export::crates_export_threshold(&[crate_type]);
+    for_each_exported_symbols_include_dep(tcx, crate_type, |symbol, info, cnum| {
+        if info.level.is_below_threshold(export_threshold) || info.used {
+            symbols.push((
+                symbol_export::linking_symbol_name_for_instance_in_crate(tcx, symbol, cnum),
+                info.kind,
+            ));
+        }
+    });
+
     symbols
 }
 
index d6ae689f254b1508b2f48d7ce75b5378ce43838f..cb6244050df24a61601af1f26eb80ae6d595279f 100644 (file)
@@ -42,7 +42,7 @@ pub struct ThinShared<B: WriteBackendMethods> {
 
 pub enum LtoModuleCodegen<B: WriteBackendMethods> {
     Fat {
-        module: Option<ModuleCodegen<B::Module>>,
+        module: ModuleCodegen<B::Module>,
         _serialized_bitcode: Vec<SerializedModule<B::ModuleBuffer>>,
     },
 
@@ -64,19 +64,15 @@ pub fn name(&self) -> &str {
     /// It's intended that the module returned is immediately code generated and
     /// dropped, and then this LTO module is dropped.
     pub unsafe fn optimize(
-        &mut self,
+        self,
         cgcx: &CodegenContext<B>,
     ) -> Result<ModuleCodegen<B::Module>, FatalError> {
-        match *self {
-            LtoModuleCodegen::Fat { ref mut module, .. } => {
-                let module = module.take().unwrap();
-                {
-                    let config = cgcx.config(module.kind);
-                    B::run_lto_pass_manager(cgcx, &module, config, false)?;
-                }
+        match self {
+            LtoModuleCodegen::Fat { mut module, .. } => {
+                B::optimize_fat(cgcx, &mut module)?;
                 Ok(module)
             }
-            LtoModuleCodegen::Thin(ref mut thin) => B::optimize_thin(cgcx, thin),
+            LtoModuleCodegen::Thin(thin) => B::optimize_thin(cgcx, thin),
         }
     }
 
index c52269805c46fa4963440661655461f82c9e355f..2e42272805682ec71881c2fc07162ac265f1872b 100644 (file)
@@ -94,7 +94,7 @@ fn search_for_metadata<'a>(
         .map_err(|e| format!("failed to read {} section in '{}': {}", section, path.display(), e))
 }
 
-fn create_object_file(sess: &Session) -> Option<write::Object<'static>> {
+pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static>> {
     let endianness = match sess.target.options.endian {
         Endian::Little => Endianness::Little,
         Endian::Big => Endianness::Big,
index 7b7c676c26cd12b7f487a99982c8154930b4589b..f651814be7ea6a8d7f3533ee4914ab0e2c97c546 100644 (file)
@@ -7,12 +7,12 @@
 use rustc_hir::Node;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::middle::exported_symbols::{
-    metadata_symbol_name, ExportedSymbol, SymbolExportLevel,
+    metadata_symbol_name, ExportedSymbol, SymbolExportInfo, SymbolExportKind, SymbolExportLevel,
 };
 use rustc_middle::ty::query::{ExternProviders, Providers};
 use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
 use rustc_middle::ty::Instance;
-use rustc_middle::ty::{SymbolName, TyCtxt};
+use rustc_middle::ty::{self, SymbolName, TyCtxt};
 use rustc_session::config::CrateType;
 use rustc_target::spec::SanitizerSet;
 
@@ -40,7 +40,7 @@ pub fn crates_export_threshold(crate_types: &[CrateType]) -> SymbolExportLevel {
     }
 }
 
-fn reachable_non_generics_provider(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap<SymbolExportLevel> {
+fn reachable_non_generics_provider(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap<SymbolExportInfo> {
     assert_eq!(cnum, LOCAL_CRATE);
 
     if !tcx.sess.opts.output_types.should_codegen() {
@@ -103,36 +103,51 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap<
             }
         })
         .map(|def_id| {
-            let export_level = if special_runtime_crate {
+            let (export_level, used) = if special_runtime_crate {
                 let name = tcx.symbol_name(Instance::mono(tcx, def_id.to_def_id())).name;
-                // We can probably do better here by just ensuring that
-                // it has hidden visibility rather than public
-                // visibility, as this is primarily here to ensure it's
-                // not stripped during LTO.
-                //
-                // In general though we won't link right if these
-                // symbols are stripped, and LTO currently strips them.
-                match name {
+                // We won't link right if these symbols are stripped during LTO.
+                let used = match name {
                     "rust_eh_personality"
                     | "rust_eh_register_frames"
-                    | "rust_eh_unregister_frames" =>
-                        SymbolExportLevel::C,
-                    _ => SymbolExportLevel::Rust,
-                }
+                    | "rust_eh_unregister_frames" => true,
+                    _ => false,
+                };
+                (SymbolExportLevel::Rust, used)
             } else {
-                symbol_export_level(tcx, def_id.to_def_id())
+                (symbol_export_level(tcx, def_id.to_def_id()), false)
             };
+            let codegen_attrs = tcx.codegen_fn_attrs(def_id.to_def_id());
             debug!(
                 "EXPORTED SYMBOL (local): {} ({:?})",
                 tcx.symbol_name(Instance::mono(tcx, def_id.to_def_id())),
                 export_level
             );
-            (def_id.to_def_id(), export_level)
+            (def_id.to_def_id(), SymbolExportInfo {
+                level: export_level,
+                kind: if tcx.is_static(def_id.to_def_id()) {
+                    if codegen_attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) {
+                        SymbolExportKind::Tls
+                    } else {
+                        SymbolExportKind::Data
+                    }
+                } else {
+                    SymbolExportKind::Text
+                },
+                used: codegen_attrs.flags.contains(CodegenFnAttrFlags::USED)
+                    || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) || used,
+            })
         })
         .collect();
 
     if let Some(id) = tcx.proc_macro_decls_static(()) {
-        reachable_non_generics.insert(id.to_def_id(), SymbolExportLevel::C);
+        reachable_non_generics.insert(
+            id.to_def_id(),
+            SymbolExportInfo {
+                level: SymbolExportLevel::C,
+                kind: SymbolExportKind::Data,
+                used: false,
+            },
+        );
     }
 
     reachable_non_generics
@@ -141,8 +156,8 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap<
 fn is_reachable_non_generic_provider_local(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
     let export_threshold = threshold(tcx);
 
-    if let Some(&level) = tcx.reachable_non_generics(def_id.krate).get(&def_id) {
-        level.is_below_threshold(export_threshold)
+    if let Some(&info) = tcx.reachable_non_generics(def_id.krate).get(&def_id) {
+        info.level.is_below_threshold(export_threshold)
     } else {
         false
     }
@@ -155,7 +170,7 @@ fn is_reachable_non_generic_provider_extern(tcx: TyCtxt<'_>, def_id: DefId) -> b
 fn exported_symbols_provider_local<'tcx>(
     tcx: TyCtxt<'tcx>,
     cnum: CrateNum,
-) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportLevel)] {
+) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)] {
     assert_eq!(cnum, LOCAL_CRATE);
 
     if !tcx.sess.opts.output_types.should_codegen() {
@@ -165,13 +180,20 @@ fn exported_symbols_provider_local<'tcx>(
     let mut symbols: Vec<_> = tcx
         .reachable_non_generics(LOCAL_CRATE)
         .iter()
-        .map(|(&def_id, &level)| (ExportedSymbol::NonGeneric(def_id), level))
+        .map(|(&def_id, &info)| (ExportedSymbol::NonGeneric(def_id), info))
         .collect();
 
     if tcx.entry_fn(()).is_some() {
         let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, "main"));
 
-        symbols.push((exported_symbol, SymbolExportLevel::C));
+        symbols.push((
+            exported_symbol,
+            SymbolExportInfo {
+                level: SymbolExportLevel::C,
+                kind: SymbolExportKind::Text,
+                used: false,
+            },
+        ));
     }
 
     if tcx.allocator_kind(()).is_some() {
@@ -179,7 +201,14 @@ fn exported_symbols_provider_local<'tcx>(
             let symbol_name = format!("__rust_{}", method.name);
             let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, &symbol_name));
 
-            symbols.push((exported_symbol, SymbolExportLevel::Rust));
+            symbols.push((
+                exported_symbol,
+                SymbolExportInfo {
+                    level: SymbolExportLevel::Rust,
+                    kind: SymbolExportKind::Text,
+                    used: false,
+                },
+            ));
         }
     }
 
@@ -192,17 +221,39 @@ fn exported_symbols_provider_local<'tcx>(
 
         symbols.extend(PROFILER_WEAK_SYMBOLS.iter().map(|sym| {
             let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, sym));
-            (exported_symbol, SymbolExportLevel::C)
+            (
+                exported_symbol,
+                SymbolExportInfo {
+                    level: SymbolExportLevel::C,
+                    kind: SymbolExportKind::Data,
+                    used: false,
+                },
+            )
         }));
     }
 
     if tcx.sess.opts.debugging_opts.sanitizer.contains(SanitizerSet::MEMORY) {
+        let mut msan_weak_symbols = Vec::new();
+
         // Similar to profiling, preserve weak msan symbol during LTO.
-        const MSAN_WEAK_SYMBOLS: [&str; 2] = ["__msan_track_origins", "__msan_keep_going"];
+        if tcx.sess.opts.debugging_opts.sanitizer_recover.contains(SanitizerSet::MEMORY) {
+            msan_weak_symbols.push("__msan_keep_going");
+        }
 
-        symbols.extend(MSAN_WEAK_SYMBOLS.iter().map(|sym| {
+        if tcx.sess.opts.debugging_opts.sanitizer_memory_track_origins != 0 {
+            msan_weak_symbols.push("__msan_track_origins");
+        }
+
+        symbols.extend(msan_weak_symbols.into_iter().map(|sym| {
             let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, sym));
-            (exported_symbol, SymbolExportLevel::C)
+            (
+                exported_symbol,
+                SymbolExportInfo {
+                    level: SymbolExportLevel::C,
+                    kind: SymbolExportKind::Data,
+                    used: false,
+                },
+            )
         }));
     }
 
@@ -210,7 +261,14 @@ fn exported_symbols_provider_local<'tcx>(
         let symbol_name = metadata_symbol_name(tcx);
         let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, &symbol_name));
 
-        symbols.push((exported_symbol, SymbolExportLevel::Rust));
+        symbols.push((
+            exported_symbol,
+            SymbolExportInfo {
+                level: SymbolExportLevel::Rust,
+                kind: SymbolExportKind::Data,
+                used: false,
+            },
+        ));
     }
 
     if tcx.sess.opts.share_generics() && tcx.local_crate_exports_generics() {
@@ -243,7 +301,14 @@ fn exported_symbols_provider_local<'tcx>(
                 MonoItem::Fn(Instance { def: InstanceDef::Item(def), substs }) => {
                     if substs.non_erasable_generics().next().is_some() {
                         let symbol = ExportedSymbol::Generic(def.did, substs);
-                        symbols.push((symbol, SymbolExportLevel::Rust));
+                        symbols.push((
+                            symbol,
+                            SymbolExportInfo {
+                                level: SymbolExportLevel::Rust,
+                                kind: SymbolExportKind::Text,
+                                used: false,
+                            },
+                        ));
                     }
                 }
                 MonoItem::Fn(Instance { def: InstanceDef::DropGlue(_, Some(ty)), substs }) => {
@@ -252,7 +317,14 @@ fn exported_symbols_provider_local<'tcx>(
                         substs.non_erasable_generics().next(),
                         Some(GenericArgKind::Type(ty))
                     );
-                    symbols.push((ExportedSymbol::DropGlue(ty), SymbolExportLevel::Rust));
+                    symbols.push((
+                        ExportedSymbol::DropGlue(ty),
+                        SymbolExportInfo {
+                            level: SymbolExportLevel::Rust,
+                            kind: SymbolExportKind::Text,
+                            used: false,
+                        },
+                    ));
                 }
                 _ => {
                     // Any other symbols don't qualify for sharing
@@ -421,6 +493,76 @@ pub fn symbol_name_for_instance_in_crate<'tcx>(
     }
 }
 
+/// This is the symbol name of the given instance as seen by the linker.
+///
+/// On 32-bit Windows symbols are decorated according to their calling conventions.
+pub fn linking_symbol_name_for_instance_in_crate<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    symbol: ExportedSymbol<'tcx>,
+    instantiating_crate: CrateNum,
+) -> String {
+    use rustc_target::abi::call::Conv;
+
+    let mut undecorated = symbol_name_for_instance_in_crate(tcx, symbol, instantiating_crate);
+
+    let target = &tcx.sess.target;
+    if !target.is_like_windows {
+        // Mach-O has a global "_" suffix and `object` crate will handle it.
+        // ELF does not have any symbol decorations.
+        return undecorated;
+    }
+
+    let x86 = match &target.arch[..] {
+        "x86" => true,
+        "x86_64" => false,
+        // Only x86/64 use symbol decorations.
+        _ => return undecorated,
+    };
+
+    let instance = match symbol {
+        ExportedSymbol::NonGeneric(def_id) | ExportedSymbol::Generic(def_id, _)
+            if tcx.is_static(def_id) =>
+        {
+            None
+        }
+        ExportedSymbol::NonGeneric(def_id) => Some(Instance::mono(tcx, def_id)),
+        ExportedSymbol::Generic(def_id, substs) => Some(Instance::new(def_id, substs)),
+        // DropGlue always use the Rust calling convention and thus follow the target's default
+        // symbol decoration scheme.
+        ExportedSymbol::DropGlue(..) => None,
+        // NoDefId always follow the target's default symbol decoration scheme.
+        ExportedSymbol::NoDefId(..) => None,
+    };
+
+    let (conv, args) = instance
+        .map(|i| {
+            tcx.fn_abi_of_instance(ty::ParamEnv::reveal_all().and((i, ty::List::empty())))
+                .unwrap_or_else(|_| bug!("fn_abi_of_instance({i:?}) failed"))
+        })
+        .map(|fnabi| (fnabi.conv, &fnabi.args[..]))
+        .unwrap_or((Conv::Rust, &[]));
+
+    // Decorate symbols with prefices, suffices and total number of bytes of arguments.
+    // Reference: https://docs.microsoft.com/en-us/cpp/build/reference/decorated-names?view=msvc-170
+    let (prefix, suffix) = match conv {
+        Conv::X86Fastcall => ("@", "@"),
+        Conv::X86Stdcall => ("_", "@"),
+        Conv::X86VectorCall => ("", "@@"),
+        _ => {
+            if x86 {
+                undecorated.insert(0, '_');
+            }
+            return undecorated;
+        }
+    };
+
+    let args_in_bytes: u64 = args
+        .iter()
+        .map(|abi| abi.layout.size.bytes().next_multiple_of(target.pointer_width as u64 / 8))
+        .sum();
+    format!("{prefix}{undecorated}{suffix}{args_in_bytes}")
+}
+
 fn wasm_import_module_map(tcx: TyCtxt<'_>, cnum: CrateNum) -> FxHashMap<DefId, String> {
     // Build up a map from DefId to a `NativeLib` structure, where
     // `NativeLib` internally contains information about
index d5d21775f0abc4ac33c861153f8d168c5f7a7a04..88293dec01cac7051acb1990000a578b13ba45a6 100644 (file)
@@ -23,7 +23,7 @@
 };
 use rustc_metadata::EncodedMetadata;
 use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
-use rustc_middle::middle::exported_symbols::SymbolExportLevel;
+use rustc_middle::middle::exported_symbols::SymbolExportInfo;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::cgu_reuse_tracker::CguReuseTracker;
 use rustc_session::config::{self, CrateType, Lto, OutputFilenames, OutputType};
@@ -304,7 +304,7 @@ pub fn new(
         + Sync,
 >;
 
-pub type ExportedSymbols = FxHashMap<CrateNum, Arc<Vec<(String, SymbolExportLevel)>>>;
+pub type ExportedSymbols = FxHashMap<CrateNum, Arc<Vec<(String, SymbolExportInfo)>>>;
 
 /// Additional resources used by optimize_and_codegen (not module specific)
 #[derive(Clone)]
@@ -889,7 +889,7 @@ fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>(
 
 fn execute_lto_work_item<B: ExtraBackendMethods>(
     cgcx: &CodegenContext<B>,
-    mut module: lto::LtoModuleCodegen<B>,
+    module: lto::LtoModuleCodegen<B>,
     module_config: &ModuleConfig,
 ) -> Result<WorkItemResult<B>, FatalError> {
     let module = unsafe { module.optimize(cgcx)? };
index 7933afb50e8ce70d9dbf52cf506c98f3c2d3ed23..5bc95614c197c32b2a4a48b3110cce816ad72e00 100644 (file)
@@ -575,15 +575,8 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
     } else if let Some(kind) = tcx.allocator_kind(()) {
         let llmod_id =
             cgu_name_builder.build_cgu_name(LOCAL_CRATE, &["crate"], Some("allocator")).to_string();
-        let mut module_llvm = backend.new_metadata(tcx, &llmod_id);
-        tcx.sess.time("write_allocator_module", || {
-            backend.codegen_allocator(
-                tcx,
-                &mut module_llvm,
-                &llmod_id,
-                kind,
-                tcx.lang_items().oom().is_some(),
-            )
+        let module_llvm = tcx.sess.time("write_allocator_module", || {
+            backend.codegen_allocator(tcx, &llmod_id, kind, tcx.lang_items().oom().is_some())
         });
 
         Some(ModuleCodegen { name: llmod_id, module_llvm, kind: ModuleKind::Allocator })
@@ -801,6 +794,12 @@ pub fn new(tcx: TyCtxt<'_>, target_cpu: String) -> CrateInfo {
             .iter()
             .map(|&c| (c, crate::back::linker::exported_symbols(tcx, c)))
             .collect();
+        let linked_symbols = tcx
+            .sess
+            .crate_types()
+            .iter()
+            .map(|&c| (c, crate::back::linker::linked_symbols(tcx, c)))
+            .collect();
         let local_crate_name = tcx.crate_name(LOCAL_CRATE);
         let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID);
         let subsystem = tcx.sess.first_attr_value_str_by_name(crate_attrs, sym::windows_subsystem);
@@ -834,6 +833,7 @@ pub fn new(tcx: TyCtxt<'_>, target_cpu: String) -> CrateInfo {
         let mut info = CrateInfo {
             target_cpu,
             exported_symbols,
+            linked_symbols,
             local_crate_name,
             compiler_builtins: None,
             profiler_runtime: None,
index ae54442e884a879548266ac852446bd9f2c8fe2e..1574b30497b4b38dbe8abce2d12b814d1f67a378 100644 (file)
@@ -2,7 +2,6 @@
 
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
 use rustc_hir::LangItem;
 use rustc_middle::mir::interpret::ConstValue;
 use rustc_middle::ty::{self, layout::TyAndLayout, Ty, TyCtxt};
@@ -10,7 +9,6 @@
 use rustc_span::Span;
 
 use crate::base;
-use crate::traits::BuilderMethods;
 use crate::traits::*;
 
 pub enum IntPredicate {
@@ -118,14 +116,15 @@ fn hash_stable(&self, _: &mut HCX, _: &mut StableHasher) {
     }
 }
 
-pub fn langcall(tcx: TyCtxt<'_>, span: Option<Span>, msg: &str, li: LangItem) -> DefId {
-    tcx.lang_items().require(li).unwrap_or_else(|s| {
-        let msg = format!("{} {}", msg, s);
-        match span {
-            Some(span) => tcx.sess.span_fatal(span, &msg),
-            None => tcx.sess.fatal(&msg),
-        }
-    })
+pub fn build_langcall<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
+    bx: &Bx,
+    span: Option<Span>,
+    li: LangItem,
+) -> (Bx::FnAbiOfResult, Bx::Value) {
+    let tcx = bx.tcx();
+    let def_id = tcx.require_lang_item(li, span);
+    let instance = ty::Instance::mono(tcx, def_id);
+    (bx.fn_abi_of_instance(instance, ty::List::empty()), bx.get_fn_addr(instance))
 }
 
 // To avoid UB from LLVM, these two functions mask RHS with an
index 5273b6cc83725521dbd49caedf2806dcaf2ed5c8..05d32972dab173b6f8746f814642182ca23ef22f 100644 (file)
@@ -7,6 +7,7 @@
 #![feature(nll)]
 #![feature(associated_type_bounds)]
 #![feature(strict_provenance)]
+#![feature(int_roundings)]
 #![recursion_limit = "256"]
 #![allow(rustc::potential_query_instability)]
 
@@ -28,6 +29,7 @@
 use rustc_hir::LangItem;
 use rustc_middle::dep_graph::WorkProduct;
 use rustc_middle::middle::dependency_format::Dependencies;
+use rustc_middle::middle::exported_symbols::SymbolExportKind;
 use rustc_middle::ty::query::{ExternProviders, Providers};
 use rustc_serialize::{opaque, Decodable, Decoder, Encoder};
 use rustc_session::config::{CrateType, OutputFilenames, OutputType, RUST_CGU_EXT};
@@ -141,6 +143,7 @@ fn from(lib: &cstore::NativeLib) -> Self {
 pub struct CrateInfo {
     pub target_cpu: String,
     pub exported_symbols: FxHashMap<CrateType, Vec<String>>,
+    pub linked_symbols: FxHashMap<CrateType, Vec<(String, SymbolExportKind)>>,
     pub local_crate_name: Symbol,
     pub compiler_builtins: Option<CrateNum>,
     pub profiler_runtime: Option<CrateNum>,
index efb424af3ed952f46bc50c0e7f99229384a0293e..fa39e8dd247d5071d3dda5639a18ff2e211276ad 100644 (file)
@@ -40,9 +40,9 @@ pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     }
 
     // If there exists a local definition that dominates all uses of that local,
-    // the definition should be visited first. Traverse blocks in preorder which
+    // the definition should be visited first. Traverse blocks in an order that
     // is a topological sort of dominance partial order.
-    for (bb, data) in traversal::preorder(&mir) {
+    for (bb, data) in traversal::reverse_postorder(&mir) {
         analyzer.visit_basic_block_data(bb, data);
     }
 
index b7d760bfbabe1d3325252df2513428803d5792ed..a185eb298e0926b825002ec928295308fd2aa1c7 100644 (file)
@@ -489,11 +489,7 @@ fn codegen_assert_terminator(
             }
         };
 
-        // Obtain the panic entry point.
-        let def_id = common::langcall(bx.tcx(), Some(span), "", lang_item);
-        let instance = ty::Instance::mono(bx.tcx(), def_id);
-        let fn_abi = bx.fn_abi_of_instance(instance, ty::List::empty());
-        let llfn = bx.get_fn_addr(instance);
+        let (fn_abi, llfn) = common::build_langcall(&bx, Some(span), lang_item);
 
         // Codegen the actual panic invoke/call.
         helper.do_call(self, &mut bx, fn_abi, llfn, &args, None, cleanup);
@@ -509,10 +505,7 @@ fn codegen_abort_terminator(
         self.set_debug_loc(&mut bx, terminator.source_info);
 
         // Obtain the panic entry point.
-        let def_id = common::langcall(bx.tcx(), Some(span), "", LangItem::PanicNoUnwind);
-        let instance = ty::Instance::mono(bx.tcx(), def_id);
-        let fn_abi = bx.fn_abi_of_instance(instance, ty::List::empty());
-        let llfn = bx.get_fn_addr(instance);
+        let (fn_abi, llfn) = common::build_langcall(&bx, Some(span), LangItem::PanicNoUnwind);
 
         // Codegen the actual panic invoke/call.
         helper.do_call(self, &mut bx, fn_abi, llfn, &[], None, None);
@@ -573,12 +566,8 @@ enum AssertIntrinsic {
                 let location = self.get_caller_location(bx, source_info).immediate();
 
                 // Obtain the panic entry point.
-                // FIXME: dedup this with `codegen_assert_terminator` above.
-                let def_id =
-                    common::langcall(bx.tcx(), Some(source_info.span), "", LangItem::Panic);
-                let instance = ty::Instance::mono(bx.tcx(), def_id);
-                let fn_abi = bx.fn_abi_of_instance(instance, ty::List::empty());
-                let llfn = bx.get_fn_addr(instance);
+                let (fn_abi, llfn) =
+                    common::build_langcall(bx, Some(source_info.span), LangItem::Panic);
 
                 // Codegen the actual panic invoke/call.
                 helper.do_call(
@@ -1440,10 +1429,7 @@ fn double_unwind_guard(&mut self) -> Bx::BasicBlock {
             let llretty = self.landing_pad_type();
             bx.cleanup_landing_pad(llretty, llpersonality);
 
-            let def_id = common::langcall(bx.tcx(), None, "", LangItem::PanicNoUnwind);
-            let instance = ty::Instance::mono(bx.tcx(), def_id);
-            let fn_abi = bx.fn_abi_of_instance(instance, ty::List::empty());
-            let fn_ptr = bx.get_fn_addr(instance);
+            let (fn_abi, fn_ptr) = common::build_langcall(&bx, None, LangItem::PanicNoUnwind);
             let fn_ty = bx.fn_decl_backend_type(&fn_abi);
 
             let llret = bx.call(fn_ty, fn_ptr, &[], None);
index bb53c722a244a2d3a5ba8c596744d4e45ac8adb2..f2d1827c792dbb38fda30623fb861dad8797cad7 100644 (file)
@@ -39,8 +39,7 @@ pub struct PerLocalVarDebugInfo<'tcx, D> {
 
 #[derive(Clone, Copy, Debug)]
 pub struct DebugScope<S, L> {
-    // FIXME(eddyb) this should never be `None`, after initialization.
-    pub dbg_scope: Option<S>,
+    pub dbg_scope: S,
 
     /// Call site location, if this scope was inlined from another function.
     pub inlined_at: Option<L>,
@@ -61,17 +60,12 @@ pub fn adjust_dbg_scope_for_span<Cx: CodegenMethods<'tcx, DIScope = S, DILocatio
         cx: &Cx,
         span: Span,
     ) -> S {
-        // FIXME(eddyb) this should never be `None`.
-        let dbg_scope = self
-            .dbg_scope
-            .unwrap_or_else(|| bug!("`dbg_scope` is only `None` during initialization"));
-
         let pos = span.lo();
         if pos < self.file_start_pos || pos >= self.file_end_pos {
             let sm = cx.sess().source_map();
-            cx.extend_scope_to_file(dbg_scope, &sm.lookup_char_pos(pos).file)
+            cx.extend_scope_to_file(self.dbg_scope, &sm.lookup_char_pos(pos).file)
         } else {
-            dbg_scope
+            self.dbg_scope
         }
     }
 }
index 6c139df0a8555c35109549a12a7305bad2bccc6a..0c958de64fa1c0edd42d1474cbbfe7ad24cf86ab 100644 (file)
@@ -244,7 +244,6 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     fx.debug_introduce_locals(&mut bx);
 
     // Codegen the body of each block using reverse postorder
-    // FIXME(eddyb) reuse RPO iterator between `analysis` and this.
     for (bb, _) in traversal::reverse_postorder(&mir) {
         fx.codegen_block(bb);
     }
index 856b7742583167ed4824ee639ef686966c3f0be0..1e53c73d1bb4ac5b4fe5b0a04de7c4b5f66050ab 100644 (file)
@@ -114,15 +114,13 @@ fn link(
 }
 
 pub trait ExtraBackendMethods: CodegenBackend + WriteBackendMethods + Sized + Send + Sync {
-    fn new_metadata(&self, sess: TyCtxt<'_>, mod_name: &str) -> Self::Module;
     fn codegen_allocator<'tcx>(
         &self,
         tcx: TyCtxt<'tcx>,
-        module_llvm: &mut Self::Module,
         module_name: &str,
         kind: AllocatorKind,
         has_alloc_error_handler: bool,
-    );
+    ) -> Self::Module;
     /// This generates the codegen unit and returns it along with
     /// a `u64` giving an estimate of the unit's processing cost.
     fn compile_codegen_unit(
index 93fbee2b49bb57a84c9921982cf00e5543e6e15a..e54ec34f1ce3716c38aec565c47951a3444c0244 100644 (file)
@@ -41,9 +41,13 @@ unsafe fn optimize(
         module: &ModuleCodegen<Self::Module>,
         config: &ModuleConfig,
     ) -> Result<(), FatalError>;
+    fn optimize_fat(
+        cgcx: &CodegenContext<Self>,
+        llmod: &mut ModuleCodegen<Self::Module>,
+    ) -> Result<(), FatalError>;
     unsafe fn optimize_thin(
         cgcx: &CodegenContext<Self>,
-        thin: &mut ThinModule<Self>,
+        thin: ThinModule<Self>,
     ) -> Result<ModuleCodegen<Self::Module>, FatalError>;
     unsafe fn codegen(
         cgcx: &CodegenContext<Self>,
@@ -53,12 +57,6 @@ unsafe fn codegen(
     ) -> Result<CompiledModule, FatalError>;
     fn prepare_thin(module: ModuleCodegen<Self::Module>) -> (String, Self::ThinBuffer);
     fn serialize_module(module: ModuleCodegen<Self::Module>) -> (String, Self::ModuleBuffer);
-    fn run_lto_pass_manager(
-        cgcx: &CodegenContext<Self>,
-        llmod: &ModuleCodegen<Self::Module>,
-        config: &ModuleConfig,
-        thin: bool,
-    ) -> Result<(), FatalError>;
 }
 
 pub trait ThinBufferMethods: Send + Sync {
index 7cca6178ab25727c989962d841deec9e17267bda..38fecf7232ebc704436755d752b000401df2afbb 100644 (file)
@@ -106,6 +106,7 @@ pub(super) fn mk_eval_cx<'mir, 'tcx>(
 
 /// This function converts an interpreter value into a constant that is meant for use in the
 /// type system.
+#[instrument(skip(ecx), level = "debug")]
 pub(super) fn op_to_const<'tcx>(
     ecx: &CompileTimeEvalContext<'_, 'tcx>,
     op: &OpTy<'tcx>,
@@ -140,21 +141,26 @@ pub(super) fn op_to_const<'tcx>(
         op.try_as_mplace()
     };
 
+    debug!(?immediate);
+
     // We know `offset` is relative to the allocation, so we can use `into_parts`.
-    let to_const_value = |mplace: &MPlaceTy<'_>| match mplace.ptr.into_parts() {
-        (Some(alloc_id), offset) => {
-            let alloc = ecx.tcx.global_alloc(alloc_id).unwrap_memory();
-            ConstValue::ByRef { alloc, offset }
-        }
-        (None, offset) => {
-            assert!(mplace.layout.is_zst());
-            assert_eq!(
-                offset.bytes() % mplace.layout.align.abi.bytes(),
-                0,
-                "this MPlaceTy must come from a validated constant, thus we can assume the \
+    let to_const_value = |mplace: &MPlaceTy<'_>| {
+        debug!("to_const_value(mplace: {:?})", mplace);
+        match mplace.ptr.into_parts() {
+            (Some(alloc_id), offset) => {
+                let alloc = ecx.tcx.global_alloc(alloc_id).unwrap_memory();
+                ConstValue::ByRef { alloc, offset }
+            }
+            (None, offset) => {
+                assert!(mplace.layout.is_zst());
+                assert_eq!(
+                    offset.bytes() % mplace.layout.align.abi.bytes(),
+                    0,
+                    "this MPlaceTy must come from a validated constant, thus we can assume the \
                 alignment is correct",
-            );
-            ConstValue::Scalar(Scalar::ZST)
+                );
+                ConstValue::Scalar(Scalar::ZST)
+            }
         }
     };
     match immediate {
@@ -166,6 +172,7 @@ pub(super) fn op_to_const<'tcx>(
                 ScalarMaybeUninit::Uninit => to_const_value(&op.assert_mem_place()),
             },
             Immediate::ScalarPair(a, b) => {
+                debug!("ScalarPair(a: {:?}, b: {:?})", a, b);
                 // We know `offset` is relative to the allocation, so we can use `into_parts`.
                 let (data, start) =
                     match ecx.scalar_to_ptr(a.check_init().unwrap()).unwrap().into_parts() {
@@ -209,7 +216,10 @@ fn turn_into_const_value<'tcx>(
     );
 
     // Turn this into a proper constant.
-    op_to_const(&ecx, &mplace.into())
+    let const_val = op_to_const(&ecx, &mplace.into());
+    debug!(?const_val);
+
+    const_val
 }
 
 pub fn eval_to_const_value_raw_provider<'tcx>(
index 19a543ae777f046045b494e3f68c23649522fa6d..1f291db55be96d596501997cdc5f9e85cc095516 100644 (file)
@@ -17,7 +17,7 @@ pub fn is_unstable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Symbol> {
 }
 
 pub fn is_parent_const_impl_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
-    let parent_id = tcx.local_parent(def_id).unwrap();
+    let parent_id = tcx.local_parent(def_id);
     tcx.def_kind(parent_id) == DefKind::Impl
         && tcx.impl_constness(parent_id) == hir::Constness::Const
 }
index 68f9bee593f65ea0f8b04da55f60ef657b0670f8..96c18d488ee8c1e38aa6186cdad0be6f64d6190d 100644 (file)
@@ -3,29 +3,26 @@
 use std::convert::TryFrom;
 
 use rustc_hir::Mutability;
-use rustc_middle::ty::layout::HasTyCtxt;
+use rustc_middle::mir;
 use rustc_middle::ty::{self, TyCtxt};
-use rustc_middle::{
-    mir::{self, interpret::ConstAlloc},
-    ty::ScalarInt,
-};
 use rustc_span::{source_map::DUMMY_SP, symbol::Symbol};
-use rustc_target::abi::VariantIdx;
 
 use crate::interpret::{
-    intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, InterpResult, MPlaceTy,
-    MemPlaceMeta, Scalar,
+    intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, InterpResult, MemPlaceMeta,
+    Scalar,
 };
 
 mod error;
 mod eval_queries;
 mod fn_queries;
 mod machine;
+mod valtrees;
 
 pub use error::*;
 pub use eval_queries::*;
 pub use fn_queries::*;
 pub use machine::*;
+pub(crate) use valtrees::{const_to_valtree, valtree_to_const_value};
 
 pub(crate) fn const_caller_location(
     tcx: TyCtxt<'_>,
@@ -41,128 +38,6 @@ pub(crate) fn const_caller_location(
     ConstValue::Scalar(Scalar::from_maybe_pointer(loc_place.ptr, &tcx))
 }
 
-/// Convert an evaluated constant to a type level constant
-pub(crate) fn const_to_valtree<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    raw: ConstAlloc<'tcx>,
-) -> Option<ty::ValTree<'tcx>> {
-    let ecx = mk_eval_cx(
-        tcx, DUMMY_SP, param_env,
-        // It is absolutely crucial for soundness that
-        // we do not read from static items or other mutable memory.
-        false,
-    );
-    let place = ecx.raw_const_to_mplace(raw).unwrap();
-    const_to_valtree_inner(&ecx, &place)
-}
-
-#[instrument(skip(ecx), level = "debug")]
-fn branches<'tcx>(
-    ecx: &CompileTimeEvalContext<'tcx, 'tcx>,
-    place: &MPlaceTy<'tcx>,
-    n: usize,
-    variant: Option<VariantIdx>,
-) -> Option<ty::ValTree<'tcx>> {
-    let place = match variant {
-        Some(variant) => ecx.mplace_downcast(&place, variant).unwrap(),
-        None => *place,
-    };
-    let variant = variant.map(|variant| Some(ty::ValTree::Leaf(ScalarInt::from(variant.as_u32()))));
-    debug!(?place, ?variant);
-
-    let fields = (0..n).map(|i| {
-        let field = ecx.mplace_field(&place, i).unwrap();
-        const_to_valtree_inner(ecx, &field)
-    });
-    // For enums, we prepend their variant index before the variant's fields so we can figure out
-    // the variant again when just seeing a valtree.
-    let branches = variant.into_iter().chain(fields);
-    Some(ty::ValTree::Branch(ecx.tcx.arena.alloc_from_iter(branches.collect::<Option<Vec<_>>>()?)))
-}
-
-fn slice_branches<'tcx>(
-    ecx: &CompileTimeEvalContext<'tcx, 'tcx>,
-    place: &MPlaceTy<'tcx>,
-) -> Option<ty::ValTree<'tcx>> {
-    let n = place.len(&ecx.tcx()).expect(&format!("expected to use len of place {:?}", place));
-    let branches = (0..n).map(|i| {
-        let place_elem = ecx.mplace_index(place, i).unwrap();
-        const_to_valtree_inner(ecx, &place_elem)
-    });
-
-    Some(ty::ValTree::Branch(ecx.tcx.arena.alloc_from_iter(branches.collect::<Option<Vec<_>>>()?)))
-}
-
-#[instrument(skip(ecx), level = "debug")]
-fn const_to_valtree_inner<'tcx>(
-    ecx: &CompileTimeEvalContext<'tcx, 'tcx>,
-    place: &MPlaceTy<'tcx>,
-) -> Option<ty::ValTree<'tcx>> {
-    match place.layout.ty.kind() {
-        ty::FnDef(..) => Some(ty::ValTree::zst()),
-        ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => {
-            let val = ecx.read_immediate(&place.into()).unwrap();
-            let val = val.to_scalar().unwrap();
-            Some(ty::ValTree::Leaf(val.assert_int()))
-        }
-
-        // Raw pointers are not allowed in type level constants, as we cannot properly test them for
-        // equality at compile-time (see `ptr_guaranteed_eq`/`_ne`).
-        // Technically we could allow function pointers (represented as `ty::Instance`), but this is not guaranteed to
-        // agree with runtime equality tests.
-        ty::FnPtr(_) | ty::RawPtr(_) => None,
-
-        ty::Ref(_, _, _)  => {
-            let derefd_place = ecx.deref_operand(&place.into()).unwrap_or_else(|e| bug!("couldn't deref {:?}, error: {:?}", place, e));
-            debug!(?derefd_place);
-
-            const_to_valtree_inner(ecx, &derefd_place)
-        }
-
-        ty::Str | ty::Slice(_) | ty::Array(_, _) => {
-            let valtree = slice_branches(ecx, place);
-            debug!(?valtree);
-
-            valtree
-        }
-        // Trait objects are not allowed in type level constants, as we have no concept for
-        // resolving their backing type, even if we can do that at const eval time. We may
-        // hypothetically be able to allow `dyn StructuralEq` trait objects in the future,
-        // but it is unclear if this is useful.
-        ty::Dynamic(..) => None,
-
-        ty::Tuple(substs) => branches(ecx, place, substs.len(), None),
-
-        ty::Adt(def, _) => {
-            if def.variants().is_empty() {
-                bug!("uninhabited types should have errored and never gotten converted to valtree")
-            }
-
-            let variant = ecx.read_discriminant(&place.into()).unwrap().1;
-
-            branches(ecx, place, def.variant(variant).fields.len(), def.is_enum().then_some(variant))
-        }
-
-        ty::Never
-        | ty::Error(_)
-        | ty::Foreign(..)
-        | ty::Infer(ty::FreshIntTy(_))
-        | ty::Infer(ty::FreshFloatTy(_))
-        | ty::Projection(..)
-        | ty::Param(_)
-        | ty::Bound(..)
-        | ty::Placeholder(..)
-        // FIXME(oli-obk): we could look behind opaque types
-        | ty::Opaque(..)
-        | ty::Infer(_)
-        // FIXME(oli-obk): we can probably encode closures just like structs
-        | ty::Closure(..)
-        | ty::Generator(..)
-        | ty::GeneratorWitness(..) => None,
-    }
-}
-
 /// This function should never fail for validated constants. However, it is also invoked from the
 /// pretty printer which might attempt to format invalid constants and in that case it might fail.
 pub(crate) fn try_destructure_const<'tcx>(
@@ -202,6 +77,7 @@ pub(crate) fn try_destructure_const<'tcx>(
     Ok(mir::DestructuredConst { variant, fields })
 }
 
+#[instrument(skip(tcx), level = "debug")]
 pub(crate) fn deref_const<'tcx>(
     tcx: TyCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
new file mode 100644 (file)
index 0000000..374179d
--- /dev/null
@@ -0,0 +1,459 @@
+use super::eval_queries::{mk_eval_cx, op_to_const};
+use super::machine::CompileTimeEvalContext;
+use crate::interpret::{
+    intern_const_alloc_recursive, ConstValue, ImmTy, Immediate, InternKind, MemPlaceMeta,
+    MemoryKind, PlaceTy, Scalar, ScalarMaybeUninit,
+};
+use rustc_middle::mir::interpret::ConstAlloc;
+use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt};
+use rustc_span::source_map::DUMMY_SP;
+use rustc_target::abi::{Align, VariantIdx};
+
+use crate::interpret::MPlaceTy;
+use crate::interpret::Value;
+
+/// Convert an evaluated constant to a type level constant
+#[instrument(skip(tcx), level = "debug")]
+pub(crate) fn const_to_valtree<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    raw: ConstAlloc<'tcx>,
+) -> Option<ty::ValTree<'tcx>> {
+    let ecx = mk_eval_cx(
+        tcx, DUMMY_SP, param_env,
+        // It is absolutely crucial for soundness that
+        // we do not read from static items or other mutable memory.
+        false,
+    );
+    let place = ecx.raw_const_to_mplace(raw).unwrap();
+    const_to_valtree_inner(&ecx, &place)
+}
+
+#[instrument(skip(ecx), level = "debug")]
+fn branches<'tcx>(
+    ecx: &CompileTimeEvalContext<'tcx, 'tcx>,
+    place: &MPlaceTy<'tcx>,
+    n: usize,
+    variant: Option<VariantIdx>,
+) -> Option<ty::ValTree<'tcx>> {
+    let place = match variant {
+        Some(variant) => ecx.mplace_downcast(&place, variant).unwrap(),
+        None => *place,
+    };
+    let variant = variant.map(|variant| Some(ty::ValTree::Leaf(ScalarInt::from(variant.as_u32()))));
+    debug!(?place, ?variant);
+
+    let fields = (0..n).map(|i| {
+        let field = ecx.mplace_field(&place, i).unwrap();
+        const_to_valtree_inner(ecx, &field)
+    });
+    // For enums, we preped their variant index before the variant's fields so we can figure out
+    // the variant again when just seeing a valtree.
+    let branches = variant.into_iter().chain(fields);
+    Some(ty::ValTree::Branch(ecx.tcx.arena.alloc_from_iter(branches.collect::<Option<Vec<_>>>()?)))
+}
+
+#[instrument(skip(ecx), level = "debug")]
+fn slice_branches<'tcx>(
+    ecx: &CompileTimeEvalContext<'tcx, 'tcx>,
+    place: &MPlaceTy<'tcx>,
+) -> Option<ty::ValTree<'tcx>> {
+    let n = place.len(&ecx.tcx.tcx).expect(&format!("expected to use len of place {:?}", place));
+    let branches = (0..n).map(|i| {
+        let place_elem = ecx.mplace_index(place, i).unwrap();
+        const_to_valtree_inner(ecx, &place_elem)
+    });
+
+    Some(ty::ValTree::Branch(ecx.tcx.arena.alloc_from_iter(branches.collect::<Option<Vec<_>>>()?)))
+}
+
+#[instrument(skip(ecx), level = "debug")]
+fn const_to_valtree_inner<'tcx>(
+    ecx: &CompileTimeEvalContext<'tcx, 'tcx>,
+    place: &MPlaceTy<'tcx>,
+) -> Option<ty::ValTree<'tcx>> {
+    match place.layout.ty.kind() {
+        ty::FnDef(..) => Some(ty::ValTree::zst()),
+        ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => {
+            let val = ecx.read_immediate(&place.into()).unwrap();
+            let val = val.to_scalar().unwrap();
+            Some(ty::ValTree::Leaf(val.assert_int()))
+        }
+
+        // Raw pointers are not allowed in type level constants, as we cannot properly test them for
+        // equality at compile-time (see `ptr_guaranteed_eq`/`_ne`).
+        // Technically we could allow function pointers (represented as `ty::Instance`), but this is not guaranteed to
+        // agree with runtime equality tests.
+        ty::FnPtr(_) | ty::RawPtr(_) => None,
+
+        ty::Ref(_, _, _)  => {
+            let derefd_place = ecx.deref_operand(&place.into()).unwrap_or_else(|e| bug!("couldn't deref {:?}, error: {:?}", place, e));
+            debug!(?derefd_place);
+
+            const_to_valtree_inner(ecx, &derefd_place)
+        }
+
+        ty::Str | ty::Slice(_) | ty::Array(_, _) => {
+            let valtree = slice_branches(ecx, place);
+            debug!(?valtree);
+
+            valtree
+        }
+        // Trait objects are not allowed in type level constants, as we have no concept for
+        // resolving their backing type, even if we can do that at const eval time. We may
+        // hypothetically be able to allow `dyn StructuralEq` trait objects in the future,
+        // but it is unclear if this is useful.
+        ty::Dynamic(..) => None,
+
+        ty::Tuple(substs) => branches(ecx, place, substs.len(), None),
+
+        ty::Adt(def, _) => {
+            if def.is_union() {
+                return None
+            } else if def.variants().is_empty() {
+                bug!("uninhabited types should have errored and never gotten converted to valtree")
+            }
+
+            let variant = ecx.read_discriminant(&place.into()).unwrap().1;
+
+            branches(ecx, place, def.variant(variant).fields.len(), def.is_enum().then_some(variant))
+        }
+
+        ty::Never
+        | ty::Error(_)
+        | ty::Foreign(..)
+        | ty::Infer(ty::FreshIntTy(_))
+        | ty::Infer(ty::FreshFloatTy(_))
+        | ty::Projection(..)
+        | ty::Param(_)
+        | ty::Bound(..)
+        | ty::Placeholder(..)
+        // FIXME(oli-obk): we could look behind opaque types
+        | ty::Opaque(..)
+        | ty::Infer(_)
+        // FIXME(oli-obk): we can probably encode closures just like structs
+        | ty::Closure(..)
+        | ty::Generator(..)
+        | ty::GeneratorWitness(..) => None,
+    }
+}
+
+#[instrument(skip(ecx), level = "debug")]
+fn create_mplace_from_layout<'tcx>(
+    ecx: &mut CompileTimeEvalContext<'tcx, 'tcx>,
+    ty: Ty<'tcx>,
+) -> MPlaceTy<'tcx> {
+    let tcx = ecx.tcx;
+    let param_env = ecx.param_env;
+    let layout = tcx.layout_of(param_env.and(ty)).unwrap();
+    debug!(?layout);
+
+    ecx.allocate(layout, MemoryKind::Stack).unwrap()
+}
+
+// Walks custom DSTs and gets the type of the unsized field and the number of elements
+// in the unsized field.
+fn get_info_on_unsized_field<'tcx>(
+    ty: Ty<'tcx>,
+    valtree: ty::ValTree<'tcx>,
+    tcx: TyCtxt<'tcx>,
+) -> (Ty<'tcx>, usize) {
+    let mut last_valtree = valtree;
+    let tail = tcx.struct_tail_with_normalize(
+        ty,
+        |ty| ty,
+        || {
+            let branches = last_valtree.unwrap_branch();
+            last_valtree = branches[branches.len() - 1];
+            debug!(?branches, ?last_valtree);
+        },
+    );
+    let unsized_inner_ty = match tail.kind() {
+        ty::Slice(t) => *t,
+        ty::Str => tail,
+        _ => bug!("expected Slice or Str"),
+    };
+
+    // Have to adjust type for ty::Str
+    let unsized_inner_ty = match unsized_inner_ty.kind() {
+        ty::Str => tcx.mk_ty(ty::Uint(ty::UintTy::U8)),
+        _ => unsized_inner_ty,
+    };
+
+    // Get the number of elements in the unsized field
+    let num_elems = last_valtree.unwrap_branch().len();
+
+    (unsized_inner_ty, num_elems)
+}
+
+#[instrument(skip(ecx), level = "debug")]
+fn create_pointee_place<'tcx>(
+    ecx: &mut CompileTimeEvalContext<'tcx, 'tcx>,
+    ty: Ty<'tcx>,
+    valtree: ty::ValTree<'tcx>,
+) -> MPlaceTy<'tcx> {
+    let tcx = ecx.tcx.tcx;
+
+    if !ty.is_sized(ecx.tcx, ty::ParamEnv::empty()) {
+        // We need to create `Allocation`s for custom DSTs
+
+        let (unsized_inner_ty, num_elems) = get_info_on_unsized_field(ty, valtree, tcx);
+        let unsized_inner_ty = match unsized_inner_ty.kind() {
+            ty::Str => tcx.mk_ty(ty::Uint(ty::UintTy::U8)),
+            _ => unsized_inner_ty,
+        };
+        let unsized_inner_ty_size =
+            tcx.layout_of(ty::ParamEnv::empty().and(unsized_inner_ty)).unwrap().layout.size();
+        debug!(?unsized_inner_ty, ?unsized_inner_ty_size, ?num_elems);
+
+        // for custom DSTs only the last field/element is unsized, but we need to also allocate
+        // space for the other fields/elements
+        let layout = tcx.layout_of(ty::ParamEnv::empty().and(ty)).unwrap();
+        let size_of_sized_part = layout.layout.size();
+
+        // Get the size of the memory behind the DST
+        let dst_size = unsized_inner_ty_size.checked_mul(num_elems as u64, &tcx).unwrap();
+
+        let ptr = ecx
+            .allocate_ptr(
+                size_of_sized_part.checked_add(dst_size, &tcx).unwrap(),
+                Align::from_bytes(1).unwrap(),
+                MemoryKind::Stack,
+            )
+            .unwrap();
+        debug!(?ptr);
+
+        let mut place = MPlaceTy::from_aligned_ptr(ptr.into(), layout);
+        place.meta = MemPlaceMeta::Meta(Scalar::from_u64(num_elems as u64));
+        debug!(?place);
+
+        place
+    } else {
+        create_mplace_from_layout(ecx, ty)
+    }
+}
+
+/// Converts a `ValTree` to a `ConstValue`, which is needed after mir
+/// construction has finished.
+// FIXME Merge `valtree_to_const_value` and `fill_place_recursively` into one function
+#[instrument(skip(tcx), level = "debug")]
+pub fn valtree_to_const_value<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    param_env_ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
+    valtree: ty::ValTree<'tcx>,
+) -> ConstValue<'tcx> {
+    // Basic idea: We directly construct `Scalar` values from trivial `ValTree`s
+    // (those for constants with type bool, int, uint, float or char).
+    // For all other types we create an `MPlace` and fill that by walking
+    // the `ValTree` and using `place_projection` and `place_field` to
+    // create inner `MPlace`s which are filled recursively.
+    // FIXME Does this need an example?
+
+    let (param_env, ty) = param_env_ty.into_parts();
+    let mut ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false);
+
+    match ty.kind() {
+        ty::FnDef(..) => {
+            assert!(valtree.unwrap_branch().is_empty());
+            ConstValue::Scalar(Scalar::ZST)
+        }
+        ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => match valtree {
+            ty::ValTree::Leaf(scalar_int) => ConstValue::Scalar(Scalar::Int(scalar_int)),
+            ty::ValTree::Branch(_) => bug!(
+                "ValTrees for Bool, Int, Uint, Float or Char should have the form ValTree::Leaf"
+            ),
+        },
+        ty::Ref(_, _, _) | ty::Tuple(_) | ty::Array(_, _) | ty::Adt(..) => {
+            let mut place = match ty.kind() {
+                ty::Ref(_, inner_ty, _) => {
+                    // Need to create a place for the pointee to fill for Refs
+                    create_pointee_place(&mut ecx, *inner_ty, valtree)
+                }
+                _ => create_mplace_from_layout(&mut ecx, ty),
+            };
+            debug!(?place);
+
+            fill_place_recursively(&mut ecx, &mut place, valtree);
+            dump_place(&ecx, place.into());
+            intern_const_alloc_recursive(&mut ecx, InternKind::Constant, &place).unwrap();
+
+            let const_val = match ty.kind() {
+                ty::Ref(_, _, _) => {
+                    let ref_place = place.to_ref(&tcx);
+                    let imm =
+                        ImmTy::from_immediate(ref_place, tcx.layout_of(param_env_ty).unwrap());
+
+                    op_to_const(&ecx, &imm.into())
+                }
+                _ => op_to_const(&ecx, &place.into()),
+            };
+            debug!(?const_val);
+
+            const_val
+        }
+        ty::Never
+        | ty::Error(_)
+        | ty::Foreign(..)
+        | ty::Infer(ty::FreshIntTy(_))
+        | ty::Infer(ty::FreshFloatTy(_))
+        | ty::Projection(..)
+        | ty::Param(_)
+        | ty::Bound(..)
+        | ty::Placeholder(..)
+        | ty::Opaque(..)
+        | ty::Infer(_)
+        | ty::Closure(..)
+        | ty::Generator(..)
+        | ty::GeneratorWitness(..)
+        | ty::FnPtr(_)
+        | ty::RawPtr(_)
+        | ty::Str
+        | ty::Slice(_)
+        | ty::Dynamic(..) => bug!("no ValTree should have been created for type {:?}", ty.kind()),
+    }
+}
+
+// FIXME Needs a better/correct name
+#[instrument(skip(ecx), level = "debug")]
+fn fill_place_recursively<'tcx>(
+    ecx: &mut CompileTimeEvalContext<'tcx, 'tcx>,
+    place: &mut MPlaceTy<'tcx>,
+    valtree: ty::ValTree<'tcx>,
+) {
+    // This will match on valtree and write the value(s) corresponding to the ValTree
+    // inside the place recursively.
+
+    let tcx = ecx.tcx.tcx;
+    let ty = place.layout.ty;
+
+    match ty.kind() {
+        ty::FnDef(_, _) => {
+            ecx.write_immediate(
+                Immediate::Scalar(ScalarMaybeUninit::Scalar(Scalar::ZST)),
+                &(*place).into(),
+            )
+            .unwrap();
+        }
+        ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => {
+            let scalar_int = valtree.unwrap_leaf();
+            debug!("writing trivial valtree {:?} to place {:?}", scalar_int, place);
+            ecx.write_immediate(
+                Immediate::Scalar(ScalarMaybeUninit::Scalar(scalar_int.into())),
+                &(*place).into(),
+            )
+            .unwrap();
+        }
+        ty::Ref(_, inner_ty, _) => {
+            let mut pointee_place = create_pointee_place(ecx, *inner_ty, valtree);
+            debug!(?pointee_place);
+
+            fill_place_recursively(ecx, &mut pointee_place, valtree);
+            dump_place(ecx, pointee_place.into());
+            intern_const_alloc_recursive(ecx, InternKind::Constant, &pointee_place).unwrap();
+
+            let imm = match inner_ty.kind() {
+                ty::Slice(_) | ty::Str => {
+                    let len = valtree.unwrap_branch().len();
+                    let len_scalar = ScalarMaybeUninit::Scalar(Scalar::from_u64(len as u64));
+
+                    Immediate::ScalarPair(
+                        ScalarMaybeUninit::from_maybe_pointer((*pointee_place).ptr, &tcx),
+                        len_scalar,
+                    )
+                }
+                _ => pointee_place.to_ref(&tcx),
+            };
+            debug!(?imm);
+
+            ecx.write_immediate(imm, &(*place).into()).unwrap();
+        }
+        ty::Adt(_, _) | ty::Tuple(_) | ty::Array(_, _) | ty::Str | ty::Slice(_) => {
+            let branches = valtree.unwrap_branch();
+
+            // Need to downcast place for enums
+            let (place_adjusted, branches, variant_idx) = match ty.kind() {
+                ty::Adt(def, _) if def.is_enum() => {
+                    // First element of valtree corresponds to variant
+                    let scalar_int = branches[0].unwrap_leaf();
+                    let variant_idx = VariantIdx::from_u32(scalar_int.try_to_u32().unwrap());
+                    let variant = def.variant(variant_idx);
+                    debug!(?variant);
+
+                    (
+                        place.project_downcast(ecx, variant_idx).unwrap(),
+                        &branches[1..],
+                        Some(variant_idx),
+                    )
+                }
+                _ => (*place, branches, None),
+            };
+            debug!(?place_adjusted, ?branches);
+
+            // Create the places (by indexing into `place`) for the fields and fill
+            // them recursively
+            for (i, inner_valtree) in branches.iter().enumerate() {
+                debug!(?i, ?inner_valtree);
+
+                let mut place_inner = match ty.kind() {
+                    ty::Str | ty::Slice(_) => ecx.mplace_index(&place, i as u64).unwrap(),
+                    _ if !ty.is_sized(ecx.tcx, ty::ParamEnv::empty())
+                        && i == branches.len() - 1 =>
+                    {
+                        // Note: For custom DSTs we need to manually process the last unsized field.
+                        // We created a `Pointer` for the `Allocation` of the complete sized version of
+                        // the Adt in `create_pointee_place` and now we fill that `Allocation` with the
+                        // values in the ValTree. For the unsized field we have to additionally add the meta
+                        // data.
+
+                        let (unsized_inner_ty, num_elems) =
+                            get_info_on_unsized_field(ty, valtree, tcx);
+                        debug!(?unsized_inner_ty);
+
+                        let inner_ty = match ty.kind() {
+                            ty::Adt(def, substs) => {
+                                def.variant(VariantIdx::from_u32(0)).fields[i].ty(tcx, substs)
+                            }
+                            ty::Tuple(inner_tys) => inner_tys[i],
+                            _ => bug!("unexpected unsized type {:?}", ty),
+                        };
+
+                        let inner_layout =
+                            tcx.layout_of(ty::ParamEnv::empty().and(inner_ty)).unwrap();
+                        debug!(?inner_layout);
+
+                        let offset = place_adjusted.layout.fields.offset(i);
+                        place
+                            .offset(
+                                offset,
+                                MemPlaceMeta::Meta(Scalar::from_u64(num_elems as u64)),
+                                inner_layout,
+                                &tcx,
+                            )
+                            .unwrap()
+                    }
+                    _ => ecx.mplace_field(&place_adjusted, i).unwrap(),
+                };
+
+                debug!(?place_inner);
+                fill_place_recursively(ecx, &mut place_inner, *inner_valtree);
+                dump_place(&ecx, place_inner.into());
+            }
+
+            debug!("dump of place_adjusted:");
+            dump_place(ecx, place_adjusted.into());
+
+            if let Some(variant_idx) = variant_idx {
+                // don't forget filling the place with the discriminant of the enum
+                ecx.write_discriminant(variant_idx, &(*place).into()).unwrap();
+            }
+
+            debug!("dump of place after writing discriminant:");
+            dump_place(ecx, (*place).into());
+        }
+        _ => bug!("shouldn't have created a ValTree for {:?}", ty),
+    }
+}
+
+fn dump_place<'tcx>(ecx: &CompileTimeEvalContext<'tcx, 'tcx>, place: PlaceTy<'tcx>) {
+    trace!("{:?}", ecx.dump_place(*place));
+}
index 2b9fe56599715b6fd87db2f9104242b507d485f0..69d6c8470a2737233cef08d2ec5e517b725adf93 100644 (file)
@@ -27,7 +27,7 @@
 pub use self::operand::{ImmTy, Immediate, OpTy, Operand};
 pub use self::place::{MPlaceTy, MemPlace, MemPlaceMeta, Place, PlaceTy};
 pub use self::validity::{CtfeValidationMode, RefTracking};
-pub use self::visitor::{MutValueVisitor, ValueVisitor};
+pub use self::visitor::{MutValueVisitor, Value, ValueVisitor};
 
 crate use self::intrinsics::eval_nullary_intrinsic;
 use eval_context::{from_known_layout, mir_assign_valid_types};
index dfc0028e87fcc92a2ebd04f8a71dbd06a7e4a229..f2d833b320249f735487bf915794e94a4d661bee 100644 (file)
@@ -424,6 +424,7 @@ pub fn operand_downcast(
         })
     }
 
+    #[instrument(skip(self), level = "debug")]
     pub fn operand_projection(
         &self,
         base: &OpTy<'tcx, M::PointerTag>,
index e4660fe090ce5fb4900d9c350908103866906a1d..380eb5263618b5f26b6bba3681e4d44c770d5704 100644 (file)
@@ -115,6 +115,12 @@ fn deref(&self) -> &MemPlace<Tag> {
     }
 }
 
+impl<'tcx, Tag: Provenance> std::ops::DerefMut for MPlaceTy<'tcx, Tag> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.mplace
+    }
+}
+
 impl<'tcx, Tag: Provenance> From<MPlaceTy<'tcx, Tag>> for PlaceTy<'tcx, Tag> {
     #[inline(always)]
     fn from(mplace: MPlaceTy<'tcx, Tag>) -> Self {
@@ -294,6 +300,7 @@ pub fn ref_to_mplace(
 
     /// Take an operand, representing a pointer, and dereference it to a place -- that
     /// will always be a MemPlace.  Lives in `place.rs` because it creates a place.
+    #[instrument(skip(self), level = "debug")]
     pub fn deref_operand(
         &self,
         src: &OpTy<'tcx, M::PointerTag>,
@@ -487,7 +494,8 @@ pub(crate) fn mplace_downcast(
     }
 
     /// Project into an mplace
-    pub(super) fn mplace_projection(
+    #[instrument(skip(self), level = "debug")]
+    pub(crate) fn mplace_projection(
         &self,
         base: &MPlaceTy<'tcx, M::PointerTag>,
         proj_elem: mir::PlaceElem<'tcx>,
@@ -548,6 +556,7 @@ pub fn mplace_to_simd(
     /// Just a convenience function, but used quite a bit.
     /// This is the only projection that might have a side-effect: We cannot project
     /// into the field of a local `ScalarPair`, we have to first allocate it.
+    #[instrument(skip(self), level = "debug")]
     pub fn place_field(
         &mut self,
         base: &PlaceTy<'tcx, M::PointerTag>,
@@ -617,6 +626,7 @@ pub fn place_to_simd(
 
     /// Computes a place. You should only use this if you intend to write into this
     /// place; for reading, a more efficient alternative is `eval_place_for_read`.
+    #[instrument(skip(self), level = "debug")]
     pub fn eval_place(
         &mut self,
         place: mir::Place<'tcx>,
@@ -646,6 +656,7 @@ pub fn eval_place(
 
     /// Write an immediate to a place
     #[inline(always)]
+    #[instrument(skip(self), level = "debug")]
     pub fn write_immediate(
         &mut self,
         src: Immediate<M::PointerTag>,
@@ -830,6 +841,7 @@ pub fn write_uninit(&mut self, dest: &PlaceTy<'tcx, M::PointerTag>) -> InterpRes
     /// Copies the data from an operand to a place. This does not support transmuting!
     /// Use `copy_op_transmute` if the layouts could disagree.
     #[inline(always)]
+    #[instrument(skip(self), level = "debug")]
     pub fn copy_op(
         &mut self,
         src: &OpTy<'tcx, M::PointerTag>,
@@ -849,6 +861,7 @@ pub fn copy_op(
     /// Use `copy_op_transmute` if the layouts could disagree.
     /// Also, if you use this you are responsible for validating that things get copied at the
     /// right type.
+    #[instrument(skip(self), level = "debug")]
     fn copy_op_no_validate(
         &mut self,
         src: &OpTy<'tcx, M::PointerTag>,
@@ -955,6 +968,7 @@ pub fn copy_op_transmute(
     /// This supports unsized types and returns the computed size to avoid some
     /// redundant computation when copying; use `force_allocation` for a simpler, sized-only
     /// version.
+    #[instrument(skip(self), level = "debug")]
     pub fn force_allocation_maybe_sized(
         &mut self,
         place: &PlaceTy<'tcx, M::PointerTag>,
@@ -1037,6 +1051,7 @@ pub fn allocate_str(
     }
 
     /// Writes the discriminant of the given variant.
+    #[instrument(skip(self), level = "debug")]
     pub fn write_discriminant(
         &mut self,
         variant_index: VariantIdx,
index d688331ae0a56f569fac57467846e593a02164b6..34a004525196dd38f94df676398abf66c4d9ac6a 100644 (file)
@@ -35,6 +35,7 @@
 pub mod util;
 
 use rustc_middle::ty::query::Providers;
+use rustc_middle::ty::ParamEnv;
 
 pub fn provide(providers: &mut Providers) {
     const_eval::provide(providers);
@@ -49,6 +50,9 @@ pub fn provide(providers: &mut Providers) {
         let (param_env, raw) = param_env_and_value.into_parts();
         const_eval::const_to_valtree(tcx, param_env, raw)
     };
+    providers.valtree_to_const_val = |tcx, (ty, valtree)| {
+        const_eval::valtree_to_const_value(tcx, ParamEnv::empty().and(ty), valtree)
+    };
     providers.deref_const = |tcx, param_env_and_value| {
         let (param_env, value) = param_env_and_value.into_parts();
         const_eval::deref_const(tcx, param_env, value)
index faea2111d9210b204164a0aa98efe2edf239c73b..1052d588fadce960edcb7e895f9ab4d37ec439e6 100644 (file)
@@ -13,7 +13,7 @@
 //! move analysis runs after promotion on broken MIR.
 
 use rustc_hir as hir;
-use rustc_middle::mir::traversal::ReversePostorder;
+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;
@@ -170,7 +170,7 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
 
 pub fn collect_temps_and_candidates<'tcx>(
     ccx: &ConstCx<'_, 'tcx>,
-    rpo: &mut ReversePostorder<'_, 'tcx>,
+    rpo: &mut ReversePostorderIter<'_, 'tcx>,
 ) -> (IndexVec<Local, TempState>, Vec<Candidate>) {
     let mut collector = Collector {
         temps: IndexVec::from_elem(TempState::Undefined, &ccx.body.local_decls),
index 79d427ccc4469c08ef9e82d908063f5c6efca281..f71bc586b4847e3d92b2ac6f7a35123ed0ba3ee3 100644 (file)
@@ -214,7 +214,8 @@ fn visit_local(&mut self, local: &Local, context: PlaceContext, location: Locati
 
     fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
         // This check is somewhat expensive, so only run it when -Zvalidate-mir is passed.
-        if self.tcx.sess.opts.debugging_opts.validate_mir {
+        if self.tcx.sess.opts.debugging_opts.validate_mir && self.mir_phase < MirPhase::DropsLowered
+        {
             // `Operand::Copy` is only supposed to be used with `Copy` types.
             if let Operand::Copy(place) = operand {
                 let ty = place.ty(&self.body.local_decls, self.tcx).ty;
index 60b45856f51fbd24920e3634a27651b8f8f4f9aa..a7a480dd1d79018063d2bb74030e875767374c3e 100644 (file)
@@ -128,9 +128,9 @@ pub fn call_kind<'tcx>(
         } else {
             None
         };
-        let parent_self_ty = tcx
-            .parent(method_did)
-            .filter(|did| tcx.def_kind(*did) == rustc_hir::def::DefKind::Impl)
+        let parent_did = tcx.parent(method_did);
+        let parent_self_ty = (tcx.def_kind(parent_did) == rustc_hir::def::DefKind::Impl)
+            .then_some(parent_did)
             .and_then(|did| match tcx.type_of(did).kind() {
                 ty::Adt(def, ..) => Some(def.did()),
                 _ => None,
index 1edd47de4cbbd0d0b6238b5dd85cf8afe9586707..eb76d1836fcb7765cc1a6d6dc6bca039b50679c8 100644 (file)
@@ -3,7 +3,7 @@ current edition, but not in all editions.
 
 Erroneous code example:
 
-```ignore (limited to a warning during 2018 edition development)
+```rust2018,compile_fail,E0705
 #![feature(rust_2018_preview)]
 #![feature(test_2018_feature)] // error: the feature
                                // `test_2018_feature` is
index 24e59a93cea6cde4c80d78a9dbfca5a12bec4850..3143b81b6098f2b2aa580a716c77dc76748350cb 100644 (file)
@@ -1,3 +1,7 @@
 parser-struct-literal-body-without-path =
     struct literal body without path
     .suggestion = you might have forgotten to add the struct literal inside the block
+
+parser-maybe-report-ambiguous-plus =
+    ambiguous `+` in a type
+    .suggestion = use parentheses to disambiguate
index 721201d93124162f438329fb522b9c3e8ccefa42..6a3235fc7728cad8044806e74ec5a51f0d54a6e3 100644 (file)
@@ -82,3 +82,11 @@ typeck-value-of-associated-struct-already-specified =
 
 typeck-address-of-temporary-taken = cannot take address of a temporary
     .label = temporary value
+
+typeck-add-return-type-add = try adding a return type
+
+typeck-add-return-type-missing-here = a return type might be missing here
+
+typeck-expected-default-return-type = expected `()` because of default return type
+
+typeck-expected-return-type = expected `{$expected}` because of return type
index cd17726c78588dae3ac87503de5ba14dd192a8c1..83e6a751394f5a44c9227b8eb1a68ef9f91c6a19 100644 (file)
@@ -78,6 +78,13 @@ fn into(self) -> FluentValue<'source> {
     }
 }
 
+/// Trait implemented by error types. This should not be implemented manually. Instead, use
+/// `#[derive(SessionSubdiagnostic)]` -- see [rustc_macros::SessionSubdiagnostic].
+pub trait AddSubdiagnostic {
+    /// Add a subdiagnostic to an existing diagnostic.
+    fn add_to_diagnostic(self, diag: &mut Diagnostic);
+}
+
 #[must_use]
 #[derive(Clone, Debug, Encodable, Decodable)]
 pub struct Diagnostic {
@@ -605,7 +612,7 @@ pub fn span_suggestion(
         &mut self,
         sp: Span,
         msg: impl Into<DiagnosticMessage>,
-        suggestion: String,
+        suggestion: impl ToString,
         applicability: Applicability,
     ) -> &mut Self {
         self.span_suggestion_with_style(
@@ -623,13 +630,13 @@ pub fn span_suggestion_with_style(
         &mut self,
         sp: Span,
         msg: impl Into<DiagnosticMessage>,
-        suggestion: String,
+        suggestion: impl ToString,
         applicability: Applicability,
         style: SuggestionStyle,
     ) -> &mut Self {
         self.push_suggestion(CodeSuggestion {
             substitutions: vec![Substitution {
-                parts: vec![SubstitutionPart { snippet: suggestion, span: sp }],
+                parts: vec![SubstitutionPart { snippet: suggestion.to_string(), span: sp }],
             }],
             msg: msg.into(),
             style,
@@ -643,7 +650,7 @@ pub fn span_suggestion_verbose(
         &mut self,
         sp: Span,
         msg: impl Into<DiagnosticMessage>,
-        suggestion: String,
+        suggestion: impl ToString,
         applicability: Applicability,
     ) -> &mut Self {
         self.span_suggestion_with_style(
@@ -711,7 +718,7 @@ pub fn span_suggestion_short(
         &mut self,
         sp: Span,
         msg: impl Into<DiagnosticMessage>,
-        suggestion: String,
+        suggestion: impl ToString,
         applicability: Applicability,
     ) -> &mut Self {
         self.span_suggestion_with_style(
@@ -734,7 +741,7 @@ pub fn span_suggestion_hidden(
         &mut self,
         sp: Span,
         msg: impl Into<DiagnosticMessage>,
-        suggestion: String,
+        suggestion: impl ToString,
         applicability: Applicability,
     ) -> &mut Self {
         self.span_suggestion_with_style(
@@ -755,7 +762,7 @@ pub fn tool_only_span_suggestion(
         &mut self,
         sp: Span,
         msg: impl Into<DiagnosticMessage>,
-        suggestion: String,
+        suggestion: impl ToString,
         applicability: Applicability,
     ) -> &mut Self {
         self.span_suggestion_with_style(
@@ -768,6 +775,13 @@ pub fn tool_only_span_suggestion(
         self
     }
 
+    /// Add a subdiagnostic from a type that implements `SessionSubdiagnostic` - see
+    /// [rustc_macros::SessionSubdiagnostic].
+    pub fn subdiagnostic(&mut self, subdiagnostic: impl AddSubdiagnostic) -> &mut Self {
+        subdiagnostic.add_to_diagnostic(self);
+        self
+    }
+
     pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self {
         self.span = sp.into();
         if let Some(span) = self.span.primary_span() {
index 74e0f7429461389194ae4f943e251750fafed9ac..96b730c2baaffd6885518af9e50c8d20c4e36f14 100644 (file)
@@ -255,19 +255,6 @@ fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Se
 /// instead of a `&DiagnosticBuilder<'a>`. This `forward!` macro makes
 /// it easy to declare such methods on the builder.
 macro_rules! forward {
-    // Forward pattern for &self -> &Self
-    (
-        $(#[$attrs:meta])*
-        pub fn $n:ident(&self, $($name:ident: $ty:ty),* $(,)?) -> &Self
-    ) => {
-        $(#[$attrs])*
-        #[doc = concat!("See [`Diagnostic::", stringify!($n), "()`].")]
-        pub fn $n(&self, $($name: $ty),*) -> &Self {
-            self.diagnostic.$n($($name),*);
-            self
-        }
-    };
-
     // Forward pattern for &mut self -> &mut Self
     (
         $(#[$attrs:meta])*
@@ -490,7 +477,7 @@ pub fn span_labels(
         &mut self,
         sp: Span,
         msg: impl Into<DiagnosticMessage>,
-        suggestion: String,
+        suggestion: impl ToString,
         applicability: Applicability,
     ) -> &mut Self);
     forward!(pub fn span_suggestions(
@@ -510,28 +497,28 @@ pub fn span_labels(
         &mut self,
         sp: Span,
         msg: impl Into<DiagnosticMessage>,
-        suggestion: String,
+        suggestion: impl ToString,
         applicability: Applicability,
     ) -> &mut Self);
     forward!(pub fn span_suggestion_verbose(
         &mut self,
         sp: Span,
         msg: impl Into<DiagnosticMessage>,
-        suggestion: String,
+        suggestion: impl ToString,
         applicability: Applicability,
     ) -> &mut Self);
     forward!(pub fn span_suggestion_hidden(
         &mut self,
         sp: Span,
         msg: impl Into<DiagnosticMessage>,
-        suggestion: String,
+        suggestion: impl ToString,
         applicability: Applicability,
     ) -> &mut Self);
     forward!(pub fn tool_only_span_suggestion(
         &mut self,
         sp: Span,
         msg: impl Into<DiagnosticMessage>,
-        suggestion: String,
+        suggestion: impl ToString,
         applicability: Applicability,
     ) -> &mut Self);
 
@@ -543,6 +530,11 @@ pub fn span_labels(
         name: impl Into<Cow<'static, str>>,
         arg: DiagnosticArgValue<'static>,
     ) -> &mut Self);
+
+    forward!(pub fn subdiagnostic(
+        &mut self,
+        subdiagnostic: impl crate::AddSubdiagnostic
+    ) -> &mut Self);
 }
 
 impl<G: EmissionGuarantee> Debug for DiagnosticBuilder<'_, G> {
index 47cdf39cd52ce056905cff618d64592d361388a9..5dd743e8d00236b93dfd4e79600a65af700c77ce 100644 (file)
@@ -212,7 +212,12 @@ fn emit_artifact_notification(&mut self, _path: &Path, _artifact_type: &str) {}
     fn emit_future_breakage_report(&mut self, _diags: Vec<Diagnostic>) {}
 
     /// Emit list of unused externs
-    fn emit_unused_externs(&mut self, _lint_level: &str, _unused_externs: &[&str]) {}
+    fn emit_unused_externs(
+        &mut self,
+        _lint_level: rustc_lint_defs::Level,
+        _unused_externs: &[&str],
+    ) {
+    }
 
     /// Checks if should show explanations about "rustc --explain"
     fn should_show_explain(&self) -> bool {
index d680e7fab704763917a2361f2c67b2100b33e915..6ff52182d6b037d6e713a66fee467af41ce8a05a 100644 (file)
@@ -171,7 +171,8 @@ fn emit_future_breakage_report(&mut self, diags: Vec<crate::Diagnostic>) {
         }
     }
 
-    fn emit_unused_externs(&mut self, lint_level: &str, unused_externs: &[&str]) {
+    fn emit_unused_externs(&mut self, lint_level: rustc_lint_defs::Level, unused_externs: &[&str]) {
+        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))
index 4e6ab0edf6666377c97b16e433619dd6c785f2c2..df41fc00714b684c9a16beaaa084b7a55b3c5bd4 100644 (file)
@@ -370,8 +370,8 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 impl error::Error for ExplicitBug {}
 
 pub use diagnostic::{
-    Diagnostic, DiagnosticArg, DiagnosticArgValue, DiagnosticId, DiagnosticStyledString,
-    IntoDiagnosticArg, SubDiagnostic,
+    AddSubdiagnostic, Diagnostic, DiagnosticArg, DiagnosticArgValue, DiagnosticId,
+    DiagnosticStyledString, IntoDiagnosticArg, SubDiagnostic,
 };
 pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee};
 use std::backtrace::Backtrace;
@@ -969,8 +969,19 @@ pub fn emit_future_breakage_report(&self, diags: Vec<Diagnostic>) {
         self.inner.borrow_mut().emitter.emit_future_breakage_report(diags)
     }
 
-    pub fn emit_unused_externs(&self, lint_level: &str, unused_externs: &[&str]) {
-        self.inner.borrow_mut().emit_unused_externs(lint_level, unused_externs)
+    pub fn emit_unused_externs(
+        &self,
+        lint_level: rustc_lint_defs::Level,
+        loud: bool,
+        unused_externs: &[&str],
+    ) {
+        let mut inner = self.inner.borrow_mut();
+
+        if loud && lint_level.is_error() {
+            inner.bump_err_count();
+        }
+
+        inner.emit_unused_externs(lint_level, unused_externs)
     }
 
     pub fn update_unstable_expectation_id(
@@ -1141,7 +1152,7 @@ fn emit_artifact_notification(&mut self, path: &Path, artifact_type: &str) {
         self.emitter.emit_artifact_notification(path, artifact_type);
     }
 
-    fn emit_unused_externs(&mut self, lint_level: &str, unused_externs: &[&str]) {
+    fn emit_unused_externs(&mut self, lint_level: rustc_lint_defs::Level, unused_externs: &[&str]) {
         self.emitter.emit_unused_externs(lint_level, unused_externs);
     }
 
index 3799623563f832054e56a611911df540a05e2094..ae1b50a4176873ef2900182fa247039af2a9ecbd 100644 (file)
@@ -1272,9 +1272,7 @@ pub fn parse_macro_name_and_helper_attrs(
     // Once we've located the `#[proc_macro_derive]` attribute, verify
     // that it's of the form `#[proc_macro_derive(Foo)]` or
     // `#[proc_macro_derive(Foo, attributes(A, ..))]`
-    let Some(list) = attr.meta_item_list() else {
-        return None;
-    };
+    let list = attr.meta_item_list()?;
     if list.len() != 1 && list.len() != 2 {
         diag.span_err(attr.span, "attribute must have either one or two arguments");
         return None;
index b8ed75cb6bb74750074cd93c925b8e4f7c5851c5..301c67f70264502cd06244ad36dc287f045b8cea 100644 (file)
@@ -113,6 +113,7 @@ pub fn typaram(
             bounds,
             kind: ast::GenericParamKind::Type { default },
             is_placeholder: false,
+            colon_span: None,
         }
     }
 
index fa628cd9ebd0b8ab62355727c1dc2bc9b097e131..c91125105d746a6c2431a892e49f29e307f116aa 100644 (file)
@@ -1,7 +1,7 @@
 //! Conditional compilation stripping.
 
 use rustc_ast::ptr::P;
-use rustc_ast::token::{DelimToken, Token, TokenKind};
+use rustc_ast::token::{Delimiter, Token, TokenKind};
 use rustc_ast::tokenstream::{AttrAnnotatedTokenStream, AttrAnnotatedTokenTree};
 use rustc_ast::tokenstream::{DelimSpan, Spacing};
 use rustc_ast::tokenstream::{LazyTokenStream, TokenTree};
@@ -418,7 +418,7 @@ fn expand_cfg_attr_item(
         // in `#[attr]`, so just use the span of the `#` token.
         let bracket_group = AttrAnnotatedTokenTree::Delimited(
             DelimSpan::from_single(pound_span),
-            DelimToken::Bracket,
+            Delimiter::Bracket,
             item.tokens
                 .as_ref()
                 .unwrap_or_else(|| panic!("Missing tokens for {:?}", item))
@@ -511,7 +511,7 @@ pub fn parse_cfg<'a>(meta_item: &'a MetaItem, sess: &Session) -> Option<&'a Meta
             err.span_suggestion(
                 span,
                 "expected syntax is",
-                suggestion.into(),
+                suggestion,
                 Applicability::HasPlaceholders,
             );
         }
index 9b224a733568bc0d544c4118c7103bc7093b7fe3..5bd89f3f42fa563c01888fee0d3904a16ef233c8 100644 (file)
@@ -8,7 +8,7 @@
 use rustc_ast as ast;
 use rustc_ast::mut_visit::*;
 use rustc_ast::ptr::P;
-use rustc_ast::token;
+use rustc_ast::token::{self, Delimiter};
 use rustc_ast::tokenstream::TokenStream;
 use rustc_ast::visit::{self, AssocCtxt, Visitor};
 use rustc_ast::{AssocItemKind, AstLike, AstLikeWrapper, AttrStyle, ExprKind, ForeignItemKind};
@@ -884,7 +884,7 @@ pub fn parse_ast_fragment<'a>(
         AstFragmentKind::Stmts => {
             let mut stmts = SmallVec::new();
             // Won't make progress on a `}`.
-            while this.token != token::Eof && this.token != token::CloseDelim(token::Brace) {
+            while this.token != token::Eof && this.token != token::CloseDelim(Delimiter::Brace) {
                 if let Some(stmt) = this.parse_full_stmt(AttemptLocalParseRecovery::Yes)? {
                     stmts.push(stmt);
                 }
index a5b8571fefe54f36a83558a9e362bd7c9475f729..36295da74adc5598ccf4898c8fe7913a7cbc23f4 100644 (file)
 crate mod transcribe;
 
 use metavar_expr::MetaVarExpr;
-use rustc_ast::token::{self, NonterminalKind, Token, TokenKind};
+use rustc_ast::token::{Delimiter, NonterminalKind, Token, TokenKind};
 use rustc_ast::tokenstream::DelimSpan;
 use rustc_span::symbol::Ident;
 use rustc_span::Span;
 
-/// Contains the sub-token-trees of a "delimited" token tree such as `(a b c)`. The delimiters
-/// might be `NoDelim`, but they are not represented explicitly.
+/// Contains the sub-token-trees of a "delimited" token tree such as `(a b c)`.
+/// The delimiters are not represented explicitly in the `tts` vector.
 #[derive(PartialEq, Encodable, Decodable, Debug)]
 struct Delimited {
-    delim: token::DelimToken,
+    delim: Delimiter,
     /// FIXME: #67062 has details about why this is sub-optimal.
     tts: Vec<TokenTree>,
 }
index c6a6e3d125f709196f09194bdfc509afb571c41d..35b5e0d0f2f61108b123b1bba46ba9240209ffdf 100644 (file)
 //! bound.
 use crate::mbe::{KleeneToken, TokenTree};
 
-use rustc_ast::token::{DelimToken, Token, TokenKind};
+use rustc_ast::token::{Delimiter, Token, TokenKind};
 use rustc_ast::{NodeId, DUMMY_NODE_ID};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::MultiSpan;
@@ -439,7 +439,7 @@ fn check_nested_occurrences(
             }
             (NestedMacroState::MacroRulesNotName, &TokenTree::Delimited(_, ref del))
             | (NestedMacroState::MacroName, &TokenTree::Delimited(_, ref del))
-                if del.delim == DelimToken::Brace =>
+                if del.delim == Delimiter::Brace =>
             {
                 let macro_rules = state == NestedMacroState::MacroRulesNotName;
                 state = NestedMacroState::Empty;
@@ -469,7 +469,7 @@ fn check_nested_occurrences(
                 check_occurrences(sess, node_id, tt, macros, binders, ops, valid);
             }
             (NestedMacroState::MacroName, &TokenTree::Delimited(_, ref del))
-                if del.delim == DelimToken::Paren =>
+                if del.delim == Delimiter::Parenthesis =>
             {
                 state = NestedMacroState::MacroNameParen;
                 nested_binders = Binders::default();
@@ -484,7 +484,7 @@ fn check_nested_occurrences(
                 );
             }
             (NestedMacroState::MacroNameParen, &TokenTree::Delimited(_, ref del))
-                if del.delim == DelimToken::Brace =>
+                if del.delim == Delimiter::Brace =>
             {
                 state = NestedMacroState::Empty;
                 check_occurrences(
index 2cfd6968accf7744a3b54d1e1588d206d92757de..050710097c331de9f5b2546fce4c57d5992f3c2b 100644 (file)
@@ -8,7 +8,7 @@
 use crate::mbe::transcribe::transcribe;
 
 use rustc_ast as ast;
-use rustc_ast::token::{self, NonterminalKind, Token, TokenKind, TokenKind::*};
+use rustc_ast::token::{self, Delimiter, NonterminalKind, Token, TokenKind, TokenKind::*};
 use rustc_ast::tokenstream::{DelimSpan, TokenStream};
 use rustc_ast::{NodeId, DUMMY_NODE_ID};
 use rustc_ast_pretty::pprust;
@@ -260,16 +260,15 @@ fn generic_extension<'cx, 'tt>(
                 // Merge the gated spans from parsing the matcher with the pre-existing ones.
                 sess.gated_spans.merge(gated_spans_snapshot);
 
-                // Ignore the delimiters on the RHS.
-                let rhs = match &rhses[i] {
-                    mbe::TokenTree::Delimited(_, delimited) => &delimited.tts,
+                let (rhs, rhs_span): (&mbe::Delimited, DelimSpan) = match &rhses[i] {
+                    mbe::TokenTree::Delimited(span, delimited) => (&delimited, *span),
                     _ => cx.span_bug(sp, "malformed macro rhs"),
                 };
                 let arm_span = rhses[i].span();
 
-                let rhs_spans = rhs.iter().map(|t| t.span()).collect::<Vec<_>>();
+                let rhs_spans = rhs.tts.iter().map(|t| t.span()).collect::<Vec<_>>();
                 // rhs has holes ( `$id` and `$(...)` that need filled)
-                let mut tts = match transcribe(cx, &named_matches, &rhs, transparency) {
+                let mut tts = match transcribe(cx, &named_matches, &rhs, rhs_span, transparency) {
                     Ok(tts) => tts,
                     Err(mut err) => {
                         err.emit();
@@ -1251,8 +1250,8 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow {
                 ];
                 match tok {
                     TokenTree::Token(token) => match token.kind {
-                        OpenDelim(token::DelimToken::Brace)
-                        | OpenDelim(token::DelimToken::Bracket)
+                        OpenDelim(Delimiter::Brace)
+                        | OpenDelim(Delimiter::Bracket)
                         | Comma
                         | FatArrow
                         | Colon
index 52a656e1d1c14e11546cca2720bd08730873b39d..cdc5e204236fb29062f261094bb5abe94f9d29f1 100644 (file)
@@ -1,4 +1,4 @@
-use rustc_ast::token;
+use rustc_ast::token::{self, Delimiter};
 use rustc_ast::tokenstream::{Cursor, TokenStream, TokenTree};
 use rustc_ast::{LitIntType, LitKind};
 use rustc_ast_pretty::pprust;
@@ -35,7 +35,7 @@ impl MetaVarExpr {
     ) -> PResult<'sess, MetaVarExpr> {
         let mut tts = input.trees();
         let ident = parse_ident(&mut tts, sess, outer_span)?;
-        let Some(TokenTree::Delimited(_, token::Paren, args)) = tts.next() else {
+        let Some(TokenTree::Delimited(_, Delimiter::Parenthesis, args)) = tts.next() else {
             let msg = "meta-variable expression parameter must be wrapped in parentheses";
             return Err(sess.span_diagnostic.struct_span_err(ident.span, msg));
         };
index 0bce6967a10ddb3a495b563802ba8c3af4167ed5..d52de24c393b7907f8ef8e42328d99810457557b 100644 (file)
@@ -1,7 +1,7 @@
 use crate::mbe::macro_parser::count_metavar_decls;
 use crate::mbe::{Delimited, KleeneOp, KleeneToken, MetaVarExpr, SequenceRepetition, TokenTree};
 
-use rustc_ast::token::{self, Token};
+use rustc_ast::token::{self, Delimiter, Token};
 use rustc_ast::{tokenstream, NodeId};
 use rustc_ast_pretty::pprust;
 use rustc_feature::Features;
@@ -147,11 +147,11 @@ fn parse_tree(
     match tree {
         // `tree` is a `$` token. Look at the next token in `trees`
         tokenstream::TokenTree::Token(Token { kind: token::Dollar, span }) => {
-            // FIXME: Handle `None`-delimited groups in a more systematic way
+            // FIXME: Handle `Invisible`-delimited groups in a more systematic way
             // during parsing.
             let mut next = outer_trees.next();
             let mut trees: Box<dyn Iterator<Item = tokenstream::TokenTree>>;
-            if let Some(tokenstream::TokenTree::Delimited(_, token::NoDelim, tts)) = next {
+            if let Some(tokenstream::TokenTree::Delimited(_, Delimiter::Invisible, tts)) = next {
                 trees = Box::new(tts.into_trees());
                 next = trees.next();
             } else {
@@ -162,7 +162,7 @@ fn parse_tree(
                 // `tree` is followed by a delimited set of token trees.
                 Some(tokenstream::TokenTree::Delimited(delim_span, delim, tts)) => {
                     if parsing_patterns {
-                        if delim != token::Paren {
+                        if delim != Delimiter::Parenthesis {
                             span_dollar_dollar_or_metavar_in_the_lhs_err(
                                 sess,
                                 &Token { kind: token::OpenDelim(delim), span: delim_span.entire() },
@@ -170,7 +170,7 @@ fn parse_tree(
                         }
                     } else {
                         match delim {
-                            token::Brace => {
+                            Delimiter::Brace => {
                                 // The delimiter is `{`.  This indicates the beginning
                                 // of a meta-variable expression (e.g. `${count(ident)}`).
                                 // Try to parse the meta-variable expression.
@@ -191,7 +191,7 @@ fn parse_tree(
                                     }
                                 }
                             }
-                            token::Paren => {}
+                            Delimiter::Parenthesis => {}
                             _ => {
                                 let tok = pprust::token_kind_to_string(&token::OpenDelim(delim));
                                 let msg = format!("expected `(` or `{{`, found `{}`", tok);
index d25f044234cf4727ff6d1b8a3b593ec12bc69a5f..94b6c3153ca30128c3f12df5c6c5b66d30156672 100644 (file)
@@ -2,7 +2,7 @@
 use crate::mbe::macro_parser::{MatchedNonterminal, MatchedSeq, MatchedTokenTree, NamedMatch};
 use crate::mbe::{self, MetaVarExpr};
 use rustc_ast::mut_visit::{self, MutVisitor};
-use rustc_ast::token::{self, Token, TokenKind};
+use rustc_ast::token::{self, Delimiter, Token, TokenKind};
 use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndSpacing};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{pluralize, PResult};
@@ -27,23 +27,14 @@ fn visit_span(&mut self, span: &mut Span) {
 
 /// An iterator over the token trees in a delimited token tree (`{ ... }`) or a sequence (`$(...)`).
 enum Frame<'a> {
-    Delimited {
-        tts: &'a [mbe::TokenTree],
-        delim_token: token::DelimToken,
-        idx: usize,
-        span: DelimSpan,
-    },
-    Sequence {
-        tts: &'a [mbe::TokenTree],
-        idx: usize,
-        sep: Option<Token>,
-    },
+    Delimited { tts: &'a [mbe::TokenTree], idx: usize, delim: Delimiter, span: DelimSpan },
+    Sequence { tts: &'a [mbe::TokenTree], idx: usize, sep: Option<Token> },
 }
 
 impl<'a> Frame<'a> {
     /// Construct a new frame around the delimited set of tokens.
-    fn new(tts: &'a [mbe::TokenTree]) -> Frame<'a> {
-        Frame::Delimited { tts, delim_token: token::NoDelim, idx: 0, span: DelimSpan::dummy() }
+    fn new(src: &'a mbe::Delimited, span: DelimSpan) -> Frame<'a> {
+        Frame::Delimited { tts: &src.tts, idx: 0, delim: src.delim, span }
     }
 }
 
@@ -85,17 +76,18 @@ fn next(&mut self) -> Option<&'a mbe::TokenTree> {
 pub(super) fn transcribe<'a>(
     cx: &ExtCtxt<'a>,
     interp: &FxHashMap<MacroRulesNormalizedIdent, NamedMatch>,
-    src: &[mbe::TokenTree],
+    src: &mbe::Delimited,
+    src_span: DelimSpan,
     transparency: Transparency,
 ) -> PResult<'a, TokenStream> {
     // Nothing for us to transcribe...
-    if src.is_empty() {
+    if src.tts.is_empty() {
         return Ok(TokenStream::default());
     }
 
     // We descend into the RHS (`src`), expanding things as we go. This stack contains the things
     // we have yet to expand/are still expanding. We start the stack off with the whole RHS.
-    let mut stack: SmallVec<[Frame<'_>; 1]> = smallvec![Frame::new(&src)];
+    let mut stack: SmallVec<[Frame<'_>; 1]> = smallvec![Frame::new(&src, src_span)];
 
     // As we descend in the RHS, we will need to be able to match nested sequences of matchers.
     // `repeats` keeps track of where we are in matching at each level, with the last element being
@@ -149,14 +141,14 @@ pub(super) fn transcribe<'a>(
                 // We are done processing a Delimited. If this is the top-level delimited, we are
                 // done. Otherwise, we unwind the result_stack to append what we have produced to
                 // any previous results.
-                Frame::Delimited { delim_token, span, .. } => {
+                Frame::Delimited { delim, span, .. } => {
                     if result_stack.is_empty() {
                         // No results left to compute! We are back at the top-level.
                         return Ok(TokenStream::new(result));
                     }
 
                     // Step back into the parent Delimited.
-                    let tree = TokenTree::Delimited(span, delim_token, TokenStream::new(result));
+                    let tree = TokenTree::Delimited(span, delim, TokenStream::new(result));
                     result = result_stack.pop().unwrap();
                     result.push(tree.into());
                 }
@@ -239,7 +231,7 @@ pub(super) fn transcribe<'a>(
                         }
                         MatchedNonterminal(ref nt) => {
                             // Other variables are emitted into the output stream as groups with
-                            // `Delimiter::None` to maintain parsing priorities.
+                            // `Delimiter::Invisible` to maintain parsing priorities.
                             // `Interpolated` is currently used for such groups in rustc parser.
                             marker.visit_span(&mut sp);
                             let token = TokenTree::token(token::Interpolated(nt.clone()), sp);
@@ -277,7 +269,7 @@ pub(super) fn transcribe<'a>(
                 mut_visit::visit_delim_span(&mut span, &mut marker);
                 stack.push(Frame::Delimited {
                     tts: &delimited.tts,
-                    delim_token: delimited.delim,
+                    delim: delimited.delim,
                     idx: 0,
                     span,
                 });
index 4a8236b2cf38d457a2028a120b36db654bca3895..5d447d911e7f4e1b7920f3282abdd1a679996df5 100644 (file)
@@ -1,7 +1,7 @@
 use crate::tests::{matches_codepattern, string_to_stream, with_error_checking_parse};
 
 use rustc_ast::ptr::P;
-use rustc_ast::token::{self, Token};
+use rustc_ast::token::{self, Delimiter, Token};
 use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree};
 use rustc_ast::visit;
 use rustc_ast::{self as ast, PatKind};
@@ -77,13 +77,14 @@ fn string_to_tts_macro() {
                         TokenTree::Delimited(_, first_delim, first_tts),
                         TokenTree::Token(Token { kind: token::FatArrow, .. }),
                         TokenTree::Delimited(_, second_delim, second_tts),
-                    ] if macro_delim == &token::Paren => {
+                    ] if macro_delim == &Delimiter::Parenthesis => {
                         let tts = &first_tts.trees().collect::<Vec<_>>();
                         match &tts[..] {
                             [
                                 TokenTree::Token(Token { kind: token::Dollar, .. }),
                                 TokenTree::Token(Token { kind: token::Ident(name, false), .. }),
-                            ] if first_delim == &token::Paren && name.as_str() == "a" => {}
+                            ] if first_delim == &Delimiter::Parenthesis && name.as_str() == "a" => {
+                            }
                             _ => panic!("value 3: {:?} {:?}", first_delim, first_tts),
                         }
                         let tts = &second_tts.trees().collect::<Vec<_>>();
@@ -91,7 +92,8 @@ fn string_to_tts_macro() {
                             [
                                 TokenTree::Token(Token { kind: token::Dollar, .. }),
                                 TokenTree::Token(Token { kind: token::Ident(name, false), .. }),
-                            ] if second_delim == &token::Paren && name.as_str() == "a" => {}
+                            ] if second_delim == &Delimiter::Parenthesis
+                                && name.as_str() == "a" => {}
                             _ => panic!("value 4: {:?} {:?}", second_delim, second_tts),
                         }
                     }
@@ -113,7 +115,7 @@ fn string_to_tts_1() {
             TokenTree::token(token::Ident(Symbol::intern("a"), false), sp(3, 4)).into(),
             TokenTree::Delimited(
                 DelimSpan::from_pair(sp(5, 6), sp(13, 14)),
-                token::DelimToken::Paren,
+                Delimiter::Parenthesis,
                 TokenStream::new(vec![
                     TokenTree::token(token::Ident(Symbol::intern("b"), false), sp(6, 7)).into(),
                     TokenTree::token(token::Colon, sp(8, 9)).into(),
@@ -124,7 +126,7 @@ fn string_to_tts_1() {
             .into(),
             TokenTree::Delimited(
                 DelimSpan::from_pair(sp(15, 16), sp(20, 21)),
-                token::DelimToken::Brace,
+                Delimiter::Brace,
                 TokenStream::new(vec![
                     TokenTree::token(token::Ident(Symbol::intern("b"), false), sp(17, 18)).into(),
                     TokenTree::token(token::Semi, sp(18, 19)).into(),
index 15af5fdc5f8e22cb175c18129b44eaf699ba6199..0d5d6ee07944f4a002e1fad66a6eda38f4146906 100644 (file)
@@ -149,6 +149,7 @@ fn mac_placeholder() -> ast::MacCall {
                 ident,
                 is_placeholder: true,
                 kind: ast::GenericParamKind::Lifetime,
+                colon_span: None,
             }
         }]),
         AstFragmentKind::Params => AstFragment::Params(smallvec![ast::Param {
index aec401a041ca35d51e29d92266c933f53ba88dda..8e1966a0711d6c6087b0dc540f34f5e34ae3a0bd 100644 (file)
@@ -9,6 +9,7 @@
 use rustc_errors::ErrorGuaranteed;
 use rustc_parse::nt_to_tokenstream;
 use rustc_parse::parser::ForceCollect;
+use rustc_span::profiling::SpannedEventArgRecorder;
 use rustc_span::{Span, DUMMY_SP};
 
 const EXEC_STRATEGY: pm::bridge::server::SameThread = pm::bridge::server::SameThread;
@@ -25,7 +26,10 @@ fn expand<'cx>(
         input: TokenStream,
     ) -> Result<TokenStream, ErrorGuaranteed> {
         let _timer =
-            ecx.sess.prof.generic_activity_with_arg("expand_proc_macro", ecx.expansion_descr());
+            ecx.sess.prof.generic_activity_with_arg_recorder("expand_proc_macro", |recorder| {
+                recorder.record_arg_with_span(ecx.expansion_descr(), span);
+            });
+
         let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace;
         let server = proc_macro_server::Rustc::new(ecx);
         self.client.run(&EXEC_STRATEGY, server, input, proc_macro_backtrace).map_err(|e| {
@@ -51,7 +55,10 @@ fn expand<'cx>(
         annotated: TokenStream,
     ) -> Result<TokenStream, ErrorGuaranteed> {
         let _timer =
-            ecx.sess.prof.generic_activity_with_arg("expand_proc_macro", ecx.expansion_descr());
+            ecx.sess.prof.generic_activity_with_arg_recorder("expand_proc_macro", |recorder| {
+                recorder.record_arg_with_span(ecx.expansion_descr(), span);
+            });
+
         let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace;
         let server = proc_macro_server::Rustc::new(ecx);
         self.client
@@ -103,7 +110,9 @@ fn expand(
 
         let stream = {
             let _timer =
-                ecx.sess.prof.generic_activity_with_arg("expand_proc_macro", ecx.expansion_descr());
+                ecx.sess.prof.generic_activity_with_arg_recorder("expand_proc_macro", |recorder| {
+                    recorder.record_arg_with_span(ecx.expansion_descr(), span);
+                });
             let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace;
             let server = proc_macro_server::Rustc::new(ecx);
             match self.client.run(&EXEC_STRATEGY, server, input, proc_macro_backtrace) {
index bd6f0b77ebf6b8f864a639146549e578ee7cb264..b7230cec3e4a99f74d7b0db409a93db61037f443 100644 (file)
@@ -28,24 +28,24 @@ trait ToInternal<T> {
     fn to_internal(self) -> T;
 }
 
-impl FromInternal<token::DelimToken> for Delimiter {
-    fn from_internal(delim: token::DelimToken) -> Delimiter {
+impl FromInternal<token::Delimiter> for Delimiter {
+    fn from_internal(delim: token::Delimiter) -> Delimiter {
         match delim {
-            token::Paren => Delimiter::Parenthesis,
-            token::Brace => Delimiter::Brace,
-            token::Bracket => Delimiter::Bracket,
-            token::NoDelim => Delimiter::None,
+            token::Delimiter::Parenthesis => Delimiter::Parenthesis,
+            token::Delimiter::Brace => Delimiter::Brace,
+            token::Delimiter::Bracket => Delimiter::Bracket,
+            token::Delimiter::Invisible => Delimiter::None,
         }
     }
 }
 
-impl ToInternal<token::DelimToken> for Delimiter {
-    fn to_internal(self) -> token::DelimToken {
+impl ToInternal<token::Delimiter> for Delimiter {
+    fn to_internal(self) -> token::Delimiter {
         match self {
-            Delimiter::Parenthesis => token::Paren,
-            Delimiter::Brace => token::Brace,
-            Delimiter::Bracket => token::Bracket,
-            Delimiter::None => token::NoDelim,
+            Delimiter::Parenthesis => token::Delimiter::Parenthesis,
+            Delimiter::Brace => token::Delimiter::Brace,
+            Delimiter::Bracket => token::Delimiter::Bracket,
+            Delimiter::None => token::Delimiter::Invisible,
         }
     }
 }
@@ -61,7 +61,7 @@ fn from_internal(
         let joint = spacing == Joint;
         let Token { kind, span } = match tree {
             tokenstream::TokenTree::Delimited(span, delim, tts) => {
-                let delimiter = Delimiter::from_internal(delim);
+                let delimiter = pm::Delimiter::from_internal(delim);
                 return TokenTree::Group(Group { delimiter, stream: tts, span, flatten: false });
             }
             tokenstream::TokenTree::Token(token) => token,
@@ -164,7 +164,7 @@ macro_rules! op {
                 .map(|kind| tokenstream::TokenTree::token(kind, span))
                 .collect();
                 stack.push(TokenTree::Group(Group {
-                    delimiter: Delimiter::Bracket,
+                    delimiter: pm::Delimiter::Bracket,
                     stream,
                     span: DelimSpan::from_single(span),
                     flatten: false,
@@ -181,7 +181,7 @@ macro_rules! op {
             Interpolated(nt) => {
                 let stream = nt_to_tokenstream(&nt, rustc.sess(), CanSynthesizeMissingTokens::No);
                 TokenTree::Group(Group {
-                    delimiter: Delimiter::None,
+                    delimiter: pm::Delimiter::None,
                     stream,
                     span: DelimSpan::from_single(span),
                     flatten: crate::base::pretty_printing_compatibility_hack(&nt, rustc.sess()),
index f3d4c8ab4384311b56a55ba6ef896bda98b40a3a..9159d60463c4c003e5cf8ba0a83db1b441f79b7e 100644 (file)
@@ -544,6 +544,8 @@ pub fn set(&self, features: &mut Features, span: Span) {
     (active, used_with_arg, "1.60.0", Some(93798), None),
     /// Allows `extern "wasm" fn`
     (active, wasm_abi, "1.53.0", Some(83788), None),
+    /// Allows `do yeet` expressions
+    (active, yeet_expr, "1.62.0", Some(96373), None),
     // !!!!    !!!!    !!!!    !!!!   !!!!    !!!!    !!!!    !!!!    !!!!    !!!!    !!!!
     // Features are listed in alphabetical order. Tidy will fail if you don't keep it this way.
     // !!!!    !!!!    !!!!    !!!!   !!!!    !!!!    !!!!    !!!!    !!!!    !!!!    !!!!
index 27ec461906419ea93328a5de07aa98cbb9f804a2..5d1314ebb488d08bd39fc386d1d3d50921f06393 100644 (file)
@@ -15,11 +15,13 @@ macro_rules! arena_types {
             [] block: rustc_hir::Block<'tcx>,
             [] bare_fn_ty: rustc_hir::BareFnTy<'tcx>,
             [] body: rustc_hir::Body<'tcx>,
+            [] generics: rustc_hir::Generics<'tcx>,
             [] generic_arg: rustc_hir::GenericArg<'tcx>,
             [] generic_args: rustc_hir::GenericArgs<'tcx>,
             [] generic_bound: rustc_hir::GenericBound<'tcx>,
             [] generic_param: rustc_hir::GenericParam<'tcx>,
             [] expr: rustc_hir::Expr<'tcx>,
+            [] impl_: rustc_hir::Impl<'tcx>,
             [] let_expr: rustc_hir::Let<'tcx>,
             [] expr_field: rustc_hir::ExprField<'tcx>,
             [] pat_field: rustc_hir::PatField<'tcx>,
index b3de86662eb09dc71da34f0f7187bab0bf975458..dfeee3f356ffb3f8cb2a78fe8cf91a7573c0c801 100644 (file)
@@ -4,8 +4,8 @@
 use crate::intravisit::FnKind;
 use crate::LangItem;
 
+use rustc_ast as ast;
 use rustc_ast::util::parser::ExprPrecedence;
-use rustc_ast::{self as ast, CrateSugar};
 use rustc_ast::{Attribute, FloatTy, IntTy, Label, LitKind, TraitObjectSyntax, UintTy};
 pub use rustc_ast::{BorrowKind, ImplPolarity, IsAuto};
 pub use rustc_ast::{CaptureBy, Movability, Mutability};
@@ -17,7 +17,7 @@
 use rustc_index::vec::IndexVec;
 use rustc_macros::HashStable_Generic;
 use rustc_span::hygiene::MacroKind;
-use rustc_span::source_map::{SourceMap, Spanned};
+use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{def_id::LocalDefId, BytePos, Span, DUMMY_SP};
 use rustc_target::asm::InlineAsmRegOrRegClass;
@@ -93,8 +93,6 @@ pub enum LifetimeName {
     Param(ParamName),
 
     /// User wrote nothing (e.g., the lifetime in `&u32`).
-    ///
-    /// The bool indicates whether the user should have written something.
     Implicit,
 
     /// Implicit lifetime in a context like `dyn Foo`. This is
@@ -444,9 +442,6 @@ pub enum GenericBound<'hir> {
     Outlives(Lifetime),
 }
 
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(GenericBound<'_>, 48);
-
 impl GenericBound<'_> {
     pub fn trait_ref(&self) -> Option<&TraitRef<'_>> {
         match self {
@@ -501,61 +496,25 @@ pub enum GenericParamKind<'hir> {
 pub struct GenericParam<'hir> {
     pub hir_id: HirId,
     pub name: ParamName,
-    pub bounds: GenericBounds<'hir>,
     pub span: Span,
     pub pure_wrt_drop: bool,
     pub kind: GenericParamKind<'hir>,
+    pub colon_span: Option<Span>,
 }
 
 impl<'hir> GenericParam<'hir> {
-    pub fn bounds_span_for_suggestions(&self) -> Option<Span> {
-        self.bounds
-            .iter()
-            .fold(None, |span: Option<Span>, bound| {
-                // We include bounds that come from a `#[derive(_)]` but point at the user's code,
-                // as we use this method to get a span appropriate for suggestions.
-                if !bound.span().can_be_used_for_suggestions() {
-                    None
-                } else {
-                    let span = span.map(|s| s.to(bound.span())).unwrap_or_else(|| bound.span());
-                    Some(span)
-                }
-            })
-            .map(|sp| sp.shrink_to_hi())
+    /// Synthetic type-parameters are inserted after normal ones.
+    /// In order for normal parameters to be able to refer to synthetic ones,
+    /// scans them first.
+    pub fn is_impl_trait(&self) -> bool {
+        matches!(self.kind, GenericParamKind::Type { synthetic: true, .. })
     }
 
-    /// Returns the span of `:` after a generic parameter.
-    ///
-    /// For example:
-    ///
-    /// ```text
-    /// fn a<T:>()
-    ///       ^
-    ///       |      here
-    ///       here   |
-    ///              v
-    /// fn b<T       :>()
+    /// This can happen for `async fn`, e.g. `async fn f<'_>(&'_ self)`.
     ///
-    /// fn c<T
-    ///
-    /// :>()
-    /// ^
-    /// |
-    /// here
-    /// ```
-    pub fn colon_span_for_suggestions(&self, source_map: &SourceMap) -> Option<Span> {
-        let sp = source_map
-            .span_extend_while(self.span.shrink_to_hi(), |c| c.is_whitespace() || c == ':')
-            .ok()?;
-
-        let snippet = source_map.span_to_snippet(sp).ok()?;
-        let offset = snippet.find(':')?;
-
-        let colon_sp = sp
-            .with_lo(BytePos(sp.lo().0 + offset as u32))
-            .with_hi(BytePos(sp.lo().0 + (offset + ':'.len_utf8()) as u32));
-
-        Some(colon_sp)
+    /// See `lifetime_to_generic_param` in `rustc_ast_lowering` for more information.
+    pub fn is_elided_lifetime(&self) -> bool {
+        matches!(self.kind, GenericParamKind::Lifetime { kind: LifetimeParamKind::Elided })
     }
 }
 
@@ -572,17 +531,22 @@ pub struct GenericParamCount {
 #[derive(Debug, HashStable_Generic)]
 pub struct Generics<'hir> {
     pub params: &'hir [GenericParam<'hir>],
-    pub where_clause: WhereClause<'hir>,
+    pub predicates: &'hir [WherePredicate<'hir>],
+    pub has_where_clause: bool,
+    pub where_clause_span: Span,
     pub span: Span,
 }
 
 impl<'hir> Generics<'hir> {
-    pub const fn empty() -> Generics<'hir> {
-        Generics {
+    pub const fn empty() -> &'hir Generics<'hir> {
+        const NOPE: Generics<'_> = Generics {
             params: &[],
-            where_clause: WhereClause { predicates: &[], span: DUMMY_SP },
+            predicates: &[],
+            has_where_clause: false,
+            where_clause_span: DUMMY_SP,
             span: DUMMY_SP,
-        }
+        };
+        &NOPE
     }
 
     pub fn get_named(&self, name: Symbol) -> Option<&GenericParam<'_>> {
@@ -601,32 +565,122 @@ pub fn spans(&self) -> MultiSpan {
             self.params.iter().map(|p| p.span).collect::<Vec<Span>>().into()
         }
     }
-}
 
-/// A where-clause in a definition.
-#[derive(Debug, HashStable_Generic)]
-pub struct WhereClause<'hir> {
-    pub predicates: &'hir [WherePredicate<'hir>],
-    // Only valid if predicates aren't empty.
-    pub span: Span,
-}
+    /// If there are generic parameters, return where to introduce a new one.
+    pub fn span_for_param_suggestion(&self) -> Option<Span> {
+        if self.params.iter().any(|p| self.span.contains(p.span)) {
+            // `fn foo<A>(t: impl Trait)`
+            //          ^ suggest `, T: Trait` here
+            let span = self.span.with_lo(self.span.hi() - BytePos(1)).shrink_to_lo();
+            Some(span)
+        } else {
+            None
+        }
+    }
 
-impl WhereClause<'_> {
-    pub fn span(&self) -> Option<Span> {
-        if self.predicates.is_empty() { None } else { Some(self.span) }
+    pub fn where_clause_span(&self) -> Option<Span> {
+        if self.predicates.is_empty() { None } else { Some(self.where_clause_span) }
     }
 
-    /// The `WhereClause` under normal circumstances points at either the predicates or the empty
+    /// The `where_span` under normal circumstances points at either the predicates or the empty
     /// space where the `where` clause should be. Only of use for diagnostic suggestions.
     pub fn span_for_predicates_or_empty_place(&self) -> Span {
-        self.span
+        self.where_clause_span
     }
 
     /// `Span` where further predicates would be suggested, accounting for trailing commas, like
     ///  in `fn foo<T>(t: T) where T: Foo,` so we don't suggest two trailing commas.
-    pub fn tail_span_for_suggestion(&self) -> Span {
+    pub fn tail_span_for_predicate_suggestion(&self) -> Span {
         let end = self.span_for_predicates_or_empty_place().shrink_to_hi();
-        self.predicates.last().map_or(end, |p| p.span()).shrink_to_hi().to(end)
+        if self.has_where_clause {
+            self.predicates
+                .iter()
+                .filter(|p| p.in_where_clause())
+                .last()
+                .map_or(end, |p| p.span())
+                .shrink_to_hi()
+                .to(end)
+        } else {
+            end
+        }
+    }
+
+    pub fn bounds_for_param(
+        &self,
+        param_def_id: LocalDefId,
+    ) -> impl Iterator<Item = &WhereBoundPredicate<'_>> {
+        self.predicates.iter().filter_map(move |pred| match pred {
+            WherePredicate::BoundPredicate(bp) if bp.is_param_bound(param_def_id.to_def_id()) => {
+                Some(bp)
+            }
+            _ => 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| {
+                // We include bounds that come from a `#[derive(_)]` but point at the user's code,
+                // as we use this method to get a span appropriate for suggestions.
+                let bs = bound.span();
+                if bs.can_be_used_for_suggestions() { Some(bs.shrink_to_hi()) } else { None }
+            },
+        )
+    }
+
+    pub fn span_for_predicate_removal(&self, pos: usize) -> Span {
+        let predicate = &self.predicates[pos];
+        let span = predicate.span();
+
+        if !predicate.in_where_clause() {
+            // <T: ?Sized, U>
+            //   ^^^^^^^^
+            return span;
+        }
+
+        // We need to find out which comma to remove.
+        if pos < self.predicates.len() - 1 {
+            let next_pred = &self.predicates[pos + 1];
+            if next_pred.in_where_clause() {
+                // where T: ?Sized, Foo: Bar,
+                //       ^^^^^^^^^^^
+                return span.until(next_pred.span());
+            }
+        }
+
+        if pos > 0 {
+            let prev_pred = &self.predicates[pos - 1];
+            if prev_pred.in_where_clause() {
+                // where Foo: Bar, T: ?Sized,
+                //               ^^^^^^^^^^^
+                return prev_pred.span().shrink_to_hi().to(span);
+            }
+        }
+
+        // This is the only predicate in the where clause.
+        // where T: ?Sized
+        // ^^^^^^^^^^^^^^^
+        self.where_clause_span
+    }
+
+    pub fn span_for_bound_removal(&self, predicate_pos: usize, bound_pos: usize) -> Span {
+        let predicate = &self.predicates[predicate_pos];
+        let bounds = predicate.bounds();
+
+        if bounds.len() == 1 {
+            return self.span_for_predicate_removal(predicate_pos);
+        }
+
+        let span = bounds[bound_pos].span();
+        if bound_pos == 0 {
+            // where T: ?Sized + Bar, Foo: Bar,
+            //          ^^^^^^^^^
+            span.to(bounds[1].span().shrink_to_lo())
+        } else {
+            // where T: Bar + ?Sized, Foo: Bar,
+            //             ^^^^^^^^^
+            bounds[bound_pos - 1].span().shrink_to_hi().to(span)
+        }
     }
 }
 
@@ -649,12 +703,29 @@ pub fn span(&self) -> Span {
             WherePredicate::EqPredicate(p) => p.span,
         }
     }
+
+    pub fn in_where_clause(&self) -> bool {
+        match self {
+            WherePredicate::BoundPredicate(p) => p.in_where_clause,
+            WherePredicate::RegionPredicate(p) => p.in_where_clause,
+            WherePredicate::EqPredicate(_) => false,
+        }
+    }
+
+    pub fn bounds(&self) -> GenericBounds<'hir> {
+        match self {
+            WherePredicate::BoundPredicate(p) => p.bounds,
+            WherePredicate::RegionPredicate(p) => p.bounds,
+            WherePredicate::EqPredicate(_) => &[],
+        }
+    }
 }
 
 /// A type bound (e.g., `for<'c> Foo: Send + Clone + 'c`).
 #[derive(Debug, HashStable_Generic)]
 pub struct WhereBoundPredicate<'hir> {
     pub span: Span,
+    pub in_where_clause: bool,
     /// Any generics from a `for` binding.
     pub bound_generic_params: &'hir [GenericParam<'hir>],
     /// The type being bounded.
@@ -666,14 +737,7 @@ pub struct WhereBoundPredicate<'hir> {
 impl<'hir> WhereBoundPredicate<'hir> {
     /// Returns `true` if `param_def_id` matches the `bounded_ty` of this predicate.
     pub fn is_param_bound(&self, param_def_id: DefId) -> bool {
-        let TyKind::Path(QPath::Resolved(None, path)) = self.bounded_ty.kind else {
-            return false;
-        };
-        match path.res {
-            Res::Def(DefKind::TyParam, def_id)
-            | Res::SelfTy { trait_: Some(def_id), alias_to: None } => def_id == param_def_id,
-            _ => false,
-        }
+        self.bounded_ty.as_generic_param().map_or(false, |(def_id, _)| def_id == param_def_id)
     }
 }
 
@@ -681,6 +745,7 @@ pub fn is_param_bound(&self, param_def_id: DefId) -> bool {
 #[derive(Debug, HashStable_Generic)]
 pub struct WhereRegionPredicate<'hir> {
     pub span: Span,
+    pub in_where_clause: bool,
     pub lifetime: Lifetime,
     pub bounds: GenericBounds<'hir>,
 }
@@ -2080,7 +2145,7 @@ pub fn hir_id(&self) -> HirId {
 pub struct TraitItem<'hir> {
     pub ident: Ident,
     pub def_id: LocalDefId,
-    pub generics: Generics<'hir>,
+    pub generics: &'hir Generics<'hir>,
     pub kind: TraitItemKind<'hir>,
     pub span: Span,
 }
@@ -2140,10 +2205,10 @@ pub fn hir_id(&self) -> HirId {
 pub struct ImplItem<'hir> {
     pub ident: Ident,
     pub def_id: LocalDefId,
-    pub vis: Visibility<'hir>,
-    pub generics: Generics<'hir>,
+    pub generics: &'hir Generics<'hir>,
     pub kind: ImplItemKind<'hir>,
     pub span: Span,
+    pub vis_span: Span,
 }
 
 impl ImplItem<'_> {
@@ -2246,6 +2311,23 @@ pub struct Ty<'hir> {
     pub span: Span,
 }
 
+impl<'hir> Ty<'hir> {
+    /// Returns `true` if `param_def_id` matches the `bounded_ty` of this predicate.
+    pub fn as_generic_param(&self) -> Option<(DefId, Ident)> {
+        let TyKind::Path(QPath::Resolved(None, path)) = self.kind else {
+            return None;
+        };
+        let [segment] = &path.segments else {
+            return None;
+        };
+        match path.res {
+            Res::Def(DefKind::TyParam, def_id)
+            | Res::SelfTy { trait_: Some(def_id), alias_to: None } => Some((def_id, segment.ident)),
+            _ => None,
+        }
+    }
+}
+
 /// Not represented directly in the AST; referred to by name through a `ty_path`.
 #[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, Debug)]
 #[derive(HashStable_Generic)]
@@ -2345,7 +2427,7 @@ pub struct BareFnTy<'hir> {
 
 #[derive(Debug, HashStable_Generic)]
 pub struct OpaqueTy<'hir> {
-    pub generics: Generics<'hir>,
+    pub generics: &'hir Generics<'hir>,
     pub bounds: GenericBounds<'hir>,
     pub origin: OpaqueTyOrigin,
 }
@@ -2645,34 +2727,11 @@ pub struct PolyTraitRef<'hir> {
     pub span: Span,
 }
 
-pub type Visibility<'hir> = Spanned<VisibilityKind<'hir>>;
-
-#[derive(Copy, Clone, Debug, HashStable_Generic)]
-pub enum VisibilityKind<'hir> {
-    Public,
-    Crate(CrateSugar),
-    Restricted { path: &'hir Path<'hir>, hir_id: HirId },
-    Inherited,
-}
-
-impl VisibilityKind<'_> {
-    pub fn is_pub(&self) -> bool {
-        matches!(*self, VisibilityKind::Public)
-    }
-
-    pub fn is_pub_restricted(&self) -> bool {
-        match *self {
-            VisibilityKind::Public | VisibilityKind::Inherited => false,
-            VisibilityKind::Crate(..) | VisibilityKind::Restricted { .. } => true,
-        }
-    }
-}
-
 #[derive(Debug, HashStable_Generic)]
 pub struct FieldDef<'hir> {
     pub span: Span,
+    pub vis_span: Span,
     pub ident: Ident,
-    pub vis: Visibility<'hir>,
     pub hir_id: HirId,
     pub ty: &'hir Ty<'hir>,
 }
@@ -2744,8 +2803,8 @@ pub struct Item<'hir> {
     pub ident: Ident,
     pub def_id: LocalDefId,
     pub kind: ItemKind<'hir>,
-    pub vis: Visibility<'hir>,
     pub span: Span,
+    pub vis_span: Span,
 }
 
 impl Item<'_> {
@@ -2842,7 +2901,7 @@ pub enum ItemKind<'hir> {
     /// A `const` item.
     Const(&'hir Ty<'hir>, BodyId),
     /// A function declaration.
-    Fn(FnSig<'hir>, Generics<'hir>, BodyId),
+    Fn(FnSig<'hir>, &'hir Generics<'hir>, BodyId),
     /// A MBE macro definition (`macro_rules!` or `macro`).
     Macro(ast::MacroDef, MacroKind),
     /// A module.
@@ -2852,22 +2911,22 @@ pub enum ItemKind<'hir> {
     /// Module-level inline assembly (from `global_asm!`).
     GlobalAsm(&'hir InlineAsm<'hir>),
     /// A type alias, e.g., `type Foo = Bar<u8>`.
-    TyAlias(&'hir Ty<'hir>, Generics<'hir>),
+    TyAlias(&'hir Ty<'hir>, &'hir Generics<'hir>),
     /// An opaque `impl Trait` type alias, e.g., `type Foo = impl Bar;`.
     OpaqueTy(OpaqueTy<'hir>),
     /// An enum definition, e.g., `enum Foo<A, B> {C<A>, D<B>}`.
-    Enum(EnumDef<'hir>, Generics<'hir>),
+    Enum(EnumDef<'hir>, &'hir Generics<'hir>),
     /// A struct definition, e.g., `struct Foo<A> {x: A}`.
-    Struct(VariantData<'hir>, Generics<'hir>),
+    Struct(VariantData<'hir>, &'hir Generics<'hir>),
     /// A union definition, e.g., `union Foo<A, B> {x: A, y: B}`.
-    Union(VariantData<'hir>, Generics<'hir>),
+    Union(VariantData<'hir>, &'hir Generics<'hir>),
     /// A trait definition.
-    Trait(IsAuto, Unsafety, Generics<'hir>, GenericBounds<'hir>, &'hir [TraitItemRef]),
+    Trait(IsAuto, Unsafety, &'hir Generics<'hir>, GenericBounds<'hir>, &'hir [TraitItemRef]),
     /// A trait alias.
-    TraitAlias(Generics<'hir>, GenericBounds<'hir>),
+    TraitAlias(&'hir Generics<'hir>, GenericBounds<'hir>),
 
     /// An implementation, e.g., `impl<A> Trait for Foo { .. }`.
-    Impl(Impl<'hir>),
+    Impl(&'hir Impl<'hir>),
 }
 
 #[derive(Debug, HashStable_Generic)]
@@ -2879,7 +2938,7 @@ pub struct Impl<'hir> {
     // decoding as `Span`s cannot be decoded when a `Session` is not available.
     pub defaultness_span: Option<Span>,
     pub constness: Constness,
-    pub generics: Generics<'hir>,
+    pub generics: &'hir Generics<'hir>,
 
     /// The trait being implemented, if any.
     pub of_trait: Option<TraitRef<'hir>>,
@@ -3002,7 +3061,7 @@ pub struct ForeignItem<'hir> {
     pub kind: ForeignItemKind<'hir>,
     pub def_id: LocalDefId,
     pub span: Span,
-    pub vis: Visibility<'hir>,
+    pub vis_span: Span,
 }
 
 impl ForeignItem<'_> {
@@ -3021,7 +3080,7 @@ pub fn foreign_item_id(&self) -> ForeignItemId {
 #[derive(Debug, HashStable_Generic)]
 pub enum ForeignItemKind<'hir> {
     /// A foreign function.
-    Fn(&'hir FnDecl<'hir>, &'hir [Ident], Generics<'hir>),
+    Fn(&'hir FnDecl<'hir>, &'hir [Ident], &'hir Generics<'hir>),
     /// A foreign static item (`static ext: u8`).
     Static(&'hir Ty<'hir>, Mutability),
     /// A foreign type.
@@ -3210,7 +3269,6 @@ pub enum Node<'hir> {
 
     Lifetime(&'hir Lifetime),
     GenericParam(&'hir GenericParam<'hir>),
-    Visibility(&'hir Visibility<'hir>),
 
     Crate(&'hir Mod<'hir>),
 
@@ -3253,7 +3311,6 @@ pub fn ident(&self) -> Option<Ident> {
             | Node::Binding(..)
             | Node::Arm(..)
             | Node::Local(..)
-            | Node::Visibility(..)
             | Node::Crate(..)
             | Node::Ty(..)
             | Node::TraitRef(..)
@@ -3318,18 +3375,18 @@ pub fn fn_kind(self) -> Option<FnKind<'hir>> {
         match self {
             Node::Item(i) => match i.kind {
                 ItemKind::Fn(ref sig, ref generics, _) => {
-                    Some(FnKind::ItemFn(i.ident, generics, sig.header, &i.vis))
+                    Some(FnKind::ItemFn(i.ident, generics, sig.header))
                 }
                 _ => None,
             },
             Node::TraitItem(ti) => match ti.kind {
                 TraitItemKind::Fn(ref sig, TraitFn::Provided(_)) => {
-                    Some(FnKind::Method(ti.ident, sig, None))
+                    Some(FnKind::Method(ti.ident, sig))
                 }
                 _ => None,
             },
             Node::ImplItem(ii) => match ii.kind {
-                ImplItemKind::Fn(ref sig, _) => Some(FnKind::Method(ii.ident, sig, Some(&ii.vis))),
+                ImplItemKind::Fn(ref sig, _) => Some(FnKind::Method(ii.ident, sig)),
                 _ => None,
             },
             Node::Expr(e) => match e.kind {
@@ -3339,6 +3396,12 @@ pub fn fn_kind(self) -> Option<FnKind<'hir>> {
             _ => None,
         }
     }
+
+    /// Get the fields for the tuple-constructor,
+    /// if this node is a tuple constructor, otherwise None
+    pub fn tuple_fields(&self) -> Option<&'hir [FieldDef<'hir>]> {
+        if let Node::Ctor(&VariantData::Tuple(fields, _)) = self { Some(fields) } else { None }
+    }
 }
 
 // Some nodes are used a lot. Make sure they don't unintentionally get bigger.
@@ -3349,9 +3412,12 @@ mod size_asserts {
     rustc_data_structures::static_assert_size!(super::Pat<'static>, 88);
     rustc_data_structures::static_assert_size!(super::QPath<'static>, 24);
     rustc_data_structures::static_assert_size!(super::Ty<'static>, 72);
-
-    rustc_data_structures::static_assert_size!(super::Item<'static>, 184);
-    rustc_data_structures::static_assert_size!(super::TraitItem<'static>, 128);
-    rustc_data_structures::static_assert_size!(super::ImplItem<'static>, 144);
-    rustc_data_structures::static_assert_size!(super::ForeignItem<'static>, 136);
+    rustc_data_structures::static_assert_size!(super::GenericBound<'_>, 48);
+    rustc_data_structures::static_assert_size!(super::Generics<'static>, 56);
+    rustc_data_structures::static_assert_size!(super::Impl<'static>, 80);
+
+    rustc_data_structures::static_assert_size!(super::Item<'static>, 80);
+    rustc_data_structures::static_assert_size!(super::TraitItem<'static>, 88);
+    rustc_data_structures::static_assert_size!(super::ImplItem<'static>, 80);
+    rustc_data_structures::static_assert_size!(super::ForeignItem<'static>, 72);
 }
index 8689e2c2afab36fd504eaf3c203bc09226bb8872..977c0eb3cd2bcf11075dc2668488ab009855fdcd 100644 (file)
@@ -100,10 +100,10 @@ fn visit_foreign_item(&self, foreign_item: &'hir ForeignItem<'hir>) {
 #[derive(Copy, Clone, Debug)]
 pub enum FnKind<'a> {
     /// `#[xxx] pub async/const/extern "Abi" fn foo()`
-    ItemFn(Ident, &'a Generics<'a>, FnHeader, &'a Visibility<'a>),
+    ItemFn(Ident, &'a Generics<'a>, FnHeader),
 
     /// `fn foo(&self)`
-    Method(Ident, &'a FnSig<'a>, Option<&'a Visibility<'a>>),
+    Method(Ident, &'a FnSig<'a>),
 
     /// `|x, y| {}`
     Closure,
@@ -112,8 +112,8 @@ pub enum FnKind<'a> {
 impl<'a> FnKind<'a> {
     pub fn header(&self) -> Option<&FnHeader> {
         match *self {
-            FnKind::ItemFn(_, _, ref header, _) => Some(header),
-            FnKind::Method(_, ref sig, _) => Some(&sig.header),
+            FnKind::ItemFn(_, _, ref header) => Some(header),
+            FnKind::Method(_, ref sig) => Some(&sig.header),
             FnKind::Closure => None,
         }
     }
@@ -163,10 +163,15 @@ fn foreign_item(&self, _: ForeignItemId) -> &'hir ForeignItem<'hir> {
 pub mod nested_filter {
     use super::Map;
 
-    /// Specifies what nested things a visitor wants to visit. The most
-    /// common choice is `OnlyBodies`, which will cause the visitor to
-    /// visit fn bodies for fns that it encounters, but skip over nested
-    /// item-like things.
+    /// Specifies what nested things a visitor wants to visit. By "nested
+    /// things", we are referring to bits of HIR that are not directly embedded
+    /// within one another but rather indirectly, through a table in the crate.
+    /// This is done to control dependencies during incremental compilation: the
+    /// non-inline bits of HIR can be tracked and hashed separately.
+    ///
+    /// The most common choice is `OnlyBodies`, which will cause the visitor to
+    /// visit fn bodies for fns that it encounters, and closure bodies, but
+    /// skip over nested item-like things.
     ///
     /// See the comments on `ItemLikeVisitor` for more details on the overall
     /// visit strategy.
@@ -217,27 +222,23 @@ impl NestedFilter<'_> for None {
 pub trait Visitor<'v>: Sized {
     // this type should not be overridden, it exists for convenient usage as `Self::Map`
     type Map: Map<'v> = <Self::NestedFilter as NestedFilter<'v>>::Map;
-    type NestedFilter: NestedFilter<'v> = nested_filter::None;
 
     ///////////////////////////////////////////////////////////////////////////
     // Nested items.
 
-    /// The default versions of the `visit_nested_XXX` routines invoke
-    /// this method to get a map to use. By selecting an enum variant,
-    /// you control which kinds of nested HIR are visited; see
-    /// `NestedVisitorMap` for details. By "nested HIR", we are
-    /// referring to bits of HIR that are not directly embedded within
-    /// one another but rather indirectly, through a table in the
-    /// crate. This is done to control dependencies during incremental
-    /// compilation: the non-inline bits of HIR can be tracked and
-    /// hashed separately.
+    /// Override this type to control which nested HIR are visited; see
+    /// [`NestedFilter`] for details. If you override this type, you
+    /// must also override [`nested_visit_map`](Self::nested_visit_map).
     ///
     /// **If for some reason you want the nested behavior, but don't
-    /// have a `Map` at your disposal:** then you should override the
-    /// `visit_nested_XXX` methods, and override this method to
-    /// `panic!()`. This way, if a new `visit_nested_XXX` variant is
-    /// added in the future, we will see the panic in your code and
-    /// fix it appropriately.
+    /// have a `Map` at your disposal:** then override the
+    /// `visit_nested_XXX` methods. If a new `visit_nested_XXX` variant is
+    /// added in the future, it will cause a panic which can be detected
+    /// and fixed appropriately.
+    type NestedFilter: NestedFilter<'v> = nested_filter::None;
+
+    /// If `type NestedFilter` is set to visit nested items, this method
+    /// must also be overridden to provide a map to retrieve nested items.
     fn nested_visit_map(&mut self) -> Self::Map {
         panic!(
             "nested_visit_map must be implemented or consider using \
@@ -245,14 +246,14 @@ fn nested_visit_map(&mut self) -> Self::Map {
         );
     }
 
-    /// Invoked when a nested item is encountered. By default does
-    /// nothing unless you override `nested_visit_map` to return other than
-    /// `None`, in which case it will walk the item. **You probably
-    /// don't want to override this method** -- instead, override
-    /// `nested_visit_map` or use the "shallow" or "deep" visit
-    /// patterns described on `itemlikevisit::ItemLikeVisitor`. The only
-    /// reason to override this method is if you want a nested pattern
-    /// but cannot supply a `Map`; see `nested_visit_map` for advice.
+    /// Invoked when a nested item is encountered. By default, when
+    /// `Self::NestedFilter` is `nested_filter::None`, this method does
+    /// nothing. **You probably don't want to override this method** --
+    /// instead, override [`Self::NestedFilter`] or use the "shallow" or
+    /// "deep" visit patterns described on
+    /// `itemlikevisit::ItemLikeVisitor`. The only reason to override
+    /// this method is if you want a nested pattern but cannot supply a
+    /// [`Map`]; see `nested_visit_map` for advice.
     fn visit_nested_item(&mut self, id: ItemId) {
         if Self::NestedFilter::INTER {
             let item = self.nested_visit_map().item(id);
@@ -291,9 +292,8 @@ fn visit_nested_foreign_item(&mut self, id: ForeignItemId) {
     }
 
     /// Invoked to visit the body of a function, method or closure. Like
-    /// visit_nested_item, does nothing by default unless you override
-    /// `nested_visit_map` to return other than `None`, in which case it will walk
-    /// the body.
+    /// `visit_nested_item`, does nothing by default unless you override
+    /// `Self::NestedFilter`.
     fn visit_nested_body(&mut self, id: BodyId) {
         if Self::NestedFilter::INTRA {
             let body = self.nested_visit_map().body(id);
@@ -475,9 +475,6 @@ fn visit_assoc_type_binding(&mut self, type_binding: &'v TypeBinding<'v>) {
         walk_assoc_type_binding(self, type_binding)
     }
     fn visit_attribute(&mut self, _id: HirId, _attr: &'v Attribute) {}
-    fn visit_vis(&mut self, vis: &'v Visibility<'v>) {
-        walk_vis(self, vis)
-    }
     fn visit_associated_item_kind(&mut self, kind: &'v AssocItemKind) {
         walk_associated_item_kind(self, kind);
     }
@@ -554,7 +551,6 @@ pub fn walk_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v Param<'v>) {
 }
 
 pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) {
-    visitor.visit_vis(&item.vis);
     visitor.visit_ident(item.ident);
     match item.kind {
         ItemKind::ExternCrate(orig_name) => {
@@ -572,7 +568,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) {
             visitor.visit_nested_body(body);
         }
         ItemKind::Fn(ref sig, ref generics, body_id) => visitor.visit_fn(
-            FnKind::ItemFn(item.ident, generics, sig.header, &item.vis),
+            FnKind::ItemFn(item.ident, generics, sig.header),
             &sig.decl,
             body_id,
             item.span,
@@ -623,7 +619,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) {
             visitor.visit_generics(generics);
             walk_list!(visitor, visit_trait_ref, of_trait);
             visitor.visit_ty(self_ty);
-            walk_list!(visitor, visit_impl_item_ref, items);
+            walk_list!(visitor, visit_impl_item_ref, *items);
         }
         ItemKind::Struct(ref struct_definition, ref generics)
         | ItemKind::Union(ref struct_definition, ref generics) => {
@@ -859,7 +855,6 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) {
 
 pub fn walk_foreign_item<'v, V: Visitor<'v>>(visitor: &mut V, foreign_item: &'v ForeignItem<'v>) {
     visitor.visit_id(foreign_item.hir_id());
-    visitor.visit_vis(&foreign_item.vis);
     visitor.visit_ident(foreign_item.ident);
 
     match foreign_item.kind {
@@ -904,7 +899,6 @@ pub fn walk_generic_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v Generi
             }
         }
     }
-    walk_list!(visitor, visit_param_bound, param.bounds);
 }
 
 pub fn walk_const_param_default<'v, V: Visitor<'v>>(visitor: &mut V, ct: &'v AnonConst) {
@@ -913,7 +907,7 @@ pub fn walk_const_param_default<'v, V: Visitor<'v>>(visitor: &mut V, ct: &'v Ano
 
 pub fn walk_generics<'v, V: Visitor<'v>>(visitor: &mut V, generics: &'v Generics<'v>) {
     walk_list!(visitor, visit_generic_param, generics.params);
-    walk_list!(visitor, visit_where_predicate, generics.where_clause.predicates);
+    walk_list!(visitor, visit_where_predicate, generics.predicates);
 }
 
 pub fn walk_where_predicate<'v, V: Visitor<'v>>(
@@ -999,7 +993,7 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v Trai
         }
         TraitItemKind::Fn(ref sig, TraitFn::Provided(body_id)) => {
             visitor.visit_fn(
-                FnKind::Method(trait_item.ident, sig, None),
+                FnKind::Method(trait_item.ident, sig),
                 &sig.decl,
                 body_id,
                 trait_item.span,
@@ -1025,10 +1019,9 @@ pub fn walk_trait_item_ref<'v, V: Visitor<'v>>(visitor: &mut V, trait_item_ref:
 
 pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplItem<'v>) {
     // N.B., deliberately force a compilation error if/when new fields are added.
-    let ImplItem { def_id: _, ident, ref vis, ref generics, ref kind, span: _ } = *impl_item;
+    let ImplItem { def_id: _, ident, ref generics, ref kind, span: _, vis_span: _ } = *impl_item;
 
     visitor.visit_ident(ident);
-    visitor.visit_vis(vis);
     visitor.visit_generics(generics);
     match *kind {
         ImplItemKind::Const(ref ty, body) => {
@@ -1038,7 +1031,7 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt
         }
         ImplItemKind::Fn(ref sig, body_id) => {
             visitor.visit_fn(
-                FnKind::Method(impl_item.ident, sig, Some(&impl_item.vis)),
+                FnKind::Method(impl_item.ident, sig),
                 &sig.decl,
                 body_id,
                 impl_item.span,
@@ -1082,7 +1075,6 @@ pub fn walk_struct_def<'v, V: Visitor<'v>>(
 
 pub fn walk_field_def<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v FieldDef<'v>) {
     visitor.visit_id(field.hir_id);
-    visitor.visit_vis(&field.vis);
     visitor.visit_ident(field.ident);
     visitor.visit_ty(&field.ty);
 }
@@ -1250,13 +1242,6 @@ pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm<'v>) {
     visitor.visit_expr(&arm.body);
 }
 
-pub fn walk_vis<'v, V: Visitor<'v>>(visitor: &mut V, vis: &'v Visibility<'v>) {
-    if let VisibilityKind::Restricted { ref path, hir_id } = vis.node {
-        visitor.visit_id(hir_id);
-        visitor.visit_path(path, hir_id)
-    }
-}
-
 pub fn walk_associated_item_kind<'v, V: Visitor<'v>>(_: &mut V, _: &'v AssocItemKind) {
     // No visitable content here: this fn exists so you can call it if
     // the right thing to do, should content be added in the future,
index db70002c2d66ac97d99d57ebb2f6da49403e6350..b2c6ca1354f107204af0e517e424135d8da00b8c 100644 (file)
@@ -17,8 +17,8 @@
 ///    an item, but don't care about how item-like things are nested
 ///    within one another.
 ///    - Example: Examine each expression to look for its type and do some check or other.
-///    - How: Implement `intravisit::Visitor` and override the `nested_visit_map()` method
-///      to return `NestedVisitorMap::OnlyBodies` and use
+///    - How: Implement `intravisit::Visitor` and override the `NestedFilter` type to
+///      `nested_filter::OnlyBodies` (and implement `nested_visit_map`), and use
 ///      `tcx.hir().visit_all_item_likes(&mut visitor.as_deep_visitor())`. Within your
 ///      `intravisit::Visitor` impl, implement methods like `visit_expr()` (don't forget to invoke
 ///      `intravisit::walk_expr()` to keep walking the subparts).
@@ -29,9 +29,9 @@
 ///    item-like things.
 ///    - Example: Lifetime resolution, which wants to bring lifetimes declared on the
 ///      impl into scope while visiting the impl-items, and then back out again.
-///    - How: Implement `intravisit::Visitor` and override the `nested_visit_map()` method
-///      to return `NestedVisitorMap::All`. Walk your crate with `intravisit::walk_crate()`
-///      invoked on `tcx.hir().krate()`.
+///    - How: Implement `intravisit::Visitor` and override the `NestedFilter` type to
+///      `nested_filter::All` (and implement `nested_visit_map`). Walk your crate with
+///      `tcx.hir().walk_toplevel_module(visitor)` invoked on `tcx.hir().krate()`.
 ///    - Pro: Visitor methods for any kind of HIR node, not just item-like things.
 ///    - Pro: Preserves nesting information
 ///    - Con: Does not integrate well into dependency tracking.
index 9318ebb40b09ba66f267554ab8eb91e17f632257..b3c22d4ec213d3864f0aaa3972b0ef6603fecf85 100644 (file)
@@ -293,6 +293,7 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
     TryTraitFromResidual,    sym::from_residual,       from_residual_fn,           Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
     TryTraitFromOutput,      sym::from_output,         from_output_fn,             Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
     TryTraitBranch,          sym::branch,              branch_fn,                  Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
+    TryTraitFromYeet,        sym::from_yeet,           from_yeet_fn,               Target::Fn,             GenericRequirement::None;
 
     PollReady,               sym::Ready,               poll_ready_variant,         Target::Variant,        GenericRequirement::None;
     PollPending,             sym::Pending,             poll_pending_variant,       Target::Variant,        GenericRequirement::None;
index 27f07a479b1b0ea0d8f14f6b3cdd010fa614aa53..7af9622b2cf76753b142dd3d1fcfeceaabb5a4da 100644 (file)
@@ -8,12 +8,11 @@
 use rustc_hir as hir;
 use rustc_hir::{GenericArg, GenericParam, GenericParamKind, Node, Term};
 use rustc_hir::{GenericBound, PatKind, RangeEnd, TraitBoundModifier};
-use rustc_span::source_map::{SourceMap, Spanned};
+use rustc_span::source_map::SourceMap;
 use rustc_span::symbol::{kw, Ident, IdentPrinter, Symbol};
 use rustc_span::{self, FileName};
 use rustc_target::spec::abi::Abi;
 
-use std::borrow::Cow;
 use std::cell::Cell;
 use std::vec;
 
@@ -98,7 +97,6 @@ pub fn print_node(&mut self, node: Node<'_>) {
                 self.print_block(&a)
             }
             Node::Lifetime(a) => self.print_lifetime(&a),
-            Node::Visibility(a) => self.print_visibility(&a),
             Node::GenericParam(_) => panic!("cannot print Node::GenericParam"),
             Node::Field(_) => panic!("cannot print Node::Field"),
             // These cases do not carry enough information in the
@@ -191,13 +189,6 @@ pub fn to_string<F>(ann: &dyn PpAnn, f: F) -> String
     printer.s.eof()
 }
 
-pub fn visibility_qualified<S: Into<Cow<'static, str>>>(vis: &hir::Visibility<'_>, w: S) -> String {
-    to_string(NO_ANN, |s| {
-        s.print_visibility(vis);
-        s.word(w)
-    })
-}
-
 pub fn generic_params_to_string(generic_params: &[GenericParam<'_>]) -> String {
     to_string(NO_ANN, |s| s.print_generic_params(generic_params))
 }
@@ -223,11 +214,10 @@ pub fn fn_to_string(
     header: hir::FnHeader,
     name: Option<Symbol>,
     generics: &hir::Generics<'_>,
-    vis: &hir::Visibility<'_>,
     arg_names: &[Ident],
     body_id: Option<hir::BodyId>,
 ) -> String {
-    to_string(NO_ANN, |s| s.print_fn(decl, header, name, generics, vis, arg_names, body_id))
+    to_string(NO_ANN, |s| s.print_fn(decl, header, name, generics, arg_names, body_id))
 }
 
 pub fn enum_def_to_string(
@@ -235,9 +225,8 @@ pub fn enum_def_to_string(
     generics: &hir::Generics<'_>,
     name: Symbol,
     span: rustc_span::Span,
-    visibility: &hir::Visibility<'_>,
 ) -> String {
-    to_string(NO_ANN, |s| s.print_enum_def(enum_definition, generics, name, span, visibility))
+    to_string(NO_ANN, |s| s.print_enum_def(enum_definition, generics, name, span))
 }
 
 impl<'a> State<'a> {
@@ -395,7 +384,6 @@ pub fn print_foreign_item(&mut self, item: &hir::ForeignItem<'_>) {
                     },
                     Some(item.ident.name),
                     generics,
-                    &item.vis,
                     arg_names,
                     None,
                 );
@@ -404,7 +392,7 @@ pub fn print_foreign_item(&mut self, item: &hir::ForeignItem<'_>) {
                 self.end() // end the outer fn box
             }
             hir::ForeignItemKind::Static(ref t, m) => {
-                self.head(visibility_qualified(&item.vis, "static"));
+                self.head("static");
                 if m == hir::Mutability::Mut {
                     self.word_space("mut");
                 }
@@ -416,7 +404,7 @@ pub fn print_foreign_item(&mut self, item: &hir::ForeignItem<'_>) {
                 self.end() // end the outer cbox
             }
             hir::ForeignItemKind::Type => {
-                self.head(visibility_qualified(&item.vis, "type"));
+                self.head("type");
                 self.print_ident(item.ident);
                 self.word(";");
                 self.end(); // end the head-ibox
@@ -430,9 +418,8 @@ fn print_associated_const(
         ident: Ident,
         ty: &hir::Ty<'_>,
         default: Option<hir::BodyId>,
-        vis: &hir::Visibility<'_>,
     ) {
-        self.word(visibility_qualified(vis, ""));
+        self.head("");
         self.word_space("const");
         self.print_ident(ident);
         self.word_space(":");
@@ -458,7 +445,7 @@ fn print_associated_type(
         if let Some(bounds) = bounds {
             self.print_bounds(":", bounds);
         }
-        self.print_where_clause(&generics.where_clause);
+        self.print_where_clause(generics);
         if let Some(ty) = ty {
             self.space();
             self.word_space("=");
@@ -473,12 +460,12 @@ fn print_item_type(
         generics: &hir::Generics<'_>,
         inner: impl Fn(&mut Self),
     ) {
-        self.head(visibility_qualified(&item.vis, "type"));
+        self.head("type");
         self.print_ident(item.ident);
         self.print_generic_params(&generics.params);
         self.end(); // end the inner ibox
 
-        self.print_where_clause(&generics.where_clause);
+        self.print_where_clause(generics);
         self.space();
         inner(self);
         self.word(";");
@@ -494,7 +481,7 @@ pub fn print_item(&mut self, item: &hir::Item<'_>) {
         self.ann.pre(self, AnnNode::Item(item));
         match item.kind {
             hir::ItemKind::ExternCrate(orig_name) => {
-                self.head(visibility_qualified(&item.vis, "extern crate"));
+                self.head("extern crate");
                 if let Some(orig_name) = orig_name {
                     self.print_name(orig_name);
                     self.space();
@@ -507,7 +494,7 @@ pub fn print_item(&mut self, item: &hir::Item<'_>) {
                 self.end(); // end outer head-block
             }
             hir::ItemKind::Use(ref path, kind) => {
-                self.head(visibility_qualified(&item.vis, "use"));
+                self.head("use");
                 self.print_path(path, false);
 
                 match kind {
@@ -526,7 +513,7 @@ pub fn print_item(&mut self, item: &hir::Item<'_>) {
                 self.end(); // end outer head-block
             }
             hir::ItemKind::Static(ref ty, m, expr) => {
-                self.head(visibility_qualified(&item.vis, "static"));
+                self.head("static");
                 if m == hir::Mutability::Mut {
                     self.word_space("mut");
                 }
@@ -542,7 +529,7 @@ pub fn print_item(&mut self, item: &hir::Item<'_>) {
                 self.end(); // end the outer cbox
             }
             hir::ItemKind::Const(ref ty, expr) => {
-                self.head(visibility_qualified(&item.vis, "const"));
+                self.head("const");
                 self.print_ident(item.ident);
                 self.word_space(":");
                 self.print_type(&ty);
@@ -561,7 +548,6 @@ pub fn print_item(&mut self, item: &hir::Item<'_>) {
                     sig.header,
                     Some(item.ident.name),
                     param_names,
-                    &item.vis,
                     &[],
                     Some(body),
                 );
@@ -571,12 +557,10 @@ pub fn print_item(&mut self, item: &hir::Item<'_>) {
                 self.ann.nested(self, Nested::Body(body));
             }
             hir::ItemKind::Macro(ref macro_def, _) => {
-                self.print_mac_def(macro_def, &item.ident, item.span, |state| {
-                    state.print_visibility(&item.vis)
-                });
+                self.print_mac_def(macro_def, &item.ident, item.span, |_| {});
             }
             hir::ItemKind::Mod(ref _mod) => {
-                self.head(visibility_qualified(&item.vis, "mod"));
+                self.head("mod");
                 self.print_ident(item.ident);
                 self.nbsp();
                 self.bopen();
@@ -594,7 +578,7 @@ pub fn print_item(&mut self, item: &hir::Item<'_>) {
                 self.bclose(item.span);
             }
             hir::ItemKind::GlobalAsm(ref asm) => {
-                self.head(visibility_qualified(&item.vis, "global_asm!"));
+                self.head("global_asm!");
                 self.print_inline_asm(asm);
                 self.end()
             }
@@ -620,14 +604,14 @@ pub fn print_item(&mut self, item: &hir::Item<'_>) {
                 });
             }
             hir::ItemKind::Enum(ref enum_definition, ref params) => {
-                self.print_enum_def(enum_definition, params, item.ident.name, item.span, &item.vis);
+                self.print_enum_def(enum_definition, params, item.ident.name, item.span);
             }
             hir::ItemKind::Struct(ref struct_def, ref generics) => {
-                self.head(visibility_qualified(&item.vis, "struct"));
+                self.head("struct");
                 self.print_struct(struct_def, generics, item.ident.name, item.span, true);
             }
             hir::ItemKind::Union(ref struct_def, ref generics) => {
-                self.head(visibility_qualified(&item.vis, "union"));
+                self.head("union");
                 self.print_struct(struct_def, generics, item.ident.name, item.span, true);
             }
             hir::ItemKind::Impl(hir::Impl {
@@ -642,9 +626,8 @@ pub fn print_item(&mut self, item: &hir::Item<'_>) {
                 items,
             }) => {
                 self.head("");
-                self.print_visibility(&item.vis);
-                self.print_defaultness(defaultness);
-                self.print_unsafety(unsafety);
+                self.print_defaultness(*defaultness);
+                self.print_unsafety(*unsafety);
                 self.word_nbsp("impl");
 
                 if !generics.params.is_empty() {
@@ -652,7 +635,7 @@ pub fn print_item(&mut self, item: &hir::Item<'_>) {
                     self.space();
                 }
 
-                if constness == hir::Constness::Const {
+                if *constness == hir::Constness::Const {
                     self.word_nbsp("const");
                 }
 
@@ -667,19 +650,18 @@ pub fn print_item(&mut self, item: &hir::Item<'_>) {
                 }
 
                 self.print_type(&self_ty);
-                self.print_where_clause(&generics.where_clause);
+                self.print_where_clause(generics);
 
                 self.space();
                 self.bopen();
                 self.print_inner_attributes(attrs);
-                for impl_item in items {
+                for impl_item in *items {
                     self.ann.nested(self, Nested::ImplItem(impl_item.id));
                 }
                 self.bclose(item.span);
             }
             hir::ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, trait_items) => {
                 self.head("");
-                self.print_visibility(&item.vis);
                 self.print_is_auto(is_auto);
                 self.print_unsafety(unsafety);
                 self.word_nbsp("trait");
@@ -696,7 +678,7 @@ pub fn print_item(&mut self, item: &hir::Item<'_>) {
                     }
                 }
                 self.print_bounds(":", real_bounds);
-                self.print_where_clause(&generics.where_clause);
+                self.print_where_clause(generics);
                 self.word(" ");
                 self.bopen();
                 for trait_item in trait_items {
@@ -705,7 +687,7 @@ pub fn print_item(&mut self, item: &hir::Item<'_>) {
                 self.bclose(item.span);
             }
             hir::ItemKind::TraitAlias(ref generics, ref bounds) => {
-                self.head(visibility_qualified(&item.vis, "trait"));
+                self.head("trait");
                 self.print_ident(item.ident);
                 self.print_generic_params(&generics.params);
                 let mut real_bounds = Vec::with_capacity(bounds.len());
@@ -721,7 +703,7 @@ pub fn print_item(&mut self, item: &hir::Item<'_>) {
                 }
                 self.nbsp();
                 self.print_bounds("=", real_bounds);
-                self.print_where_clause(&generics.where_clause);
+                self.print_where_clause(generics);
                 self.word(";");
                 self.end(); // end inner head-block
                 self.end(); // end outer head-block
@@ -753,12 +735,11 @@ pub fn print_enum_def(
         generics: &hir::Generics<'_>,
         name: Symbol,
         span: rustc_span::Span,
-        visibility: &hir::Visibility<'_>,
     ) {
-        self.head(visibility_qualified(visibility, "enum"));
+        self.head("enum");
         self.print_name(name);
         self.print_generic_params(&generics.params);
-        self.print_where_clause(&generics.where_clause);
+        self.print_where_clause(generics);
         self.space();
         self.print_variants(&enum_definition.variants, span)
     }
@@ -778,27 +759,6 @@ pub fn print_variants(&mut self, variants: &[hir::Variant<'_>], span: rustc_span
         self.bclose(span)
     }
 
-    pub fn print_visibility(&mut self, vis: &hir::Visibility<'_>) {
-        match vis.node {
-            hir::VisibilityKind::Public => self.word_nbsp("pub"),
-            hir::VisibilityKind::Crate(ast::CrateSugar::JustCrate) => self.word_nbsp("crate"),
-            hir::VisibilityKind::Crate(ast::CrateSugar::PubCrate) => self.word_nbsp("pub(crate)"),
-            hir::VisibilityKind::Restricted { ref path, .. } => {
-                self.word("pub(");
-                if path.segments.len() == 1 && path.segments[0].ident.name == kw::Super {
-                    // Special case: `super` can print like `pub(super)`.
-                    self.word("super");
-                } else {
-                    // Everything else requires `in` at present.
-                    self.word_nbsp("in");
-                    self.print_path(path, false);
-                }
-                self.word_nbsp(")");
-            }
-            hir::VisibilityKind::Inherited => (),
-        }
-    }
-
     pub fn print_defaultness(&mut self, defaultness: hir::Defaultness) {
         match defaultness {
             hir::Defaultness::Default { .. } => self.word_nbsp("default"),
@@ -823,12 +783,11 @@ pub fn print_struct(
                     self.commasep(Inconsistent, struct_def.fields(), |s, field| {
                         s.maybe_print_comment(field.span.lo());
                         s.print_outer_attributes(s.attrs(field.hir_id));
-                        s.print_visibility(&field.vis);
                         s.print_type(&field.ty)
                     });
                     self.pclose();
                 }
-                self.print_where_clause(&generics.where_clause);
+                self.print_where_clause(generics);
                 if print_finalizer {
                     self.word(";");
                 }
@@ -836,7 +795,7 @@ pub fn print_struct(
                 self.end() // close the outer-box
             }
             hir::VariantData::Struct(..) => {
-                self.print_where_clause(&generics.where_clause);
+                self.print_where_clause(generics);
                 self.nbsp();
                 self.bopen();
                 self.hardbreak_if_not_bol();
@@ -845,7 +804,6 @@ pub fn print_struct(
                     self.hardbreak_if_not_bol();
                     self.maybe_print_comment(field.span.lo());
                     self.print_outer_attributes(self.attrs(field.hir_id));
-                    self.print_visibility(&field.vis);
                     self.print_ident(field.ident);
                     self.word_nbsp(":");
                     self.print_type(&field.ty);
@@ -872,11 +830,10 @@ pub fn print_method_sig(
         ident: Ident,
         m: &hir::FnSig<'_>,
         generics: &hir::Generics<'_>,
-        vis: &hir::Visibility<'_>,
         arg_names: &[Ident],
         body_id: Option<hir::BodyId>,
     ) {
-        self.print_fn(&m.decl, m.header, Some(ident.name), generics, vis, arg_names, body_id)
+        self.print_fn(&m.decl, m.header, Some(ident.name), generics, arg_names, body_id)
     }
 
     pub fn print_trait_item(&mut self, ti: &hir::TraitItem<'_>) {
@@ -886,21 +843,15 @@ pub fn print_trait_item(&mut self, ti: &hir::TraitItem<'_>) {
         self.print_outer_attributes(self.attrs(ti.hir_id()));
         match ti.kind {
             hir::TraitItemKind::Const(ref ty, default) => {
-                let vis =
-                    Spanned { span: rustc_span::DUMMY_SP, node: hir::VisibilityKind::Inherited };
-                self.print_associated_const(ti.ident, &ty, default, &vis);
+                self.print_associated_const(ti.ident, &ty, default);
             }
             hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(ref arg_names)) => {
-                let vis =
-                    Spanned { span: rustc_span::DUMMY_SP, node: hir::VisibilityKind::Inherited };
-                self.print_method_sig(ti.ident, sig, &ti.generics, &vis, arg_names, None);
+                self.print_method_sig(ti.ident, sig, &ti.generics, arg_names, None);
                 self.word(";");
             }
             hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
-                let vis =
-                    Spanned { span: rustc_span::DUMMY_SP, node: hir::VisibilityKind::Inherited };
                 self.head("");
-                self.print_method_sig(ti.ident, sig, &ti.generics, &vis, &[], Some(body));
+                self.print_method_sig(ti.ident, sig, &ti.generics, &[], Some(body));
                 self.nbsp();
                 self.end(); // need to close a box
                 self.end(); // need to close a box
@@ -926,11 +877,11 @@ pub fn print_impl_item(&mut self, ii: &hir::ImplItem<'_>) {
 
         match ii.kind {
             hir::ImplItemKind::Const(ref ty, expr) => {
-                self.print_associated_const(ii.ident, &ty, Some(expr), &ii.vis);
+                self.print_associated_const(ii.ident, &ty, Some(expr));
             }
             hir::ImplItemKind::Fn(ref sig, body) => {
                 self.head("");
-                self.print_method_sig(ii.ident, sig, &ii.generics, &ii.vis, &[], Some(body));
+                self.print_method_sig(ii.ident, sig, &ii.generics, &[], Some(body));
                 self.nbsp();
                 self.end(); // need to close a box
                 self.end(); // need to close a box
@@ -2008,11 +1959,10 @@ pub fn print_fn(
         header: hir::FnHeader,
         name: Option<Symbol>,
         generics: &hir::Generics<'_>,
-        vis: &hir::Visibility<'_>,
         arg_names: &[Ident],
         body_id: Option<hir::BodyId>,
     ) {
-        self.print_fn_header_info(header, vis);
+        self.print_fn_header_info(header);
 
         if let Some(name) = name {
             self.nbsp();
@@ -2045,7 +1995,7 @@ pub fn print_fn(
         self.pclose();
 
         self.print_fn_output(decl);
-        self.print_where_clause(&generics.where_clause)
+        self.print_where_clause(generics)
     }
 
     fn print_closure_params(&mut self, decl: &hir::FnDecl<'_>, body_id: hir::BodyId) {
@@ -2146,21 +2096,8 @@ pub fn print_generic_param(&mut self, param: &GenericParam<'_>) {
         self.print_ident(param.name.ident());
 
         match param.kind {
-            GenericParamKind::Lifetime { .. } => {
-                let mut sep = ":";
-                for bound in param.bounds {
-                    match bound {
-                        GenericBound::Outlives(ref lt) => {
-                            self.word(sep);
-                            self.print_lifetime(lt);
-                            sep = "+";
-                        }
-                        _ => panic!(),
-                    }
-                }
-            }
+            GenericParamKind::Lifetime { .. } => {}
             GenericParamKind::Type { ref default, .. } => {
-                self.print_bounds(":", param.bounds);
                 if let Some(default) = default {
                     self.space();
                     self.word_space("=");
@@ -2183,15 +2120,15 @@ pub fn print_lifetime(&mut self, lifetime: &hir::Lifetime) {
         self.print_ident(lifetime.name.ident())
     }
 
-    pub fn print_where_clause(&mut self, where_clause: &hir::WhereClause<'_>) {
-        if where_clause.predicates.is_empty() {
+    pub fn print_where_clause(&mut self, generics: &hir::Generics<'_>) {
+        if generics.predicates.is_empty() {
             return;
         }
 
         self.space();
         self.word_space("where");
 
-        for (i, predicate) in where_clause.predicates.iter().enumerate() {
+        for (i, predicate) in generics.predicates.iter().enumerate() {
             if i != 0 {
                 self.word_space(",");
             }
@@ -2286,11 +2223,7 @@ pub fn print_ty_fn(
     ) {
         self.ibox(INDENT_UNIT);
         self.print_formal_generic_params(generic_params);
-        let generics = hir::Generics {
-            params: &[],
-            where_clause: hir::WhereClause { predicates: &[], span: rustc_span::DUMMY_SP },
-            span: rustc_span::DUMMY_SP,
-        };
+        let generics = hir::Generics::empty();
         self.print_fn(
             decl,
             hir::FnHeader {
@@ -2301,16 +2234,13 @@ pub fn print_ty_fn(
             },
             name,
             &generics,
-            &Spanned { span: rustc_span::DUMMY_SP, node: hir::VisibilityKind::Inherited },
             arg_names,
             None,
         );
         self.end();
     }
 
-    pub fn print_fn_header_info(&mut self, header: hir::FnHeader, vis: &hir::Visibility<'_>) {
-        self.word(visibility_qualified(vis, ""));
-
+    pub fn print_fn_header_info(&mut self, header: hir::FnHeader) {
         match header.constness {
             hir::Constness::NotConst => {}
             hir::Constness::Const => self.word_nbsp("const"),
index 60b48e9bc8a0124d1b2fc793121ba42e901fb173..2d06c9d8ec92c60d8f6cb3d56820d56d7c0d29d7 100644 (file)
@@ -241,7 +241,7 @@ fn dump_graph(query: &DepGraphQuery) {
             let targets = node_set(&query, &edge_filter.target);
             filter_nodes(&query, &sources, &targets)
         }
-        Err(_) => query.nodes().into_iter().collect(),
+        Err(_) => query.nodes().into_iter().map(|n| n.kind).collect(),
     };
     let edges = filter_edges(&query, &nodes);
 
@@ -264,33 +264,33 @@ fn dump_graph(query: &DepGraphQuery) {
 }
 
 #[allow(missing_docs)]
-pub struct GraphvizDepGraph<'q>(FxHashSet<&'q DepNode>, Vec<(&'q DepNode, &'q DepNode)>);
+pub struct GraphvizDepGraph(FxHashSet<DepKind>, Vec<(DepKind, DepKind)>);
 
-impl<'a, 'q> dot::GraphWalk<'a> for GraphvizDepGraph<'q> {
-    type Node = &'q DepNode;
-    type Edge = (&'q DepNode, &'q DepNode);
-    fn nodes(&self) -> dot::Nodes<'_, &'q DepNode> {
+impl<'a> dot::GraphWalk<'a> for GraphvizDepGraph {
+    type Node = DepKind;
+    type Edge = (DepKind, DepKind);
+    fn nodes(&self) -> dot::Nodes<'_, DepKind> {
         let nodes: Vec<_> = self.0.iter().cloned().collect();
         nodes.into()
     }
-    fn edges(&self) -> dot::Edges<'_, (&'q DepNode, &'q DepNode)> {
+    fn edges(&self) -> dot::Edges<'_, (DepKind, DepKind)> {
         self.1[..].into()
     }
-    fn source(&self, edge: &(&'q DepNode, &'q DepNode)) -> &'q DepNode {
+    fn source(&self, edge: &(DepKind, DepKind)) -> DepKind {
         edge.0
     }
-    fn target(&self, edge: &(&'q DepNode, &'q DepNode)) -> &'q DepNode {
+    fn target(&self, edge: &(DepKind, DepKind)) -> DepKind {
         edge.1
     }
 }
 
-impl<'a, 'q> dot::Labeller<'a> for GraphvizDepGraph<'q> {
-    type Node = &'q DepNode;
-    type Edge = (&'q DepNode, &'q DepNode);
+impl<'a> dot::Labeller<'a> for GraphvizDepGraph {
+    type Node = DepKind;
+    type Edge = (DepKind, DepKind);
     fn graph_id(&self) -> dot::Id<'_> {
         dot::Id::new("DependencyGraph").unwrap()
     }
-    fn node_id(&self, n: &&'q DepNode) -> dot::Id<'_> {
+    fn node_id(&self, n: &DepKind) -> dot::Id<'_> {
         let s: String = format!("{:?}", n)
             .chars()
             .map(|c| if c == '_' || c.is_alphanumeric() { c } else { '_' })
@@ -298,7 +298,7 @@ fn node_id(&self, n: &&'q DepNode) -> dot::Id<'_> {
         debug!("n={:?} s={:?}", n, s);
         dot::Id::new(s).unwrap()
     }
-    fn node_label(&self, n: &&'q DepNode) -> dot::LabelText<'_> {
+    fn node_label(&self, n: &DepKind) -> dot::LabelText<'_> {
         dot::LabelText::label(format!("{:?}", n))
     }
 }
@@ -323,7 +323,7 @@ fn filter_nodes<'q>(
     query: &'q DepGraphQuery,
     sources: &Option<FxHashSet<&'q DepNode>>,
     targets: &Option<FxHashSet<&'q DepNode>>,
-) -> FxHashSet<&'q DepNode> {
+) -> FxHashSet<DepKind> {
     if let Some(sources) = sources {
         if let Some(targets) = targets {
             walk_between(query, sources, targets)
@@ -333,7 +333,7 @@ fn filter_nodes<'q>(
     } else if let Some(targets) = targets {
         walk_nodes(query, targets, INCOMING)
     } else {
-        query.nodes().into_iter().collect()
+        query.nodes().into_iter().map(|n| n.kind).collect()
     }
 }
 
@@ -341,17 +341,17 @@ fn walk_nodes<'q>(
     query: &'q DepGraphQuery,
     starts: &FxHashSet<&'q DepNode>,
     direction: Direction,
-) -> FxHashSet<&'q DepNode> {
+) -> FxHashSet<DepKind> {
     let mut set = FxHashSet::default();
     for &start in starts {
         debug!("walk_nodes: start={:?} outgoing?={:?}", start, direction == OUTGOING);
-        if set.insert(start) {
+        if set.insert(start.kind) {
             let mut stack = vec![query.indices[start]];
             while let Some(index) = stack.pop() {
                 for (_, edge) in query.graph.adjacent_edges(index, direction) {
                     let neighbor_index = edge.source_or_target(direction);
                     let neighbor = query.graph.node_data(neighbor_index);
-                    if set.insert(neighbor) {
+                    if set.insert(neighbor.kind) {
                         stack.push(neighbor_index);
                     }
                 }
@@ -365,7 +365,7 @@ fn walk_between<'q>(
     query: &'q DepGraphQuery,
     sources: &FxHashSet<&'q DepNode>,
     targets: &FxHashSet<&'q DepNode>,
-) -> FxHashSet<&'q DepNode> {
+) -> FxHashSet<DepKind> {
     // This is a bit tricky. We want to include a node only if it is:
     // (a) reachable from a source and (b) will reach a target. And we
     // have to be careful about cycles etc.  Luckily efficiency is not
@@ -396,6 +396,7 @@ enum State {
             let index = query.indices[n];
             node_states[index.0] == State::Included
         })
+        .map(|n| n.kind)
         .collect();
 
     fn recurse(query: &DepGraphQuery, node_states: &mut [State], node: NodeIndex) -> bool {
@@ -433,11 +434,13 @@ fn recurse(query: &DepGraphQuery, node_states: &mut [State], node: NodeIndex) ->
 
 fn filter_edges<'q>(
     query: &'q DepGraphQuery,
-    nodes: &FxHashSet<&'q DepNode>,
-) -> Vec<(&'q DepNode, &'q DepNode)> {
-    query
+    nodes: &FxHashSet<DepKind>,
+) -> Vec<(DepKind, DepKind)> {
+    let uniq: FxHashSet<_> = query
         .edges()
         .into_iter()
-        .filter(|&(source, target)| nodes.contains(source) && nodes.contains(target))
-        .collect()
+        .map(|(s, t)| (s.kind, t.kind))
+        .filter(|(source, target)| nodes.contains(source) && nodes.contains(target))
+        .collect();
+    uniq.into_iter().collect()
 }
index cdc05095e685111a983d32dc24e9ae2b92699992..059755a743b6676f9db2cba0b79fb3acd13329e6 100644 (file)
@@ -479,6 +479,11 @@ pub fn contains(&self, elem: T) -> bool {
         }
     }
 
+    #[inline]
+    pub fn iter(&self) -> ChunkedBitIter<'_, T> {
+        ChunkedBitIter::new(self)
+    }
+
     /// Insert `elem`. Returns whether the set has changed.
     pub fn insert(&mut self, elem: T) -> bool {
         assert!(elem.index() < self.domain_size);
@@ -697,6 +702,49 @@ fn clone_from(&mut self, from: &Self) {
     }
 }
 
+pub struct ChunkedBitIter<'a, T: Idx> {
+    index: usize,
+    bitset: &'a ChunkedBitSet<T>,
+}
+
+impl<'a, T: Idx> ChunkedBitIter<'a, T> {
+    #[inline]
+    fn new(bitset: &'a ChunkedBitSet<T>) -> ChunkedBitIter<'a, T> {
+        ChunkedBitIter { index: 0, bitset }
+    }
+}
+
+impl<'a, T: Idx> Iterator for ChunkedBitIter<'a, T> {
+    type Item = T;
+    fn next(&mut self) -> Option<T> {
+        while self.index < self.bitset.domain_size() {
+            let elem = T::new(self.index);
+            let chunk = &self.bitset.chunks[chunk_index(elem)];
+            match &chunk {
+                Zeros(chunk_domain_size) => {
+                    self.index += *chunk_domain_size as usize;
+                }
+                Ones(_chunk_domain_size) => {
+                    self.index += 1;
+                    return Some(elem);
+                }
+                Mixed(_chunk_domain_size, _, words) => loop {
+                    let elem = T::new(self.index);
+                    self.index += 1;
+                    let (word_index, mask) = chunk_word_index_and_mask(elem);
+                    if (words[word_index] & mask) != 0 {
+                        return Some(elem);
+                    }
+                    if self.index % CHUNK_BITS == 0 {
+                        break;
+                    }
+                },
+            }
+        }
+        None
+    }
+}
+
 impl Chunk {
     #[cfg(test)]
     fn assert_valid(&self) {
@@ -1714,7 +1762,7 @@ pub fn iter<'a>(&'a self, row: R) -> impl Iterator<Item = C> + 'a {
     }
 
     pub fn row(&self, row: R) -> Option<&HybridBitSet<C>> {
-        if let Some(Some(row)) = self.rows.get(row) { Some(row) } else { None }
+        self.rows.get(row)?.as_ref()
     }
 
     /// Intersects `row` with `set`. `set` can be either `BitSet` or
index eec7dab5189a664c955a88bffe827560e497ac71..cfc891e97a32bbf4f79b041b794834686f67de96 100644 (file)
@@ -342,6 +342,40 @@ fn chunked_bitset() {
     b10000b.assert_valid();
 }
 
+#[test]
+fn chunked_bitset_iter() {
+    fn with_elements(elements: &[usize], domain_size: usize) -> ChunkedBitSet<usize> {
+        let mut s = ChunkedBitSet::new_empty(domain_size);
+        for &e in elements {
+            s.insert(e);
+        }
+        s
+    }
+
+    // Empty
+    let vec: Vec<usize> = Vec::new();
+    let bit = with_elements(&vec, 9000);
+    assert_eq!(vec, bit.iter().collect::<Vec<_>>());
+
+    // Filled
+    let n = 10000;
+    let vec: Vec<usize> = (0..n).collect();
+    let bit = with_elements(&vec, n);
+    assert_eq!(vec, bit.iter().collect::<Vec<_>>());
+
+    // Filled with trailing zeros
+    let n = 10000;
+    let vec: Vec<usize> = (0..n).collect();
+    let bit = with_elements(&vec, 2 * n);
+    assert_eq!(vec, bit.iter().collect::<Vec<_>>());
+
+    // Mixed
+    let n = 12345;
+    let vec: Vec<usize> = vec![0, 1, 2, 2010, 2047, 2099, 6000, 6002, 6004];
+    let bit = with_elements(&vec, n);
+    assert_eq!(vec, bit.iter().collect::<Vec<_>>());
+}
+
 #[test]
 fn grow() {
     let mut set: GrowableBitSet<usize> = GrowableBitSet::with_capacity(65);
index f2dd4f5d5cbcae1273fa0d4d3a7bf5d91d9d7ca2..2e50dbff51089a9df7a52808e293bc115f198c27 100644 (file)
@@ -61,7 +61,7 @@
 use rustc_errors::{pluralize, struct_span_err, Diagnostic, ErrorGuaranteed};
 use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString, MultiSpan};
 use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{Item, ItemKind, Node};
 use rustc_middle::dep_graph::DepContext;
@@ -2198,7 +2198,7 @@ fn emit_tuple_wrap_err(
             err.span_suggestion(
                 span.with_hi(before_close).shrink_to_hi(),
                 msg,
-                ",".into(),
+                ",",
                 Applicability::MachineApplicable,
             );
         } else {
@@ -2285,7 +2285,9 @@ pub fn report_generic_bound_failure(
         bound_kind: GenericKind<'tcx>,
         sub: Region<'tcx>,
     ) {
-        self.construct_generic_bound_failure(span, origin, bound_kind, sub).emit();
+        let owner =
+            self.in_progress_typeck_results.map(|typeck_results| typeck_results.borrow().hir_owner);
+        self.construct_generic_bound_failure(span, origin, bound_kind, sub, owner).emit();
     }
 
     pub fn construct_generic_bound_failure(
@@ -2294,31 +2296,29 @@ pub fn construct_generic_bound_failure(
         origin: Option<SubregionOrigin<'tcx>>,
         bound_kind: GenericKind<'tcx>,
         sub: Region<'tcx>,
+        owner: Option<LocalDefId>,
     ) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
         let hir = self.tcx.hir();
         // Attempt to obtain the span of the parameter so we can
         // suggest adding an explicit lifetime bound to it.
-        let generics = self
-            .in_progress_typeck_results
-            .map(|typeck_results| typeck_results.borrow().hir_owner)
-            .map(|owner| {
-                let hir_id = hir.local_def_id_to_hir_id(owner);
-                let parent_id = hir.get_parent_item(hir_id);
-                (
-                    // Parent item could be a `mod`, so we check the HIR before calling:
-                    if let Some(Node::Item(Item {
-                        kind: ItemKind::Trait(..) | ItemKind::Impl { .. },
-                        ..
-                    })) = hir.find_by_def_id(parent_id)
-                    {
-                        Some(self.tcx.generics_of(parent_id))
-                    } else {
-                        None
-                    },
-                    self.tcx.generics_of(owner.to_def_id()),
-                    hir.span(hir_id),
-                )
-            });
+        let generics = owner.map(|owner| {
+            let hir_id = hir.local_def_id_to_hir_id(owner);
+            let parent_id = hir.get_parent_item(hir_id);
+            (
+                // Parent item could be a `mod`, so we check the HIR before calling:
+                if let Some(Node::Item(Item {
+                    kind: ItemKind::Trait(..) | ItemKind::Impl { .. },
+                    ..
+                })) = hir.find_by_def_id(parent_id)
+                {
+                    Some(self.tcx.generics_of(parent_id))
+                } else {
+                    None
+                },
+                self.tcx.generics_of(owner.to_def_id()),
+                hir.span(hir_id),
+            )
+        });
 
         let span = match generics {
             // This is to get around the trait identity obligation, that has a `DUMMY_SP` as signal
@@ -2327,6 +2327,7 @@ pub fn construct_generic_bound_failure(
             _ => span,
         };
 
+        // type_param_span is (span, has_bounds)
         let type_param_span = match (generics, bound_kind) {
             (Some((_, ref generics, _)), GenericKind::Param(ref param)) => {
                 // Account for the case where `param` corresponds to `Self`,
@@ -2337,25 +2338,18 @@ pub fn construct_generic_bound_failure(
                         // Get the `hir::Param` to verify whether it already has any bounds.
                         // We do this to avoid suggesting code that ends up as `T: 'a'b`,
                         // instead we suggest `T: 'a + 'b` in that case.
-                        let id = hir.local_def_id_to_hir_id(def_id);
-                        let mut has_bounds = false;
-                        if let Node::GenericParam(param) = hir.get(id) {
-                            has_bounds = !param.bounds.is_empty();
-                        }
-                        let sp = self.tcx.def_span(def_id);
+                        let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
+                        let ast_generics = self.tcx.hir().get_generics(hir_id.owner);
+                        let bounds =
+                            ast_generics.and_then(|g| g.bounds_span_for_suggestions(def_id));
                         // `sp` only covers `T`, change it so that it covers
                         // `T:` when appropriate
-                        let is_impl_trait = bound_kind.to_string().starts_with("impl ");
-                        let sp = if has_bounds && !is_impl_trait {
-                            sp.to(self
-                                .tcx
-                                .sess
-                                .source_map()
-                                .next_point(self.tcx.sess.source_map().next_point(sp)))
+                        if let Some(span) = bounds {
+                            (span, true)
                         } else {
-                            sp
-                        };
-                        (sp, has_bounds, is_impl_trait)
+                            let sp = self.tcx.def_span(def_id);
+                            (sp.shrink_to_hi(), false)
+                        }
                     })
                 } else {
                     None
@@ -2411,52 +2405,37 @@ pub fn construct_generic_bound_failure(
 
         fn binding_suggestion<'tcx, S: fmt::Display>(
             err: &mut Diagnostic,
-            type_param_span: Option<(Span, bool, bool)>,
+            type_param_span: Option<(Span, bool)>,
             bound_kind: GenericKind<'tcx>,
             sub: S,
         ) {
             let msg = "consider adding an explicit lifetime bound";
-            if let Some((sp, has_lifetimes, is_impl_trait)) = type_param_span {
-                let suggestion = if is_impl_trait {
-                    format!("{} + {}", bound_kind, sub)
-                } else {
-                    let tail = if has_lifetimes { " + " } else { "" };
-                    format!("{}: {}{}", bound_kind, sub, tail)
-                };
-                err.span_suggestion(
+            if let Some((sp, has_lifetimes)) = type_param_span {
+                let suggestion =
+                    if has_lifetimes { format!(" + {}", sub) } else { format!(": {}", sub) };
+                err.span_suggestion_verbose(
                     sp,
                     &format!("{}...", msg),
                     suggestion,
                     Applicability::MaybeIncorrect, // Issue #41966
                 );
             } else {
-                let consider = format!(
-                    "{} {}...",
-                    msg,
-                    if type_param_span.map_or(false, |(_, _, is_impl_trait)| is_impl_trait) {
-                        format!(" `{}` to `{}`", sub, bound_kind)
-                    } else {
-                        format!("`{}: {}`", bound_kind, sub)
-                    },
-                );
+                let consider = format!("{} `{}: {}`...", msg, bound_kind, sub,);
                 err.help(&consider);
             }
         }
 
         let new_binding_suggestion =
-            |err: &mut Diagnostic,
-             type_param_span: Option<(Span, bool, bool)>,
-             bound_kind: GenericKind<'tcx>| {
+            |err: &mut Diagnostic, type_param_span: Option<(Span, bool)>| {
                 let msg = "consider introducing an explicit lifetime bound";
-                if let Some((sp, has_lifetimes, is_impl_trait)) = type_param_span {
-                    let suggestion = if is_impl_trait {
-                        (sp.shrink_to_hi(), format!(" + {}", new_lt))
+                if let Some((sp, has_lifetimes)) = type_param_span {
+                    let suggestion = if has_lifetimes {
+                        format!(" + {}", new_lt)
                     } else {
-                        let tail = if has_lifetimes { " +" } else { "" };
-                        (sp, format!("{}: {}{}", bound_kind, new_lt, tail))
+                        format!(": {}", new_lt)
                     };
                     let mut sugg =
-                        vec![suggestion, (span.shrink_to_hi(), format!(" + {}", new_lt))];
+                        vec![(sp, suggestion), (span.shrink_to_hi(), format!(" + {}", new_lt))];
                     if let Some(lt) = add_lt_sugg {
                         sugg.push(lt);
                         sugg.rotate_right(1);
@@ -2543,11 +2522,11 @@ enum SubOrigin<'hir> {
                 let pred = format!("{}: {}", bound_kind, sub);
                 let suggestion = format!(
                     "{} {}",
-                    if !generics.where_clause.predicates.is_empty() { "," } else { " where" },
+                    if !generics.predicates.is_empty() { "," } else { " where" },
                     pred,
                 );
                 err.span_suggestion(
-                    generics.where_clause.tail_span_for_suggestion(),
+                    generics.tail_span_for_predicate_suggestion(),
                     "consider adding a where clause",
                     suggestion,
                     Applicability::MaybeIncorrect,
@@ -2606,11 +2585,8 @@ enum SubOrigin<'hir> {
                     None,
                 );
                 if let Some(infer::RelateParamBound(_, t, _)) = origin {
-                    let return_impl_trait = self
-                        .in_progress_typeck_results
-                        .map(|typeck_results| typeck_results.borrow().hir_owner)
-                        .and_then(|owner| self.tcx.return_type_impl_trait(owner))
-                        .is_some();
+                    let return_impl_trait =
+                        owner.and_then(|owner| self.tcx.return_type_impl_trait(owner)).is_some();
                     let t = self.resolve_vars_if_possible(t);
                     match t.kind() {
                         // We've got:
@@ -2618,7 +2594,7 @@ enum SubOrigin<'hir> {
                         // suggest:
                         // fn get_later<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a
                         ty::Closure(_, _substs) | ty::Opaque(_, _substs) if return_impl_trait => {
-                            new_binding_suggestion(&mut err, type_param_span, bound_kind);
+                            new_binding_suggestion(&mut err, type_param_span);
                         }
                         _ => {
                             binding_suggestion(&mut err, type_param_span, bound_kind, new_lt);
index a9a92fdbd6448c9cb7c92c3f1bbe8e026acb256c..b1eb9f0da87f774ef9b19233c56dd375365ae347 100644 (file)
@@ -341,7 +341,7 @@ fn cannot_infer_msg(&self, use_diag: Option<&UseDiagnostic<'_>>) -> String {
 
 impl InferenceDiagnosticsParentData {
     fn for_def_id(tcx: TyCtxt<'_>, def_id: DefId) -> Option<InferenceDiagnosticsParentData> {
-        let parent_def_id = tcx.parent(def_id)?;
+        let parent_def_id = tcx.parent(def_id);
 
         let parent_name =
             tcx.def_key(parent_def_id).disambiguated_data.data.get_opt_name()?.to_string();
@@ -734,22 +734,28 @@ pub fn emit_inference_failure_err(
                 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_segment] = path.segments
+                    && let [_] = path.segments
                 {
+                    let mut eraser = TypeParamEraser(self.tcx);
                     let candidate_len = impl_candidates.len();
-                    let suggestions = impl_candidates.iter().map(|candidate| {
-                        format!(
-                            "{}::{}({})",
-                            candidate, segment.ident, path_segment.ident
-                        )
-                    });
-                    err.span_suggestions(
-                        e.span,
+                    let mut suggestions: Vec<_> = impl_candidates.iter().map(|candidate| {
+                        let candidate = candidate.super_fold_with(&mut eraser);
+                        vec![
+                            (expr.span.shrink_to_lo(), format!("{}::{}(", candidate, segment.ident)),
+                            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));
+                    err.multipart_suggestions(
                         &format!(
                             "use the fully qualified path for the potential candidate{}",
                             pluralize!(candidate_len),
                         ),
-                        suggestions,
+                        suggestions.into_iter(),
                         Applicability::MaybeIncorrect,
                     );
                 }
@@ -848,10 +854,8 @@ fn trait_def_from_hir_fn(&self, hir_id: hir::HirId) -> Option<DefId> {
         if let Some((DefKind::AssocFn, def_id)) =
             self.in_progress_typeck_results?.borrow().type_dependent_def(hir_id)
         {
-            return self
-                .tcx
-                .parent(def_id)
-                .filter(|&parent_def_id| self.tcx.is_trait(parent_def_id));
+            let parent_def_id = self.tcx.parent(def_id);
+            return self.tcx.is_trait(parent_def_id).then_some(parent_def_id);
         }
 
         None
@@ -1037,3 +1041,18 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
         }
     }
 }
+
+/// Replace type parameters with `ty::Infer(ty::Var)` to display `_`.
+struct TypeParamEraser<'tcx>(TyCtxt<'tcx>);
+
+impl<'tcx> TypeFolder<'tcx> for TypeParamEraser<'tcx> {
+    fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
+        self.0
+    }
+    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),
+        }
+    }
+}
index 7721e00c141d788f61f9e59e3a36fba5f33856ae..be9db6aa25b75cb2c1ea13048b346a276b7c7f8d 100644 (file)
@@ -6,6 +6,7 @@
 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
 use crate::infer::lexical_region_resolve::RegionResolutionError;
 use crate::infer::SubregionOrigin;
+use crate::infer::TyCtxt;
 
 use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed};
 use rustc_hir as hir;
@@ -145,84 +146,83 @@ pub(super) fn try_report_anon_anon_conflict(&self) -> Option<ErrorGuaranteed> {
             }
         }
 
-        self.suggest_adding_lifetime_params(sub, ty_sup, ty_sub, &mut err);
+        if suggest_adding_lifetime_params(self.tcx(), sub, ty_sup, ty_sub, &mut err) {
+            err.note("each elided lifetime in input position becomes a distinct lifetime");
+        }
 
         let reported = err.emit();
         Some(reported)
     }
+}
 
-    fn suggest_adding_lifetime_params(
-        &self,
-        sub: Region<'tcx>,
-        ty_sup: &Ty<'_>,
-        ty_sub: &Ty<'_>,
-        err: &mut Diagnostic,
-    ) {
-        if let (
-            hir::Ty { kind: hir::TyKind::Rptr(lifetime_sub, _), .. },
-            hir::Ty { kind: hir::TyKind::Rptr(lifetime_sup, _), .. },
-        ) = (ty_sub, ty_sup)
-        {
-            if lifetime_sub.name.is_elided() && lifetime_sup.name.is_elided() {
-                if let Some(anon_reg) = self.tcx().is_suitable_region(sub) {
-                    let hir_id = self.tcx().hir().local_def_id_to_hir_id(anon_reg.def_id);
-
-                    let node = self.tcx().hir().get(hir_id);
-                    let is_impl = matches!(&node, hir::Node::ImplItem(_));
-                    let generics = match node {
-                        hir::Node::Item(&hir::Item {
-                            kind: hir::ItemKind::Fn(_, ref generics, ..),
-                            ..
-                        })
-                        | hir::Node::TraitItem(&hir::TraitItem { ref generics, .. })
-                        | hir::Node::ImplItem(&hir::ImplItem { ref generics, .. }) => generics,
-                        _ => return,
-                    };
-
-                    let (suggestion_param_name, introduce_new) = generics
-                        .params
-                        .iter()
-                        .find(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
-                        .and_then(|p| self.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())
-                        } 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() + " ")
-                        },
-                    ];
-
-                    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))
-                            }
-                        };
-
-                        suggestions.push(new_param_suggestion);
-                    }
-
-                    let mut sugg = String::from("consider introducing a named lifetime parameter");
-                    if is_impl {
-                        sugg.push_str(" and update trait if needed");
-                    }
-                    err.multipart_suggestion(
-                        sugg.as_str(),
-                        suggestions,
-                        Applicability::MaybeIncorrect,
-                    );
-                    err.note("each elided lifetime in input position becomes a distinct lifetime");
-                }
-            }
-        }
+pub fn suggest_adding_lifetime_params<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    sub: Region<'tcx>,
+    ty_sup: &Ty<'_>,
+    ty_sub: &Ty<'_>,
+    err: &mut Diagnostic,
+) -> bool {
+    let (
+        hir::Ty { kind: hir::TyKind::Rptr(lifetime_sub, _), .. },
+        hir::Ty { kind: hir::TyKind::Rptr(lifetime_sup, _), .. },
+    ) = (ty_sub, ty_sup) else {
+        return false;
+    };
+
+    if !lifetime_sub.name.is_elided() || !lifetime_sup.name.is_elided() {
+        return false;
+    };
+
+    let Some(anon_reg) = tcx.is_suitable_region(sub) else {
+        return false;
+    };
+
+    let hir_id = tcx.hir().local_def_id_to_hir_id(anon_reg.def_id);
+
+    let node = tcx.hir().get(hir_id);
+    let is_impl = matches!(&node, hir::Node::ImplItem(_));
+    let generics = match node {
+        hir::Node::Item(&hir::Item { kind: hir::ItemKind::Fn(_, ref generics, ..), .. })
+        | hir::Node::TraitItem(&hir::TraitItem { ref generics, .. })
+        | hir::Node::ImplItem(&hir::ImplItem { ref generics, .. }) => generics,
+        _ => return false,
+    };
+
+    let (suggestion_param_name, introduce_new) = 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())
+        } 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() + " ")
+        },
+    ];
+
+    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)),
+        };
+
+        suggestions.push(new_param_suggestion);
     }
+
+    let mut sugg = String::from("consider introducing a named lifetime parameter");
+    if is_impl {
+        sugg.push_str(" and update trait if needed");
+    }
+    err.multipart_suggestion(sugg.as_str(), suggestions, Applicability::MaybeIncorrect);
+
+    true
 }
index 135714af2a6c18fa13af2722bf1f45845395980a..9c5b944c1e987b3ea5cf9e6870d84787da5ca796 100644 (file)
 /// ```
 /// The function returns the nested type corresponding to the anonymous region
 /// for e.g., `&u8` and `Vec<&u8>`.
-pub(crate) fn find_anon_type<'tcx>(
+pub fn find_anon_type<'tcx>(
     tcx: TyCtxt<'tcx>,
     region: Region<'tcx>,
     br: &ty::BoundRegionKind,
 ) -> Option<(&'tcx hir::Ty<'tcx>, &'tcx hir::FnSig<'tcx>)> {
-    if let Some(anon_reg) = tcx.is_suitable_region(region) {
-        let hir_id = tcx.hir().local_def_id_to_hir_id(anon_reg.def_id);
-        let Some(fn_sig) = tcx.hir().get(hir_id).fn_sig() else {
-            return None
-        };
+    let anon_reg = tcx.is_suitable_region(region)?;
+    let hir_id = tcx.hir().local_def_id_to_hir_id(anon_reg.def_id);
+    let fn_sig = tcx.hir().get(hir_id).fn_sig()?;
 
-        fn_sig
-            .decl
-            .inputs
-            .iter()
-            .find_map(|arg| find_component_for_bound_region(tcx, arg, br))
-            .map(|ty| (ty, fn_sig))
-    } else {
-        None
-    }
+    fn_sig
+        .decl
+        .inputs
+        .iter()
+        .find_map(|arg| find_component_for_bound_region(tcx, arg, br))
+        .map(|ty| (ty, fn_sig))
 }
 
 // This method creates a FindNestedTypeVisitor which returns the type corresponding
index df81aea6ef9ecfb1ceda0f93dd452fc701883633..9948d15c43115a09199d2d4d3f93123893f8967b 100644 (file)
 mod trait_impl_difference;
 mod util;
 
+pub use different_lifetimes::suggest_adding_lifetime_params;
+pub use find_anon_type::find_anon_type;
 pub use static_impl_trait::suggest_new_region_bound;
+pub use util::find_param_with_region;
 
 impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
     pub fn try_report_nice_region_error(&self, error: &RegionResolutionError<'tcx>) -> bool {
index 719f6b37a434353b2d4c9bb83657a32815868119..da03d944ceb773e6a1816c23830957ec8e9c0192 100644 (file)
@@ -2,6 +2,7 @@
 //! anonymous regions.
 
 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
+use crate::infer::TyCtxt;
 use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
 use rustc_middle::ty::{self, Binder, DefIdTree, Region, Ty, TypeFoldable};
@@ -9,7 +10,7 @@
 
 /// Information about the anonymous region we are searching for.
 #[derive(Debug)]
-pub(super) struct AnonymousParamInfo<'tcx> {
+pub struct AnonymousParamInfo<'tcx> {
     /// The parameter corresponding to the anonymous region.
     pub param: &'tcx hir::Param<'tcx>,
     /// The type corresponding to the anonymous region parameter.
@@ -22,76 +23,83 @@ pub(super) struct AnonymousParamInfo<'tcx> {
     pub is_first: bool,
 }
 
+// This method walks the Type of the function body parameters using
+// `fold_regions()` function and returns the
+// &hir::Param of the function parameter corresponding to the anonymous
+// region and the Ty corresponding to the named region.
+// Currently only the case where the function declaration consists of
+// one named region and one anonymous region is handled.
+// Consider the example `fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32`
+// Here, we would return the hir::Param for y, we return the type &'a
+// i32, which is the type of y but with the anonymous region replaced
+// with 'a, the corresponding bound region and is_first which is true if
+// the hir::Param is the first parameter in the function declaration.
+pub fn find_param_with_region<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    anon_region: Region<'tcx>,
+    replace_region: Region<'tcx>,
+) -> Option<AnonymousParamInfo<'tcx>> {
+    let (id, bound_region) = match *anon_region {
+        ty::ReFree(ref free_region) => (free_region.scope, free_region.bound_region),
+        ty::ReEarlyBound(ebr) => {
+            (tcx.parent(ebr.def_id), ty::BoundRegionKind::BrNamed(ebr.def_id, ebr.name))
+        }
+        _ => return None, // not a free region
+    };
+
+    let hir = &tcx.hir();
+    let hir_id = hir.local_def_id_to_hir_id(id.as_local()?);
+    let body_id = hir.maybe_body_owned_by(hir_id)?;
+    let body = hir.body(body_id);
+    let owner_id = hir.body_owner(body_id);
+    let fn_decl = hir.fn_decl_by_hir_id(owner_id).unwrap();
+    let poly_fn_sig = tcx.fn_sig(id);
+    let fn_sig = tcx.liberate_late_bound_regions(id, poly_fn_sig);
+    body.params
+        .iter()
+        .take(if fn_sig.c_variadic {
+            fn_sig.inputs().len()
+        } else {
+            assert_eq!(fn_sig.inputs().len(), body.params.len());
+            body.params.len()
+        })
+        .enumerate()
+        .find_map(|(index, param)| {
+            // May return None; sometimes the tables are not yet populated.
+            let ty = fn_sig.inputs()[index];
+            let mut found_anon_region = false;
+            let new_param_ty = tcx.fold_regions(ty, &mut false, |r, _| {
+                if r == anon_region {
+                    found_anon_region = true;
+                    replace_region
+                } else {
+                    r
+                }
+            });
+            if found_anon_region {
+                let ty_hir_id = fn_decl.inputs[index].hir_id;
+                let param_ty_span = hir.span(ty_hir_id);
+                let is_first = index == 0;
+                Some(AnonymousParamInfo {
+                    param,
+                    param_ty: new_param_ty,
+                    param_ty_span,
+                    bound_region,
+                    is_first,
+                })
+            } else {
+                None
+            }
+        })
+}
+
 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
-    // This method walks the Type of the function body parameters using
-    // `fold_regions()` function and returns the
-    // &hir::Param of the function parameter corresponding to the anonymous
-    // region and the Ty corresponding to the named region.
-    // Currently only the case where the function declaration consists of
-    // one named region and one anonymous region is handled.
-    // Consider the example `fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32`
-    // Here, we would return the hir::Param for y, we return the type &'a
-    // i32, which is the type of y but with the anonymous region replaced
-    // with 'a, the corresponding bound region and is_first which is true if
-    // the hir::Param is the first parameter in the function declaration.
     pub(super) fn find_param_with_region(
         &self,
         anon_region: Region<'tcx>,
         replace_region: Region<'tcx>,
     ) -> Option<AnonymousParamInfo<'_>> {
-        let (id, bound_region) = match *anon_region {
-            ty::ReFree(ref free_region) => (free_region.scope, free_region.bound_region),
-            ty::ReEarlyBound(ebr) => (
-                self.tcx().parent(ebr.def_id).unwrap(),
-                ty::BoundRegionKind::BrNamed(ebr.def_id, ebr.name),
-            ),
-            _ => return None, // not a free region
-        };
-
-        let hir = &self.tcx().hir();
-        let hir_id = hir.local_def_id_to_hir_id(id.as_local()?);
-        let body_id = hir.maybe_body_owned_by(hir_id)?;
-        let body = hir.body(body_id);
-        let owner_id = hir.body_owner(body_id);
-        let fn_decl = hir.fn_decl_by_hir_id(owner_id).unwrap();
-        let poly_fn_sig = self.tcx().fn_sig(id);
-        let fn_sig = self.tcx().liberate_late_bound_regions(id, poly_fn_sig);
-        body.params
-            .iter()
-            .take(if fn_sig.c_variadic {
-                fn_sig.inputs().len()
-            } else {
-                assert_eq!(fn_sig.inputs().len(), body.params.len());
-                body.params.len()
-            })
-            .enumerate()
-            .find_map(|(index, param)| {
-                // May return None; sometimes the tables are not yet populated.
-                let ty = fn_sig.inputs()[index];
-                let mut found_anon_region = false;
-                let new_param_ty = self.tcx().fold_regions(ty, &mut false, |r, _| {
-                    if r == anon_region {
-                        found_anon_region = true;
-                        replace_region
-                    } else {
-                        r
-                    }
-                });
-                if found_anon_region {
-                    let ty_hir_id = fn_decl.inputs[index].hir_id;
-                    let param_ty_span = hir.span(ty_hir_id);
-                    let is_first = index == 0;
-                    Some(AnonymousParamInfo {
-                        param,
-                        param_ty: new_param_ty,
-                        param_ty_span,
-                        bound_region,
-                        is_first,
-                    })
-                } else {
-                    None
-                }
-            })
+        find_param_with_region(self.tcx(), anon_region, replace_region)
     }
 
     // Here, we check for the case where the anonymous region
index baea3e8285af26c078a90fd908cb78215191f0bc..cbdcf01352271cca90e40244e62c61553fb3befd 100644 (file)
@@ -372,8 +372,8 @@ pub(super) fn report_concrete_failure(
                         .hir()
                         .get_generics(impl_item_def_id)
                         .unwrap()
-                        .where_clause
-                        .tail_span_for_suggestion();
+                        .where_clause_span
+                        .shrink_to_hi();
 
                     let suggestion = format!(
                         "{} {}",
index fe75ee8b37b8d06fd748bebed146d452ce4e00a9..1327bf6fcd427a9523213875f9ae02fec1fce78d 100644 (file)
@@ -66,6 +66,7 @@ fn new_public_extern_entry<S, I>(locations: I) -> ExternEntry
         location: ExternLocation::ExactPaths(locations),
         is_private_dep: false,
         add_prelude: true,
+        nounused_dep: false,
     }
 }
 
@@ -751,6 +752,7 @@ macro_rules! tracked {
     tracked!(location_detail, LocationDetail { file: true, line: false, column: false });
     tracked!(merge_functions, Some(MergeFunctions::Disabled));
     tracked!(mir_emit_retag, true);
+    tracked!(mir_enable_passes, vec![("DestProp".to_string(), false)]);
     tracked!(mir_opt_level, Some(4));
     tracked!(move_size_limit, Some(4096));
     tracked!(mutable_noalias, Some(true));
index a14d6020361312067c94f33b1971511dbee3a0c3..dff2e31c6070c67bbe8478aeb9c81bff8f8d09f6 100644 (file)
@@ -129,7 +129,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
                 diag.span_suggestion(
                     call.ident.span,
                     "use `.iter()` instead of `.into_iter()` to avoid ambiguity",
-                    "iter".into(),
+                    "iter",
                     Applicability::MachineApplicable,
                 );
                 if self.for_expr_span == expr.span {
index 77fe76af2de21ce7d777168524540788f5145347..3564f15e210ad74efa7a99aa7dcf71fcbca60719 100644 (file)
@@ -36,8 +36,7 @@
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet, CRATE_DEF_ID};
-use rustc_hir::{ForeignItemKind, GenericParamKind, PatKind};
-use rustc_hir::{HirId, Node};
+use rustc_hir::{ForeignItemKind, GenericParamKind, HirId, PatKind};
 use rustc_index::vec::Idx;
 use rustc_middle::lint::LintDiagnosticBuilder;
 use rustc_middle::ty::layout::{LayoutError, LayoutOf};
@@ -487,9 +486,6 @@ fn check_fn(&mut self, cx: &EarlyContext<'_>, fk: FnKind<'_>, span: Span, _: ast
 pub struct MissingDoc {
     /// Stack of whether `#[doc(hidden)]` is set at each level which has lint attributes.
     doc_hidden_stack: Vec<bool>,
-
-    /// Private traits or trait items that leaked through. Don't check their methods.
-    private_traits: FxHashSet<hir::HirId>,
 }
 
 impl_lint_pass!(MissingDoc => [MISSING_DOCS]);
@@ -520,7 +516,7 @@ fn has_doc(attr: &ast::Attribute) -> bool {
 
 impl MissingDoc {
     pub fn new() -> MissingDoc {
-        MissingDoc { doc_hidden_stack: vec![false], private_traits: FxHashSet::default() }
+        MissingDoc { doc_hidden_stack: vec![false] }
     }
 
     fn doc_hidden(&self) -> bool {
@@ -598,30 +594,16 @@ fn check_crate(&mut self, cx: &LateContext<'_>) {
 
     fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
         match it.kind {
-            hir::ItemKind::Trait(.., trait_item_refs) => {
+            hir::ItemKind::Trait(..) => {
                 // Issue #11592: traits are always considered exported, even when private.
-                if let hir::VisibilityKind::Inherited = it.vis.node {
-                    self.private_traits.insert(it.hir_id());
-                    for trait_item_ref in trait_item_refs {
-                        self.private_traits.insert(trait_item_ref.id.hir_id());
-                    }
+                if cx.tcx.visibility(it.def_id)
+                    == ty::Visibility::Restricted(
+                        cx.tcx.parent_module_from_def_id(it.def_id).to_def_id(),
+                    )
+                {
                     return;
                 }
             }
-            hir::ItemKind::Impl(hir::Impl { of_trait: Some(ref trait_ref), items, .. }) => {
-                // If the trait is private, add the impl items to `private_traits` so they don't get
-                // reported for missing docs.
-                let real_trait = trait_ref.path.res.def_id();
-                let Some(def_id) = real_trait.as_local() else { return };
-                let Some(Node::Item(item)) = cx.tcx.hir().find_by_def_id(def_id) else { return };
-                if let hir::VisibilityKind::Inherited = item.vis.node {
-                    for impl_item_ref in items {
-                        self.private_traits.insert(impl_item_ref.id.hir_id());
-                    }
-                }
-                return;
-            }
-
             hir::ItemKind::TyAlias(..)
             | hir::ItemKind::Fn(..)
             | hir::ItemKind::Macro(..)
@@ -641,10 +623,6 @@ fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
     }
 
     fn check_trait_item(&mut self, cx: &LateContext<'_>, trait_item: &hir::TraitItem<'_>) {
-        if self.private_traits.contains(&trait_item.hir_id()) {
-            return;
-        }
-
         let (article, desc) = cx.tcx.article_and_description(trait_item.def_id.to_def_id());
 
         self.check_missing_docs_attrs(cx, trait_item.def_id, trait_item.span, article, desc);
@@ -1221,8 +1199,8 @@ fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
                     });
                 }
             }
-            hir::ItemKind::Impl(hir::Impl { ref generics, items, .. }) => {
-                for it in items {
+            hir::ItemKind::Impl(hir::Impl { generics, items, .. }) => {
+                for it in *items {
                     if let hir::AssocItemKind::Fn { .. } = it.kind {
                         if let Some(no_mangle_attr) = cx
                             .sess()
@@ -1384,46 +1362,47 @@ fn perform_lint(
         cx: &LateContext<'_>,
         what: &str,
         def_id: LocalDefId,
-        vis: &hir::Visibility<'_>,
         span: Span,
+        vis_span: Span,
         exportable: bool,
     ) {
         let mut applicability = Applicability::MachineApplicable;
-        match vis.node {
-            hir::VisibilityKind::Public if !cx.access_levels.is_reachable(def_id) => {
-                if span.from_expansion() {
-                    applicability = Applicability::MaybeIncorrect;
+        if cx.tcx.visibility(def_id).is_public() && !cx.access_levels.is_reachable(def_id) {
+            if vis_span.from_expansion() {
+                applicability = Applicability::MaybeIncorrect;
+            }
+            let def_span = cx.tcx.sess.source_map().guess_head_span(span);
+            cx.struct_span_lint(UNREACHABLE_PUB, def_span, |lint| {
+                let mut err = lint.build(&format!("unreachable `pub` {}", what));
+                let replacement = if cx.tcx.features().crate_visibility_modifier {
+                    "crate"
+                } else {
+                    "pub(crate)"
                 }
-                let def_span = cx.tcx.sess.source_map().guess_head_span(span);
-                cx.struct_span_lint(UNREACHABLE_PUB, def_span, |lint| {
-                    let mut err = lint.build(&format!("unreachable `pub` {}", what));
-                    let replacement = if cx.tcx.features().crate_visibility_modifier {
-                        "crate"
-                    } else {
-                        "pub(crate)"
-                    }
-                    .to_owned();
+                .to_owned();
 
-                    err.span_suggestion(
-                        vis.span,
-                        "consider restricting its visibility",
-                        replacement,
-                        applicability,
-                    );
-                    if exportable {
-                        err.help("or consider exporting it for use by other crates");
-                    }
-                    err.emit();
-                });
-            }
-            _ => {}
+                err.span_suggestion(
+                    vis_span,
+                    "consider restricting its visibility",
+                    replacement,
+                    applicability,
+                );
+                if exportable {
+                    err.help("or consider exporting it for use by other crates");
+                }
+                err.emit();
+            });
         }
     }
 }
 
 impl<'tcx> LateLintPass<'tcx> for UnreachablePub {
     fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
-        self.perform_lint(cx, "item", item.def_id, &item.vis, item.span, true);
+        // Do not warn for fake `use` statements.
+        if let hir::ItemKind::Use(_, hir::UseKind::ListStem) = &item.kind {
+            return;
+        }
+        self.perform_lint(cx, "item", item.def_id, item.span, item.vis_span, true);
     }
 
     fn check_foreign_item(&mut self, cx: &LateContext<'_>, foreign_item: &hir::ForeignItem<'tcx>) {
@@ -1431,19 +1410,29 @@ fn check_foreign_item(&mut self, cx: &LateContext<'_>, foreign_item: &hir::Forei
             cx,
             "item",
             foreign_item.def_id,
-            &foreign_item.vis,
             foreign_item.span,
+            foreign_item.vis_span,
             true,
         );
     }
 
     fn check_field_def(&mut self, cx: &LateContext<'_>, field: &hir::FieldDef<'_>) {
         let def_id = cx.tcx.hir().local_def_id(field.hir_id);
-        self.perform_lint(cx, "field", def_id, &field.vis, field.span, false);
+        self.perform_lint(cx, "field", def_id, field.span, field.vis_span, false);
     }
 
     fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) {
-        self.perform_lint(cx, "item", impl_item.def_id, &impl_item.vis, impl_item.span, false);
+        // Only lint inherent impl items.
+        if cx.tcx.associated_item(impl_item.def_id).trait_item_def_id.is_none() {
+            self.perform_lint(
+                cx,
+                "item",
+                impl_item.def_id,
+                impl_item.span,
+                impl_item.vis_span,
+                false,
+            );
+        }
     }
 }
 
@@ -1528,59 +1517,61 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
             // Bounds are respected for `type X = impl Trait`
             return;
         }
-        let mut suggested_changing_assoc_types = false;
         // There must not be a where clause
-        if !type_alias_generics.where_clause.predicates.is_empty() {
-            cx.lint(
-                TYPE_ALIAS_BOUNDS,
-                |lint| {
-                    let mut err = lint.build("where clauses are not enforced in type aliases");
-                    let spans: Vec<_> = type_alias_generics
-                        .where_clause
-                        .predicates
-                        .iter()
-                        .map(|pred| pred.span())
-                        .collect();
-                    err.set_span(spans);
-                    err.span_suggestion(
-                        type_alias_generics.where_clause.span_for_predicates_or_empty_place(),
-                        "the clause will not be checked when the type alias is used, and should be removed",
-                        String::new(),
-                        Applicability::MachineApplicable,
-                    );
-                    if !suggested_changing_assoc_types {
-                        TypeAliasBounds::suggest_changing_assoc_types(ty, &mut err);
-                        suggested_changing_assoc_types = true;
-                    }
-                    err.emit();
-                },
-            );
+        if type_alias_generics.predicates.is_empty() {
+            return;
         }
-        // The parameters must not have bounds
-        for param in type_alias_generics.params.iter() {
-            let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
-            let suggestion = spans
-                .iter()
-                .map(|sp| {
-                    let start = param.span.between(*sp); // Include the `:` in `T: Bound`.
-                    (start.to(*sp), String::new())
-                })
-                .collect();
-            if !spans.is_empty() {
-                cx.struct_span_lint(TYPE_ALIAS_BOUNDS, spans, |lint| {
-                    let mut err =
-                        lint.build("bounds on generic parameters are not enforced in type aliases");
-                    let msg = "the bound will not be checked when the type alias is used, \
-                                   and should be removed";
-                    err.multipart_suggestion(msg, suggestion, Applicability::MachineApplicable);
-                    if !suggested_changing_assoc_types {
-                        TypeAliasBounds::suggest_changing_assoc_types(ty, &mut err);
-                        suggested_changing_assoc_types = true;
-                    }
-                    err.emit();
-                });
+
+        let mut where_spans = Vec::new();
+        let mut inline_spans = Vec::new();
+        let mut inline_sugg = Vec::new();
+        for p in type_alias_generics.predicates {
+            let span = p.span();
+            if p.in_where_clause() {
+                where_spans.push(span);
+            } else {
+                for b in p.bounds() {
+                    inline_spans.push(b.span());
+                }
+                inline_sugg.push((span, String::new()));
             }
         }
+
+        let mut suggested_changing_assoc_types = false;
+        if !where_spans.is_empty() {
+            cx.lint(TYPE_ALIAS_BOUNDS, |lint| {
+                let mut err = lint.build("where clauses are not enforced in type aliases");
+                err.set_span(where_spans);
+                err.span_suggestion(
+                    type_alias_generics.where_clause_span,
+                    "the clause will not be checked when the type alias is used, and should be removed",
+                    String::new(),
+                    Applicability::MachineApplicable,
+                );
+                if !suggested_changing_assoc_types {
+                    TypeAliasBounds::suggest_changing_assoc_types(ty, &mut err);
+                    suggested_changing_assoc_types = true;
+                }
+                err.emit();
+            });
+        }
+
+        if !inline_spans.is_empty() {
+            cx.lint(TYPE_ALIAS_BOUNDS, |lint| {
+                let mut err =
+                    lint.build("bounds on generic parameters are not enforced in type aliases");
+                err.set_span(inline_spans);
+                err.multipart_suggestion(
+                    "the bound will not be checked when the type alias is used, and should be removed",
+                    inline_sugg,
+                    Applicability::MachineApplicable,
+                );
+                if !suggested_changing_assoc_types {
+                    TypeAliasBounds::suggest_changing_assoc_types(ty, &mut err);
+                }
+                err.emit();
+            });
+        }
     }
 }
 
@@ -2096,27 +2087,6 @@ fn lifetimes_outliving_type<'tcx>(
             .collect()
     }
 
-    fn collect_outlived_lifetimes<'tcx>(
-        &self,
-        param: &'tcx hir::GenericParam<'tcx>,
-        tcx: TyCtxt<'tcx>,
-        inferred_outlives: &'tcx [(ty::Predicate<'tcx>, Span)],
-        ty_generics: &'tcx ty::Generics,
-    ) -> Vec<ty::Region<'tcx>> {
-        let index =
-            ty_generics.param_def_id_to_index[&tcx.hir().local_def_id(param.hir_id).to_def_id()];
-
-        match param.kind {
-            hir::GenericParamKind::Lifetime { .. } => {
-                Self::lifetimes_outliving_lifetime(inferred_outlives, index)
-            }
-            hir::GenericParamKind::Type { .. } => {
-                Self::lifetimes_outliving_type(inferred_outlives, index)
-            }
-            hir::GenericParamKind::Const { .. } => Vec::new(),
-        }
-    }
-
     fn collect_outlives_bound_spans<'tcx>(
         &self,
         tcx: TyCtxt<'tcx>,
@@ -2224,41 +2194,11 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
 
             let mut bound_count = 0;
             let mut lint_spans = Vec::new();
-
-            for param in hir_generics.params {
-                let has_lifetime_bounds = param
-                    .bounds
-                    .iter()
-                    .any(|bound| matches!(bound, hir::GenericBound::Outlives(_)));
-                if !has_lifetime_bounds {
-                    continue;
-                }
-
-                let relevant_lifetimes =
-                    self.collect_outlived_lifetimes(param, cx.tcx, inferred_outlives, ty_generics);
-                if relevant_lifetimes.is_empty() {
-                    continue;
-                }
-
-                let bound_spans = self.collect_outlives_bound_spans(
-                    cx.tcx,
-                    &param.bounds,
-                    &relevant_lifetimes,
-                    infer_static,
-                );
-                bound_count += bound_spans.len();
-                lint_spans.extend(self.consolidate_outlives_bound_spans(
-                    param.span.shrink_to_hi(),
-                    &param.bounds,
-                    bound_spans,
-                ));
-            }
-
             let mut where_lint_spans = Vec::new();
             let mut dropped_predicate_count = 0;
-            let num_predicates = hir_generics.where_clause.predicates.len();
-            for (i, where_predicate) in hir_generics.where_clause.predicates.iter().enumerate() {
-                let (relevant_lifetimes, bounds, span) = match where_predicate {
+            let num_predicates = hir_generics.predicates.len();
+            for (i, where_predicate) in hir_generics.predicates.iter().enumerate() {
+                let (relevant_lifetimes, bounds, span, in_where_clause) = match where_predicate {
                     hir::WherePredicate::RegionPredicate(predicate) => {
                         if let Some(Region::EarlyBound(index, ..)) =
                             cx.tcx.named_region(predicate.lifetime.hir_id)
@@ -2267,6 +2207,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
                                 Self::lifetimes_outliving_lifetime(inferred_outlives, index),
                                 &predicate.bounds,
                                 predicate.span,
+                                predicate.in_where_clause,
                             )
                         } else {
                             continue;
@@ -2285,6 +2226,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
                                     Self::lifetimes_outliving_type(inferred_outlives, index),
                                     &predicate.bounds,
                                     predicate.span,
+                                    predicate.in_where_clause,
                                 )
                             }
                             _ => {
@@ -2311,10 +2253,12 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
                     dropped_predicate_count += 1;
                 }
 
-                // If all the bounds on a predicate were inferable and there are
-                // further predicates, we want to eat the trailing comma.
-                if drop_predicate && i + 1 < num_predicates {
-                    let next_predicate_span = hir_generics.where_clause.predicates[i + 1].span();
+                if drop_predicate && !in_where_clause {
+                    lint_spans.push(span);
+                } else if drop_predicate && i + 1 < num_predicates {
+                    // If all the bounds on a predicate were inferable and there are
+                    // further predicates, we want to eat the trailing comma.
+                    let next_predicate_span = hir_generics.predicates[i + 1].span();
                     where_lint_spans.push(span.to(next_predicate_span.shrink_to_lo()));
                 } else {
                     where_lint_spans.extend(self.consolidate_outlives_bound_spans(
@@ -2327,10 +2271,9 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
 
             // If all predicates are inferable, drop the entire clause
             // (including the `where`)
-            if num_predicates > 0 && dropped_predicate_count == num_predicates {
+            if hir_generics.has_where_clause && dropped_predicate_count == num_predicates {
                 let where_span = hir_generics
-                    .where_clause
-                    .span()
+                    .where_clause_span()
                     .expect("span of (nonempty) where clause should exist");
                 // Extend the where clause back to the closing `>` of the
                 // generics, except for tuple struct, which have the `where`
@@ -2357,7 +2300,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
                             },
                             lint_spans
                                 .into_iter()
-                                .map(|span| (span, "".to_owned()))
+                                .map(|span| (span, String::new()))
                                 .collect::<Vec<_>>(),
                             Applicability::MachineApplicable,
                         )
index 0ffa65b79b584a5070e06bc93b2bcd717a6f91cb..d7cd5ec04f323a74dafce65c9cc9932b60a54f6c 100644 (file)
@@ -738,7 +738,7 @@ fn lookup_with_diagnostics(
                     db.span_suggestion_verbose(
                         span.shrink_to_hi(),
                         "insert whitespace here to avoid this being parsed as a prefix in Rust 2021",
-                        " ".into(),
+                        " ",
                         Applicability::MachineApplicable,
                     );
                 }
index f21f25c35847eb0b6dc0209271ac5c5f27aa0c20..71769fceec1f2994c98bc6d9a478fc2e6cbc1b4c 100644 (file)
@@ -176,7 +176,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
                 l.span_suggestion_verbose(
                     arg_span.shrink_to_lo(),
                     "add a \"{}\" format string to Display the message",
-                    "\"{}\", ".into(),
+                    "\"{}\", ",
                     fmt_applicability,
                 );
             } else if suggest_debug {
@@ -186,7 +186,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
                         "add a \"{{:?}}\" format string to use the Debug implementation of `{}`",
                         ty,
                     ),
-                    "\"{:?}\", ".into(),
+                    "\"{:?}\", ",
                     fmt_applicability,
                 );
             }
@@ -266,13 +266,13 @@ fn check_panic_str<'tcx>(
                 l.span_suggestion(
                     arg.span.shrink_to_hi(),
                     &format!("add the missing argument{}", pluralize!(n_arguments)),
-                    ", ...".into(),
+                    ", ...",
                     Applicability::HasPlaceholders,
                 );
                 l.span_suggestion(
                     arg.span.shrink_to_lo(),
                     "or add a \"{}\" format string to use the message literally",
-                    "\"{}\", ".into(),
+                    "\"{}\", ",
                     Applicability::MachineApplicable,
                 );
             }
@@ -297,7 +297,7 @@ fn check_panic_str<'tcx>(
                 l.span_suggestion(
                     arg.span.shrink_to_lo(),
                     "add a \"{}\" format string to use the message literally",
-                    "\"{}\", ".into(),
+                    "\"{}\", ",
                     Applicability::MachineApplicable,
                 );
             }
index f73388c675ee2a25dcc178ffe013976a6daa534d..e1507d0fbb48ff0525d7f68f08c44008e84dae33 100644 (file)
@@ -406,7 +406,7 @@ fn check_fn(
                 }
                 _ => (),
             },
-            FnKind::ItemFn(ident, _, header, _) => {
+            FnKind::ItemFn(ident, _, header) => {
                 // Skip foreign-ABI #[no_mangle] functions (Issue #31924)
                 if header.abi != Abi::Rust && cx.sess().contains_name(attrs, sym::no_mangle) {
                     return;
index 437104d1aaf5d3df7eca8a293a89fd7230392cdc..dfce30171ff2b851234e0a242fa1e1a929e1f996 100644 (file)
@@ -1471,7 +1471,7 @@ fn inherent_atomic_method_call<'hir>(
             && let Some(adt) = cx.tcx.type_of(impl_did).ty_adt_def()
             // skip extension traits, only lint functions from the standard library
             && cx.tcx.trait_id_of_impl(impl_did).is_none()
-            && let Some(parent) = cx.tcx.parent(adt.did())
+            && let parent = cx.tcx.parent(adt.did())
             && cx.tcx.is_diagnostic_item(sym::atomic_mod, parent)
             && ATOMIC_TYPES.contains(&cx.tcx.item_name(adt.did()))
         {
@@ -1486,9 +1486,9 @@ fn matches_ordering(cx: &LateContext<'_>, did: DefId, orderings: &[Symbol]) -> b
         orderings.iter().any(|ordering| {
             tcx.item_name(did) == *ordering && {
                 let parent = tcx.parent(did);
-                parent == atomic_ordering
+                Some(parent) == atomic_ordering
                     // needed in case this is a ctor, not a variant
-                    || parent.map_or(false, |parent| tcx.parent(parent) == atomic_ordering)
+                    || tcx.opt_parent(parent) == atomic_ordering
             }
         })
     }
index f590172af4f9ccf8c2b33e456b6be0fd4dec2ea6..57b4f96dc100d5b689dd29a420d51a42d2d875c0 100644 (file)
@@ -214,6 +214,13 @@ pub fn from_attr(attr: &Attribute) -> Option<Level> {
             _ => None,
         }
     }
+
+    pub fn is_error(self) -> bool {
+        match self {
+            Level::Allow | Level::Expect(_) | Level::Warn | Level::ForceWarn => false,
+            Level::Deny | Level::Forbid => true,
+        }
+    }
 }
 
 /// Specification of a single lint.
index 71f21dc666686fd5e80a1d5a7c90a26fa49bc4da..38fddbdba54ddf9a04a22a7b52c7fe05065a6161 100644 (file)
@@ -107,6 +107,7 @@ static LLVMRustPassKind toRust(PassKind Kind) {
 }
 
 extern "C" LLVMPassRef LLVMRustFindAndCreatePass(const char *PassName) {
+#if LLVM_VERSION_LT(15, 0)
   StringRef SR(PassName);
   PassRegistry *PR = PassRegistry::getPassRegistry();
 
@@ -115,36 +116,59 @@ extern "C" LLVMPassRef LLVMRustFindAndCreatePass(const char *PassName) {
     return wrap(PI->createPass());
   }
   return nullptr;
+#else
+  report_fatal_error("Legacy PM not supported with LLVM 15");
+#endif
 }
 
 extern "C" LLVMPassRef LLVMRustCreateAddressSanitizerFunctionPass(bool Recover) {
+#if LLVM_VERSION_LT(15, 0)
   const bool CompileKernel = false;
   const bool UseAfterScope = true;
 
   return wrap(createAddressSanitizerFunctionPass(CompileKernel, Recover, UseAfterScope));
+#else
+  report_fatal_error("Legacy PM not supported with LLVM 15");
+#endif
 }
 
 extern "C" LLVMPassRef LLVMRustCreateModuleAddressSanitizerPass(bool Recover) {
+#if LLVM_VERSION_LT(15, 0)
   const bool CompileKernel = false;
 
   return wrap(createModuleAddressSanitizerLegacyPassPass(CompileKernel, Recover));
+#else
+  report_fatal_error("Legacy PM not supported with LLVM 15");
+#endif
 }
 
 extern "C" LLVMPassRef LLVMRustCreateMemorySanitizerPass(int TrackOrigins, bool Recover) {
+#if LLVM_VERSION_LT(15, 0)
   const bool CompileKernel = false;
 
   return wrap(createMemorySanitizerLegacyPassPass(
       MemorySanitizerOptions{TrackOrigins, Recover, CompileKernel}));
+#else
+  report_fatal_error("Legacy PM not supported with LLVM 15");
+#endif
 }
 
 extern "C" LLVMPassRef LLVMRustCreateThreadSanitizerPass() {
+#if LLVM_VERSION_LT(15, 0)
   return wrap(createThreadSanitizerLegacyPassPass());
+#else
+  report_fatal_error("Legacy PM not supported with LLVM 15");
+#endif
 }
 
 extern "C" LLVMPassRef LLVMRustCreateHWAddressSanitizerPass(bool Recover) {
+#if LLVM_VERSION_LT(15, 0)
   const bool CompileKernel = false;
 
   return wrap(createHWAddressSanitizerLegacyPassPass(CompileKernel, Recover));
+#else
+  report_fatal_error("Legacy PM not supported with LLVM 15");
+#endif
 }
 
 extern "C" LLVMRustPassKind LLVMRustPassKind(LLVMPassRef RustPass) {
@@ -154,10 +178,57 @@ extern "C" LLVMRustPassKind LLVMRustPassKind(LLVMPassRef RustPass) {
 }
 
 extern "C" void LLVMRustAddPass(LLVMPassManagerRef PMR, LLVMPassRef RustPass) {
+#if LLVM_VERSION_LT(15, 0)
   assert(RustPass);
   Pass *Pass = unwrap(RustPass);
   PassManagerBase *PMB = unwrap(PMR);
   PMB->add(Pass);
+#else
+  report_fatal_error("Legacy PM not supported with LLVM 15");
+#endif
+}
+
+extern "C" LLVMPassManagerBuilderRef LLVMRustPassManagerBuilderCreate() {
+#if LLVM_VERSION_LT(15, 0)
+  return LLVMPassManagerBuilderCreate();
+#else
+  report_fatal_error("Legacy PM not supported with LLVM 15");
+#endif
+}
+
+extern "C" void LLVMRustPassManagerBuilderDispose(LLVMPassManagerBuilderRef PMB) {
+#if LLVM_VERSION_LT(15, 0)
+  LLVMPassManagerBuilderDispose(PMB);
+#else
+  report_fatal_error("Legacy PM not supported with LLVM 15");
+#endif
+}
+
+extern "C" void LLVMRustPassManagerBuilderPopulateFunctionPassManager(
+  LLVMPassManagerBuilderRef PMB, LLVMPassManagerRef PM) {
+#if LLVM_VERSION_LT(15, 0)
+  LLVMPassManagerBuilderPopulateFunctionPassManager(PMB, PM);
+#else
+  report_fatal_error("Legacy PM not supported with LLVM 15");
+#endif
+}
+
+extern "C" void LLVMRustPassManagerBuilderPopulateModulePassManager(
+  LLVMPassManagerBuilderRef PMB, LLVMPassManagerRef PM) {
+#if LLVM_VERSION_LT(15, 0)
+  LLVMPassManagerBuilderPopulateModulePassManager(PMB, PM);
+#else
+  report_fatal_error("Legacy PM not supported with LLVM 15");
+#endif
+}
+
+extern "C" void LLVMRustPassManagerBuilderPopulateLTOPassManager(
+  LLVMPassManagerBuilderRef PMB, LLVMPassManagerRef PM, bool Internalize, bool RunInliner) {
+#if LLVM_VERSION_LT(15, 0)
+  LLVMPassManagerBuilderPopulateLTOPassManager(PMB, PM, Internalize, RunInliner);
+#else
+  report_fatal_error("Legacy PM not supported with LLVM 15");
+#endif
 }
 
 extern "C"
@@ -165,12 +236,26 @@ void LLVMRustPassManagerBuilderPopulateThinLTOPassManager(
   LLVMPassManagerBuilderRef PMBR,
   LLVMPassManagerRef PMR
 ) {
+#if LLVM_VERSION_LT(15, 0)
   unwrap(PMBR)->populateThinLTOPassManager(*unwrap(PMR));
+#else
+  report_fatal_error("Legacy PM not supported with LLVM 15");
+#endif
+}
+
+extern "C" void LLVMRustPassManagerBuilderUseInlinerWithThreshold(
+  LLVMPassManagerBuilderRef PMB, unsigned Threshold) {
+#if LLVM_VERSION_LT(15, 0)
+  LLVMPassManagerBuilderUseInlinerWithThreshold(PMB, Threshold);
+#else
+  report_fatal_error("Legacy PM not supported with LLVM 15");
+#endif
 }
 
 extern "C"
 void LLVMRustAddLastExtensionPasses(
     LLVMPassManagerBuilderRef PMBR, LLVMPassRef *Passes, size_t NumPasses) {
+#if LLVM_VERSION_LT(15, 0)
   auto AddExtensionPasses = [Passes, NumPasses](
       const PassManagerBuilder &Builder, PassManagerBase &PM) {
     for (size_t I = 0; I < NumPasses; I++) {
@@ -183,6 +268,9 @@ void LLVMRustAddLastExtensionPasses(
                              AddExtensionPasses);
   unwrap(PMBR)->addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0,
                              AddExtensionPasses);
+#else
+  report_fatal_error("Legacy PM not supported with LLVM 15");
+#endif
 }
 
 #ifdef LLVM_COMPONENT_X86
@@ -533,12 +621,16 @@ extern "C" void LLVMRustDisposeTargetMachine(LLVMTargetMachineRef TM) {
 extern "C" void LLVMRustConfigurePassManagerBuilder(
     LLVMPassManagerBuilderRef PMBR, LLVMRustCodeGenOptLevel OptLevel,
     bool MergeFunctions, bool SLPVectorize, bool LoopVectorize, bool PrepareForThinLTO,
-    const char* PGOGenPath, const char* PGOUsePath, const char* PGOSampleUsePath) {
+    const char* PGOGenPath, const char* PGOUsePath, const char* PGOSampleUsePath,
+    int SizeLevel) {
+#if LLVM_VERSION_LT(15, 0)
   unwrap(PMBR)->MergeFunctions = MergeFunctions;
   unwrap(PMBR)->SLPVectorize = SLPVectorize;
   unwrap(PMBR)->OptLevel = fromRust(OptLevel);
   unwrap(PMBR)->LoopVectorize = LoopVectorize;
   unwrap(PMBR)->PrepareForThinLTO = PrepareForThinLTO;
+  unwrap(PMBR)->SizeLevel = SizeLevel;
+  unwrap(PMBR)->DisableUnrollLoops = SizeLevel != 0;
 
   if (PGOGenPath) {
     assert(!PGOUsePath && !PGOSampleUsePath);
@@ -550,6 +642,9 @@ extern "C" void LLVMRustConfigurePassManagerBuilder(
   } else if (PGOSampleUsePath) {
     unwrap(PMBR)->PGOSampleUse = PGOSampleUsePath;
   }
+#else
+  report_fatal_error("Legacy PM not supported with LLVM 15");
+#endif
 }
 
 // Unfortunately, the LLVM C API doesn't provide a way to set the `LibraryInfo`
index 3ed4396d1e955c2bc531f69d323a1a6deb7e0e18..6d79e662a42796d17a60b859e14e73abb3067782 100644 (file)
@@ -6,6 +6,7 @@
 #include "llvm/IR/GlobalVariable.h"
 #include "llvm/IR/Instructions.h"
 #include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/Mangler.h"
 #include "llvm/Object/Archive.h"
 #include "llvm/Object/COFFImportFile.h"
 #include "llvm/Object/ObjectFile.h"
@@ -1216,6 +1217,11 @@ extern "C" LLVMTypeKind LLVMRustGetTypeKind(LLVMTypeRef Ty) {
     return LLVMBFloatTypeKind;
   case Type::X86_AMXTyID:
     return LLVMX86_AMXTypeKind;
+#if LLVM_VERSION_GE(15, 0)
+  case Type::DXILPointerTyID:
+    report_fatal_error("Rust does not support DirectX typed pointers.");
+    break;
+#endif
   }
   report_fatal_error("Unhandled TypeID.");
 }
diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs
new file mode 100644 (file)
index 0000000..f491664
--- /dev/null
@@ -0,0 +1,586 @@
+#![deny(unused_must_use)]
+
+use crate::diagnostics::error::{
+    invalid_nested_attr, span_err, throw_invalid_attr, throw_invalid_nested_attr, throw_span_err,
+    SessionDiagnosticDeriveError,
+};
+use crate::diagnostics::utils::{
+    option_inner_ty, report_error_if_not_applied_to_span, type_matches_path, Applicability,
+    FieldInfo, HasFieldMap, SetOnce,
+};
+use proc_macro2::TokenStream;
+use quote::{format_ident, quote};
+use std::collections::HashMap;
+use std::str::FromStr;
+use syn::{spanned::Spanned, Attribute, Meta, MetaList, MetaNameValue, Type};
+use synstructure::Structure;
+
+/// The central struct for constructing the `into_diagnostic` method from an annotated struct.
+pub(crate) struct SessionDiagnosticDerive<'a> {
+    structure: Structure<'a>,
+    builder: SessionDiagnosticDeriveBuilder,
+}
+
+impl<'a> SessionDiagnosticDerive<'a> {
+    pub(crate) fn new(diag: syn::Ident, sess: syn::Ident, structure: Structure<'a>) -> Self {
+        // Build the mapping of field names to fields. This allows attributes to peek values from
+        // other fields.
+        let mut fields_map = HashMap::new();
+
+        // Convenience bindings.
+        let ast = structure.ast();
+
+        if let syn::Data::Struct(syn::DataStruct { fields, .. }) = &ast.data {
+            for field in fields.iter() {
+                if let Some(ident) = &field.ident {
+                    fields_map.insert(ident.to_string(), quote! { &self.#ident });
+                }
+            }
+        }
+
+        Self {
+            builder: SessionDiagnosticDeriveBuilder {
+                diag,
+                sess,
+                fields: fields_map,
+                kind: None,
+                code: None,
+                slug: None,
+            },
+            structure,
+        }
+    }
+
+    pub(crate) fn into_tokens(self) -> TokenStream {
+        let SessionDiagnosticDerive { mut structure, mut builder } = self;
+
+        let ast = structure.ast();
+        let attrs = &ast.attrs;
+
+        let (implementation, param_ty) = {
+            if let syn::Data::Struct(..) = ast.data {
+                let preamble = {
+                    let preamble = attrs.iter().map(|attr| {
+                        builder
+                            .generate_structure_code(attr)
+                            .unwrap_or_else(|v| v.to_compile_error())
+                    });
+
+                    quote! {
+                        #(#preamble)*;
+                    }
+                };
+
+                // Generates calls to `span_label` and similar functions based on the attributes
+                // on fields. Code for suggestions uses formatting machinery and the value of
+                // other fields - because any given field can be referenced multiple times, it
+                // should be accessed through a borrow. When passing fields to `set_arg` (which
+                // happens below) for Fluent, we want to move the data, so that has to happen
+                // in a separate pass over the fields.
+                let attrs = structure.each(|field_binding| {
+                    let field = field_binding.ast();
+                    let result = field.attrs.iter().map(|attr| {
+                        builder
+                            .generate_field_attr_code(
+                                attr,
+                                FieldInfo {
+                                    vis: &field.vis,
+                                    binding: field_binding,
+                                    ty: &field.ty,
+                                    span: &field.span(),
+                                },
+                            )
+                            .unwrap_or_else(|v| v.to_compile_error())
+                    });
+
+                    quote! { #(#result);* }
+                });
+
+                // When generating `set_arg` calls, move data rather than borrow it to avoid
+                // requiring clones - this must therefore be the last use of each field (for
+                // example, any formatting machinery that might refer to a field should be
+                // generated already).
+                structure.bind_with(|_| synstructure::BindStyle::Move);
+                let args = structure.each(|field_binding| {
+                    let field = field_binding.ast();
+                    // When a field has attributes like `#[label]` or `#[note]` then it doesn't
+                    // need to be passed as an argument to the diagnostic. But when a field has no
+                    // attributes then it must be passed as an argument to the diagnostic so that
+                    // it can be referred to by Fluent messages.
+                    if field.attrs.is_empty() {
+                        let diag = &builder.diag;
+                        let ident = field_binding.ast().ident.as_ref().unwrap();
+                        quote! {
+                            #diag.set_arg(
+                                stringify!(#ident),
+                                #field_binding.into_diagnostic_arg()
+                            );
+                        }
+                    } else {
+                        quote! {}
+                    }
+                });
+
+                let span = ast.span().unwrap();
+                let (diag, sess) = (&builder.diag, &builder.sess);
+                let init = match (builder.kind, builder.slug) {
+                    (None, _) => {
+                        span_err(span, "diagnostic kind not specified")
+                            .help("use the `#[error(...)]` attribute to create an error")
+                            .emit();
+                        return SessionDiagnosticDeriveError::ErrorHandled.to_compile_error();
+                    }
+                    (Some((kind, _)), None) => {
+                        span_err(span, "`slug` not specified")
+                            .help(&format!("use the `#[{}(slug = \"...\")]` attribute to set this diagnostic's slug", kind.descr()))
+                            .emit();
+                        return SessionDiagnosticDeriveError::ErrorHandled.to_compile_error();
+                    }
+                    (Some((SessionDiagnosticKind::Error, _)), Some((slug, _))) => {
+                        quote! {
+                            let mut #diag = #sess.struct_err(
+                                rustc_errors::DiagnosticMessage::fluent(#slug),
+                            );
+                        }
+                    }
+                    (Some((SessionDiagnosticKind::Warn, _)), Some((slug, _))) => {
+                        quote! {
+                            let mut #diag = #sess.struct_warn(
+                                rustc_errors::DiagnosticMessage::fluent(#slug),
+                            );
+                        }
+                    }
+                };
+
+                let implementation = quote! {
+                    #init
+                    #preamble
+                    match self {
+                        #attrs
+                    }
+                    match self {
+                        #args
+                    }
+                    #diag
+                };
+                let param_ty = match builder.kind {
+                    Some((SessionDiagnosticKind::Error, _)) => {
+                        quote! { rustc_errors::ErrorGuaranteed }
+                    }
+                    Some((SessionDiagnosticKind::Warn, _)) => quote! { () },
+                    _ => unreachable!(),
+                };
+
+                (implementation, param_ty)
+            } else {
+                span_err(
+                    ast.span().unwrap(),
+                    "`#[derive(SessionDiagnostic)]` can only be used on structs",
+                )
+                .emit();
+
+                let implementation = SessionDiagnosticDeriveError::ErrorHandled.to_compile_error();
+                let param_ty = quote! { rustc_errors::ErrorGuaranteed };
+                (implementation, param_ty)
+            }
+        };
+
+        let sess = &builder.sess;
+        structure.gen_impl(quote! {
+            gen impl<'__session_diagnostic_sess> rustc_session::SessionDiagnostic<'__session_diagnostic_sess, #param_ty>
+                    for @Self
+            {
+                fn into_diagnostic(
+                    self,
+                    #sess: &'__session_diagnostic_sess rustc_session::parse::ParseSess
+                ) -> rustc_errors::DiagnosticBuilder<'__session_diagnostic_sess, #param_ty> {
+                    use rustc_errors::IntoDiagnosticArg;
+                    #implementation
+                }
+            }
+        })
+    }
+}
+
+/// What kind of session diagnostic is being derived - an error or a warning?
+#[derive(Copy, Clone)]
+enum SessionDiagnosticKind {
+    /// `#[error(..)]`
+    Error,
+    /// `#[warn(..)]`
+    Warn,
+}
+
+impl SessionDiagnosticKind {
+    /// Returns human-readable string corresponding to the kind.
+    fn descr(&self) -> &'static str {
+        match self {
+            SessionDiagnosticKind::Error => "error",
+            SessionDiagnosticKind::Warn => "warning",
+        }
+    }
+}
+
+/// Tracks persistent information required for building up the individual calls to diagnostic
+/// methods for the final generated method. This is a separate struct to `SessionDiagnosticDerive`
+/// only to be able to destructure and split `self.builder` and the `self.structure` up to avoid a
+/// double mut borrow later on.
+struct SessionDiagnosticDeriveBuilder {
+    /// Name of the session parameter that's passed in to the `as_error` method.
+    sess: syn::Ident,
+    /// The identifier to use for the generated `DiagnosticBuilder` instance.
+    diag: syn::Ident,
+
+    /// Store a map of field name to its corresponding field. This is built on construction of the
+    /// derive builder.
+    fields: HashMap<String, TokenStream>,
+
+    /// Kind of diagnostic requested via the struct attribute.
+    kind: Option<(SessionDiagnosticKind, proc_macro::Span)>,
+    /// Slug is a mandatory part of the struct attribute as corresponds to the Fluent message that
+    /// has the actual diagnostic message.
+    slug: Option<(String, proc_macro::Span)>,
+    /// Error codes are a optional part of the struct attribute - this is only set to detect
+    /// multiple specifications.
+    code: Option<(String, proc_macro::Span)>,
+}
+
+impl HasFieldMap for SessionDiagnosticDeriveBuilder {
+    fn get_field_binding(&self, field: &String) -> Option<&TokenStream> {
+        self.fields.get(field)
+    }
+}
+
+impl SessionDiagnosticDeriveBuilder {
+    /// Establishes state in the `SessionDiagnosticDeriveBuilder` resulting from the struct
+    /// attributes like `#[error(..)#`, such as the diagnostic kind and slug. Generates
+    /// diagnostic builder calls for setting error code and creating note/help messages.
+    fn generate_structure_code(
+        &mut self,
+        attr: &Attribute,
+    ) -> Result<TokenStream, SessionDiagnosticDeriveError> {
+        let span = attr.span().unwrap();
+
+        let name = attr.path.segments.last().unwrap().ident.to_string();
+        let name = name.as_str();
+        let meta = attr.parse_meta()?;
+
+        if matches!(name, "help" | "note") && matches!(meta, Meta::Path(_) | Meta::NameValue(_)) {
+            let diag = &self.diag;
+            let slug = match &self.slug {
+                Some((slug, _)) => slug.as_str(),
+                None => throw_span_err!(
+                    span,
+                    &format!(
+                        "`#[{}{}]` must come after `#[error(..)]` or `#[warn(..)]`",
+                        name,
+                        match meta {
+                            Meta::Path(_) => "",
+                            Meta::NameValue(_) => " = ...",
+                            _ => unreachable!(),
+                        }
+                    )
+                ),
+            };
+            let id = match meta {
+                Meta::Path(..) => quote! { #name },
+                Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(s), .. }) => {
+                    quote! { #s }
+                }
+                _ => unreachable!(),
+            };
+            let fn_name = proc_macro2::Ident::new(name, attr.span());
+
+            return Ok(quote! {
+                #diag.#fn_name(rustc_errors::DiagnosticMessage::fluent_attr(#slug, #id));
+            });
+        }
+
+        let nested = match meta {
+            Meta::List(MetaList { ref nested, .. }) => nested,
+            _ => throw_invalid_attr!(attr, &meta),
+        };
+
+        let kind = match name {
+            "error" => SessionDiagnosticKind::Error,
+            "warning" => SessionDiagnosticKind::Warn,
+            _ => throw_invalid_attr!(attr, &meta, |diag| {
+                diag.help("only `error` and `warning` are valid attributes")
+            }),
+        };
+        self.kind.set_once((kind, span));
+
+        let mut tokens = Vec::new();
+        for nested_attr in nested {
+            let meta = match nested_attr {
+                syn::NestedMeta::Meta(meta) => meta,
+                _ => throw_invalid_nested_attr!(attr, &nested_attr),
+            };
+
+            let path = meta.path();
+            let nested_name = path.segments.last().unwrap().ident.to_string();
+            match &meta {
+                // Struct attributes are only allowed to be applied once, and the diagnostic
+                // changes will be set in the initialisation code.
+                Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(s), .. }) => {
+                    let span = s.span().unwrap();
+                    match nested_name.as_str() {
+                        "slug" => {
+                            self.slug.set_once((s.value(), span));
+                        }
+                        "code" => {
+                            self.code.set_once((s.value(), span));
+                            let (diag, code) = (&self.diag, &self.code.as_ref().map(|(v, _)| v));
+                            tokens.push(quote! {
+                                #diag.code(rustc_errors::DiagnosticId::Error(#code.to_string()));
+                            });
+                        }
+                        _ => invalid_nested_attr(attr, &nested_attr)
+                            .help("only `slug` and `code` are valid nested attributes")
+                            .emit(),
+                    }
+                }
+                _ => invalid_nested_attr(attr, &nested_attr).emit(),
+            }
+        }
+
+        Ok(tokens.drain(..).collect())
+    }
+
+    fn generate_field_attr_code(
+        &mut self,
+        attr: &syn::Attribute,
+        info: FieldInfo<'_>,
+    ) -> Result<TokenStream, SessionDiagnosticDeriveError> {
+        let field_binding = &info.binding.binding;
+        let option_ty = option_inner_ty(&info.ty);
+        let generated_code = self.generate_non_option_field_code(
+            attr,
+            FieldInfo {
+                vis: info.vis,
+                binding: info.binding,
+                ty: option_ty.unwrap_or(&info.ty),
+                span: info.span,
+            },
+        )?;
+
+        if option_ty.is_none() {
+            Ok(quote! { #generated_code })
+        } else {
+            Ok(quote! {
+                if let Some(#field_binding) = #field_binding {
+                    #generated_code
+                }
+            })
+        }
+    }
+
+    fn generate_non_option_field_code(
+        &mut self,
+        attr: &Attribute,
+        info: FieldInfo<'_>,
+    ) -> Result<TokenStream, SessionDiagnosticDeriveError> {
+        let diag = &self.diag;
+        let field_binding = &info.binding.binding;
+
+        let name = attr.path.segments.last().unwrap().ident.to_string();
+        let name = name.as_str();
+
+        let meta = attr.parse_meta()?;
+        match meta {
+            Meta::Path(_) => match name {
+                "skip_arg" => {
+                    // Don't need to do anything - by virtue of the attribute existing, the
+                    // `set_arg` call will not be generated.
+                    Ok(quote! {})
+                }
+                "primary_span" => {
+                    report_error_if_not_applied_to_span(attr, &info)?;
+                    Ok(quote! {
+                        #diag.set_span(*#field_binding);
+                    })
+                }
+                "label" | "note" | "help" => {
+                    report_error_if_not_applied_to_span(attr, &info)?;
+                    Ok(self.add_subdiagnostic(field_binding, name, name))
+                }
+                "subdiagnostic" => Ok(quote! { #diag.subdiagnostic(*#field_binding); }),
+                _ => throw_invalid_attr!(attr, &meta, |diag| {
+                    diag
+                        .help("only `skip_arg`, `primary_span`, `label`, `note`, `help` and `subdiagnostic` are valid field attributes")
+                }),
+            },
+            Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(ref s), .. }) => match name {
+                "label" | "note" | "help" => {
+                    report_error_if_not_applied_to_span(attr, &info)?;
+                    Ok(self.add_subdiagnostic(field_binding, name, &s.value()))
+                }
+                _ => throw_invalid_attr!(attr, &meta, |diag| {
+                    diag.help("only `label`, `note` and `help` are valid field attributes")
+                }),
+            },
+            Meta::List(MetaList { ref path, ref nested, .. }) => {
+                let name = path.segments.last().unwrap().ident.to_string();
+                let name = name.as_ref();
+
+                match name {
+                    "suggestion" | "suggestion_short" | "suggestion_hidden"
+                    | "suggestion_verbose" => (),
+                    _ => throw_invalid_attr!(attr, &meta, |diag| {
+                        diag
+                            .help("only `suggestion{,_short,_hidden,_verbose}` are valid field attributes")
+                    }),
+                };
+
+                let (span_field, mut applicability) = self.span_and_applicability_of_ty(info)?;
+
+                let mut msg = None;
+                let mut code = None;
+
+                for nested_attr in nested {
+                    let meta = match nested_attr {
+                        syn::NestedMeta::Meta(ref meta) => meta,
+                        syn::NestedMeta::Lit(_) => throw_invalid_nested_attr!(attr, &nested_attr),
+                    };
+
+                    let nested_name = meta.path().segments.last().unwrap().ident.to_string();
+                    let nested_name = nested_name.as_str();
+                    match meta {
+                        Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(s), .. }) => {
+                            let span = meta.span().unwrap();
+                            match nested_name {
+                                "message" => {
+                                    msg = Some(s.value());
+                                }
+                                "code" => {
+                                    let formatted_str = self.build_format(&s.value(), s.span());
+                                    code = Some(formatted_str);
+                                }
+                                "applicability" => {
+                                    applicability = match applicability {
+                                        Some(v) => {
+                                            span_err(
+                                                span,
+                                                "applicability cannot be set in both the field and attribute"
+                                            ).emit();
+                                            Some(v)
+                                        }
+                                        None => match Applicability::from_str(&s.value()) {
+                                            Ok(v) => Some(quote! { #v }),
+                                            Err(()) => {
+                                                span_err(span, "invalid applicability").emit();
+                                                None
+                                            }
+                                        },
+                                    }
+                                }
+                                _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
+                                    diag.help(
+                                        "only `message`, `code` and `applicability` are valid field attributes",
+                                    )
+                                }),
+                            }
+                        }
+                        _ => throw_invalid_nested_attr!(attr, &nested_attr),
+                    }
+                }
+
+                let applicability = applicability
+                    .unwrap_or_else(|| quote!(rustc_errors::Applicability::Unspecified));
+
+                let method = format_ident!("span_{}", name);
+
+                let slug = self
+                    .slug
+                    .as_ref()
+                    .map(|(slug, _)| slug.as_str())
+                    .unwrap_or_else(|| "missing-slug");
+                let msg = msg.as_deref().unwrap_or("suggestion");
+                let msg = quote! { rustc_errors::DiagnosticMessage::fluent_attr(#slug, #msg) };
+                let code = code.unwrap_or_else(|| quote! { String::new() });
+
+                Ok(quote! { #diag.#method(#span_field, #msg, #code, #applicability); })
+            }
+            _ => throw_invalid_attr!(attr, &meta),
+        }
+    }
+
+    /// Adds a subdiagnostic by generating a `diag.span_$kind` call with the current slug and
+    /// `fluent_attr_identifier`.
+    fn add_subdiagnostic(
+        &self,
+        field_binding: &proc_macro2::Ident,
+        kind: &str,
+        fluent_attr_identifier: &str,
+    ) -> TokenStream {
+        let diag = &self.diag;
+
+        let slug =
+            self.slug.as_ref().map(|(slug, _)| slug.as_str()).unwrap_or_else(|| "missing-slug");
+        let fn_name = format_ident!("span_{}", kind);
+        quote! {
+            #diag.#fn_name(
+                *#field_binding,
+                rustc_errors::DiagnosticMessage::fluent_attr(#slug, #fluent_attr_identifier)
+            );
+        }
+    }
+
+    fn span_and_applicability_of_ty(
+        &self,
+        info: FieldInfo<'_>,
+    ) -> Result<(TokenStream, Option<TokenStream>), SessionDiagnosticDeriveError> {
+        match &info.ty {
+            // If `ty` is `Span` w/out applicability, then use `Applicability::Unspecified`.
+            ty @ Type::Path(..) if type_matches_path(ty, &["rustc_span", "Span"]) => {
+                let binding = &info.binding.binding;
+                Ok((quote!(*#binding), None))
+            }
+            // If `ty` is `(Span, Applicability)` then return tokens accessing those.
+            Type::Tuple(tup) => {
+                let mut span_idx = None;
+                let mut applicability_idx = None;
+
+                for (idx, elem) in tup.elems.iter().enumerate() {
+                    if type_matches_path(elem, &["rustc_span", "Span"]) {
+                        if span_idx.is_none() {
+                            span_idx = Some(syn::Index::from(idx));
+                        } else {
+                            throw_span_err!(
+                                info.span.unwrap(),
+                                "type of field annotated with `#[suggestion(...)]` contains more than one `Span`"
+                            );
+                        }
+                    } else if type_matches_path(elem, &["rustc_errors", "Applicability"]) {
+                        if applicability_idx.is_none() {
+                            applicability_idx = Some(syn::Index::from(idx));
+                        } else {
+                            throw_span_err!(
+                                info.span.unwrap(),
+                                "type of field annotated with `#[suggestion(...)]` contains more than one Applicability"
+                            );
+                        }
+                    }
+                }
+
+                if let Some(span_idx) = span_idx {
+                    let binding = &info.binding.binding;
+                    let span = quote!(#binding.#span_idx);
+                    let applicability = applicability_idx
+                        .map(|applicability_idx| quote!(#binding.#applicability_idx))
+                        .unwrap_or_else(|| quote!(rustc_errors::Applicability::Unspecified));
+
+                    return Ok((span, Some(applicability)));
+                }
+
+                throw_span_err!(info.span.unwrap(), "wrong types for suggestion", |diag| {
+                    diag.help("`#[suggestion(...)]` on a tuple field must be applied to fields of type `(Span, Applicability)`")
+                });
+            }
+            // If `ty` isn't a `Span` or `(Span, Applicability)` then emit an error.
+            _ => throw_span_err!(info.span.unwrap(), "wrong field type for suggestion", |diag| {
+                diag.help("`#[suggestion(...)]` should be applied to fields of type `Span` or `(Span, Applicability)`")
+            }),
+        }
+    }
+}
diff --git a/compiler/rustc_macros/src/diagnostics/error.rs b/compiler/rustc_macros/src/diagnostics/error.rs
new file mode 100644 (file)
index 0000000..fd1dc2f
--- /dev/null
@@ -0,0 +1,132 @@
+use proc_macro::{Diagnostic, Level, MultiSpan};
+use proc_macro2::TokenStream;
+use quote::quote;
+use syn::{spanned::Spanned, Attribute, Error as SynError, Meta, NestedMeta};
+
+#[derive(Debug)]
+pub(crate) enum SessionDiagnosticDeriveError {
+    SynError(SynError),
+    ErrorHandled,
+}
+
+impl SessionDiagnosticDeriveError {
+    pub(crate) fn to_compile_error(self) -> TokenStream {
+        match self {
+            SessionDiagnosticDeriveError::SynError(e) => e.to_compile_error(),
+            SessionDiagnosticDeriveError::ErrorHandled => {
+                // Return ! to avoid having to create a blank DiagnosticBuilder to return when an
+                // error has already been emitted to the compiler.
+                quote! {
+                    { unreachable!(); }
+                }
+            }
+        }
+    }
+}
+
+impl From<SynError> for SessionDiagnosticDeriveError {
+    fn from(e: SynError) -> Self {
+        SessionDiagnosticDeriveError::SynError(e)
+    }
+}
+
+/// Helper function for use with `throw_*` macros - constraints `$f` to an `impl FnOnce`.
+pub(crate) fn _throw_err(
+    diag: Diagnostic,
+    f: impl FnOnce(Diagnostic) -> Diagnostic,
+) -> SessionDiagnosticDeriveError {
+    f(diag).emit();
+    SessionDiagnosticDeriveError::ErrorHandled
+}
+
+/// Returns an error diagnostic on span `span` with msg `msg`.
+pub(crate) fn span_err(span: impl MultiSpan, msg: &str) -> Diagnostic {
+    Diagnostic::spanned(span, Level::Error, msg)
+}
+
+/// Emit a diagnostic on span `$span` with msg `$msg` (optionally performing additional decoration
+/// using the `FnOnce` passed in `diag`) and return `Err(ErrorHandled)`.
+///
+/// For methods that return a `Result<_, SessionDiagnosticDeriveError>`:
+macro_rules! throw_span_err {
+    ($span:expr, $msg:expr) => {{ throw_span_err!($span, $msg, |diag| diag) }};
+    ($span:expr, $msg:expr, $f:expr) => {{
+        let diag = span_err($span, $msg);
+        return Err(crate::diagnostics::error::_throw_err(diag, $f));
+    }};
+}
+
+pub(crate) use throw_span_err;
+
+/// Returns an error diagnostic for an invalid attribute.
+pub(crate) fn invalid_attr(attr: &Attribute, meta: &Meta) -> Diagnostic {
+    let span = attr.span().unwrap();
+    let name = attr.path.segments.last().unwrap().ident.to_string();
+    let name = name.as_str();
+
+    match meta {
+        Meta::Path(_) => span_err(span, &format!("`#[{}]` is not a valid attribute", name)),
+        Meta::NameValue(_) => {
+            span_err(span, &format!("`#[{} = ...]` is not a valid attribute", name))
+        }
+        Meta::List(_) => span_err(span, &format!("`#[{}(...)]` is not a valid attribute", name)),
+    }
+}
+
+/// Emit a error diagnostic for an invalid attribute (optionally performing additional decoration
+/// using the `FnOnce` passed in `diag`) and return `Err(ErrorHandled)`.
+///
+/// For methods that return a `Result<_, SessionDiagnosticDeriveError>`:
+macro_rules! throw_invalid_attr {
+    ($attr:expr, $meta:expr) => {{ throw_invalid_attr!($attr, $meta, |diag| diag) }};
+    ($attr:expr, $meta:expr, $f:expr) => {{
+        let diag = crate::diagnostics::error::invalid_attr($attr, $meta);
+        return Err(crate::diagnostics::error::_throw_err(diag, $f));
+    }};
+}
+
+pub(crate) use throw_invalid_attr;
+
+/// Returns an error diagnostic for an invalid nested attribute.
+pub(crate) fn invalid_nested_attr(attr: &Attribute, nested: &NestedMeta) -> Diagnostic {
+    let name = attr.path.segments.last().unwrap().ident.to_string();
+    let name = name.as_str();
+
+    let span = nested.span().unwrap();
+    let meta = match nested {
+        syn::NestedMeta::Meta(meta) => meta,
+        syn::NestedMeta::Lit(_) => {
+            return span_err(span, &format!("`#[{}(\"...\")]` is not a valid attribute", name));
+        }
+    };
+
+    let span = meta.span().unwrap();
+    let nested_name = meta.path().segments.last().unwrap().ident.to_string();
+    let nested_name = nested_name.as_str();
+    match meta {
+        Meta::NameValue(..) => span_err(
+            span,
+            &format!("`#[{}({} = ...)]` is not a valid attribute", name, nested_name),
+        ),
+        Meta::Path(..) => {
+            span_err(span, &format!("`#[{}({})]` is not a valid attribute", name, nested_name))
+        }
+        Meta::List(..) => {
+            span_err(span, &format!("`#[{}({}(...))]` is not a valid attribute", name, nested_name))
+        }
+    }
+}
+
+/// Emit a error diagnostic for an invalid nested attribute (optionally performing additional
+/// decoration using the `FnOnce` passed in `diag`) and return `Err(ErrorHandled)`.
+///
+/// For methods that return a `Result<_, SessionDiagnosticDeriveError>`:
+macro_rules! throw_invalid_nested_attr {
+    ($attr:expr, $nested_attr:expr) => {{ throw_invalid_nested_attr!($attr, $nested_attr, |diag| diag) }};
+    ($attr:expr, $nested_attr:expr, $f:expr) => {{
+        let diag = crate::diagnostics::error::invalid_nested_attr($attr, $nested_attr);
+        return Err(crate::diagnostics::error::_throw_err(diag, $f));
+    }};
+}
+
+pub(crate) use throw_invalid_nested_attr;
diff --git a/compiler/rustc_macros/src/diagnostics/mod.rs b/compiler/rustc_macros/src/diagnostics/mod.rs
new file mode 100644 (file)
index 0000000..73ad415
--- /dev/null
@@ -0,0 +1,114 @@
+mod diagnostic;
+mod error;
+mod subdiagnostic;
+mod utils;
+
+use diagnostic::SessionDiagnosticDerive;
+use proc_macro2::TokenStream;
+use quote::format_ident;
+use subdiagnostic::SessionSubdiagnosticDerive;
+use synstructure::Structure;
+
+/// Implements `#[derive(SessionDiagnostic)]`, which allows for errors to be specified as a struct,
+/// independent from the actual diagnostics emitting code.
+///
+/// ```ignore (pseudo-rust)
+/// # extern crate rustc_errors;
+/// # use rustc_errors::Applicability;
+/// # extern crate rustc_span;
+/// # use rustc_span::{symbol::Ident, Span};
+/// # extern crate rust_middle;
+/// # use rustc_middle::ty::Ty;
+/// #[derive(SessionDiagnostic)]
+/// #[error(code = "E0505", slug = "borrowck-move-out-of-borrow")]
+/// pub struct MoveOutOfBorrowError<'tcx> {
+///     pub name: Ident,
+///     pub ty: Ty<'tcx>,
+///     #[primary_span]
+///     #[label]
+///     pub span: Span,
+///     #[label = "first-borrow-label"]
+///     pub first_borrow_span: Span,
+///     #[suggestion(code = "{name}.clone()")]
+///     pub clone_sugg: Option<(Span, Applicability)>
+/// }
+/// ```
+///
+/// ```fluent
+/// move-out-of-borrow = cannot move out of {$name} because it is borrowed
+///     .label = cannot move out of borrow
+///     .first-borrow-label = `{$ty}` first borrowed here
+///     .suggestion = consider cloning here
+/// ```
+///
+/// Then, later, to emit the error:
+///
+/// ```ignore (pseudo-rust)
+/// sess.emit_err(MoveOutOfBorrowError {
+///     expected,
+///     actual,
+///     span,
+///     first_borrow_span,
+///     clone_sugg: Some(suggestion, Applicability::MachineApplicable),
+/// });
+/// ```
+///
+/// See rustc dev guide for more examples on using the `#[derive(SessionDiagnostic)]`:
+/// <https://rustc-dev-guide.rust-lang.org/diagnostics/sessiondiagnostic.html>
+pub fn session_diagnostic_derive(s: Structure<'_>) -> TokenStream {
+    // Names for the diagnostic we build and the session we build it from.
+    let diag = format_ident!("diag");
+    let sess = format_ident!("sess");
+
+    SessionDiagnosticDerive::new(diag, sess, s).into_tokens()
+}
+
+/// Implements `#[derive(SessionSubdiagnostic)]`, which allows for labels, notes, helps and
+/// suggestions to be specified as a structs or enums, independent from the actual diagnostics
+/// emitting code or diagnostic derives.
+///
+/// ```ignore (pseudo-rust)
+/// #[derive(SessionSubdiagnostic)]
+/// pub enum ExpectedIdentifierLabel<'tcx> {
+///     #[label(slug = "parser-expected-identifier")]
+///     WithoutFound {
+///         #[primary_span]
+///         span: Span,
+///     }
+///     #[label(slug = "parser-expected-identifier-found")]
+///     WithFound {
+///         #[primary_span]
+///         span: Span,
+///         found: String,
+///     }
+/// }
+///
+/// #[derive(SessionSubdiagnostic)]
+/// #[suggestion_verbose(slug = "parser-raw-identifier")]
+/// pub struct RawIdentifierSuggestion<'tcx> {
+///     #[primary_span]
+///     span: Span,
+///     #[applicability]
+///     applicability: Applicability,
+///     ident: Ident,
+/// }
+/// ```
+///
+/// ```fluent
+/// parser-expected-identifier = expected identifier
+///
+/// parser-expected-identifier-found = expected identifier, found {$found}
+///
+/// parser-raw-identifier = escape `{$ident}` to use it as an identifier
+/// ```
+///
+/// Then, later, to add the subdiagnostic:
+///
+/// ```ignore (pseudo-rust)
+/// diag.subdiagnostic(ExpectedIdentifierLabel::WithoutFound { span });
+///
+/// diag.subdiagnostic(RawIdentifierSuggestion { span, applicability, ident });
+/// ```
+pub fn session_subdiagnostic_derive(s: Structure<'_>) -> TokenStream {
+    SessionSubdiagnosticDerive::new(s).into_tokens()
+}
diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
new file mode 100644 (file)
index 0000000..961b42f
--- /dev/null
@@ -0,0 +1,437 @@
+#![deny(unused_must_use)]
+
+use crate::diagnostics::error::{
+    span_err, throw_invalid_attr, throw_invalid_nested_attr, throw_span_err,
+    SessionDiagnosticDeriveError,
+};
+use crate::diagnostics::utils::{
+    option_inner_ty, report_error_if_not_applied_to_applicability,
+    report_error_if_not_applied_to_span, Applicability, FieldInfo, HasFieldMap, SetOnce,
+};
+use proc_macro2::TokenStream;
+use quote::{format_ident, quote};
+use std::collections::HashMap;
+use std::fmt;
+use std::str::FromStr;
+use syn::{spanned::Spanned, Meta, MetaList, MetaNameValue};
+use synstructure::{BindingInfo, Structure, VariantInfo};
+
+/// Which kind of suggestion is being created?
+#[derive(Clone, Copy)]
+enum SubdiagnosticSuggestionKind {
+    /// `#[suggestion]`
+    Normal,
+    /// `#[suggestion_short]`
+    Short,
+    /// `#[suggestion_hidden]`
+    Hidden,
+    /// `#[suggestion_verbose]`
+    Verbose,
+}
+
+/// Which kind of subdiagnostic is being created from a variant?
+#[derive(Clone, Copy)]
+enum SubdiagnosticKind {
+    /// `#[label(...)]`
+    Label,
+    /// `#[note(...)]`
+    Note,
+    /// `#[help(...)]`
+    Help,
+    /// `#[suggestion{,_short,_hidden,_verbose}]`
+    Suggestion(SubdiagnosticSuggestionKind),
+}
+
+impl FromStr for SubdiagnosticKind {
+    type Err = ();
+
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        match s {
+            "label" => Ok(SubdiagnosticKind::Label),
+            "note" => Ok(SubdiagnosticKind::Note),
+            "help" => Ok(SubdiagnosticKind::Help),
+            "suggestion" => Ok(SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Normal)),
+            "suggestion_short" => {
+                Ok(SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Short))
+            }
+            "suggestion_hidden" => {
+                Ok(SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Hidden))
+            }
+            "suggestion_verbose" => {
+                Ok(SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Verbose))
+            }
+            _ => Err(()),
+        }
+    }
+}
+
+impl quote::IdentFragment for SubdiagnosticKind {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            SubdiagnosticKind::Label => write!(f, "label"),
+            SubdiagnosticKind::Note => write!(f, "note"),
+            SubdiagnosticKind::Help => write!(f, "help"),
+            SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Normal) => {
+                write!(f, "suggestion")
+            }
+            SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Short) => {
+                write!(f, "suggestion_short")
+            }
+            SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Hidden) => {
+                write!(f, "suggestion_hidden")
+            }
+            SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Verbose) => {
+                write!(f, "suggestion_verbose")
+            }
+        }
+    }
+
+    fn span(&self) -> Option<proc_macro2::Span> {
+        None
+    }
+}
+
+/// The central struct for constructing the `add_to_diagnostic` method from an annotated struct.
+pub(crate) struct SessionSubdiagnosticDerive<'a> {
+    structure: Structure<'a>,
+    diag: syn::Ident,
+}
+
+impl<'a> SessionSubdiagnosticDerive<'a> {
+    pub(crate) fn new(structure: Structure<'a>) -> Self {
+        let diag = format_ident!("diag");
+        Self { structure, diag }
+    }
+
+    pub(crate) fn into_tokens(self) -> TokenStream {
+        let SessionSubdiagnosticDerive { mut structure, diag } = self;
+        let implementation = {
+            let ast = structure.ast();
+            let span = ast.span().unwrap();
+            match ast.data {
+                syn::Data::Struct(..) | syn::Data::Enum(..) => (),
+                syn::Data::Union(..) => {
+                    span_err(
+                        span,
+                        "`#[derive(SessionSubdiagnostic)]` can only be used on structs and enums",
+                    );
+                }
+            }
+
+            if matches!(ast.data, syn::Data::Enum(..)) {
+                for attr in &ast.attrs {
+                    span_err(
+                        attr.span().unwrap(),
+                        "unsupported type attribute for subdiagnostic enum",
+                    )
+                    .emit();
+                }
+            }
+
+            structure.bind_with(|_| synstructure::BindStyle::Move);
+            let variants_ = structure.each_variant(|variant| {
+                // Build the mapping of field names to fields. This allows attributes to peek
+                // values from other fields.
+                let mut fields_map = HashMap::new();
+                for binding in variant.bindings() {
+                    let field = binding.ast();
+                    if let Some(ident) = &field.ident {
+                        fields_map.insert(ident.to_string(), quote! { #binding });
+                    }
+                }
+
+                let mut builder = SessionSubdiagnosticDeriveBuilder {
+                    diag: &diag,
+                    variant,
+                    span,
+                    fields: fields_map,
+                    kind: None,
+                    slug: None,
+                    code: None,
+                    span_field: None,
+                    applicability: None,
+                };
+                builder.into_tokens().unwrap_or_else(|v| v.to_compile_error())
+            });
+
+            quote! {
+                match self {
+                    #variants_
+                }
+            }
+        };
+
+        let ret = structure.gen_impl(quote! {
+            gen impl rustc_errors::AddSubdiagnostic for @Self {
+                fn add_to_diagnostic(self, #diag: &mut rustc_errors::Diagnostic) {
+                    use rustc_errors::{Applicability, IntoDiagnosticArg};
+                    #implementation
+                }
+            }
+        });
+        ret
+    }
+}
+
+/// Tracks persistent information required for building up the call to add to the diagnostic
+/// for the final generated method. This is a separate struct to `SessionSubdiagnosticDerive`
+/// only to be able to destructure and split `self.builder` and the `self.structure` up to avoid a
+/// double mut borrow later on.
+struct SessionSubdiagnosticDeriveBuilder<'a> {
+    /// The identifier to use for the generated `DiagnosticBuilder` instance.
+    diag: &'a syn::Ident,
+
+    /// Info for the current variant (or the type if not an enum).
+    variant: &'a VariantInfo<'a>,
+    /// Span for the entire type.
+    span: proc_macro::Span,
+
+    /// Store a map of field name to its corresponding field. This is built on construction of the
+    /// derive builder.
+    fields: HashMap<String, TokenStream>,
+
+    /// Subdiagnostic kind of the type/variant.
+    kind: Option<(SubdiagnosticKind, proc_macro::Span)>,
+
+    /// Slug of the subdiagnostic - corresponds to the Fluent identifier for the message - from the
+    /// `#[kind(slug = "...")]` attribute on the type or variant.
+    slug: Option<(String, proc_macro::Span)>,
+    /// If a suggestion, the code to suggest as a replacement - from the `#[kind(code = "...")]`
+    /// attribute on the type or variant.
+    code: Option<(TokenStream, proc_macro::Span)>,
+
+    /// Identifier for the binding to the `#[primary_span]` field.
+    span_field: Option<(proc_macro2::Ident, proc_macro::Span)>,
+    /// If a suggestion, the identifier for the binding to the `#[applicability]` field or a
+    /// `rustc_errors::Applicability::*` variant directly.
+    applicability: Option<(TokenStream, proc_macro::Span)>,
+}
+
+impl<'a> HasFieldMap for SessionSubdiagnosticDeriveBuilder<'a> {
+    fn get_field_binding(&self, field: &String) -> Option<&TokenStream> {
+        self.fields.get(field)
+    }
+}
+
+impl<'a> SessionSubdiagnosticDeriveBuilder<'a> {
+    fn identify_kind(&mut self) -> Result<(), SessionDiagnosticDeriveError> {
+        for attr in self.variant.ast().attrs {
+            let span = attr.span().unwrap();
+
+            let name = attr.path.segments.last().unwrap().ident.to_string();
+            let name = name.as_str();
+
+            let meta = attr.parse_meta()?;
+            let kind = match meta {
+                Meta::List(MetaList { ref nested, .. }) => {
+                    for nested_attr in nested {
+                        let meta = match nested_attr {
+                            syn::NestedMeta::Meta(ref meta) => meta,
+                            _ => throw_invalid_nested_attr!(attr, &nested_attr),
+                        };
+
+                        let span = meta.span().unwrap();
+                        let nested_name = meta.path().segments.last().unwrap().ident.to_string();
+                        let nested_name = nested_name.as_str();
+
+                        match meta {
+                            Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(s), .. }) => {
+                                match nested_name {
+                                    "code" => {
+                                        let formatted_str = self.build_format(&s.value(), s.span());
+                                        self.code.set_once((formatted_str, span));
+                                    }
+                                    "slug" => self.slug.set_once((s.value(), span)),
+                                    "applicability" => {
+                                        let value = match Applicability::from_str(&s.value()) {
+                                            Ok(v) => v,
+                                            Err(()) => {
+                                                span_err(span, "invalid applicability").emit();
+                                                Applicability::Unspecified
+                                            }
+                                        };
+                                        self.applicability.set_once((quote! { #value }, span));
+                                    }
+                                    _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
+                                        diag.help("only `code`, `slug` and `applicability` are valid nested attributes")
+                                    }),
+                                }
+                            }
+                            _ => throw_invalid_nested_attr!(attr, &nested_attr),
+                        }
+                    }
+
+                    let Ok(kind) = SubdiagnosticKind::from_str(name) else {
+                        throw_invalid_attr!(attr, &meta)
+                    };
+
+                    kind
+                }
+                _ => throw_invalid_attr!(attr, &meta),
+            };
+
+            if matches!(
+                kind,
+                SubdiagnosticKind::Label | SubdiagnosticKind::Help | SubdiagnosticKind::Note
+            ) && self.code.is_some()
+            {
+                throw_span_err!(
+                    span,
+                    &format!("`code` is not a valid nested attribute of a `{}` attribute", name)
+                );
+            }
+
+            if self.slug.is_none() {
+                throw_span_err!(
+                    span,
+                    &format!("`slug` must be set in a `#[{}(...)]` attribute", name)
+                );
+            }
+
+            self.kind.set_once((kind, span));
+        }
+
+        Ok(())
+    }
+
+    fn generate_field_code(
+        &mut self,
+        binding: &BindingInfo<'_>,
+        is_suggestion: bool,
+    ) -> Result<TokenStream, SessionDiagnosticDeriveError> {
+        let ast = binding.ast();
+
+        let option_ty = option_inner_ty(&ast.ty);
+        let info = FieldInfo {
+            vis: &ast.vis,
+            binding: binding,
+            ty: option_ty.unwrap_or(&ast.ty),
+            span: &ast.span(),
+        };
+
+        for attr in &ast.attrs {
+            let name = attr.path.segments.last().unwrap().ident.to_string();
+            let name = name.as_str();
+            let span = attr.span().unwrap();
+
+            let meta = attr.parse_meta()?;
+            match meta {
+                Meta::Path(_) => match name {
+                    "primary_span" => {
+                        report_error_if_not_applied_to_span(attr, &info)?;
+                        self.span_field.set_once((binding.binding.clone(), span));
+                        return Ok(quote! {});
+                    }
+                    "applicability" if is_suggestion => {
+                        report_error_if_not_applied_to_applicability(attr, &info)?;
+                        let binding = binding.binding.clone();
+                        self.applicability.set_once((quote! { #binding }, span));
+                        return Ok(quote! {});
+                    }
+                    "applicability" => {
+                        span_err(span, "`#[applicability]` is only valid on suggestions").emit();
+                        return Ok(quote! {});
+                    }
+                    "skip_arg" => {
+                        return Ok(quote! {});
+                    }
+                    _ => throw_invalid_attr!(attr, &meta, |diag| {
+                        diag.help("only `primary_span`, `applicability` and `skip_arg` are valid field attributes")
+                    }),
+                },
+                _ => throw_invalid_attr!(attr, &meta),
+            }
+        }
+
+        let ident = ast.ident.as_ref().unwrap();
+
+        let diag = &self.diag;
+        let generated = quote! {
+            #diag.set_arg(
+                stringify!(#ident),
+                #binding.into_diagnostic_arg()
+            );
+        };
+
+        if option_ty.is_none() {
+            Ok(quote! { #generated })
+        } else {
+            Ok(quote! {
+                if let Some(#binding) = #binding {
+                    #generated
+                }
+            })
+        }
+    }
+
+    fn into_tokens(&mut self) -> Result<TokenStream, SessionDiagnosticDeriveError> {
+        self.identify_kind()?;
+        let Some(kind) = self.kind.map(|(kind, _)| kind) else {
+            throw_span_err!(
+                self.variant.ast().ident.span().unwrap(),
+                "subdiagnostic kind not specified"
+            );
+        };
+
+        let is_suggestion = matches!(kind, SubdiagnosticKind::Suggestion(_));
+
+        let mut args = TokenStream::new();
+        for binding in self.variant.bindings() {
+            let arg = self
+                .generate_field_code(binding, is_suggestion)
+                .unwrap_or_else(|v| v.to_compile_error());
+            args.extend(arg);
+        }
+
+        // Missing slug errors will already have been reported.
+        let slug = self.slug.as_ref().map(|(slug, _)| &**slug).unwrap_or("missing-slug");
+        let code = match self.code.as_ref() {
+            Some((code, _)) => Some(quote! { #code }),
+            None if is_suggestion => {
+                span_err(self.span, "suggestion without `code = \"...\"`").emit();
+                Some(quote! { /* macro error */ "..." })
+            }
+            None => None,
+        };
+
+        let span_field = self.span_field.as_ref().map(|(span, _)| span);
+        let applicability = match self.applicability.clone() {
+            Some((applicability, _)) => Some(applicability),
+            None if is_suggestion => {
+                span_err(self.span, "suggestion without `applicability`").emit();
+                Some(quote! { rustc_errors::Applicability::Unspecified })
+            }
+            None => None,
+        };
+
+        let diag = &self.diag;
+        let name = format_ident!("{}{}", if span_field.is_some() { "span_" } else { "" }, kind);
+        let message = quote! { rustc_errors::DiagnosticMessage::fluent(#slug) };
+        let call = if matches!(kind, SubdiagnosticKind::Suggestion(..)) {
+            if let Some(span) = span_field {
+                quote! { #diag.#name(#span, #message, #code, #applicability); }
+            } else {
+                span_err(self.span, "suggestion without `#[primary_span]` field").emit();
+                quote! { unreachable!(); }
+            }
+        } else if matches!(kind, SubdiagnosticKind::Label) {
+            if let Some(span) = span_field {
+                quote! { #diag.#name(#span, #message); }
+            } else {
+                span_err(self.span, "label without `#[primary_span]` field").emit();
+                quote! { unreachable!(); }
+            }
+        } else {
+            if let Some(span) = span_field {
+                quote! { #diag.#name(#span, #message); }
+            } else {
+                quote! { #diag.#name(#message); }
+            }
+        };
+
+        Ok(quote! {
+            #call
+            #args
+        })
+    }
+}
diff --git a/compiler/rustc_macros/src/diagnostics/utils.rs b/compiler/rustc_macros/src/diagnostics/utils.rs
new file mode 100644 (file)
index 0000000..1f36af0
--- /dev/null
@@ -0,0 +1,267 @@
+use crate::diagnostics::error::{span_err, throw_span_err, SessionDiagnosticDeriveError};
+use proc_macro::Span;
+use proc_macro2::TokenStream;
+use quote::{format_ident, quote};
+use std::collections::BTreeSet;
+use std::str::FromStr;
+use syn::{spanned::Spanned, Attribute, Meta, Type, Visibility};
+use synstructure::BindingInfo;
+
+/// Checks whether the type name of `ty` matches `name`.
+///
+/// Given some struct at `a::b::c::Foo`, this will return true for `c::Foo`, `b::c::Foo`, or
+/// `a::b::c::Foo`. This reasonably allows qualified names to be used in the macro.
+pub(crate) fn type_matches_path(ty: &Type, name: &[&str]) -> bool {
+    if let Type::Path(ty) = ty {
+        ty.path
+            .segments
+            .iter()
+            .map(|s| s.ident.to_string())
+            .rev()
+            .zip(name.iter().rev())
+            .all(|(x, y)| &x.as_str() == y)
+    } else {
+        false
+    }
+}
+
+/// Reports an error if the field's type is not `Applicability`.
+fn report_error_if_not_applied_to_ty(
+    attr: &Attribute,
+    info: &FieldInfo<'_>,
+    path: &[&str],
+    ty_name: &str,
+) -> Result<(), SessionDiagnosticDeriveError> {
+    if !type_matches_path(&info.ty, path) {
+        let name = attr.path.segments.last().unwrap().ident.to_string();
+        let name = name.as_str();
+        let meta = attr.parse_meta()?;
+
+        throw_span_err!(
+            attr.span().unwrap(),
+            &format!(
+                "the `#[{}{}]` attribute can only be applied to fields of type `{}`",
+                name,
+                match meta {
+                    Meta::Path(_) => "",
+                    Meta::NameValue(_) => " = ...",
+                    Meta::List(_) => "(...)",
+                },
+                ty_name
+            )
+        );
+    }
+
+    Ok(())
+}
+
+/// Reports an error if the field's type is not `Applicability`.
+pub(crate) fn report_error_if_not_applied_to_applicability(
+    attr: &Attribute,
+    info: &FieldInfo<'_>,
+) -> Result<(), SessionDiagnosticDeriveError> {
+    report_error_if_not_applied_to_ty(
+        attr,
+        info,
+        &["rustc_errors", "Applicability"],
+        "Applicability",
+    )
+}
+
+/// Reports an error if the field's type is not `Span`.
+pub(crate) fn report_error_if_not_applied_to_span(
+    attr: &Attribute,
+    info: &FieldInfo<'_>,
+) -> Result<(), SessionDiagnosticDeriveError> {
+    report_error_if_not_applied_to_ty(attr, info, &["rustc_span", "Span"], "Span")
+}
+
+/// If `ty` is an Option, returns `Some(inner type)`, otherwise returns `None`.
+pub(crate) fn option_inner_ty(ty: &Type) -> Option<&Type> {
+    if type_matches_path(ty, &["std", "option", "Option"]) {
+        if let Type::Path(ty_path) = ty {
+            let path = &ty_path.path;
+            let ty = path.segments.iter().last().unwrap();
+            if let syn::PathArguments::AngleBracketed(bracketed) = &ty.arguments {
+                if bracketed.args.len() == 1 {
+                    if let syn::GenericArgument::Type(ty) = &bracketed.args[0] {
+                        return Some(ty);
+                    }
+                }
+            }
+        }
+    }
+    None
+}
+
+/// Field information passed to the builder. Deliberately omits attrs to discourage the
+/// `generate_*` methods from walking the attributes themselves.
+pub(crate) struct FieldInfo<'a> {
+    pub(crate) vis: &'a Visibility,
+    pub(crate) binding: &'a BindingInfo<'a>,
+    pub(crate) ty: &'a Type,
+    pub(crate) span: &'a proc_macro2::Span,
+}
+
+/// Small helper trait for abstracting over `Option` fields that contain a value and a `Span`
+/// for error reporting if they are set more than once.
+pub(crate) trait SetOnce<T> {
+    fn set_once(&mut self, value: T);
+}
+
+impl<T> SetOnce<(T, Span)> for Option<(T, Span)> {
+    fn set_once(&mut self, (value, span): (T, Span)) {
+        match self {
+            None => {
+                *self = Some((value, span));
+            }
+            Some((_, prev_span)) => {
+                span_err(span, "specified multiple times")
+                    .span_note(*prev_span, "previously specified here")
+                    .emit();
+            }
+        }
+    }
+}
+
+pub(crate) trait HasFieldMap {
+    /// Returns the binding for the field with the given name, if it exists on the type.
+    fn get_field_binding(&self, field: &String) -> Option<&TokenStream>;
+
+    /// In the strings in the attributes supplied to this macro, we want callers to be able to
+    /// reference fields in the format string. For example:
+    ///
+    /// ```ignore (not-usage-example)
+    /// /// Suggest `==` when users wrote `===`.
+    /// #[suggestion(slug = "parser-not-javascript-eq", code = "{lhs} == {rhs}")]
+    /// struct NotJavaScriptEq {
+    ///     #[primary_span]
+    ///     span: Span,
+    ///     lhs: Ident,
+    ///     rhs: Ident,
+    /// }
+    /// ```
+    ///
+    /// We want to automatically pick up that `{lhs}` refers `self.lhs` and `{rhs}` refers to
+    /// `self.rhs`, then generate this call to `format!`:
+    ///
+    /// ```ignore (not-usage-example)
+    /// format!("{lhs} == {rhs}", lhs = self.lhs, rhs = self.rhs)
+    /// ```
+    ///
+    /// This function builds the entire call to `format!`.
+    fn build_format(&self, input: &str, span: proc_macro2::Span) -> TokenStream {
+        // This set is used later to generate the final format string. To keep builds reproducible,
+        // the iteration order needs to be deterministic, hence why we use a `BTreeSet` here
+        // instead of a `HashSet`.
+        let mut referenced_fields: BTreeSet<String> = BTreeSet::new();
+
+        // At this point, we can start parsing the format string.
+        let mut it = input.chars().peekable();
+
+        // Once the start of a format string has been found, process the format string and spit out
+        // the referenced fields. Leaves `it` sitting on the closing brace of the format string, so
+        // the next call to `it.next()` retrieves the next character.
+        while let Some(c) = it.next() {
+            if c == '{' && *it.peek().unwrap_or(&'\0') != '{' {
+                let mut eat_argument = || -> Option<String> {
+                    let mut result = String::new();
+                    // Format specifiers look like:
+                    //
+                    //   format   := '{' [ argument ] [ ':' format_spec ] '}' .
+                    //
+                    // Therefore, we only need to eat until ':' or '}' to find the argument.
+                    while let Some(c) = it.next() {
+                        result.push(c);
+                        let next = *it.peek().unwrap_or(&'\0');
+                        if next == '}' {
+                            break;
+                        } else if next == ':' {
+                            // Eat the ':' character.
+                            assert_eq!(it.next().unwrap(), ':');
+                            break;
+                        }
+                    }
+                    // Eat until (and including) the matching '}'
+                    while it.next()? != '}' {
+                        continue;
+                    }
+                    Some(result)
+                };
+
+                if let Some(referenced_field) = eat_argument() {
+                    referenced_fields.insert(referenced_field);
+                }
+            }
+        }
+
+        // At this point, `referenced_fields` contains a set of the unique fields that were
+        // referenced in the format string. Generate the corresponding "x = self.x" format
+        // string parameters:
+        let args = referenced_fields.into_iter().map(|field: String| {
+            let field_ident = format_ident!("{}", field);
+            let value = match self.get_field_binding(&field) {
+                Some(value) => value.clone(),
+                // This field doesn't exist. Emit a diagnostic.
+                None => {
+                    span_err(
+                        span.unwrap(),
+                        &format!("`{}` doesn't refer to a field on this type", field),
+                    )
+                    .emit();
+                    quote! {
+                        "{#field}"
+                    }
+                }
+            };
+            quote! {
+                #field_ident = #value
+            }
+        });
+        quote! {
+            format!(#input #(,#args)*)
+        }
+    }
+}
+
+/// `Applicability` of a suggestion - mirrors `rustc_errors::Applicability` - and used to represent
+/// the user's selection of applicability if specified in an attribute.
+pub(crate) enum Applicability {
+    MachineApplicable,
+    MaybeIncorrect,
+    HasPlaceholders,
+    Unspecified,
+}
+
+impl FromStr for Applicability {
+    type Err = ();
+
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        match s {
+            "machine-applicable" => Ok(Applicability::MachineApplicable),
+            "maybe-incorrect" => Ok(Applicability::MaybeIncorrect),
+            "has-placeholders" => Ok(Applicability::HasPlaceholders),
+            "unspecified" => Ok(Applicability::Unspecified),
+            _ => Err(()),
+        }
+    }
+}
+
+impl quote::ToTokens for Applicability {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        tokens.extend(match self {
+            Applicability::MachineApplicable => {
+                quote! { rustc_errors::Applicability::MachineApplicable }
+            }
+            Applicability::MaybeIncorrect => {
+                quote! { rustc_errors::Applicability::MaybeIncorrect }
+            }
+            Applicability::HasPlaceholders => {
+                quote! { rustc_errors::Applicability::HasPlaceholders }
+            }
+            Applicability::Unspecified => {
+                quote! { rustc_errors::Applicability::Unspecified }
+            }
+        });
+    }
+}
index b53ef8161359a48fec2941ff7624152df91b82cf..b01e01414e878cd725b893f40178278bfe195187 100644 (file)
@@ -1,5 +1,6 @@
-#![feature(proc_macro_diagnostic)]
 #![feature(allow_internal_unstable)]
+#![feature(let_else)]
+#![feature(proc_macro_diagnostic)]
 #![allow(rustc::default_hash_types)]
 #![recursion_limit = "128"]
 
@@ -7,12 +8,12 @@
 
 use proc_macro::TokenStream;
 
+mod diagnostics;
 mod hash_stable;
 mod lift;
 mod newtype;
 mod query;
 mod serialize;
-mod session_diagnostic;
 mod symbols;
 mod type_foldable;
 
@@ -72,8 +73,24 @@ pub fn newtype_index(input: TokenStream) -> TokenStream {
         skip_arg,
         primary_span,
         label,
+        subdiagnostic,
         suggestion,
         suggestion_short,
         suggestion_hidden,
-        suggestion_verbose)] => session_diagnostic::session_diagnostic_derive
+        suggestion_verbose)] => diagnostics::session_diagnostic_derive
+);
+decl_derive!(
+    [SessionSubdiagnostic, attributes(
+        // struct/variant attributes
+        label,
+        help,
+        note,
+        suggestion,
+        suggestion_short,
+        suggestion_hidden,
+        suggestion_verbose,
+        // field attributes
+        skip_arg,
+        primary_span,
+        applicability)] => diagnostics::session_subdiagnostic_derive
 );
diff --git a/compiler/rustc_macros/src/session_diagnostic.rs b/compiler/rustc_macros/src/session_diagnostic.rs
deleted file mode 100644 (file)
index 46f698f..0000000
+++ /dev/null
@@ -1,956 +0,0 @@
-#![deny(unused_must_use)]
-use proc_macro::Diagnostic;
-use quote::{format_ident, quote};
-use syn::spanned::Spanned;
-
-use std::collections::{BTreeSet, HashMap};
-
-/// Implements `#[derive(SessionDiagnostic)]`, which allows for errors to be specified as a struct,
-/// independent from the actual diagnostics emitting code.
-///
-/// ```ignore (pseudo-rust)
-/// # extern crate rustc_errors;
-/// # use rustc_errors::Applicability;
-/// # extern crate rustc_span;
-/// # use rustc_span::{symbol::Ident, Span};
-/// # extern crate rust_middle;
-/// # use rustc_middle::ty::Ty;
-/// #[derive(SessionDiagnostic)]
-/// #[error(code = "E0505", slug = "move-out-of-borrow-error")]
-/// pub struct MoveOutOfBorrowError<'tcx> {
-///     pub name: Ident,
-///     pub ty: Ty<'tcx>,
-///     #[primary_span]
-///     #[label = "cannot move out of borrow"]
-///     pub span: Span,
-///     #[label = "`{ty}` first borrowed here"]
-///     pub other_span: Span,
-///     #[suggestion(message = "consider cloning here", code = "{name}.clone()")]
-///     pub opt_sugg: Option<(Span, Applicability)>
-/// }
-/// ```
-///
-/// Then, later, to emit the error:
-///
-/// ```ignore (pseudo-rust)
-/// sess.emit_err(MoveOutOfBorrowError {
-///     expected,
-///     actual,
-///     span,
-///     other_span,
-///     opt_sugg: Some(suggestion, Applicability::MachineApplicable),
-/// });
-/// ```
-pub fn session_diagnostic_derive(s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
-    // Names for the diagnostic we build and the session we build it from.
-    let diag = format_ident!("diag");
-    let sess = format_ident!("sess");
-
-    SessionDiagnosticDerive::new(diag, sess, s).into_tokens()
-}
-
-/// Checks whether the type name of `ty` matches `name`.
-///
-/// Given some struct at `a::b::c::Foo`, this will return true for `c::Foo`, `b::c::Foo`, or
-/// `a::b::c::Foo`. This reasonably allows qualified names to be used in the macro.
-fn type_matches_path(ty: &syn::Type, name: &[&str]) -> bool {
-    if let syn::Type::Path(ty) = ty {
-        ty.path
-            .segments
-            .iter()
-            .map(|s| s.ident.to_string())
-            .rev()
-            .zip(name.iter().rev())
-            .all(|(x, y)| &x.as_str() == y)
-    } else {
-        false
-    }
-}
-
-/// The central struct for constructing the `as_error` method from an annotated struct.
-struct SessionDiagnosticDerive<'a> {
-    structure: synstructure::Structure<'a>,
-    builder: SessionDiagnosticDeriveBuilder<'a>,
-}
-
-impl std::convert::From<syn::Error> for SessionDiagnosticDeriveError {
-    fn from(e: syn::Error) -> Self {
-        SessionDiagnosticDeriveError::SynError(e)
-    }
-}
-
-#[derive(Debug)]
-enum SessionDiagnosticDeriveError {
-    SynError(syn::Error),
-    ErrorHandled,
-}
-
-impl SessionDiagnosticDeriveError {
-    fn to_compile_error(self) -> proc_macro2::TokenStream {
-        match self {
-            SessionDiagnosticDeriveError::SynError(e) => e.to_compile_error(),
-            SessionDiagnosticDeriveError::ErrorHandled => {
-                // Return ! to avoid having to create a blank DiagnosticBuilder to return when an
-                // error has already been emitted to the compiler.
-                quote! {
-                    { unreachable!(); }
-                }
-            }
-        }
-    }
-}
-
-fn span_err(span: impl proc_macro::MultiSpan, msg: &str) -> proc_macro::Diagnostic {
-    Diagnostic::spanned(span, proc_macro::Level::Error, msg)
-}
-
-/// For methods that return a `Result<_, SessionDiagnosticDeriveError>`:
-///
-/// Emit a diagnostic on span `$span` with msg `$msg` (optionally performing additional decoration
-/// using the `FnOnce` passed in `diag`) and return `Err(ErrorHandled)`.
-macro_rules! throw_span_err {
-    ($span:expr, $msg:expr) => {{ throw_span_err!($span, $msg, |diag| diag) }};
-    ($span:expr, $msg:expr, $f:expr) => {{
-        return Err(_throw_span_err($span, $msg, $f));
-    }};
-}
-
-/// When possible, prefer using `throw_span_err!` over using this function directly. This only
-/// exists as a function to constrain `f` to an `impl FnOnce`.
-fn _throw_span_err(
-    span: impl proc_macro::MultiSpan,
-    msg: &str,
-    f: impl FnOnce(proc_macro::Diagnostic) -> proc_macro::Diagnostic,
-) -> SessionDiagnosticDeriveError {
-    let diag = span_err(span, msg);
-    f(diag).emit();
-    SessionDiagnosticDeriveError::ErrorHandled
-}
-
-impl<'a> SessionDiagnosticDerive<'a> {
-    fn new(diag: syn::Ident, sess: syn::Ident, structure: synstructure::Structure<'a>) -> Self {
-        // Build the mapping of field names to fields. This allows attributes to peek values from
-        // other fields.
-        let mut fields_map = HashMap::new();
-
-        // Convenience bindings.
-        let ast = structure.ast();
-
-        if let syn::Data::Struct(syn::DataStruct { fields, .. }) = &ast.data {
-            for field in fields.iter() {
-                if let Some(ident) = &field.ident {
-                    fields_map.insert(ident.to_string(), field);
-                }
-            }
-        }
-
-        Self {
-            builder: SessionDiagnosticDeriveBuilder {
-                diag,
-                sess,
-                fields: fields_map,
-                kind: None,
-                code: None,
-                slug: None,
-            },
-            structure,
-        }
-    }
-
-    fn into_tokens(self) -> proc_macro2::TokenStream {
-        let SessionDiagnosticDerive { mut structure, mut builder } = self;
-
-        let ast = structure.ast();
-        let attrs = &ast.attrs;
-
-        let (implementation, param_ty) = {
-            if let syn::Data::Struct(..) = ast.data {
-                let preamble = {
-                    let preamble = attrs.iter().map(|attr| {
-                        builder
-                            .generate_structure_code(attr)
-                            .unwrap_or_else(|v| v.to_compile_error())
-                    });
-
-                    quote! {
-                        #(#preamble)*;
-                    }
-                };
-
-                // Generates calls to `span_label` and similar functions based on the attributes
-                // on fields. Code for suggestions uses formatting machinery and the value of
-                // other fields - because any given field can be referenced multiple times, it
-                // should be accessed through a borrow. When passing fields to `set_arg` (which
-                // happens below) for Fluent, we want to move the data, so that has to happen
-                // in a separate pass over the fields.
-                let attrs = structure.each(|field_binding| {
-                    let field = field_binding.ast();
-                    let result = field.attrs.iter().map(|attr| {
-                        builder
-                            .generate_field_attr_code(
-                                attr,
-                                FieldInfo {
-                                    vis: &field.vis,
-                                    binding: field_binding,
-                                    ty: &field.ty,
-                                    span: &field.span(),
-                                },
-                            )
-                            .unwrap_or_else(|v| v.to_compile_error())
-                    });
-
-                    quote! { #(#result);* }
-                });
-
-                // When generating `set_arg` calls, move data rather than borrow it to avoid
-                // requiring clones - this must therefore be the last use of each field (for
-                // example, any formatting machinery that might refer to a field should be
-                // generated already).
-                structure.bind_with(|_| synstructure::BindStyle::Move);
-                let args = structure.each(|field_binding| {
-                    let field = field_binding.ast();
-                    // When a field has attributes like `#[label]` or `#[note]` then it doesn't
-                    // need to be passed as an argument to the diagnostic. But when a field has no
-                    // attributes then it must be passed as an argument to the diagnostic so that
-                    // it can be referred to by Fluent messages.
-                    if field.attrs.is_empty() {
-                        let diag = &builder.diag;
-                        let ident = field_binding.ast().ident.as_ref().unwrap();
-                        quote! {
-                            #diag.set_arg(
-                                stringify!(#ident),
-                                #field_binding.into_diagnostic_arg()
-                            );
-                        }
-                    } else {
-                        quote! {}
-                    }
-                });
-
-                let span = ast.span().unwrap();
-                let (diag, sess) = (&builder.diag, &builder.sess);
-                let init = match (builder.kind, builder.slug) {
-                    (None, _) => {
-                        span_err(span, "diagnostic kind not specified")
-                            .help("use the `#[error(...)]` attribute to create an error")
-                            .emit();
-                        return SessionDiagnosticDeriveError::ErrorHandled.to_compile_error();
-                    }
-                    (Some((kind, _)), None) => {
-                        span_err(span, "`slug` not specified")
-                            .help(&format!("use the `#[{}(slug = \"...\")]` attribute to set this diagnostic's slug", kind.descr()))
-                            .emit();
-                        return SessionDiagnosticDeriveError::ErrorHandled.to_compile_error();
-                    }
-                    (Some((SessionDiagnosticKind::Error, _)), Some((slug, _))) => {
-                        quote! {
-                            let mut #diag = #sess.struct_err(
-                                rustc_errors::DiagnosticMessage::fluent(#slug),
-                            );
-                        }
-                    }
-                    (Some((SessionDiagnosticKind::Warn, _)), Some((slug, _))) => {
-                        quote! {
-                            let mut #diag = #sess.struct_warn(
-                                rustc_errors::DiagnosticMessage::fluent(#slug),
-                            );
-                        }
-                    }
-                };
-
-                let implementation = quote! {
-                    #init
-                    #preamble
-                    match self {
-                        #attrs
-                    }
-                    match self {
-                        #args
-                    }
-                    #diag
-                };
-                let param_ty = match builder.kind {
-                    Some((SessionDiagnosticKind::Error, _)) => {
-                        quote! { rustc_errors::ErrorGuaranteed }
-                    }
-                    Some((SessionDiagnosticKind::Warn, _)) => quote! { () },
-                    _ => unreachable!(),
-                };
-
-                (implementation, param_ty)
-            } else {
-                span_err(
-                    ast.span().unwrap(),
-                    "`#[derive(SessionDiagnostic)]` can only be used on structs",
-                )
-                .emit();
-
-                let implementation = SessionDiagnosticDeriveError::ErrorHandled.to_compile_error();
-                let param_ty = quote! { rustc_errors::ErrorGuaranteed };
-                (implementation, param_ty)
-            }
-        };
-
-        let sess = &builder.sess;
-        structure.gen_impl(quote! {
-            gen impl<'__session_diagnostic_sess> rustc_session::SessionDiagnostic<'__session_diagnostic_sess, #param_ty>
-                    for @Self
-            {
-                fn into_diagnostic(
-                    self,
-                    #sess: &'__session_diagnostic_sess rustc_session::Session
-                ) -> rustc_errors::DiagnosticBuilder<'__session_diagnostic_sess, #param_ty> {
-                    use rustc_errors::IntoDiagnosticArg;
-                    #implementation
-                }
-            }
-        })
-    }
-}
-
-/// Field information passed to the builder. Deliberately omits attrs to discourage the
-/// `generate_*` methods from walking the attributes themselves.
-struct FieldInfo<'a> {
-    vis: &'a syn::Visibility,
-    binding: &'a synstructure::BindingInfo<'a>,
-    ty: &'a syn::Type,
-    span: &'a proc_macro2::Span,
-}
-
-/// What kind of session diagnostic is being derived - an error or a warning?
-#[derive(Copy, Clone)]
-enum SessionDiagnosticKind {
-    /// `#[error(..)]`
-    Error,
-    /// `#[warn(..)]`
-    Warn,
-}
-
-impl SessionDiagnosticKind {
-    /// Returns human-readable string corresponding to the kind.
-    fn descr(&self) -> &'static str {
-        match self {
-            SessionDiagnosticKind::Error => "error",
-            SessionDiagnosticKind::Warn => "warning",
-        }
-    }
-}
-
-/// Tracks persistent information required for building up the individual calls to diagnostic
-/// methods for the final generated method. This is a separate struct to `SessionDiagnosticDerive`
-/// only to be able to destructure and split `self.builder` and the `self.structure` up to avoid a
-/// double mut borrow later on.
-struct SessionDiagnosticDeriveBuilder<'a> {
-    /// Name of the session parameter that's passed in to the `as_error` method.
-    sess: syn::Ident,
-    /// The identifier to use for the generated `DiagnosticBuilder` instance.
-    diag: syn::Ident,
-
-    /// Store a map of field name to its corresponding field. This is built on construction of the
-    /// derive builder.
-    fields: HashMap<String, &'a syn::Field>,
-
-    /// Kind of diagnostic requested via the struct attribute.
-    kind: Option<(SessionDiagnosticKind, proc_macro::Span)>,
-    /// Slug is a mandatory part of the struct attribute as corresponds to the Fluent message that
-    /// has the actual diagnostic message.
-    slug: Option<(String, proc_macro::Span)>,
-    /// Error codes are a optional part of the struct attribute - this is only set to detect
-    /// multiple specifications.
-    code: Option<proc_macro::Span>,
-}
-
-impl<'a> SessionDiagnosticDeriveBuilder<'a> {
-    /// Establishes state in the `SessionDiagnosticDeriveBuilder` resulting from the struct
-    /// attributes like `#[error(..)#`, such as the diagnostic kind and slug. Generates
-    /// diagnostic builder calls for setting error code and creating note/help messages.
-    fn generate_structure_code(
-        &mut self,
-        attr: &syn::Attribute,
-    ) -> Result<proc_macro2::TokenStream, SessionDiagnosticDeriveError> {
-        let span = attr.span().unwrap();
-
-        let name = attr.path.segments.last().unwrap().ident.to_string();
-        let name = name.as_str();
-        let meta = attr.parse_meta()?;
-
-        if matches!(name, "help" | "note")
-            && matches!(meta, syn::Meta::Path(_) | syn::Meta::NameValue(_))
-        {
-            let diag = &self.diag;
-            let slug = match &self.slug {
-                Some((slug, _)) => slug.as_str(),
-                None => throw_span_err!(
-                    span,
-                    &format!(
-                        "`#[{}{}]` must come after `#[error(..)]` or `#[warn(..)]`",
-                        name,
-                        match meta {
-                            syn::Meta::Path(_) => "",
-                            syn::Meta::NameValue(_) => " = ...",
-                            _ => unreachable!(),
-                        }
-                    )
-                ),
-            };
-            let id = match meta {
-                syn::Meta::Path(..) => quote! { #name },
-                syn::Meta::NameValue(syn::MetaNameValue { lit: syn::Lit::Str(s), .. }) => {
-                    quote! { #s }
-                }
-                _ => unreachable!(),
-            };
-            let fn_name = proc_macro2::Ident::new(name, attr.span());
-
-            return Ok(quote! {
-                #diag.#fn_name(rustc_errors::DiagnosticMessage::fluent_attr(#slug, #id));
-            });
-        }
-
-        let nested = match meta {
-            syn::Meta::List(syn::MetaList { nested, .. }) => nested,
-            syn::Meta::Path(..) => throw_span_err!(
-                span,
-                &format!("`#[{}]` is not a valid `SessionDiagnostic` struct attribute", name)
-            ),
-            syn::Meta::NameValue(..) => throw_span_err!(
-                span,
-                &format!("`#[{} = ...]` is not a valid `SessionDiagnostic` struct attribute", name)
-            ),
-        };
-
-        let kind = match name {
-            "error" => SessionDiagnosticKind::Error,
-            "warning" => SessionDiagnosticKind::Warn,
-            other => throw_span_err!(
-                span,
-                &format!("`#[{}(...)]` is not a valid `SessionDiagnostic` struct attribute", other)
-            ),
-        };
-        self.set_kind_once(kind, span)?;
-
-        let mut tokens = Vec::new();
-        for attr in nested {
-            let span = attr.span().unwrap();
-            let meta = match attr {
-                syn::NestedMeta::Meta(meta) => meta,
-                syn::NestedMeta::Lit(_) => throw_span_err!(
-                    span,
-                    &format!(
-                        "`#[{}(\"...\")]` is not a valid `SessionDiagnostic` struct attribute",
-                        name
-                    )
-                ),
-            };
-
-            let path = meta.path();
-            let nested_name = path.segments.last().unwrap().ident.to_string();
-            match &meta {
-                // Struct attributes are only allowed to be applied once, and the diagnostic
-                // changes will be set in the initialisation code.
-                syn::Meta::NameValue(syn::MetaNameValue { lit: syn::Lit::Str(s), .. }) => {
-                    match nested_name.as_str() {
-                        "slug" => {
-                            self.set_slug_once(s.value(), s.span().unwrap());
-                        }
-                        "code" => {
-                            tokens.push(self.set_code_once(s.value(), s.span().unwrap()));
-                        }
-                        other => {
-                            let diag = span_err(
-                                span,
-                                &format!(
-                                    "`#[{}({} = ...)]` is not a valid `SessionDiagnostic` struct attribute",
-                                    name, other
-                                ),
-                            );
-                            diag.emit();
-                        }
-                    }
-                }
-                syn::Meta::NameValue(..) => {
-                    span_err(
-                        span,
-                        &format!(
-                            "`#[{}({} = ...)]` is not a valid `SessionDiagnostic` struct attribute",
-                            name, nested_name
-                        ),
-                    )
-                    .help("value must be a string")
-                    .emit();
-                }
-                syn::Meta::Path(..) => {
-                    span_err(
-                        span,
-                        &format!(
-                            "`#[{}({})]` is not a valid `SessionDiagnostic` struct attribute",
-                            name, nested_name
-                        ),
-                    )
-                    .emit();
-                }
-                syn::Meta::List(..) => {
-                    span_err(
-                        span,
-                        &format!(
-                            "`#[{}({}(...))]` is not a valid `SessionDiagnostic` struct attribute",
-                            name, nested_name
-                        ),
-                    )
-                    .emit();
-                }
-            }
-        }
-
-        Ok(tokens.drain(..).collect())
-    }
-
-    #[must_use]
-    fn set_kind_once(
-        &mut self,
-        kind: SessionDiagnosticKind,
-        span: proc_macro::Span,
-    ) -> Result<(), SessionDiagnosticDeriveError> {
-        match self.kind {
-            None => {
-                self.kind = Some((kind, span));
-                Ok(())
-            }
-            Some((prev_kind, prev_span)) => {
-                let existing = prev_kind.descr();
-                let current = kind.descr();
-
-                let msg = if current == existing {
-                    format!("`{}` specified multiple times", existing)
-                } else {
-                    format!("`{}` specified when `{}` was already specified", current, existing)
-                };
-                throw_span_err!(span, &msg, |diag| diag
-                    .span_note(prev_span, "previously specified here"));
-            }
-        }
-    }
-
-    fn set_code_once(&mut self, code: String, span: proc_macro::Span) -> proc_macro2::TokenStream {
-        match self.code {
-            None => {
-                self.code = Some(span);
-            }
-            Some(prev_span) => {
-                span_err(span, "`code` specified multiple times")
-                    .span_note(prev_span, "previously specified here")
-                    .emit();
-            }
-        }
-
-        let diag = &self.diag;
-        quote! { #diag.code(rustc_errors::DiagnosticId::Error(#code.to_string())); }
-    }
-
-    fn set_slug_once(&mut self, slug: String, span: proc_macro::Span) {
-        match self.slug {
-            None => {
-                self.slug = Some((slug, span));
-            }
-            Some((_, prev_span)) => {
-                span_err(span, "`slug` specified multiple times")
-                    .span_note(prev_span, "previously specified here")
-                    .emit();
-            }
-        }
-    }
-
-    fn generate_field_attr_code(
-        &mut self,
-        attr: &syn::Attribute,
-        info: FieldInfo<'_>,
-    ) -> Result<proc_macro2::TokenStream, SessionDiagnosticDeriveError> {
-        let field_binding = &info.binding.binding;
-        let option_ty = option_inner_ty(&info.ty);
-        let generated_code = self.generate_non_option_field_code(
-            attr,
-            FieldInfo {
-                vis: info.vis,
-                binding: info.binding,
-                ty: option_ty.unwrap_or(&info.ty),
-                span: info.span,
-            },
-        )?;
-
-        if option_ty.is_none() {
-            Ok(quote! { #generated_code })
-        } else {
-            Ok(quote! {
-                if let Some(#field_binding) = #field_binding {
-                    #generated_code
-                }
-            })
-        }
-    }
-
-    fn generate_non_option_field_code(
-        &mut self,
-        attr: &syn::Attribute,
-        info: FieldInfo<'_>,
-    ) -> Result<proc_macro2::TokenStream, SessionDiagnosticDeriveError> {
-        let diag = &self.diag;
-        let span = attr.span().unwrap();
-        let field_binding = &info.binding.binding;
-
-        let name = attr.path.segments.last().unwrap().ident.to_string();
-        let name = name.as_str();
-
-        let meta = attr.parse_meta()?;
-        match meta {
-            syn::Meta::Path(_) => match name {
-                "skip_arg" => {
-                    // Don't need to do anything - by virtue of the attribute existing, the
-                    // `set_arg` call will not be generated.
-                    Ok(quote! {})
-                }
-                "primary_span" => {
-                    self.report_error_if_not_applied_to_span(attr, info)?;
-                    Ok(quote! {
-                        #diag.set_span(*#field_binding);
-                    })
-                }
-                "label" | "note" | "help" => {
-                    self.report_error_if_not_applied_to_span(attr, info)?;
-                    Ok(self.add_subdiagnostic(field_binding, name, name))
-                }
-                other => throw_span_err!(
-                    span,
-                    &format!("`#[{}]` is not a valid `SessionDiagnostic` field attribute", other)
-                ),
-            },
-            syn::Meta::NameValue(syn::MetaNameValue { lit: syn::Lit::Str(s), .. }) => match name {
-                "label" | "note" | "help" => {
-                    self.report_error_if_not_applied_to_span(attr, info)?;
-                    Ok(self.add_subdiagnostic(field_binding, name, &s.value()))
-                }
-                other => throw_span_err!(
-                    span,
-                    &format!(
-                        "`#[{} = ...]` is not a valid `SessionDiagnostic` field attribute",
-                        other
-                    )
-                ),
-            },
-            syn::Meta::NameValue(_) => throw_span_err!(
-                span,
-                &format!("`#[{} = ...]` is not a valid `SessionDiagnostic` field attribute", name),
-                |diag| diag.help("value must be a string")
-            ),
-            syn::Meta::List(syn::MetaList { path, nested, .. }) => {
-                let name = path.segments.last().unwrap().ident.to_string();
-                let name = name.as_ref();
-
-                match name {
-                    "suggestion" | "suggestion_short" | "suggestion_hidden"
-                    | "suggestion_verbose" => (),
-                    other => throw_span_err!(
-                        span,
-                        &format!(
-                            "`#[{}(...)]` is not a valid `SessionDiagnostic` field attribute",
-                            other
-                        )
-                    ),
-                };
-
-                let (span_, applicability) = self.span_and_applicability_of_ty(info)?;
-
-                let mut msg = None;
-                let mut code = None;
-
-                for attr in nested {
-                    let meta = match attr {
-                        syn::NestedMeta::Meta(meta) => meta,
-                        syn::NestedMeta::Lit(_) => throw_span_err!(
-                            span,
-                            &format!(
-                                "`#[{}(\"...\")]` is not a valid `SessionDiagnostic` field attribute",
-                                name
-                            )
-                        ),
-                    };
-
-                    let span = meta.span().unwrap();
-                    let nested_name = meta.path().segments.last().unwrap().ident.to_string();
-                    let nested_name = nested_name.as_str();
-
-                    match meta {
-                        syn::Meta::NameValue(syn::MetaNameValue {
-                            lit: syn::Lit::Str(s), ..
-                        }) => match nested_name {
-                            "message" => {
-                                msg = Some(s.value());
-                            }
-                            "code" => {
-                                let formatted_str = self.build_format(&s.value(), s.span());
-                                code = Some(formatted_str);
-                            }
-                            other => throw_span_err!(
-                                span,
-                                &format!(
-                                    "`#[{}({} = ...)]` is not a valid `SessionDiagnostic` field attribute",
-                                    name, other
-                                )
-                            ),
-                        },
-                        syn::Meta::NameValue(..) => throw_span_err!(
-                            span,
-                            &format!(
-                                "`#[{}({} = ...)]` is not a valid `SessionDiagnostic` struct attribute",
-                                name, nested_name
-                            ),
-                            |diag| diag.help("value must be a string")
-                        ),
-                        syn::Meta::Path(..) => throw_span_err!(
-                            span,
-                            &format!(
-                                "`#[{}({})]` is not a valid `SessionDiagnostic` struct attribute",
-                                name, nested_name
-                            )
-                        ),
-                        syn::Meta::List(..) => throw_span_err!(
-                            span,
-                            &format!(
-                                "`#[{}({}(...))]` is not a valid `SessionDiagnostic` struct attribute",
-                                name, nested_name
-                            )
-                        ),
-                    }
-                }
-
-                let method = format_ident!("span_{}", name);
-
-                let slug = self
-                    .slug
-                    .as_ref()
-                    .map(|(slug, _)| slug.as_str())
-                    .unwrap_or_else(|| "missing-slug");
-                let msg = msg.as_deref().unwrap_or("suggestion");
-                let msg = quote! { rustc_errors::DiagnosticMessage::fluent_attr(#slug, #msg) };
-                let code = code.unwrap_or_else(|| quote! { String::new() });
-
-                Ok(quote! { #diag.#method(#span_, #msg, #code, #applicability); })
-            }
-        }
-    }
-
-    /// Reports an error if the field's type is not `Span`.
-    fn report_error_if_not_applied_to_span(
-        &self,
-        attr: &syn::Attribute,
-        info: FieldInfo<'_>,
-    ) -> Result<(), SessionDiagnosticDeriveError> {
-        if !type_matches_path(&info.ty, &["rustc_span", "Span"]) {
-            let name = attr.path.segments.last().unwrap().ident.to_string();
-            let name = name.as_str();
-            let meta = attr.parse_meta()?;
-
-            throw_span_err!(
-                attr.span().unwrap(),
-                &format!(
-                    "the `#[{}{}]` attribute can only be applied to fields of type `Span`",
-                    name,
-                    match meta {
-                        syn::Meta::Path(_) => "",
-                        syn::Meta::NameValue(_) => " = ...",
-                        syn::Meta::List(_) => "(...)",
-                    }
-                )
-            );
-        }
-
-        Ok(())
-    }
-
-    /// Adds a subdiagnostic by generating a `diag.span_$kind` call with the current slug and
-    /// `fluent_attr_identifier`.
-    fn add_subdiagnostic(
-        &self,
-        field_binding: &proc_macro2::Ident,
-        kind: &str,
-        fluent_attr_identifier: &str,
-    ) -> proc_macro2::TokenStream {
-        let diag = &self.diag;
-
-        let slug =
-            self.slug.as_ref().map(|(slug, _)| slug.as_str()).unwrap_or_else(|| "missing-slug");
-        let fn_name = format_ident!("span_{}", kind);
-        quote! {
-            #diag.#fn_name(
-                *#field_binding,
-                rustc_errors::DiagnosticMessage::fluent_attr(#slug, #fluent_attr_identifier)
-            );
-        }
-    }
-
-    fn span_and_applicability_of_ty(
-        &self,
-        info: FieldInfo<'_>,
-    ) -> Result<(proc_macro2::TokenStream, proc_macro2::TokenStream), SessionDiagnosticDeriveError>
-    {
-        match &info.ty {
-            // If `ty` is `Span` w/out applicability, then use `Applicability::Unspecified`.
-            ty @ syn::Type::Path(..) if type_matches_path(ty, &["rustc_span", "Span"]) => {
-                let binding = &info.binding.binding;
-                Ok((quote!(*#binding), quote!(rustc_errors::Applicability::Unspecified)))
-            }
-            // If `ty` is `(Span, Applicability)` then return tokens accessing those.
-            syn::Type::Tuple(tup) => {
-                let mut span_idx = None;
-                let mut applicability_idx = None;
-
-                for (idx, elem) in tup.elems.iter().enumerate() {
-                    if type_matches_path(elem, &["rustc_span", "Span"]) {
-                        if span_idx.is_none() {
-                            span_idx = Some(syn::Index::from(idx));
-                        } else {
-                            throw_span_err!(
-                                info.span.unwrap(),
-                                "type of field annotated with `#[suggestion(...)]` contains more than one `Span`"
-                            );
-                        }
-                    } else if type_matches_path(elem, &["rustc_errors", "Applicability"]) {
-                        if applicability_idx.is_none() {
-                            applicability_idx = Some(syn::Index::from(idx));
-                        } else {
-                            throw_span_err!(
-                                info.span.unwrap(),
-                                "type of field annotated with `#[suggestion(...)]` contains more than one Applicability"
-                            );
-                        }
-                    }
-                }
-
-                if let Some(span_idx) = span_idx {
-                    let binding = &info.binding.binding;
-                    let span = quote!(#binding.#span_idx);
-                    let applicability = applicability_idx
-                        .map(|applicability_idx| quote!(#binding.#applicability_idx))
-                        .unwrap_or_else(|| quote!(rustc_errors::Applicability::Unspecified));
-
-                    return Ok((span, applicability));
-                }
-
-                throw_span_err!(info.span.unwrap(), "wrong types for suggestion", |diag| {
-                    diag.help("`#[suggestion(...)]` on a tuple field must be applied to fields of type `(Span, Applicability)`")
-                });
-            }
-            // If `ty` isn't a `Span` or `(Span, Applicability)` then emit an error.
-            _ => throw_span_err!(info.span.unwrap(), "wrong field type for suggestion", |diag| {
-                diag.help("`#[suggestion(...)]` should be applied to fields of type `Span` or `(Span, Applicability)`")
-            }),
-        }
-    }
-
-    /// In the strings in the attributes supplied to this macro, we want callers to be able to
-    /// reference fields in the format string. For example:
-    ///
-    /// ```ignore (not-usage-example)
-    /// struct Point {
-    ///     #[error = "Expected a point greater than ({x}, {y})"]
-    ///     x: i32,
-    ///     y: i32,
-    /// }
-    /// ```
-    ///
-    /// We want to automatically pick up that `{x}` refers `self.x` and `{y}` refers to `self.y`,
-    /// then generate this call to `format!`:
-    ///
-    /// ```ignore (not-usage-example)
-    /// format!("Expected a point greater than ({x}, {y})", x = self.x, y = self.y)
-    /// ```
-    ///
-    /// This function builds the entire call to `format!`.
-    fn build_format(&self, input: &str, span: proc_macro2::Span) -> proc_macro2::TokenStream {
-        // This set is used later to generate the final format string. To keep builds reproducible,
-        // the iteration order needs to be deterministic, hence why we use a BTreeSet here instead
-        // of a HashSet.
-        let mut referenced_fields: BTreeSet<String> = BTreeSet::new();
-
-        // At this point, we can start parsing the format string.
-        let mut it = input.chars().peekable();
-        // Once the start of a format string has been found, process the format string and spit out
-        // the referenced fields. Leaves `it` sitting on the closing brace of the format string, so the
-        // next call to `it.next()` retrieves the next character.
-        while let Some(c) = it.next() {
-            if c == '{' && *it.peek().unwrap_or(&'\0') != '{' {
-                let mut eat_argument = || -> Option<String> {
-                    let mut result = String::new();
-                    // Format specifiers look like
-                    // format   := '{' [ argument ] [ ':' format_spec ] '}' .
-                    // Therefore, we only need to eat until ':' or '}' to find the argument.
-                    while let Some(c) = it.next() {
-                        result.push(c);
-                        let next = *it.peek().unwrap_or(&'\0');
-                        if next == '}' {
-                            break;
-                        } else if next == ':' {
-                            // Eat the ':' character.
-                            assert_eq!(it.next().unwrap(), ':');
-                            break;
-                        }
-                    }
-                    // Eat until (and including) the matching '}'
-                    while it.next()? != '}' {
-                        continue;
-                    }
-                    Some(result)
-                };
-
-                if let Some(referenced_field) = eat_argument() {
-                    referenced_fields.insert(referenced_field);
-                }
-            }
-        }
-        // At this point, `referenced_fields` contains a set of the unique fields that were
-        // referenced in the format string. Generate the corresponding "x = self.x" format
-        // string parameters:
-        let args = referenced_fields.into_iter().map(|field: String| {
-            let field_ident = format_ident!("{}", field);
-            let value = if self.fields.contains_key(&field) {
-                quote! {
-                    &self.#field_ident
-                }
-            } else {
-                // This field doesn't exist. Emit a diagnostic.
-                Diagnostic::spanned(
-                    span.unwrap(),
-                    proc_macro::Level::Error,
-                    format!("`{}` doesn't refer to a field on this type", field),
-                )
-                .emit();
-                quote! {
-                    "{#field}"
-                }
-            };
-            quote! {
-                #field_ident = #value
-            }
-        });
-        quote! {
-            format!(#input #(,#args)*)
-        }
-    }
-}
-
-/// If `ty` is an Option, returns `Some(inner type)`, otherwise returns `None`.
-fn option_inner_ty(ty: &syn::Type) -> Option<&syn::Type> {
-    if type_matches_path(ty, &["std", "option", "Option"]) {
-        if let syn::Type::Path(ty_path) = ty {
-            let path = &ty_path.path;
-            let ty = path.segments.iter().last().unwrap();
-            if let syn::PathArguments::AngleBracketed(bracketed) = &ty.arguments {
-                if bracketed.args.len() == 1 {
-                    if let syn::GenericArgument::Type(ty) = &bracketed.args[0] {
-                        return Some(ty);
-                    }
-                }
-            }
-        }
-    }
-    None
-}
index e5d0cd289255206ebc6d72dd7530a090f6058786..3c545e6a0d2404f040c0f405bdc05b265a731f07 100644 (file)
@@ -195,10 +195,12 @@ fn crate_dependencies_in_reverse_postorder(&self, cnum: CrateNum) -> Vec<CrateNu
     }
 
     pub fn report_unused_deps(&self, tcx: TyCtxt<'_>) {
+        let json_unused_externs = tcx.sess.opts.json_unused_externs;
+
         // We put the check for the option before the lint_level_at_node call
         // because the call mutates internal state and introducing it
         // leads to some ui tests failing.
-        if !tcx.sess.opts.json_unused_externs {
+        if !json_unused_externs.is_enabled() {
             return;
         }
         let level = tcx
@@ -208,10 +210,11 @@ pub fn report_unused_deps(&self, tcx: TyCtxt<'_>) {
             let unused_externs =
                 self.unused_externs.iter().map(|ident| ident.to_ident_string()).collect::<Vec<_>>();
             let unused_externs = unused_externs.iter().map(String::as_str).collect::<Vec<&str>>();
-            tcx.sess
-                .parse_sess
-                .span_diagnostic
-                .emit_unused_externs(level.as_str(), &unused_externs);
+            tcx.sess.parse_sess.span_diagnostic.emit_unused_externs(
+                level,
+                json_unused_externs.is_loud(),
+                &unused_externs,
+            );
         }
     }
 }
@@ -907,13 +910,17 @@ fn report_unused_deps(&mut self, krate: &ast::Crate) {
                 // Don't worry about pathless `--extern foo` sysroot references
                 continue;
             }
+            if entry.nounused_dep {
+                // We're not worried about this one
+                continue;
+            }
             let name_interned = Symbol::intern(name);
             if self.used_extern_options.contains(&name_interned) {
                 continue;
             }
 
             // Got a real unused --extern
-            if self.sess.opts.json_unused_externs {
+            if self.sess.opts.json_unused_externs.is_enabled() {
                 self.cstore.unused_externs.push(name_interned);
                 continue;
             }
index 77afa7b4a5cf0a7f1d94b90c17d47046c37caf97..1edb62e189f9768c3b8dbc16b8dfbee25621ccb4 100644 (file)
@@ -22,7 +22,7 @@
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_middle::arena::ArenaAllocatable;
 use rustc_middle::metadata::ModChild;
-use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel};
+use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
 use rustc_middle::middle::stability::DeprecationEntry;
 use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState};
 use rustc_middle::thir;
@@ -1429,7 +1429,7 @@ fn get_missing_lang_items(self, tcx: TyCtxt<'tcx>) -> &'tcx [lang_items::LangIte
     fn exported_symbols(
         self,
         tcx: TyCtxt<'tcx>,
-    ) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportLevel)] {
+    ) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)] {
         tcx.arena.alloc_from_iter(self.root.exported_symbols.decode((self, tcx)))
     }
 
index 6b1f7d55026ad7ed9ec4eb5f591dcffdcf288696..da1dd6af65a5dd72a27ec00a1d00a5324882119f 100644 (file)
@@ -190,9 +190,9 @@ fn into_args(self) -> (DefId, SimplifiedType) {
         let reachable_non_generics = tcx
             .exported_symbols(cdata.cnum)
             .iter()
-            .filter_map(|&(exported_symbol, export_level)| {
+            .filter_map(|&(exported_symbol, export_info)| {
                 if let ExportedSymbol::NonGeneric(def_id) = exported_symbol {
-                    Some((def_id, export_level))
+                    Some((def_id, export_info))
                 } else {
                     None
                 }
@@ -532,6 +532,14 @@ pub fn incoherent_impls_in_crate_untracked(
         self.get_crate_data(cnum).get_all_incoherent_impls()
     }
 
+    pub fn associated_item_def_ids_untracked<'a>(
+        &'a self,
+        def_id: DefId,
+        sess: &'a Session,
+    ) -> impl Iterator<Item = DefId> + 'a {
+        self.get_crate_data(def_id.krate).get_associated_item_def_ids(def_id.index, sess)
+    }
+
     pub fn may_have_doc_links_untracked(&self, def_id: DefId) -> bool {
         self.get_crate_data(def_id.krate).get_may_have_doc_links(def_id.index)
     }
index f485e09913e9d0d054179c1fab53db12167bd4e0..b46ea955a3a82541fd44e6795c6ca88bc67d6dc3 100644 (file)
@@ -22,7 +22,7 @@
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::dependency_format::Linkage;
 use rustc_middle::middle::exported_symbols::{
-    metadata_symbol_name, ExportedSymbol, SymbolExportLevel,
+    metadata_symbol_name, ExportedSymbol, SymbolExportInfo,
 };
 use rustc_middle::mir::interpret;
 use rustc_middle::thir;
@@ -1462,8 +1462,8 @@ fn encode_info_for_item(&mut self, def_id: DefId, item: &'tcx hir::Item<'tcx>) {
                 }))
             }
             hir::ItemKind::Impl(hir::Impl { defaultness, constness, .. }) => {
-                self.tables.impl_defaultness.set(def_id.index, defaultness);
-                self.tables.impl_constness.set(def_id.index, constness);
+                self.tables.impl_defaultness.set(def_id.index, *defaultness);
+                self.tables.impl_constness.set(def_id.index, *constness);
 
                 let trait_ref = self.tcx.impl_trait_ref(def_id);
                 if let Some(trait_ref) = trait_ref {
@@ -1874,8 +1874,8 @@ fn encode_incoherent_impls(&mut self) -> Lazy<[IncoherentImpls]> {
     // definition (as that's not defined in this crate).
     fn encode_exported_symbols(
         &mut self,
-        exported_symbols: &[(ExportedSymbol<'tcx>, SymbolExportLevel)],
-    ) -> Lazy<[(ExportedSymbol<'tcx>, SymbolExportLevel)]> {
+        exported_symbols: &[(ExportedSymbol<'tcx>, SymbolExportInfo)],
+    ) -> Lazy<[(ExportedSymbol<'tcx>, SymbolExportInfo)]> {
         empty_proc_macro!(self);
         // The metadata symbol name is special. It should not show up in
         // downstream crates.
index f1498665ff3853bcf92b7dde96f58a46dce7905a..cdbed90e6b98e8623bf4a2a9e25f7998b64ea2a5 100644 (file)
@@ -14,7 +14,7 @@
 use rustc_hir::lang_items;
 use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec};
 use rustc_middle::metadata::ModChild;
-use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel};
+use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
 use rustc_middle::mir;
 use rustc_middle::thir;
 use rustc_middle::ty::fast_reject::SimplifiedType;
@@ -220,7 +220,7 @@ macro_rules! Lazy {
 
     tables: LazyTables<'tcx>,
 
-    exported_symbols: Lazy!([(ExportedSymbol<'tcx>, SymbolExportLevel)]),
+    exported_symbols: Lazy!([(ExportedSymbol<'tcx>, SymbolExportInfo)]),
 
     syntax_contexts: SyntaxContextTable,
     expn_data: ExpnDataTable,
index d74759e31a2d907514c87232a8ed1344c4b4d75f..85e53559c292403104c4f8f4939f3662ffecd4fd 100644 (file)
@@ -14,7 +14,6 @@
 use rustc_index::vec::Idx;
 use rustc_middle::hir::nested_filter;
 use rustc_span::def_id::StableCrateId;
-use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::Span;
 use rustc_target::spec::abi::Abi;
@@ -304,7 +303,6 @@ pub fn opt_def_kind(self, local_def_id: LocalDefId) -> Option<DefKind> {
             | Node::Param(_)
             | Node::Arm(_)
             | Node::Lifetime(_)
-            | Node::Visibility(_)
             | Node::Block(_) => return None,
         };
         Some(def_kind)
@@ -548,7 +546,7 @@ pub fn ty_param_owner(self, def_id: LocalDefId) -> LocalDefId {
         let def_kind = self.tcx.def_kind(def_id);
         match def_kind {
             DefKind::Trait | DefKind::TraitAlias => def_id,
-            DefKind::TyParam | DefKind::ConstParam => self.tcx.local_parent(def_id).unwrap(),
+            DefKind::TyParam | DefKind::ConstParam => self.tcx.local_parent(def_id),
             _ => bug!("ty_param_owner: {:?} is a {:?} not a type parameter", def_id, def_kind),
         }
     }
@@ -1000,12 +998,7 @@ pub fn opt_span(self, hir_id: HirId) -> Option<Span> {
             },
             Node::Lifetime(lifetime) => lifetime.span,
             Node::GenericParam(param) => param.span,
-            Node::Visibility(&Spanned {
-                node: VisibilityKind::Restricted { ref path, .. },
-                ..
-            }) => path.span,
             Node::Infer(i) => i.span,
-            Node::Visibility(v) => bug!("unexpected Visibility {:?}", v),
             Node::Local(local) => local.span,
             Node::Crate(item) => item.spans.inner_span,
         };
@@ -1128,6 +1121,10 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Svh {
     }
     tcx.sess.opts.dep_tracking_hash(true).hash_stable(&mut hcx, &mut stable_hasher);
     tcx.sess.local_stable_crate_id().hash_stable(&mut hcx, &mut stable_hasher);
+    // Hash visibility information since it does not appear in HIR.
+    let resolutions = tcx.resolutions(());
+    resolutions.visibilities.hash_stable(&mut hcx, &mut stable_hasher);
+    resolutions.has_pub_restricted.hash_stable(&mut hcx, &mut stable_hasher);
 
     let crate_hash: Fingerprint = stable_hasher.finish();
     Svh::new(crate_hash.to_smaller_hash())
@@ -1232,7 +1229,6 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String {
         Some(Node::Ctor(..)) => format!("ctor {}{}", path_str(), id_str),
         Some(Node::Lifetime(_)) => node_str("lifetime"),
         Some(Node::GenericParam(ref param)) => format!("generic_param {:?}{}", param, id_str),
-        Some(Node::Visibility(ref vis)) => format!("visibility {:?}{}", vis, id_str),
         Some(Node::Crate(..)) => String::from("root_crate"),
         None => format!("unknown node{}", id_str),
     }
index 5ea78e087f8451c34d6503dc45060f4f93bdfc46..631fd09ec4cf6e10916ec9a5a589bee48ebf046b 100644 (file)
@@ -21,6 +21,23 @@ pub fn is_below_threshold(self, threshold: SymbolExportLevel) -> bool {
     }
 }
 
+/// Kind of exported symbols.
+#[derive(Eq, PartialEq, Debug, Copy, Clone, Encodable, Decodable, HashStable)]
+pub enum SymbolExportKind {
+    Text,
+    Data,
+    Tls,
+}
+
+/// The `SymbolExportInfo` of a symbols specifies symbol-related information
+/// that is relevant to code generation and linking.
+#[derive(Eq, PartialEq, Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)]
+pub struct SymbolExportInfo {
+    pub level: SymbolExportLevel,
+    pub kind: SymbolExportKind,
+    pub used: bool,
+}
+
 #[derive(Eq, PartialEq, Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)]
 pub enum ExportedSymbol<'tcx> {
     NonGeneric(DefId),
index 758658c3d8c941c8f07081001c9493590f28b955..32041143240aa4022af8be480f30f016f0a61a5a 100644 (file)
@@ -289,7 +289,7 @@ fn suggestion_for_allocator_api(
     feature: Symbol,
 ) -> Option<(Span, String, String, Applicability)> {
     if feature == sym::allocator_api {
-        if let Some(trait_) = tcx.parent(def_id) {
+        if let Some(trait_) = tcx.opt_parent(def_id) {
             if tcx.is_diagnostic_item(sym::Vec, trait_) {
                 let sm = tcx.sess.parse_sess.source_map();
                 let inner_types = sm.span_extend_to_prev_char(span, '<', true);
index c628406064fb63e4703bf503d75519a680c07534..8cfc5ed0a95d06147ceab0adbbb5a6bf0670bad2 100644 (file)
@@ -418,6 +418,7 @@ pub fn read_scalar(
     ///
     /// It is the caller's responsibility to check bounds and alignment beforehand.
     /// Most likely, you want to call `InterpCx::write_scalar` instead of this method.
+    #[instrument(skip(self, cx), level = "debug")]
     pub fn write_scalar(
         &mut self,
         cx: &impl HasDataLayout,
index 4f4b6cf704fa9d75e147c0a5462ef21dcfcab541..188ca8048055cae9cf1085b42cbe6e4081b40478 100644 (file)
@@ -62,7 +62,9 @@
 mod switch_sources;
 pub mod tcx;
 pub mod terminator;
+use crate::mir::traversal::PostorderCache;
 pub use terminator::*;
+
 pub mod traversal;
 mod type_foldable;
 pub mod visit;
@@ -166,7 +168,8 @@ pub enum MirPhase {
     /// * [`StatementKind::Retag`]
     ///
     /// Furthermore, `Drop` now uses explicit drop flags visible in the MIR and reaching a `Drop`
-    /// terminator means that the auto-generated drop glue will be invoked.
+    /// terminator means that the auto-generated drop glue will be invoked. Also, `Copy` operands
+    /// are allowed for non-`Copy` types.
     DropsLowered = 3,
     /// Beginning with this phase, the following variant is disallowed:
     /// * [`Rvalue::Aggregate`] for any `AggregateKind` except `Array`
@@ -322,6 +325,7 @@ pub struct Body<'tcx> {
     predecessor_cache: PredecessorCache,
     switch_source_cache: SwitchSourceCache,
     is_cyclic: GraphIsCyclicCache,
+    postorder_cache: PostorderCache,
 
     pub tainted_by_errors: Option<ErrorGuaranteed>,
 }
@@ -371,6 +375,7 @@ pub fn new(
             predecessor_cache: PredecessorCache::new(),
             switch_source_cache: SwitchSourceCache::new(),
             is_cyclic: GraphIsCyclicCache::new(),
+            postorder_cache: PostorderCache::new(),
             tainted_by_errors,
         };
         body.is_polymorphic = body.has_param_types_or_consts();
@@ -400,6 +405,7 @@ pub fn new_cfg_only(basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>) ->
             predecessor_cache: PredecessorCache::new(),
             switch_source_cache: SwitchSourceCache::new(),
             is_cyclic: GraphIsCyclicCache::new(),
+            postorder_cache: PostorderCache::new(),
             tainted_by_errors: None,
         };
         body.is_polymorphic = body.has_param_types_or_consts();
@@ -421,6 +427,7 @@ pub fn basic_blocks_mut(&mut self) -> &mut IndexVec<BasicBlock, BasicBlockData<'
         self.predecessor_cache.invalidate();
         self.switch_source_cache.invalidate();
         self.is_cyclic.invalidate();
+        self.postorder_cache.invalidate();
         &mut self.basic_blocks
     }
 
@@ -431,6 +438,7 @@ pub fn basic_blocks_and_local_decls_mut(
         self.predecessor_cache.invalidate();
         self.switch_source_cache.invalidate();
         self.is_cyclic.invalidate();
+        self.postorder_cache.invalidate();
         (&mut self.basic_blocks, &mut self.local_decls)
     }
 
@@ -445,6 +453,7 @@ pub fn basic_blocks_local_decls_mut_and_var_debug_info(
         self.predecessor_cache.invalidate();
         self.switch_source_cache.invalidate();
         self.is_cyclic.invalidate();
+        self.postorder_cache.invalidate();
         (&mut self.basic_blocks, &mut self.local_decls, &mut self.var_debug_info)
     }
 
@@ -1078,6 +1087,8 @@ pub enum LocalInfo<'tcx> {
     /// A temporary created during the creation of an aggregate
     /// (e.g. a temporary for `foo` in `MyStruct { my_field: foo }`)
     AggregateTemp,
+    /// A temporary created during the pass `Derefer` to avoid it's retagging
+    DerefTemp,
 }
 
 impl<'tcx> LocalDecl<'tcx> {
@@ -2330,7 +2341,10 @@ pub struct SourceScopeLocalData {
 /// validator.
 #[derive(Clone, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]
 pub enum Operand<'tcx> {
-    /// Creates a value by loading the given place. The type of the place must be `Copy`
+    /// Creates a value by loading the given place.
+    ///
+    /// Before drop elaboration, the type of the place must be `Copy`. After drop elaboration there
+    /// is no such requirement.
     Copy(Place<'tcx>),
 
     /// Creates a value by performing loading the place, just like the `Copy` operand.
@@ -2547,16 +2561,12 @@ pub enum Rvalue<'tcx> {
     UnaryOp(UnOp, Operand<'tcx>),
 
     /// Computes the discriminant of the place, returning it as an integer of type
-    /// [`discriminant_ty`].
+    /// [`discriminant_ty`]. Returns zero for types without discriminant.
     ///
     /// The validity requirements for the underlying value are undecided for this rvalue, see
     /// [#91095]. Note too that the value of the discriminant is not the same thing as the
     /// variant index; use [`discriminant_for_variant`] to convert.
     ///
-    /// For types defined in the source code as enums, this is well behaved. This is also well
-    /// formed for other types, but yields no particular value - there is no reason it couldn't be
-    /// defined to yield eg zero though.
-    ///
     /// [`discriminant_ty`]: crate::ty::Ty::discriminant_ty
     /// [#91095]: https://github.com/rust-lang/rust/issues/91095
     /// [`discriminant_for_variant`]: crate::ty::Ty::discriminant_for_variant
@@ -2577,8 +2587,6 @@ pub enum Rvalue<'tcx> {
     /// This is different from a normal transmute because dataflow analysis will treat the box as
     /// initialized but its content as uninitialized. Like other pointer casts, this in general
     /// affects alias analysis.
-    ///
-    /// Disallowed after drop elaboration.
     ShallowInitBox(Operand<'tcx>, Ty<'tcx>),
 }
 
index 1f571a36441be101cd22eed473dd2bac343e488f..d03f9235efd587e621d95e8a1ca09565e8f22585 100644 (file)
@@ -78,13 +78,24 @@ pub fn terminator_loc(&self, body: &Body<'tcx>, bb: BasicBlock) -> Location {
         Location { block: bb, statement_index: offset }
     }
 
-    pub fn new_temp(&mut self, ty: Ty<'tcx>, span: Span) -> Local {
+    pub fn new_local_with_info(
+        &mut self,
+        ty: Ty<'tcx>,
+        span: Span,
+        local_info: Option<Box<LocalInfo<'tcx>>>,
+    ) -> Local {
         let index = self.next_local;
         self.next_local += 1;
-        self.new_locals.push(LocalDecl::new(ty, span));
+        let mut new_decl = LocalDecl::new(ty, span);
+        new_decl.local_info = local_info;
+        self.new_locals.push(new_decl);
         Local::new(index as usize)
     }
 
+    pub fn new_temp(&mut self, ty: Ty<'tcx>, span: Span) -> Local {
+        self.new_local_with_info(ty, span, None)
+    }
+
     pub fn new_internal(&mut self, ty: Ty<'tcx>, span: Span) -> Local {
         let index = self.next_local;
         self.next_local += 1;
@@ -141,6 +152,7 @@ pub fn apply(self, body: &mut Body<'tcx>) {
 
         let mut delta = 0;
         let mut last_bb = START_BLOCK;
+        let mut stmts_and_targets: Vec<(Statement<'_>, BasicBlock)> = Vec::new();
         for (mut loc, stmt) in new_statements {
             if loc.block != last_bb {
                 delta = 0;
@@ -149,11 +161,30 @@ pub fn apply(self, body: &mut Body<'tcx>) {
             debug!("MirPatch: adding statement {:?} at loc {:?}+{}", stmt, loc, delta);
             loc.statement_index += delta;
             let source_info = Self::source_info_for_index(&body[loc.block], loc);
+
+            // For mir-opt `Derefer` to work in all cases we need to
+            // get terminator's targets and apply the statement to all of them.
+            if loc.statement_index > body[loc.block].statements.len() {
+                let term = body[loc.block].terminator();
+                let successors = term.successors().clone();
+
+                for i in successors {
+                    stmts_and_targets
+                        .push((Statement { source_info, kind: stmt.clone() }, i.clone()));
+                }
+                delta += 1;
+                continue;
+            }
+
             body[loc.block]
                 .statements
                 .insert(loc.statement_index, Statement { source_info, kind: stmt });
             delta += 1;
         }
+
+        for (stmt, target) in stmts_and_targets.into_iter().rev() {
+            body[target].statements.insert(0, stmt);
+        }
     }
 
     pub fn source_info_for_index(data: &BasicBlockData<'_>, loc: Location) -> SourceInfo {
index d08bede1d733447900eece1c22e6952a98f13d57..8d831cc73b8a40409d5cb8b0deb3caa85c342e78 100644 (file)
@@ -1,4 +1,7 @@
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::sync::OnceCell;
 use rustc_index::bit_set::BitSet;
+use rustc_serialize as serialize;
 
 use super::*;
 
@@ -268,10 +271,6 @@ pub fn new(body: &'a Body<'tcx>, root: BasicBlock) -> ReversePostorder<'a, 'tcx>
     }
 }
 
-pub fn reverse_postorder<'a, 'tcx>(body: &'a Body<'tcx>) -> ReversePostorder<'a, 'tcx> {
-    ReversePostorder::new(body, START_BLOCK)
-}
-
 impl<'a, 'tcx> Iterator for ReversePostorder<'a, 'tcx> {
     type Item = (BasicBlock, &'a BasicBlockData<'tcx>);
 
@@ -307,3 +306,86 @@ pub fn reachable_as_bitset<'tcx>(body: &Body<'tcx>) -> BitSet<BasicBlock> {
     (&mut iter).for_each(drop);
     iter.visited
 }
+
+#[derive(Clone)]
+pub struct ReversePostorderIter<'a, 'tcx> {
+    body: &'a Body<'tcx>,
+    blocks: &'a Vec<BasicBlock>,
+    idx: usize,
+}
+
+impl<'a, 'tcx> Iterator for ReversePostorderIter<'a, 'tcx> {
+    type Item = (BasicBlock, &'a BasicBlockData<'tcx>);
+
+    fn next(&mut self) -> Option<(BasicBlock, &'a BasicBlockData<'tcx>)> {
+        if self.idx == 0 {
+            return None;
+        }
+        self.idx -= 1;
+
+        self.blocks.get(self.idx).map(|&bb| (bb, &self.body[bb]))
+    }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        (self.idx, Some(self.idx))
+    }
+}
+
+impl<'a, 'tcx> ExactSizeIterator for ReversePostorderIter<'a, 'tcx> {}
+
+pub fn reverse_postorder<'a, 'tcx>(body: &'a Body<'tcx>) -> ReversePostorderIter<'a, 'tcx> {
+    let blocks = body.postorder_cache.compute(body);
+
+    let len = blocks.len();
+
+    ReversePostorderIter { body, blocks, idx: len }
+}
+
+#[derive(Clone, Debug)]
+pub(super) struct PostorderCache {
+    cache: OnceCell<Vec<BasicBlock>>,
+}
+
+impl PostorderCache {
+    #[inline]
+    pub(super) fn new() -> Self {
+        PostorderCache { cache: OnceCell::new() }
+    }
+
+    /// Invalidates the postorder cache.
+    #[inline]
+    pub(super) fn invalidate(&mut self) {
+        self.cache = OnceCell::new();
+    }
+
+    /// Returns the &Vec<BasicBlocks> represents the postorder graph for this MIR.
+    #[inline]
+    pub(super) fn compute(&self, body: &Body<'_>) -> &Vec<BasicBlock> {
+        self.cache.get_or_init(|| Postorder::new(body, START_BLOCK).map(|(bb, _)| bb).collect())
+    }
+}
+
+impl<S: serialize::Encoder> serialize::Encodable<S> for PostorderCache {
+    #[inline]
+    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
+        s.emit_unit()
+    }
+}
+
+impl<D: serialize::Decoder> serialize::Decodable<D> for PostorderCache {
+    #[inline]
+    fn decode(_: &mut D) -> Self {
+        Self::new()
+    }
+}
+
+impl<CTX> HashStable<CTX> for PostorderCache {
+    #[inline]
+    fn hash_stable(&self, _: &mut CTX, _: &mut StableHasher) {
+        // do nothing
+    }
+}
+
+TrivialTypeFoldableAndLiftImpls! {
+    PostorderCache,
+}
index 78a3383243306b42187e2cf48fab7dea0867e254..cc80ab8f16e9c9f7ff007f930c349948eca3a50e 100644 (file)
         remap_env_constness
     }
 
+    /// Converts a type level constant value into `ConstValue`
+    query valtree_to_const_val(key: (Ty<'tcx>, ty::ValTree<'tcx>)) -> ConstValue<'tcx> {
+        desc { "convert type-level constant value to mir constant value"}
+    }
+
     /// Destructure a constant ADT or array into its variant index and its
     /// field values or return `None` if constant is invalid.
     ///
     // Does not include external symbols that don't have a corresponding DefId,
     // like the compiler-generated `main` function and so on.
     query reachable_non_generics(_: CrateNum)
-        -> DefIdMap<SymbolExportLevel> {
+        -> DefIdMap<SymbolExportInfo> {
         storage(ArenaCacheSelector<'tcx>)
         desc { "looking up the exported symbols of a crate" }
         separate_provide_extern
     ///   correspond to a publicly visible symbol in `cnum` machine code.
     /// - The `exported_symbols` sets of different crates do not intersect.
     query exported_symbols(_: CrateNum)
-        -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportLevel)] {
+        -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)] {
         desc { "exported_symbols" }
         separate_provide_extern
     }
index e56efb8d497269439f00cd4611aae5654ae26500..fdf5ecfdaf7ef25f599a228886b759f19d11f918 100644 (file)
@@ -66,7 +66,7 @@ macro_rules! thir_with_elements {
         /// A container for a THIR body.
         ///
         /// This can be indexed directly by any THIR index (e.g. [`ExprId`]).
-        #[derive(Debug, HashStable)]
+        #[derive(Debug, HashStable, Clone)]
         pub struct Thir<'tcx> {
             $(
                 pub $name: IndexVec<$id, $value>,
@@ -106,7 +106,7 @@ pub enum LintLevel {
     Explicit(hir::HirId),
 }
 
-#[derive(Debug, HashStable)]
+#[derive(Clone, Debug, HashStable)]
 pub struct Block {
     /// Whether the block itself has a label. Used by `label: {}`
     /// and `try` blocks.
@@ -125,7 +125,7 @@ pub struct Block {
     pub safety_mode: BlockSafety,
 }
 
-#[derive(Debug, HashStable)]
+#[derive(Clone, Debug, HashStable)]
 pub struct Adt<'tcx> {
     /// The ADT we're constructing.
     pub adt_def: AdtDef<'tcx>,
@@ -151,13 +151,13 @@ pub enum BlockSafety {
     ExplicitUnsafe(hir::HirId),
 }
 
-#[derive(Debug, HashStable)]
+#[derive(Clone, Debug, HashStable)]
 pub struct Stmt<'tcx> {
     pub kind: StmtKind<'tcx>,
     pub opt_destruction_scope: Option<region::Scope>,
 }
 
-#[derive(Debug, HashStable)]
+#[derive(Clone, Debug, HashStable)]
 pub enum StmtKind<'tcx> {
     /// An expression with a trailing semicolon.
     Expr {
@@ -196,7 +196,7 @@ pub enum StmtKind<'tcx> {
 rustc_data_structures::static_assert_size!(Expr<'_>, 104);
 
 /// A THIR expression.
-#[derive(Debug, HashStable)]
+#[derive(Clone, Debug, HashStable)]
 pub struct Expr<'tcx> {
     /// The type of this expression
     pub ty: Ty<'tcx>,
@@ -212,7 +212,7 @@ pub struct Expr<'tcx> {
     pub kind: ExprKind<'tcx>,
 }
 
-#[derive(Debug, HashStable)]
+#[derive(Clone, Debug, HashStable)]
 pub enum ExprKind<'tcx> {
     /// `Scope`s are used to explicitly mark destruction scopes,
     /// and to track the `HirId` of the expressions within the scope.
@@ -461,20 +461,20 @@ pub fn zero_sized_literal(user_ty: Option<Canonical<'tcx, UserType<'tcx>>>) -> S
 /// Represents the association of a field identifier and an expression.
 ///
 /// This is used in struct constructors.
-#[derive(Debug, HashStable)]
+#[derive(Clone, Debug, HashStable)]
 pub struct FieldExpr {
     pub name: Field,
     pub expr: ExprId,
 }
 
-#[derive(Debug, HashStable)]
+#[derive(Clone, Debug, HashStable)]
 pub struct FruInfo<'tcx> {
     pub base: ExprId,
     pub field_types: Box<[Ty<'tcx>]>,
 }
 
 /// A `match` arm.
-#[derive(Debug, HashStable)]
+#[derive(Clone, Debug, HashStable)]
 pub struct Arm<'tcx> {
     pub pattern: Pat<'tcx>,
     pub guard: Option<Guard<'tcx>>,
@@ -485,7 +485,7 @@ pub struct Arm<'tcx> {
 }
 
 /// A `match` guard.
-#[derive(Debug, HashStable)]
+#[derive(Clone, Debug, HashStable)]
 pub enum Guard<'tcx> {
     If(ExprId),
     IfLet(Pat<'tcx>, ExprId),
@@ -499,7 +499,7 @@ pub enum LogicalOp {
     Or,
 }
 
-#[derive(Debug, HashStable)]
+#[derive(Clone, Debug, HashStable)]
 pub enum InlineAsmOperand<'tcx> {
     In {
         reg: InlineAsmRegOrRegClass,
index 7fcc46cc7c206fd0b7d103bbbbb62d91d74412fb..23c377651cc6c8f1595e4f329052e8411eeb60a1 100644 (file)
@@ -453,9 +453,6 @@ fn decode(decoder: &mut D) -> &'tcx Self {
             }
         }
     };
-    ([$ignore:ident $(, $attrs:ident)*]$args:tt) => {
-        impl_arena_allocatable_decoder!([$($attrs),*]$args);
-    };
 }
 
 macro_rules! impl_arena_allocatable_decoders {
index 72623ba54eeb46f97170e7d58c3202c9704d0d80..a3ce674c115241614060f95d118b14f6b313362e 100644 (file)
@@ -237,6 +237,98 @@ pub fn to_bits(self, target_size: Size) -> Result<u128, Size> {
     pub fn try_to_machine_usize<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Result<u64, Size> {
         Ok(self.to_bits(tcx.data_layout.pointer_size)? as u64)
     }
+
+    /// Tries to convert the `ScalarInt` to an unsigned integer of the given size.
+    /// Fails if the size of the `ScalarInt` is unequal to `size` and returns the
+    /// `ScalarInt`s size in that case.
+    #[inline]
+    pub fn try_to_uint(self, size: Size) -> Result<u128, Size> {
+        self.to_bits(size)
+    }
+
+    // Tries to convert the `ScalarInt` to `u8`. Fails if the `size` of the `ScalarInt`
+    // in not equal to `Size { raw: 1 }` and returns the `size` value of the `ScalarInt` in
+    // that case.
+    #[inline]
+    pub fn try_to_u8(self) -> Result<u8, Size> {
+        self.to_bits(Size::from_bits(8)).map(|v| u8::try_from(v).unwrap())
+    }
+
+    /// Tries to convert the `ScalarInt` to `u16`. Fails if the size of the `ScalarInt`
+    /// in not equal to `Size { raw: 2 }` and returns the `size` value of the `ScalarInt` in
+    /// that case.
+    #[inline]
+    pub fn try_to_u16(self) -> Result<u16, Size> {
+        self.to_bits(Size::from_bits(16)).map(|v| u16::try_from(v).unwrap())
+    }
+
+    /// Tries to convert the `ScalarInt` to `u32`. Fails if the `size` of the `ScalarInt`
+    /// in not equal to `Size { raw: 4 }` and returns the `size` value of the `ScalarInt` in
+    /// that case.
+    #[inline]
+    pub fn try_to_u32(self) -> Result<u32, Size> {
+        self.to_bits(Size::from_bits(32)).map(|v| u32::try_from(v).unwrap())
+    }
+
+    /// Tries to convert the `ScalarInt` to `u64`. Fails if the `size` of the `ScalarInt`
+    /// in not equal to `Size { raw: 8 }` and returns the `size` value of the `ScalarInt` in
+    /// that case.
+    #[inline]
+    pub fn try_to_u64(self) -> Result<u64, Size> {
+        self.to_bits(Size::from_bits(64)).map(|v| u64::try_from(v).unwrap())
+    }
+
+    /// Tries to convert the `ScalarInt` to `u128`. Fails if the `size` of the `ScalarInt`
+    /// in not equal to `Size { raw: 16 }` and returns the `size` value of the `ScalarInt` in
+    /// that case.
+    #[inline]
+    pub fn try_to_u128(self) -> Result<u128, Size> {
+        self.to_bits(Size::from_bits(128))
+    }
+
+    /// Tries to convert the `ScalarInt` to a signed integer of the given size.
+    /// Fails if the size of the `ScalarInt` is unequal to `size` and returns the
+    /// `ScalarInt`s size in that case.
+    #[inline]
+    pub fn try_to_int(self, size: Size) -> Result<i128, Size> {
+        let b = self.to_bits(size)?;
+        Ok(size.sign_extend(b) as i128)
+    }
+
+    /// Tries to convert the `ScalarInt` to i8.
+    /// Fails if the size of the `ScalarInt` is unequal to `Size { raw: 1 }`
+    /// and returns the `ScalarInt`s size in that case.
+    pub fn try_to_i8(self) -> Result<i8, Size> {
+        self.try_to_int(Size::from_bits(8)).map(|v| i8::try_from(v).unwrap())
+    }
+
+    /// Tries to convert the `ScalarInt` to i16.
+    /// Fails if the size of the `ScalarInt` is unequal to `Size { raw: 2 }`
+    /// and returns the `ScalarInt`s size in that case.
+    pub fn try_to_i16(self) -> Result<i16, Size> {
+        self.try_to_int(Size::from_bits(16)).map(|v| i16::try_from(v).unwrap())
+    }
+
+    /// Tries to convert the `ScalarInt` to i32.
+    /// Fails if the size of the `ScalarInt` is unequal to `Size { raw: 4 }`
+    /// and returns the `ScalarInt`s size in that case.
+    pub fn try_to_i32(self) -> Result<i32, Size> {
+        self.try_to_int(Size::from_bits(32)).map(|v| i32::try_from(v).unwrap())
+    }
+
+    /// Tries to convert the `ScalarInt` to i64.
+    /// Fails if the size of the `ScalarInt` is unequal to `Size { raw: 8 }`
+    /// and returns the `ScalarInt`s size in that case.
+    pub fn try_to_i64(self) -> Result<i64, Size> {
+        self.try_to_int(Size::from_bits(64)).map(|v| i64::try_from(v).unwrap())
+    }
+
+    /// Tries to convert the `ScalarInt` to i128.
+    /// Fails if the size of the `ScalarInt` is unequal to `Size { raw: 16 }`
+    /// and returns the `ScalarInt`s size in that case.
+    pub fn try_to_i128(self) -> Result<i128, Size> {
+        self.try_to_int(Size::from_bits(128)).map(|v| i128::try_from(v).unwrap())
+    }
 }
 
 macro_rules! from {
index 195760c059081bf607e54c26a33dfec44e4dbb77..418848f69d726bc731fe1cfc56c917fc29353206 100644 (file)
@@ -20,6 +20,9 @@ pub enum ValTree<'tcx> {
     /// See the `ScalarInt` documentation for how `ScalarInt` guarantees that equal values
     /// of these types have the same representation.
     Leaf(ScalarInt),
+
+    //SliceOrStr(ValSlice<'tcx>),
+    // dont use SliceOrStr for now
     /// The fields of any kind of aggregate. Structs, tuples and arrays are represented by
     /// listing their fields' values in order.
     /// Enums are represented by storing their discriminant as a field, followed by all
@@ -31,4 +34,20 @@ impl<'tcx> ValTree<'tcx> {
     pub fn zst() -> Self {
         Self::Branch(&[])
     }
+
+    #[inline]
+    pub fn unwrap_leaf(self) -> ScalarInt {
+        match self {
+            Self::Leaf(s) => s,
+            _ => bug!("expected leaf, got {:?}", self),
+        }
+    }
+
+    #[inline]
+    pub fn unwrap_branch(self) -> &'tcx [Self] {
+        match self {
+            Self::Branch(branch) => branch,
+            _ => bug!("expected branch, got {:?}", self),
+        }
+    }
 }
index 30fe3ffa7e3c46c0b438269ebf430942b85397c8..f9ef264f68ebab9487af9632ce7e1a726c78eb46 100644 (file)
@@ -1491,7 +1491,7 @@ pub fn is_suitable_region(self, region: Region<'tcx>) -> Option<FreeRegionInfo>
                 (free_region.scope.expect_local(), free_region.bound_region)
             }
             ty::ReEarlyBound(ref ebr) => (
-                self.parent(ebr.def_id).unwrap().expect_local(),
+                self.local_parent(ebr.def_id.expect_local()),
                 ty::BoundRegionKind::BrNamed(ebr.def_id, ebr.name),
             ),
             _ => return None, // not a free region
index 3b044b19259d0b2000dad7c3abc5387c3b1cb3e9..a6717746979197808da71d385777fb8bb372fbf2 100644 (file)
@@ -3,15 +3,15 @@
 use crate::ty::subst::{GenericArg, GenericArgKind};
 use crate::ty::TyKind::*;
 use crate::ty::{
-    ConstKind, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, InferTy,
-    ProjectionTy, Term, Ty, TyCtxt, TypeAndMut,
+    ConstKind, DefIdTree, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef,
+    InferTy, ProjectionTy, Term, Ty, TyCtxt, TypeAndMut,
 };
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{Applicability, Diagnostic, DiagnosticArgValue, IntoDiagnosticArg};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
-use rustc_hir::{QPath, TyKind, WhereBoundPredicate, WherePredicate};
+use rustc_hir::WherePredicate;
 use rustc_span::Span;
 
 impl<'tcx> IntoDiagnosticArg for Ty<'tcx> {
@@ -74,10 +74,10 @@ pub fn is_simple_text(self) -> bool {
     }
 
     /// Whether the type can be safely suggested during error recovery.
-    pub fn is_suggestable(self) -> bool {
-        fn generic_arg_is_suggestible(arg: GenericArg<'_>) -> bool {
+    pub fn is_suggestable(self, tcx: TyCtxt<'tcx>) -> bool {
+        fn generic_arg_is_suggestible<'tcx>(arg: GenericArg<'tcx>, tcx: TyCtxt<'tcx>) -> bool {
             match arg.unpack() {
-                GenericArgKind::Type(ty) => ty.is_suggestable(),
+                GenericArgKind::Type(ty) => ty.is_suggestable(tcx),
                 GenericArgKind::Const(c) => const_is_suggestable(c.val()),
                 _ => true,
             }
@@ -99,8 +99,7 @@ fn const_is_suggestable(kind: ConstKind<'_>) -> bool {
         // temporary, so I'll leave this as a fixme.
 
         match self.kind() {
-            Opaque(..)
-            | FnDef(..)
+            FnDef(..)
             | Closure(..)
             | Infer(..)
             | Generator(..)
@@ -108,27 +107,38 @@ fn const_is_suggestable(kind: ConstKind<'_>) -> bool {
             | Bound(_, _)
             | Placeholder(_)
             | Error(_) => false,
+            Opaque(did, substs) => {
+                let parent = tcx.parent(*did);
+                if let hir::def::DefKind::TyAlias | hir::def::DefKind::AssocTy = tcx.def_kind(parent)
+                    && let Opaque(parent_did, _) = tcx.type_of(parent).kind()
+                    && parent_did == did
+                {
+                    substs.iter().all(|a| generic_arg_is_suggestible(a, tcx))
+                } else {
+                    false
+                }
+            }
             Dynamic(dty, _) => dty.iter().all(|pred| match pred.skip_binder() {
                 ExistentialPredicate::Trait(ExistentialTraitRef { substs, .. }) => {
-                    substs.iter().all(generic_arg_is_suggestible)
+                    substs.iter().all(|a| generic_arg_is_suggestible(a, tcx))
                 }
                 ExistentialPredicate::Projection(ExistentialProjection {
                     substs, term, ..
                 }) => {
                     let term_is_suggestable = match term {
-                        Term::Ty(ty) => ty.is_suggestable(),
+                        Term::Ty(ty) => ty.is_suggestable(tcx),
                         Term::Const(c) => const_is_suggestable(c.val()),
                     };
-                    term_is_suggestable && substs.iter().all(generic_arg_is_suggestible)
+                    term_is_suggestable && substs.iter().all(|a| generic_arg_is_suggestible(a, tcx))
                 }
                 _ => true,
             }),
             Projection(ProjectionTy { substs: args, .. }) | Adt(_, args) => {
-                args.iter().all(generic_arg_is_suggestible)
+                args.iter().all(|a| generic_arg_is_suggestible(a, tcx))
             }
-            Tuple(args) => args.iter().all(|ty| ty.is_suggestable()),
-            Slice(ty) | RawPtr(TypeAndMut { ty, .. }) | Ref(_, ty, _) => ty.is_suggestable(),
-            Array(ty, c) => ty.is_suggestable() && const_is_suggestable(c.val()),
+            Tuple(args) => args.iter().all(|ty| ty.is_suggestable(tcx)),
+            Slice(ty) | RawPtr(TypeAndMut { ty, .. }) | Ref(_, ty, _) => ty.is_suggestable(tcx),
+            Array(ty, c) => ty.is_suggestable(tcx) && const_is_suggestable(c.val()),
             _ => true,
         }
     }
@@ -146,13 +156,13 @@ pub fn suggest_arbitrary_trait_bound(
         _ => {}
     }
     // Suggest a where clause bound for a non-type parameter.
-    let (action, prefix) = if generics.where_clause.predicates.is_empty() {
-        ("introducing a", " where ")
-    } else {
+    let (action, prefix) = if generics.has_where_clause {
         ("extending the", ", ")
+    } else {
+        ("introducing a", " where ")
     };
     err.span_suggestion_verbose(
-        generics.where_clause.tail_span_for_suggestion(),
+        generics.tail_span_for_predicate_suggestion(),
         &format!(
             "consider {} `where` bound, but there might be an alternative better way to express \
              this requirement",
@@ -173,104 +183,37 @@ enum SuggestChangingConstraintsMessage<'a> {
 }
 
 fn suggest_removing_unsized_bound(
+    tcx: TyCtxt<'_>,
     generics: &hir::Generics<'_>,
     suggestions: &mut Vec<(Span, String, SuggestChangingConstraintsMessage<'_>)>,
-    param_name: &str,
     param: &hir::GenericParam<'_>,
     def_id: Option<DefId>,
 ) {
     // See if there's a `?Sized` bound that can be removed to suggest that.
     // First look at the `where` clause because we can have `where T: ?Sized`,
     // then look at params.
-    for (where_pos, predicate) in generics.where_clause.predicates.iter().enumerate() {
-        match predicate {
-            WherePredicate::BoundPredicate(WhereBoundPredicate {
-                bounded_ty:
-                    hir::Ty {
-                        kind:
-                            hir::TyKind::Path(hir::QPath::Resolved(
-                                None,
-                                hir::Path {
-                                    segments: [segment],
-                                    res: hir::def::Res::Def(hir::def::DefKind::TyParam, _),
-                                    ..
-                                },
-                            )),
-                        ..
-                    },
-                bounds,
-                span,
-                ..
-            }) if segment.ident.as_str() == param_name => {
-                for (pos, bound) in bounds.iter().enumerate() {
-                    match bound {
-                        hir::GenericBound::Trait(poly, hir::TraitBoundModifier::Maybe)
-                            if poly.trait_ref.trait_def_id() == def_id => {}
-                        _ => continue,
-                    }
-                    let sp = match (
-                        bounds.len(),
-                        pos,
-                        generics.where_clause.predicates.len(),
-                        where_pos,
-                    ) {
-                        // where T: ?Sized
-                        // ^^^^^^^^^^^^^^^
-                        (1, _, 1, _) => generics.where_clause.span,
-                        // where Foo: Bar, T: ?Sized,
-                        //               ^^^^^^^^^^^
-                        (1, _, len, pos) if pos == len - 1 => generics.where_clause.predicates
-                            [pos - 1]
-                            .span()
-                            .shrink_to_hi()
-                            .to(*span),
-                        // where T: ?Sized, Foo: Bar,
-                        //       ^^^^^^^^^^^
-                        (1, _, _, pos) => {
-                            span.until(generics.where_clause.predicates[pos + 1].span())
-                        }
-                        // where T: ?Sized + Bar, Foo: Bar,
-                        //          ^^^^^^^^^
-                        (_, 0, _, _) => bound.span().to(bounds[1].span().shrink_to_lo()),
-                        // where T: Bar + ?Sized, Foo: Bar,
-                        //             ^^^^^^^^^
-                        (_, pos, _, _) => bounds[pos - 1].span().shrink_to_hi().to(bound.span()),
-                    };
+    let param_def_id = tcx.hir().local_def_id(param.hir_id);
+    for (where_pos, predicate) in generics.predicates.iter().enumerate() {
+        let WherePredicate::BoundPredicate(predicate) = predicate else {
+            continue;
+        };
+        if !predicate.is_param_bound(param_def_id.to_def_id()) {
+            continue;
+        };
 
-                    suggestions.push((
-                        sp,
-                        String::new(),
-                        SuggestChangingConstraintsMessage::RemovingQSized,
-                    ));
-                }
-            }
-            _ => {}
-        }
-    }
-    for (pos, bound) in param.bounds.iter().enumerate() {
-        match bound {
-            hir::GenericBound::Trait(poly, hir::TraitBoundModifier::Maybe)
-                if poly.trait_ref.trait_def_id() == def_id =>
-            {
-                let sp = match (param.bounds.len(), pos) {
-                    // T: ?Sized,
-                    //  ^^^^^^^^
-                    (1, _) => param.span.shrink_to_hi().to(bound.span()),
-                    // T: ?Sized + Bar,
-                    //    ^^^^^^^^^
-                    (_, 0) => bound.span().to(param.bounds[1].span().shrink_to_lo()),
-                    // T: Bar + ?Sized,
-                    //       ^^^^^^^^^
-                    (_, pos) => param.bounds[pos - 1].span().shrink_to_hi().to(bound.span()),
-                };
-
-                suggestions.push((
-                    sp,
-                    String::new(),
-                    SuggestChangingConstraintsMessage::RemovingQSized,
-                ));
+        for (pos, bound) in predicate.bounds.iter().enumerate() {
+            let    hir::GenericBound::Trait(poly, hir::TraitBoundModifier::Maybe) = bound else {
+                continue;
+            };
+            if poly.trait_ref.trait_def_id() != def_id {
+                continue;
             }
-            _ => {}
+            let sp = generics.span_for_bound_removal(where_pos, pos);
+            suggestions.push((
+                sp,
+                String::new(),
+                SuggestChangingConstraintsMessage::RemovingQSized,
+            ));
         }
     }
 }
@@ -321,13 +264,7 @@ pub fn suggest_constraining_type_params<'a>(
                     param.span,
                     &format!("this type parameter needs to be `{}`", constraint),
                 );
-                suggest_removing_unsized_bound(
-                    generics,
-                    &mut suggestions,
-                    param_name,
-                    param,
-                    def_id,
-                );
+                suggest_removing_unsized_bound(tcx, generics, &mut suggestions, param, def_id);
             }
         }
 
@@ -348,76 +285,45 @@ pub fn suggest_constraining_type_params<'a>(
             ))
         };
 
-        if param_name.starts_with("impl ") {
-            // If there's an `impl Trait` used in argument position, suggest
-            // restricting it:
-            //
-            //   fn foo(t: impl Foo) { ... }
-            //             --------
-            //             |
-            //             help: consider further restricting this bound with `+ Bar`
-            //
-            // Suggestion for tools in this case is:
-            //
-            //   fn foo(t: impl Foo) { ... }
-            //             --------
-            //             |
-            //             replace with: `impl Foo + Bar`
-
-            // `impl Trait` must have at least one trait in the list
-            let bound_list_non_empty = true;
-
-            suggest_restrict(param.span.shrink_to_hi(), bound_list_non_empty);
+        // When the type parameter has been provided bounds
+        //
+        //    Message:
+        //      fn foo<T>(t: T) where T: Foo { ... }
+        //                            ^^^^^^
+        //                            |
+        //                            help: consider further restricting this bound with `+ Bar`
+        //
+        //    Suggestion:
+        //      fn foo<T>(t: T) where T: Foo { ... }
+        //                                  ^
+        //                                  |
+        //                                  replace with: ` + Bar`
+        //
+        // Or, if user has provided some bounds, suggest restricting them:
+        //
+        //   fn foo<T: Foo>(t: T) { ... }
+        //             ---
+        //             |
+        //             help: consider further restricting this bound with `+ Bar`
+        //
+        // Suggestion for tools in this case is:
+        //
+        //   fn foo<T: Foo>(t: T) { ... }
+        //          --
+        //          |
+        //          replace with: `T: Bar +`
+        let param_def_id = tcx.hir().local_def_id(param.hir_id);
+        if let Some(span) = generics.bounds_span_for_suggestions(param_def_id) {
+            suggest_restrict(span, true);
             continue;
         }
 
-        if generics.where_clause.predicates.is_empty()
-        // Given `trait Base<T = String>: Super<T>` where `T: Copy`, suggest restricting in the
-        // `where` clause instead of `trait Base<T: Copy = String>: Super<T>`.
-        && !matches!(param.kind, hir::GenericParamKind::Type { default: Some(_), .. })
-        {
-            if let Some(span) = param.bounds_span_for_suggestions() {
-                // If user has provided some bounds, suggest restricting them:
-                //
-                //   fn foo<T: Foo>(t: T) { ... }
-                //             ---
-                //             |
-                //             help: consider further restricting this bound with `+ Bar`
-                //
-                // Suggestion for tools in this case is:
-                //
-                //   fn foo<T: Foo>(t: T) { ... }
-                //          --
-                //          |
-                //          replace with: `T: Bar +`
-
-                // `bounds_span_for_suggestions` returns `None` if the list is empty
-                let bound_list_non_empty = true;
-
-                suggest_restrict(span, bound_list_non_empty);
-            } else {
-                let (colon, span) = match param.colon_span_for_suggestions(tcx.sess.source_map()) {
-                    // If there is already a colon after generic, do not suggest adding it again
-                    Some(sp) => ("", sp.shrink_to_hi()),
-                    None => (":", param.span.shrink_to_hi()),
-                };
-
-                // If user hasn't provided any bounds, suggest adding a new one:
-                //
-                //   fn foo<T>(t: T) { ... }
-                //          - help: consider restricting this type parameter with `T: Foo`
-                suggestions.push((
-                    span,
-                    format!("{colon} {constraint}"),
-                    SuggestChangingConstraintsMessage::RestrictType { ty: param_name },
-                ));
-            }
-        } else {
+        if generics.has_where_clause {
             // This part is a bit tricky, because using the `where` clause user can
             // provide zero, one or many bounds for the same type parameter, so we
             // have following cases to consider:
             //
-            // 1) When the type parameter has been provided zero bounds
+            // When the type parameter has been provided zero bounds
             //
             //    Message:
             //      fn foo<X, Y>(x: X, y: Y) where Y: Foo { ... }
@@ -426,95 +332,59 @@ pub fn suggest_constraining_type_params<'a>(
             //    Suggestion:
             //      fn foo<X, Y>(x: X, y: Y) where Y: Foo { ... }
             //                                           - insert: `, X: Bar`
-            //
-            //
-            // 2) When the type parameter has been provided one bound
-            //
-            //    Message:
-            //      fn foo<T>(t: T) where T: Foo { ... }
-            //                            ^^^^^^
-            //                            |
-            //                            help: consider further restricting this bound with `+ Bar`
-            //
-            //    Suggestion:
-            //      fn foo<T>(t: T) where T: Foo { ... }
-            //                            ^^
-            //                            |
-            //                            replace with: `T: Bar +`
-            //
-            //
-            // 3) When the type parameter has been provided many bounds
-            //
-            //    Message:
-            //      fn foo<T>(t: T) where T: Foo, T: Bar {... }
-            //             - help: consider further restricting this type parameter with `where T: Zar`
-            //
-            //    Suggestion:
-            //      fn foo<T>(t: T) where T: Foo, T: Bar {... }
-            //                                          - insert: `, T: Zar`
-            //
-            // Additionally, there may be no `where` clause whatsoever in the case that this was
-            // reached because the generic parameter has a default:
-            //
-            //    Message:
-            //      trait Foo<T=()> {... }
-            //             - help: consider further restricting this type parameter with `where T: Zar`
-            //
-            //    Suggestion:
-            //      trait Foo<T=()> where T: Zar {... }
-            //                     - insert: `where T: Zar`
-
-            if matches!(param.kind, hir::GenericParamKind::Type { default: Some(_), .. })
-                && generics.where_clause.predicates.len() == 0
-            {
-                // Suggest a bound, but there is no existing `where` clause *and* the type param has a
-                // default (`<T=Foo>`), so we suggest adding `where T: Bar`.
-                suggestions.push((
-                    generics.where_clause.tail_span_for_suggestion(),
-                    format!(" where {}: {}", param_name, constraint),
-                    SuggestChangingConstraintsMessage::RestrictTypeFurther { ty: param_name },
-                ));
-            } else {
-                let mut param_spans = Vec::new();
-                let mut non_empty = false;
-
-                for predicate in generics.where_clause.predicates {
-                    if let WherePredicate::BoundPredicate(WhereBoundPredicate {
-                        span,
-                        bounded_ty,
-                        bounds,
-                        ..
-                    }) = predicate
-                    {
-                        if let TyKind::Path(QPath::Resolved(_, path)) = &bounded_ty.kind {
-                            if let Some(segment) = path.segments.first() {
-                                if segment.ident.to_string() == param_name {
-                                    non_empty = !bounds.is_empty();
-
-                                    param_spans.push(span);
-                                }
-                            }
-                        }
-                    }
-                }
+            suggestions.push((
+                generics.tail_span_for_predicate_suggestion(),
+                constraints
+                    .iter()
+                    .map(|&(constraint, _)| format!(", {}: {}", param_name, constraint))
+                    .collect::<String>(),
+                SuggestChangingConstraintsMessage::RestrictTypeFurther { ty: param_name },
+            ));
+            continue;
+        }
 
-                match param_spans[..] {
-                    [&param_span] => suggest_restrict(param_span.shrink_to_hi(), non_empty),
-                    _ => {
-                        suggestions.push((
-                            generics.where_clause.tail_span_for_suggestion(),
-                            constraints
-                                .iter()
-                                .map(|&(constraint, _)| format!(", {}: {}", param_name, constraint))
-                                .collect::<String>(),
-                            SuggestChangingConstraintsMessage::RestrictTypeFurther {
-                                ty: param_name,
-                            },
-                        ));
-                    }
-                }
-            }
+        // Additionally, there may be no `where` clause but the generic parameter has a default:
+        //
+        //    Message:
+        //      trait Foo<T=()> {... }
+        //                - help: consider further restricting this type parameter with `where T: Zar`
+        //
+        //    Suggestion:
+        //      trait Foo<T=()> {... }
+        //                     - insert: `where T: Zar`
+        if matches!(param.kind, hir::GenericParamKind::Type { default: Some(_), .. }) {
+            // Suggest a bound, but there is no existing `where` clause *and* the type param has a
+            // default (`<T=Foo>`), so we suggest adding `where T: Bar`.
+            suggestions.push((
+                generics.tail_span_for_predicate_suggestion(),
+                format!(" where {}: {}", param_name, constraint),
+                SuggestChangingConstraintsMessage::RestrictTypeFurther { ty: param_name },
+            ));
+            continue;
         }
+
+        // If user has provided a colon, don't suggest adding another:
+        //
+        //   fn foo<T:>(t: T) { ... }
+        //            - insert: consider restricting this type parameter with `T: Foo`
+        if let Some(colon_span) = param.colon_span {
+            suggestions.push((
+                colon_span.shrink_to_hi(),
+                format!(" {}", constraint),
+                SuggestChangingConstraintsMessage::RestrictType { ty: param_name },
+            ));
+            continue;
+        }
+
+        // If user hasn't provided any bounds, suggest adding a new one:
+        //
+        //   fn foo<T>(t: T) { ... }
+        //          - help: consider restricting this type parameter with `T: Foo`
+        suggestions.push((
+            param.span.shrink_to_hi(),
+            format!(": {}", constraint),
+            SuggestChangingConstraintsMessage::RestrictType { ty: param_name },
+        ));
     }
 
     if suggestions.len() == 1 {
index 07878defa8ccdef1562f5ff78fa7ad7398c11c25..da0934b67c5df70d0c87e5245fad7957c0c586c2 100644 (file)
@@ -602,53 +602,24 @@ fn suggest_constraint(
                 } else {
                     return false;
                 };
+                let Some(def_id) = def_id.as_local() else {
+                    return false;
+                };
 
                 // First look in the `where` clause, as this might be
                 // `fn foo<T>(x: T) where T: Trait`.
-                for predicate in hir_generics.where_clause.predicates {
-                    if let hir::WherePredicate::BoundPredicate(pred) = predicate {
-                        if let hir::TyKind::Path(hir::QPath::Resolved(None, path)) =
-                            pred.bounded_ty.kind
-                        {
-                            if path.res.opt_def_id() == Some(def_id) {
-                                // This predicate is binding type param `A` in `<A as T>::Foo` to
-                                // something, potentially `T`.
-                            } else {
-                                continue;
-                            }
-                        } else {
-                            continue;
-                        }
-
-                        if self.constrain_generic_bound_associated_type_structured_suggestion(
-                            diag,
-                            &trait_ref,
-                            pred.bounds,
-                            &assoc,
-                            assoc_substs,
-                            ty,
-                            msg,
-                            false,
-                        ) {
-                            return true;
-                        }
-                    }
-                }
-                for param in hir_generics.params {
-                    if self.hir().opt_local_def_id(param.hir_id).map(|id| id.to_def_id())
-                        == Some(def_id)
-                    {
-                        // This is type param `A` in `<A as T>::Foo`.
-                        return self.constrain_generic_bound_associated_type_structured_suggestion(
-                            diag,
-                            &trait_ref,
-                            param.bounds,
-                            &assoc,
-                            assoc_substs,
-                            ty,
-                            msg,
-                            false,
-                        );
+                for pred in hir_generics.bounds_for_param(def_id) {
+                    if self.constrain_generic_bound_associated_type_structured_suggestion(
+                        diag,
+                        &trait_ref,
+                        pred.bounds,
+                        &assoc,
+                        assoc_substs,
+                        ty,
+                        msg,
+                        false,
+                    ) {
+                        return true;
                     }
                 }
             }
index f6d139fe59d3cf5b7f98173a75829d124539cae1..cd4b23fca393282a40126213a1b24c35be53a042 100644 (file)
@@ -1120,21 +1120,12 @@ fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<Layout<'tcx>, LayoutError<'
                                 match st[i].abi() {
                                     Abi::Scalar(_) => Abi::Scalar(niche_scalar),
                                     Abi::ScalarPair(first, second) => {
-                                        // We need to use scalar_unit to reset the
-                                        // valid range to the maximal one for that
-                                        // primitive, because only the niche is
-                                        // guaranteed to be initialised, not the
-                                        // other primitive.
+                                        // Only the niche is guaranteed to be initialised,
+                                        // so use union layout for the other primitive.
                                         if offset.bytes() == 0 {
-                                            Abi::ScalarPair(
-                                                niche_scalar,
-                                                scalar_unit(second.primitive()),
-                                            )
+                                            Abi::ScalarPair(niche_scalar, second.to_union())
                                         } else {
-                                            Abi::ScalarPair(
-                                                scalar_unit(first.primitive()),
-                                                niche_scalar,
-                                            )
+                                            Abi::ScalarPair(first.to_union(), niche_scalar)
                                         }
                                     }
                                     _ => Abi::Aggregate { sized: true },
@@ -1329,6 +1320,7 @@ fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<Layout<'tcx>, LayoutError<'
                 } else {
                     // Try to use a ScalarPair for all tagged enums.
                     let mut common_prim = None;
+                    let mut common_prim_initialized_in_all_variants = true;
                     for (field_layouts, layout_variant) in iter::zip(&variants, &layout_variants) {
                         let FieldsShape::Arbitrary { ref offsets, .. } = layout_variant.fields else {
                             bug!();
@@ -1336,7 +1328,10 @@ fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<Layout<'tcx>, LayoutError<'
                         let mut fields =
                             iter::zip(field_layouts, offsets).filter(|p| !p.0.is_zst());
                         let (field, offset) = match (fields.next(), fields.next()) {
-                            (None, None) => continue,
+                            (None, None) => {
+                                common_prim_initialized_in_all_variants = false;
+                                continue;
+                            }
                             (Some(pair), None) => pair,
                             _ => {
                                 common_prim = None;
@@ -1344,7 +1339,11 @@ fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<Layout<'tcx>, LayoutError<'
                             }
                         };
                         let prim = match field.abi {
-                            Abi::Scalar(scalar) => scalar.primitive(),
+                            Abi::Scalar(scalar) => {
+                                common_prim_initialized_in_all_variants &=
+                                    matches!(scalar, Scalar::Initialized { .. });
+                                scalar.primitive()
+                            }
                             _ => {
                                 common_prim = None;
                                 break;
@@ -1364,7 +1363,13 @@ fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<Layout<'tcx>, LayoutError<'
                         }
                     }
                     if let Some((prim, offset)) = common_prim {
-                        let pair = self.scalar_pair(tag, scalar_unit(prim));
+                        let prim_scalar = if common_prim_initialized_in_all_variants {
+                            scalar_unit(prim)
+                        } else {
+                            // Common prim might be uninit.
+                            Scalar::Union { value: prim }
+                        };
+                        let pair = self.scalar_pair(tag, prim_scalar);
                         let pair_offsets = match pair.fields {
                             FieldsShape::Arbitrary { ref offsets, ref memory_index } => {
                                 assert_eq!(memory_index, &[0, 1]);
@@ -2587,6 +2592,22 @@ fn ty_and_layout_pointee_info_at(
 
         pointee_info
     }
+
+    fn is_adt(this: TyAndLayout<'tcx>) -> bool {
+        matches!(this.ty.kind(), ty::Adt(..))
+    }
+
+    fn is_never(this: TyAndLayout<'tcx>) -> bool {
+        this.ty.kind() == &ty::Never
+    }
+
+    fn is_tuple(this: TyAndLayout<'tcx>) -> bool {
+        matches!(this.ty.kind(), ty::Tuple(..))
+    }
+
+    fn is_unit(this: TyAndLayout<'tcx>) -> bool {
+        matches!(this.ty.kind(), ty::Tuple(list) if list.len() == 0)
+    }
 }
 
 impl<'tcx> ty::Instance<'tcx> {
index adba7d131592ec81b11a1b4096499445edd57824..197dc9205b4804d97fb79d07360afba35606ce72 100644 (file)
@@ -61,6 +61,10 @@ pub fn empty<'a>() -> &'a List<T> {
         static EMPTY_SLICE: InOrder<usize, MaxAlign> = InOrder(0, MaxAlign);
         unsafe { &*(&EMPTY_SLICE as *const _ as *const List<T>) }
     }
+
+    pub fn len(&self) -> usize {
+        self.len
+    }
 }
 
 impl<T: Copy> List<T> {
index d59fdf47904f7939109376f398623796c0b66516..af9216a990a72dd1c3bbf9ff34159d61688cc26e 100644 (file)
@@ -36,7 +36,7 @@
 use rustc_data_structures::tagged_ptr::CopyTaggedPtr;
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
-use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalDefIdMap, CRATE_DEF_ID};
+use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalDefIdMap};
 use rustc_hir::Node;
 use rustc_macros::HashStable;
 use rustc_query_system::ich::StableHashingContext;
@@ -131,6 +131,8 @@ pub struct ResolverOutputs {
     pub definitions: rustc_hir::definitions::Definitions,
     pub cstore: Box<CrateStoreDyn>,
     pub visibilities: FxHashMap<LocalDefId, Visibility>,
+    /// This field is used to decide whether we should make `PRIVATE_IN_PUBLIC` a hard error.
+    pub has_pub_restricted: bool,
     pub access_levels: AccessLevels,
     pub extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
     pub maybe_unused_trait_imports: FxHashSet<LocalDefId>,
@@ -288,11 +290,28 @@ pub struct ClosureSizeProfileData<'tcx> {
 }
 
 pub trait DefIdTree: Copy {
-    fn parent(self, id: DefId) -> Option<DefId>;
+    fn opt_parent(self, id: DefId) -> Option<DefId>;
 
     #[inline]
-    fn local_parent(self, id: LocalDefId) -> Option<LocalDefId> {
-        Some(self.parent(id.to_def_id())?.expect_local())
+    #[track_caller]
+    fn parent(self, id: DefId) -> DefId {
+        match self.opt_parent(id) {
+            Some(id) => id,
+            // not `unwrap_or_else` to avoid breaking caller tracking
+            None => bug!("{id:?} doesn't have a parent"),
+        }
+    }
+
+    #[inline]
+    #[track_caller]
+    fn opt_local_parent(self, id: LocalDefId) -> Option<LocalDefId> {
+        self.opt_parent(id.to_def_id()).map(DefId::expect_local)
+    }
+
+    #[inline]
+    #[track_caller]
+    fn local_parent(self, id: LocalDefId) -> LocalDefId {
+        self.parent(id.to_def_id()).expect_local()
     }
 
     fn is_descendant_of(self, mut descendant: DefId, ancestor: DefId) -> bool {
@@ -301,7 +320,7 @@ fn is_descendant_of(self, mut descendant: DefId, ancestor: DefId) -> bool {
         }
 
         while descendant != ancestor {
-            match self.parent(descendant) {
+            match self.opt_parent(descendant) {
                 Some(parent) => descendant = parent,
                 None => return false,
             }
@@ -311,28 +330,13 @@ fn is_descendant_of(self, mut descendant: DefId, ancestor: DefId) -> bool {
 }
 
 impl<'tcx> DefIdTree for TyCtxt<'tcx> {
-    fn parent(self, id: DefId) -> Option<DefId> {
+    #[inline]
+    fn opt_parent(self, id: DefId) -> Option<DefId> {
         self.def_key(id).parent.map(|index| DefId { index, ..id })
     }
 }
 
 impl Visibility {
-    pub fn from_hir(visibility: &hir::Visibility<'_>, id: hir::HirId, tcx: TyCtxt<'_>) -> Self {
-        match visibility.node {
-            hir::VisibilityKind::Public => Visibility::Public,
-            hir::VisibilityKind::Crate(_) => Visibility::Restricted(CRATE_DEF_ID.to_def_id()),
-            hir::VisibilityKind::Restricted { ref path, .. } => match path.res {
-                // If there is no resolution, `resolve` will have already reported an error, so
-                // assume that the visibility is public to avoid reporting more privacy errors.
-                Res::Err => Visibility::Public,
-                def => Visibility::Restricted(def.def_id()),
-            },
-            hir::VisibilityKind::Inherited => {
-                Visibility::Restricted(tcx.parent_module(id).to_def_id())
-            }
-        }
-    }
-
     /// Returns `true` if an item with this visibility is accessible from the given block.
     pub fn is_accessible_from<T: DefIdTree>(self, module: DefId, tree: T) -> bool {
         let restriction = match self {
@@ -2137,17 +2141,17 @@ pub fn impls_are_allowed_to_overlap(
     pub fn expect_variant_res(self, res: Res) -> &'tcx VariantDef {
         match res {
             Res::Def(DefKind::Variant, did) => {
-                let enum_did = self.parent(did).unwrap();
+                let enum_did = self.parent(did);
                 self.adt_def(enum_did).variant_with_id(did)
             }
             Res::Def(DefKind::Struct | DefKind::Union, did) => self.adt_def(did).non_enum_variant(),
             Res::Def(DefKind::Ctor(CtorOf::Variant, ..), variant_ctor_did) => {
-                let variant_did = self.parent(variant_ctor_did).unwrap();
-                let enum_did = self.parent(variant_did).unwrap();
+                let variant_did = self.parent(variant_ctor_did);
+                let enum_did = self.parent(variant_did);
                 self.adt_def(enum_did).variant_with_ctor_id(variant_ctor_did)
             }
             Res::Def(DefKind::Ctor(CtorOf::Struct, ..), ctor_did) => {
-                let struct_did = self.parent(ctor_did).expect("struct ctor has no parent");
+                let struct_did = self.parent(ctor_did);
                 self.adt_def(struct_did).non_enum_variant()
             }
             _ => bug!("expect_variant_res used with unexpected res {:?}", res),
index c74b3e9d0fc3937d620350ad21b612c1086f789e..3fe68f723ec14ead710ab75b8b82025fb9712365 100644 (file)
@@ -235,11 +235,11 @@ fn default_print_impl_path(
         // as the trait.
         let in_self_mod = match characteristic_def_id_of_type(self_ty) {
             None => false,
-            Some(ty_def_id) => self.tcx().parent(ty_def_id) == Some(parent_def_id),
+            Some(ty_def_id) => self.tcx().parent(ty_def_id) == parent_def_id,
         };
         let in_trait_mod = match impl_trait_ref {
             None => false,
-            Some(trait_ref) => self.tcx().parent(trait_ref.def_id) == Some(parent_def_id),
+            Some(trait_ref) => self.tcx().parent(trait_ref.def_id) == parent_def_id,
         };
 
         if !in_self_mod && !in_trait_mod {
index 38362a4cbb92529a8a164ba137096bd1cda4e70a..991666908f94a83c2ee1409518e0f8d15dd09df9 100644 (file)
@@ -408,7 +408,7 @@ fn try_print_visible_def_path_recur(
             return Ok((self, false));
         };
 
-        let actual_parent = self.tcx().parent(def_id);
+        let actual_parent = self.tcx().opt_parent(def_id);
         debug!(
             "try_print_visible_def_path: visible_parent={:?} actual_parent={:?}",
             visible_parent, actual_parent,
@@ -643,7 +643,7 @@ fn pretty_print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error>
                     return Ok(self);
                 }
 
-                let parent = self.tcx().parent(def_id).expect("opaque types always have a parent");
+                let parent = self.tcx().parent(def_id);
                 match self.tcx().def_kind(parent) {
                     DefKind::TyAlias | DefKind::AssocTy => {
                         if let ty::Opaque(d, _) = *self.tcx().type_of(parent).kind() {
index 7629d7a8259b8b841598e95c2c70519f186a04cc..fb937ded65af12d43ae2d29813f139df4dad83a4 100644 (file)
@@ -3,7 +3,7 @@
 use crate::lint::LintLevelMap;
 use crate::metadata::ModChild;
 use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
-use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel};
+use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
 use crate::middle::lib_features::LibFeatures;
 use crate::middle::privacy::AccessLevels;
 use crate::middle::region;
index 5a13216846d54e8d8a5ad7c61f33711be0b36989..0d55fe3a3929b206abbd69d5b43fb18f531bbc43 100644 (file)
@@ -1798,7 +1798,7 @@ pub fn type_flags(self) -> TypeFlags {
     /// function might return the `DefId` of a closure.
     pub fn free_region_binding_scope(self, tcx: TyCtxt<'_>) -> DefId {
         match *self {
-            ty::ReEarlyBound(br) => tcx.parent(br.def_id).unwrap(),
+            ty::ReEarlyBound(br) => tcx.parent(br.def_id),
             ty::ReFree(fr) => fr.scope,
             _ => bug!("free_region_binding_scope invoked on inappropriate region: {:?}", self),
         }
@@ -2273,7 +2273,7 @@ pub fn ptr_metadata_ty(
         tcx: TyCtxt<'tcx>,
         normalize: impl FnMut(Ty<'tcx>) -> Ty<'tcx>,
     ) -> (Ty<'tcx>, bool) {
-        let tail = tcx.struct_tail_with_normalize(self, normalize);
+        let tail = tcx.struct_tail_with_normalize(self, normalize, || {});
         match tail.kind() {
             // Sized types
             ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
index 39038e85b11a086a52733ca6a542deea4018237a..c190eec7e5a161f4833d403de3f51c1c1be7d1b1 100644 (file)
@@ -142,10 +142,10 @@ pub fn type_id_hash(self, ty: Ty<'tcx>) -> u64 {
     pub fn res_generics_def_id(self, res: Res) -> Option<DefId> {
         match res {
             Res::Def(DefKind::Ctor(CtorOf::Variant, _), def_id) => {
-                Some(self.parent(def_id).and_then(|def_id| self.parent(def_id)).unwrap())
+                Some(self.parent(self.parent(def_id)))
             }
             Res::Def(DefKind::Variant | DefKind::Ctor(CtorOf::Struct, _), def_id) => {
-                Some(self.parent(def_id).unwrap())
+                Some(self.parent(def_id))
             }
             // Other `DefKind`s don't have generics and would ICE when calling
             // `generics_of`.
@@ -187,7 +187,7 @@ pub fn has_error_field(self, ty: Ty<'tcx>) -> bool {
     /// if input `ty` is not a structure at all.
     pub fn struct_tail_without_normalization(self, ty: Ty<'tcx>) -> Ty<'tcx> {
         let tcx = self;
-        tcx.struct_tail_with_normalize(ty, |ty| ty)
+        tcx.struct_tail_with_normalize(ty, |ty| ty, || {})
     }
 
     /// Returns the deeply last field of nested structures, or the same type if
@@ -203,7 +203,7 @@ pub fn struct_tail_erasing_lifetimes(
         param_env: ty::ParamEnv<'tcx>,
     ) -> Ty<'tcx> {
         let tcx = self;
-        tcx.struct_tail_with_normalize(ty, |ty| tcx.normalize_erasing_regions(param_env, ty))
+        tcx.struct_tail_with_normalize(ty, |ty| tcx.normalize_erasing_regions(param_env, ty), || {})
     }
 
     /// Returns the deeply last field of nested structures, or the same type if
@@ -220,6 +220,10 @@ pub fn struct_tail_with_normalize(
         self,
         mut ty: Ty<'tcx>,
         mut normalize: impl FnMut(Ty<'tcx>) -> Ty<'tcx>,
+        // This is currently used to allow us to walk a ValTree
+        // in lockstep with the type in order to get the ValTree branch that
+        // corresponds to an unsized field.
+        mut f: impl FnMut() -> (),
     ) -> Ty<'tcx> {
         let recursion_limit = self.recursion_limit();
         for iteration in 0.. {
@@ -235,12 +239,16 @@ pub fn struct_tail_with_normalize(
                         break;
                     }
                     match def.non_enum_variant().fields.last() {
-                        Some(f) => ty = f.ty(self, substs),
+                        Some(field) => {
+                            f();
+                            ty = field.ty(self, substs);
+                        }
                         None => break,
                     }
                 }
 
                 ty::Tuple(tys) if let Some((&last_ty, _)) = tys.split_last() => {
+                    f();
                     ty = last_ty;
                 }
 
@@ -492,9 +500,7 @@ pub fn is_constructor(self, def_id: DefId) -> bool {
     pub fn typeck_root_def_id(self, def_id: DefId) -> DefId {
         let mut def_id = def_id;
         while self.is_typeck_child(def_id) {
-            def_id = self.parent(def_id).unwrap_or_else(|| {
-                bug!("closure {:?} has no parent", def_id);
-            });
+            def_id = self.parent(def_id);
         }
         def_id
     }
index eadce3dc9c4679a36b310450f38b4b0ce7206b8a..a841cce23dee994af0a520b202c6f34c98903888 100644 (file)
@@ -12,6 +12,7 @@
 use rustc_span::symbol::Symbol;
 use rustc_span::Span;
 
+use std::borrow::Cow;
 use std::ops::Bound;
 
 struct UnsafetyVisitor<'a, 'tcx> {
@@ -70,7 +71,6 @@ fn in_safety_context(&mut self, safety_context: SafetyContext, f: impl FnOnce(&m
     }
 
     fn requires_unsafe(&mut self, span: Span, kind: UnsafeOpKind) {
-        let (description, note) = kind.description_and_note();
         let unsafe_op_in_unsafe_fn_allowed = self.unsafe_op_in_unsafe_fn_allowed();
         match self.safety_context {
             SafetyContext::BuiltinUnsafeBlock => {}
@@ -82,6 +82,7 @@ fn requires_unsafe(&mut self, span: Span, kind: UnsafeOpKind) {
             }
             SafetyContext::UnsafeFn if unsafe_op_in_unsafe_fn_allowed => {}
             SafetyContext::UnsafeFn => {
+                let (description, note) = kind.description_and_note(self.tcx);
                 // unsafe_op_in_unsafe_fn is disallowed
                 self.tcx.struct_span_lint_hir(
                     UNSAFE_OP_IN_UNSAFE_FN,
@@ -92,13 +93,14 @@ fn requires_unsafe(&mut self, span: Span, kind: UnsafeOpKind) {
                             "{} is unsafe and requires unsafe block (error E0133)",
                             description,
                         ))
-                        .span_label(span, description)
+                        .span_label(span, kind.simple_description())
                         .note(note)
                         .emit();
                     },
                 )
             }
             SafetyContext::Safe => {
+                let (description, note) = kind.description_and_note(self.tcx);
                 let fn_sugg = if unsafe_op_in_unsafe_fn_allowed { " function or" } else { "" };
                 struct_span_err!(
                     self.tcx.sess,
@@ -108,7 +110,7 @@ fn requires_unsafe(&mut self, span: Span, kind: UnsafeOpKind) {
                     description,
                     fn_sugg,
                 )
-                .span_label(span, description)
+                .span_label(span, kind.simple_description())
                 .note(note)
                 .emit();
             }
@@ -350,7 +352,12 @@ fn visit_expr(&mut self, expr: &Expr<'tcx>) {
             }
             ExprKind::Call { fun, ty: _, args: _, from_hir_call: _, fn_span: _ } => {
                 if self.thir[fun].ty.fn_sig(self.tcx).unsafety() == hir::Unsafety::Unsafe {
-                    self.requires_unsafe(expr.span, CallToUnsafeFunction);
+                    let func_id = if let ty::FnDef(func_id, _) = self.thir[fun].ty.kind() {
+                        Some(*func_id)
+                    } else {
+                        None
+                    };
+                    self.requires_unsafe(expr.span, CallToUnsafeFunction(func_id));
                 } else if let &ty::FnDef(func_did, _) = self.thir[fun].ty.kind() {
                     // If the called function has target features the calling function hasn't,
                     // the call requires `unsafe`. Don't check this on wasm
@@ -364,7 +371,7 @@ fn visit_expr(&mut self, expr: &Expr<'tcx>) {
                             .iter()
                             .all(|feature| self.body_target_features.contains(feature))
                     {
-                        self.requires_unsafe(expr.span, CallToFunctionWith);
+                        self.requires_unsafe(expr.span, CallToFunctionWith(func_did));
                     }
                 }
             }
@@ -523,7 +530,7 @@ fn unsafe_fn_sig_span(self) -> Option<Span> {
 
 #[derive(Clone, Copy, PartialEq)]
 enum UnsafeOpKind {
-    CallToUnsafeFunction,
+    CallToUnsafeFunction(Option<DefId>),
     UseOfInlineAssembly,
     InitializingTypeWith,
     UseOfMutableStatic,
@@ -533,64 +540,89 @@ enum UnsafeOpKind {
     AccessToUnionField,
     MutationOfLayoutConstrainedField,
     BorrowOfLayoutConstrainedField,
-    CallToFunctionWith,
+    CallToFunctionWith(DefId),
 }
 
 use UnsafeOpKind::*;
 
 impl UnsafeOpKind {
-    pub fn description_and_note(&self) -> (&'static str, &'static str) {
+    pub fn simple_description(&self) -> &'static str {
         match self {
-            CallToUnsafeFunction => (
-                "call to unsafe function",
+            CallToUnsafeFunction(..) => "call to unsafe function",
+            UseOfInlineAssembly => "use of inline assembly",
+            InitializingTypeWith => "initializing type with `rustc_layout_scalar_valid_range` attr",
+            UseOfMutableStatic => "use of mutable static",
+            UseOfExternStatic => "use of extern static",
+            DerefOfRawPointer => "dereference of raw pointer",
+            AssignToDroppingUnionField => "assignment to union field that might need dropping",
+            AccessToUnionField => "access to union field",
+            MutationOfLayoutConstrainedField => "mutation of layout constrained field",
+            BorrowOfLayoutConstrainedField => {
+                "borrow of layout constrained field with interior mutability"
+            }
+            CallToFunctionWith(..) => "call to function with `#[target_feature]`",
+        }
+    }
+
+    pub fn description_and_note(&self, tcx: TyCtxt<'_>) -> (Cow<'static, str>, &'static str) {
+        match self {
+            CallToUnsafeFunction(did) => (
+                if let Some(did) = did {
+                    Cow::from(format!("call to unsafe function `{}`", tcx.def_path_str(*did)))
+                } else {
+                    Cow::Borrowed(self.simple_description())
+                },
                 "consult the function's documentation for information on how to avoid undefined \
                  behavior",
             ),
             UseOfInlineAssembly => (
-                "use of inline assembly",
+                Cow::Borrowed(self.simple_description()),
                 "inline assembly is entirely unchecked and can cause undefined behavior",
             ),
             InitializingTypeWith => (
-                "initializing type with `rustc_layout_scalar_valid_range` attr",
+                Cow::Borrowed(self.simple_description()),
                 "initializing a layout restricted type's field with a value outside the valid \
                  range is undefined behavior",
             ),
             UseOfMutableStatic => (
-                "use of mutable static",
+                Cow::Borrowed(self.simple_description()),
                 "mutable statics can be mutated by multiple threads: aliasing violations or data \
                  races will cause undefined behavior",
             ),
             UseOfExternStatic => (
-                "use of extern static",
+                Cow::Borrowed(self.simple_description()),
                 "extern statics are not controlled by the Rust type system: invalid data, \
                  aliasing violations or data races will cause undefined behavior",
             ),
             DerefOfRawPointer => (
-                "dereference of raw pointer",
+                Cow::Borrowed(self.simple_description()),
                 "raw pointers may be null, dangling or unaligned; they can violate aliasing rules \
                  and cause data races: all of these are undefined behavior",
             ),
             AssignToDroppingUnionField => (
-                "assignment to union field that might need dropping",
+                Cow::Borrowed(self.simple_description()),
                 "the previous content of the field will be dropped, which causes undefined \
                  behavior if the field was not properly initialized",
             ),
             AccessToUnionField => (
-                "access to union field",
+                Cow::Borrowed(self.simple_description()),
                 "the field may not be properly initialized: using uninitialized data will cause \
                  undefined behavior",
             ),
             MutationOfLayoutConstrainedField => (
-                "mutation of layout constrained field",
+                Cow::Borrowed(self.simple_description()),
                 "mutating layout constrained fields cannot statically be checked for valid values",
             ),
             BorrowOfLayoutConstrainedField => (
-                "borrow of layout constrained field with interior mutability",
+                Cow::Borrowed(self.simple_description()),
                 "references to fields of layout constrained fields lose the constraints. Coupled \
                  with interior mutability, the field can be changed to invalid values",
             ),
-            CallToFunctionWith => (
-                "call to function with `#[target_feature]`",
+            CallToFunctionWith(did) => (
+                Cow::from(format!(
+                    "call to function `{}` with `#[target_feature]`",
+                    tcx.def_path_str(*did)
+                )),
                 "can only be called if the required target features are available",
             ),
         }
index dbcd701c1adddbecd8e9e4c4de7be5ab9efe3126..5b0aa4309a8ed9918141507e8ae3e08153b0d75b 100644 (file)
@@ -377,7 +377,7 @@ fn lower_variant_or_leaf(
     ) -> PatKind<'tcx> {
         let res = match res {
             Res::Def(DefKind::Ctor(CtorOf::Variant, ..), variant_ctor_id) => {
-                let variant_id = self.tcx.parent(variant_ctor_id).unwrap();
+                let variant_id = self.tcx.parent(variant_ctor_id);
                 Res::Def(DefKind::Variant, variant_id)
             }
             res => res,
@@ -385,7 +385,7 @@ fn lower_variant_or_leaf(
 
         let mut kind = match res {
             Res::Def(DefKind::Variant, variant_id) => {
-                let enum_id = self.tcx.parent(variant_id).unwrap();
+                let enum_id = self.tcx.parent(variant_id);
                 let adt_def = self.tcx.adt_def(enum_id);
                 if adt_def.is_enum() {
                     let substs = match ty.kind() {
index 99735673f4d58fc6991a072ffe6a9e42bd61b687..209e6f7ac9fe41c98c605de5e70388e67f2d3306 100644 (file)
@@ -93,57 +93,83 @@ fn fmt_diff_with(&self, old: &Self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt
             };
         }
 
-        let mut first = true;
-        for idx in set_in_self.iter() {
-            let delim = if first {
-                "\u{001f}+"
-            } else if f.alternate() {
-                "\n\u{001f}+"
-            } else {
-                ", "
-            };
+        fmt_diff(&set_in_self, &cleared_in_self, ctxt, f)
+    }
+}
 
-            write!(f, "{}", delim)?;
-            idx.fmt_with(ctxt, f)?;
-            first = false;
-        }
+impl<T, C> DebugWithContext<C> for ChunkedBitSet<T>
+where
+    T: Idx + DebugWithContext<C>,
+{
+    fn fmt_with(&self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_set().entries(self.iter().map(|i| DebugWithAdapter { this: i, ctxt })).finish()
+    }
 
-        if !f.alternate() {
-            first = true;
-            if !set_in_self.is_empty() && !cleared_in_self.is_empty() {
-                write!(f, "\t")?;
-            }
-        }
+    fn fmt_diff_with(&self, old: &Self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let size = self.domain_size();
+        assert_eq!(size, old.domain_size());
 
-        for idx in cleared_in_self.iter() {
-            let delim = if first {
-                "\u{001f}-"
-            } else if f.alternate() {
-                "\n\u{001f}-"
-            } else {
-                ", "
-            };
+        let mut set_in_self = HybridBitSet::new_empty(size);
+        let mut cleared_in_self = HybridBitSet::new_empty(size);
 
-            write!(f, "{}", delim)?;
-            idx.fmt_with(ctxt, f)?;
-            first = false;
+        for i in (0..size).map(T::new) {
+            match (self.contains(i), old.contains(i)) {
+                (true, false) => set_in_self.insert(i),
+                (false, true) => cleared_in_self.insert(i),
+                _ => continue,
+            };
         }
 
-        Ok(())
+        fmt_diff(&set_in_self, &cleared_in_self, ctxt, f)
     }
 }
 
-impl<T, C> DebugWithContext<C> for ChunkedBitSet<T>
+fn fmt_diff<T, C>(
+    inserted: &HybridBitSet<T>,
+    removed: &HybridBitSet<T>,
+    ctxt: &C,
+    f: &mut fmt::Formatter<'_>,
+) -> fmt::Result
 where
     T: Idx + DebugWithContext<C>,
 {
-    fn fmt_with(&self, _ctxt: &C, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        unimplemented!("implement when/if needed");
+    let mut first = true;
+    for idx in inserted.iter() {
+        let delim = if first {
+            "\u{001f}+"
+        } else if f.alternate() {
+            "\n\u{001f}+"
+        } else {
+            ", "
+        };
+
+        write!(f, "{}", delim)?;
+        idx.fmt_with(ctxt, f)?;
+        first = false;
+    }
+
+    if !f.alternate() {
+        first = true;
+        if !inserted.is_empty() && !removed.is_empty() {
+            write!(f, "\t")?;
+        }
     }
 
-    fn fmt_diff_with(&self, _old: &Self, _ctxt: &C, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        unimplemented!("implement when/if needed");
+    for idx in removed.iter() {
+        let delim = if first {
+            "\u{001f}-"
+        } else if f.alternate() {
+            "\n\u{001f}-"
+        } else {
+            ", "
+        };
+
+        write!(f, "{}", delim)?;
+        idx.fmt_with(ctxt, f)?;
+        first = false;
     }
+
+    Ok(())
 }
 
 impl<T, C> DebugWithContext<C> for &'_ T
index 28a5a22dd9d5d1558acf329222a4366d26462e47..a245da658b9753b3fff83e77f130cfe9b50b3a0c 100644 (file)
@@ -57,6 +57,17 @@ fn may_be_reference(ty: Ty<'_>) -> bool {
     }
 }
 
+/// Determines whether or not this LocalDecl is temp, if not it needs retagging.
+fn is_not_temp<'tcx>(local_decl: &LocalDecl<'tcx>) -> bool {
+    if let Some(local_info) = &local_decl.local_info {
+        match local_info.as_ref() {
+            LocalInfo::DerefTemp => return false,
+            _ => (),
+        };
+    }
+    return true;
+}
+
 impl<'tcx> MirPass<'tcx> for AddRetag {
     fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
         sess.opts.debugging_opts.mir_emit_retag
@@ -71,7 +82,9 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         let needs_retag = |place: &Place<'tcx>| {
             // FIXME: Instead of giving up for unstable places, we should introduce
             // a temporary and retag on that.
-            is_stable(place.as_ref()) && may_be_reference(place.ty(&*local_decls, tcx).ty)
+            is_stable(place.as_ref())
+                && may_be_reference(place.ty(&*local_decls, tcx).ty)
+                && is_not_temp(&local_decls[place.local])
         };
         let place_base_raw = |place: &Place<'tcx>| {
             // If this is a `Deref`, get the type of what we are deref'ing.
index 1b4510b62206803d6b9a710bbaee2fb13db5fdc0..dde79214b16470e16b942d08992448172c2e1874 100644 (file)
@@ -70,6 +70,8 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
 
             TerminatorKind::Call { ref func, .. } => {
                 let func_ty = func.ty(self.body, self.tcx);
+                let func_id =
+                    if let ty::FnDef(func_id, _) = func_ty.kind() { Some(func_id) } else { None };
                 let sig = func_ty.fn_sig(self.tcx);
                 if let hir::Unsafety::Unsafe = sig.unsafety() {
                     self.require_unsafe(
@@ -78,7 +80,7 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
                     )
                 }
 
-                if let ty::FnDef(func_id, _) = func_ty.kind() {
+                if let Some(func_id) = func_id {
                     self.check_target_features(*func_id);
                 }
             }
index 13b49256d488a8f1b25c0c5168e00f0db8acd72e..691f4fb0e54259a29e5532a8f154274d76e59cc8 100644 (file)
@@ -313,9 +313,7 @@ struct ConstPropagator<'mir, 'tcx> {
     ecx: InterpCx<'mir, 'tcx, ConstPropMachine<'mir, 'tcx>>,
     tcx: TyCtxt<'tcx>,
     param_env: ParamEnv<'tcx>,
-    // FIXME(eddyb) avoid cloning this field more than once,
-    // by accessing it through `ecx` instead.
-    local_decls: IndexVec<Local, LocalDecl<'tcx>>,
+    local_decls: &'mir IndexVec<Local, LocalDecl<'tcx>>,
     // Because we have `MutVisitor` we can't obtain the `SourceInfo` from a `Location`. So we store
     // the last known `SourceInfo` here and just keep revisiting it.
     source_info: Option<SourceInfo>,
@@ -361,10 +359,6 @@ fn new(
         let substs = &InternalSubsts::identity_for_item(tcx, def_id);
         let param_env = tcx.param_env_reveal_all_normalized(def_id);
 
-        let span = tcx.def_span(def_id);
-        // FIXME: `CanConstProp::check` computes the layout of all locals, return those layouts
-        // so we can write them to `ecx.frame_mut().locals.layout, reducing the duplication in
-        // `layout_of` query invocations.
         let can_const_prop = CanConstProp::check(tcx, param_env, body);
         let mut only_propagate_inside_block_locals = BitSet::new_empty(can_const_prop.len());
         for (l, mode) in can_const_prop.iter_enumerated() {
@@ -374,7 +368,7 @@ fn new(
         }
         let mut ecx = InterpCx::new(
             tcx,
-            span,
+            tcx.def_span(def_id),
             param_env,
             ConstPropMachine::new(only_propagate_inside_block_locals, can_const_prop),
         );
@@ -405,10 +399,7 @@ fn new(
             ecx,
             tcx,
             param_env,
-            // FIXME(eddyb) avoid cloning this field more than once,
-            // by accessing it through `ecx` instead.
-            //FIXME(wesleywiser) we can't steal this because `Visitor::super_visit_body()` needs it
-            local_decls: body.local_decls.clone(),
+            local_decls: &dummy_body.local_decls,
             source_info: None,
         }
     }
@@ -511,7 +502,7 @@ fn check_binary_op(
             let r = r?;
             // We need the type of the LHS. We cannot use `place_layout` as that is the type
             // of the result, which for checked binops is not the same!
-            let left_ty = left.ty(&self.local_decls, self.tcx);
+            let left_ty = left.ty(self.local_decls, self.tcx);
             let left_size = self.ecx.layout_of(left_ty).ok()?.size;
             let right_size = r.layout.size;
             let r_bits = r.to_scalar().ok();
index d6331a88c5b7da31a7d4e3679a3afe37f8c92066..4945c10c9aaa900aa35f826435a2dd7f083ebd85 100644 (file)
@@ -308,10 +308,8 @@ struct ConstPropagator<'mir, 'tcx> {
     ecx: InterpCx<'mir, 'tcx, ConstPropMachine<'mir, 'tcx>>,
     tcx: TyCtxt<'tcx>,
     param_env: ParamEnv<'tcx>,
-    // FIXME(eddyb) avoid cloning these two fields more than once,
-    // by accessing them through `ecx` instead.
-    source_scopes: IndexVec<SourceScope, SourceScopeData<'tcx>>,
-    local_decls: IndexVec<Local, LocalDecl<'tcx>>,
+    source_scopes: &'mir IndexVec<SourceScope, SourceScopeData<'tcx>>,
+    local_decls: &'mir IndexVec<Local, LocalDecl<'tcx>>,
     // Because we have `MutVisitor` we can't obtain the `SourceInfo` from a `Location`. So we store
     // the last known `SourceInfo` here and just keep revisiting it.
     source_info: Option<SourceInfo>,
@@ -357,10 +355,6 @@ fn new(
         let substs = &InternalSubsts::identity_for_item(tcx, def_id);
         let param_env = tcx.param_env_reveal_all_normalized(def_id);
 
-        let span = tcx.def_span(def_id);
-        // FIXME: `CanConstProp::check` computes the layout of all locals, return those layouts
-        // so we can write them to `ecx.frame_mut().locals.layout, reducing the duplication in
-        // `layout_of` query invocations.
         let can_const_prop = CanConstProp::check(tcx, param_env, body);
         let mut only_propagate_inside_block_locals = BitSet::new_empty(can_const_prop.len());
         for (l, mode) in can_const_prop.iter_enumerated() {
@@ -370,7 +364,7 @@ fn new(
         }
         let mut ecx = InterpCx::new(
             tcx,
-            span,
+            tcx.def_span(def_id),
             param_env,
             ConstPropMachine::new(only_propagate_inside_block_locals, can_const_prop),
         );
@@ -401,11 +395,8 @@ fn new(
             ecx,
             tcx,
             param_env,
-            // FIXME(eddyb) avoid cloning these two fields more than once,
-            // by accessing them through `ecx` instead.
-            source_scopes: body.source_scopes.clone(),
-            //FIXME(wesleywiser) we can't steal this because `Visitor::super_visit_body()` needs it
-            local_decls: body.local_decls.clone(),
+            source_scopes: &dummy_body.source_scopes,
+            local_decls: &dummy_body.local_decls,
             source_info: None,
         }
     }
@@ -435,7 +426,7 @@ fn remove_const(ecx: &mut InterpCx<'mir, 'tcx, ConstPropMachine<'mir, 'tcx>>, lo
     }
 
     fn lint_root(&self, source_info: SourceInfo) -> Option<HirId> {
-        source_info.scope.lint_root(&self.source_scopes)
+        source_info.scope.lint_root(self.source_scopes)
     }
 
     fn use_ecx<F, T>(&mut self, f: F) -> Option<T>
@@ -572,7 +563,7 @@ fn check_binary_op(
             let r = r?;
             // We need the type of the LHS. We cannot use `place_layout` as that is the type
             // of the result, which for checked binops is not the same!
-            let left_ty = left.ty(&self.local_decls, self.tcx);
+            let left_ty = left.ty(self.local_decls, self.tcx);
             let left_size = self.ecx.layout_of(left_ty).ok()?.size;
             let right_size = r.layout.size;
             let r_bits = r.to_scalar().ok();
index 24b626ad96658080859d6c7e0d04c540b1b03495..57a95a67df70c94aade44db653832f7c30677d3a 100644 (file)
@@ -1,68 +1,92 @@
 use crate::MirPass;
+use rustc_index::vec::IndexVec;
 use rustc_middle::mir::patch::MirPatch;
+use rustc_middle::mir::visit::{MutVisitor, PlaceContext};
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
 pub struct Derefer;
 
-pub fn deref_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-    let mut patch = MirPatch::new(body);
-    let (basic_blocks, local_decl) = body.basic_blocks_and_local_decls_mut();
-    for (block, data) in basic_blocks.iter_enumerated_mut() {
-        for (i, stmt) in data.statements.iter_mut().enumerate() {
-            match stmt.kind {
-                StatementKind::Assign(box (og_place, Rvalue::Ref(region, borrow_knd, place))) => {
-                    let mut place_local = place.local;
-                    let mut last_len = 0;
-                    for (idx, (p_ref, p_elem)) in place.iter_projections().enumerate() {
-                        if p_elem == ProjectionElem::Deref && !p_ref.projection.is_empty() {
-                            // The type that we are derefing.
-                            let ty = p_ref.ty(local_decl, tcx).ty;
-                            let temp = patch.new_temp(ty, stmt.source_info.span);
-
-                            // Because we are assigning this right before original statement
-                            // we are using index i of statement.
-                            let loc = Location { block: block, statement_index: i };
-                            patch.add_statement(loc, StatementKind::StorageLive(temp));
-
-                            // We are adding current p_ref's projections to our
-                            // temp value, excluding projections we already covered.
-                            let deref_place = Place::from(place_local)
-                                .project_deeper(&p_ref.projection[last_len..], tcx);
-                            patch.add_assign(
-                                loc,
-                                Place::from(temp),
-                                Rvalue::Use(Operand::Move(deref_place)),
-                            );
-
-                            place_local = temp;
-                            last_len = p_ref.projection.len();
-
-                            // We are creating a place by using our temp value's location
-                            // and copying derefed values which we need to create new statement.
-                            let temp_place =
-                                Place::from(temp).project_deeper(&place.projection[idx..], tcx);
-                            let new_stmt = Statement {
-                                source_info: stmt.source_info,
-                                kind: StatementKind::Assign(Box::new((
-                                    og_place,
-                                    Rvalue::Ref(region, borrow_knd, temp_place),
-                                ))),
-                            };
-
-                            // Replace current statement with newly created one.
-                            *stmt = new_stmt;
-
-                            // Since our job with the temp is done it should be gone
-                            let loc = Location { block: block, statement_index: i + 1 };
-                            patch.add_statement(loc, StatementKind::StorageDead(temp));
-                        }
-                    }
+pub struct DerefChecker<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    patcher: MirPatch<'tcx>,
+    local_decls: IndexVec<Local, LocalDecl<'tcx>>,
+}
+
+impl<'tcx> MutVisitor<'tcx> for DerefChecker<'tcx> {
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
+    fn visit_place(&mut self, place: &mut Place<'tcx>, _: PlaceContext, loc: Location) {
+        let mut place_local = place.local;
+        let mut last_len = 0;
+        let mut last_deref_idx = 0;
+
+        let mut prev_temp: Option<Local> = None;
+
+        for (idx, (p_ref, p_elem)) in place.iter_projections().enumerate() {
+            if p_elem == ProjectionElem::Deref && !p_ref.projection.is_empty() {
+                last_deref_idx = idx;
+            }
+        }
+
+        for (idx, (p_ref, p_elem)) in place.iter_projections().enumerate() {
+            if p_elem == ProjectionElem::Deref && !p_ref.projection.is_empty() {
+                let ty = p_ref.ty(&self.local_decls, self.tcx).ty;
+                let temp = self.patcher.new_local_with_info(
+                    ty,
+                    self.local_decls[p_ref.local].source_info.span,
+                    Some(Box::new(LocalInfo::DerefTemp)),
+                );
+
+                self.patcher.add_statement(loc, StatementKind::StorageLive(temp));
+
+                // We are adding current p_ref's projections to our
+                // temp value, excluding projections we already covered.
+                let deref_place = Place::from(place_local)
+                    .project_deeper(&p_ref.projection[last_len..], self.tcx);
+
+                self.patcher.add_assign(
+                    loc,
+                    Place::from(temp),
+                    Rvalue::Use(Operand::Move(deref_place)),
+                );
+                place_local = temp;
+                last_len = p_ref.projection.len();
+
+                // Change `Place` only if we are actually at the Place's last deref
+                if idx == last_deref_idx {
+                    let temp_place =
+                        Place::from(temp).project_deeper(&place.projection[idx..], self.tcx);
+                    *place = temp_place;
+                }
+
+                // We are destroying the previous temp since it's no longer used.
+                if let Some(prev_temp) = prev_temp {
+                    self.patcher.add_statement(loc, StatementKind::StorageDead(prev_temp));
                 }
-                _ => (),
+
+                prev_temp = Some(temp);
             }
         }
+
+        // Since we won't be able to reach final temp, we destroy it outside the loop.
+        if let Some(prev_temp) = prev_temp {
+            let last_loc = Location { block: loc.block, statement_index: loc.statement_index + 1 };
+            self.patcher.add_statement(last_loc, StatementKind::StorageDead(prev_temp));
+        }
     }
-    patch.apply(body);
+}
+
+pub fn deref_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+    let patch = MirPatch::new(body);
+    let mut checker = DerefChecker { tcx, patcher: patch, local_decls: body.local_decls.clone() };
+
+    for (bb, data) in body.basic_blocks_mut().iter_enumerated_mut() {
+        checker.visit_basic_block_data(bb, data);
+    }
+
+    checker.patcher.apply(body);
 }
 
 impl<'tcx> MirPass<'tcx> for Derefer {
index 5bde0c01412ac3106ff9009af281b1d20b158786..33f201cbd28326bb92ff61547a2f22ef2f9db410 100644 (file)
@@ -336,9 +336,7 @@ fn evaluate_candidate<'tcx>(
             Some(poss)
         }
     };
-    let Some((_, child)) = targets.iter().next() else {
-        return None
-    };
+    let (_, child) = targets.iter().next()?;
     let child_terminator = &bbs[child].terminator();
     let TerminatorKind::SwitchInt {
         switch_ty: child_ty,
index d395ccd3819336640da691dd9f6628c72b4845d5..40cc6dafe6177c11aecc7e93df64baff07895c7d 100644 (file)
@@ -426,13 +426,13 @@ fn run_post_borrowck_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tc
         &add_moves_for_packed_drops::AddMovesForPackedDrops,
         // `AddRetag` needs to run after `ElaborateDrops`. Otherwise it should run fairly late,
         // but before optimizations begin.
+        &deref_separator::Derefer,
         &add_retag::AddRetag,
         &lower_intrinsics::LowerIntrinsics,
         &simplify::SimplifyCfg::new("elaborate-drops"),
         // `Deaggregator` is conceptually part of MIR building, some backends rely on it happening
         // and it can help optimizations.
         &deaggregator::Deaggregator,
-        &deref_separator::Derefer,
         &Lint(const_prop_lint::ConstProp),
     ];
 
index 740a2168b41cc52865c92782309d41f5beeb2331..2380391d09a914042e3b83e77c740543c1077175 100644 (file)
@@ -77,17 +77,30 @@ pub fn run_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, passes: &[&dyn
     let mut cnt = 0;
 
     let validate = tcx.sess.opts.debugging_opts.validate_mir;
+    let overridden_passes = &tcx.sess.opts.debugging_opts.mir_enable_passes;
+    trace!(?overridden_passes);
 
     if validate {
         validate_body(tcx, body, format!("start of phase transition from {:?}", start_phase));
     }
 
     for pass in passes {
-        if !pass.is_enabled(&tcx.sess) {
-            continue;
-        }
-
         let name = pass.name();
+
+        if let Some((_, polarity)) = overridden_passes.iter().rev().find(|(s, _)| s == &*name) {
+            trace!(
+                pass = %name,
+                "{} as requested by flag",
+                if *polarity { "Running" } else { "Not running" },
+            );
+            if !polarity {
+                continue;
+            }
+        } else {
+            if !pass.is_enabled(&tcx.sess) {
+                continue;
+            }
+        }
         let dump_enabled = pass.is_mir_dump_enabled();
 
         if dump_enabled {
index 0e0a4fbc2155641b87a080983c72fae181044db1..1828aecb375c4fdcc9943cb5542e8908f7adf104 100644 (file)
 use rustc_data_structures::sync::{par_iter, MTLock, MTRef, ParallelIterator};
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
-use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId};
 use rustc_hir::lang_items::LangItem;
 use rustc_index::bit_set::GrowableBitSet;
 use rustc_middle::mir::interpret::{AllocId, ConstValue};
@@ -393,6 +393,7 @@ fn collect_items_rec<'tcx>(
     // error count. If it has changed, a PME occurred, and we trigger some diagnostics about the
     // current step of mono items collection.
     //
+    // FIXME: don't rely on global state, instead bubble up errors. Note: this is very hard to do.
     let error_count = tcx.sess.diagnostic().err_count();
 
     match starting_point.node {
@@ -473,12 +474,9 @@ fn collect_items_rec<'tcx>(
     }
 
     // Check for PMEs and emit a diagnostic if one happened. To try to show relevant edges of the
-    // mono item graph where the PME diagnostics are currently the most problematic (e.g. ones
-    // involving a dependency, and the lack of context is confusing) in this MVP, we focus on
-    // diagnostics on edges crossing a crate boundary: the collected mono items which are not
-    // defined in the local crate.
+    // mono item graph.
     if tcx.sess.diagnostic().err_count() > error_count
-        && starting_point.node.krate() != LOCAL_CRATE
+        && starting_point.node.is_generic_fn()
         && starting_point.node.is_user_defined()
     {
         let formatted_item = with_no_trimmed_paths!(starting_point.node.to_string());
index 167741988798862b79e05f008190fa65b38f46ae..320765e7af34ad2c3f62a77bb3b05a4cb7df67db 100644 (file)
@@ -5,7 +5,7 @@
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_hir::definitions::DefPathDataName;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
-use rustc_middle::middle::exported_symbols::SymbolExportLevel;
+use rustc_middle::middle::exported_symbols::{SymbolExportInfo, SymbolExportLevel};
 use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, Linkage, Visibility};
 use rustc_middle::mir::mono::{InstantiationMode, MonoItem};
 use rustc_middle::ty::print::characteristic_def_id_of_type;
@@ -352,7 +352,7 @@ fn compute_codegen_unit_name(
             cgu_def_id = None;
         }
 
-        current_def_id = tcx.parent(current_def_id).unwrap();
+        current_def_id = tcx.parent(current_def_id);
     }
 
     let cgu_def_id = cgu_def_id.unwrap();
@@ -554,7 +554,7 @@ fn default_visibility(tcx: TyCtxt<'_>, id: DefId, is_generic: bool) -> Visibilit
     // C-export level items remain at `Default`, all other internal
     // items become `Hidden`.
     match tcx.reachable_non_generics(id.krate).get(&id) {
-        Some(SymbolExportLevel::C) => Visibility::Default,
+        Some(SymbolExportInfo { level: SymbolExportLevel::C, .. }) => Visibility::Default,
         _ => Visibility::Hidden,
     }
 }
index a823607ab0ec2191c86a3630fd2488d0c9198fb2..c6ca260e9831e184b2b9d366ab019cfd0567b1d3 100644 (file)
@@ -13,6 +13,7 @@ rustc_ast_pretty = { path = "../rustc_ast_pretty" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_feature = { path = "../rustc_feature" }
 rustc_lexer = { path = "../rustc_lexer" }
+rustc_macros = { path = "../rustc_macros" }
 rustc_errors = { path = "../rustc_errors" }
 rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
index bfa13ce79bab47c99c376d857ea671ffbbb90d3c..ee54dd44f7194e7fc48ec1291e5f54a0578f5527 100644 (file)
@@ -1,6 +1,6 @@
 use crate::lexer::unicode_chars::UNICODE_ARRAY;
 use rustc_ast::ast::{self, AttrStyle};
-use rustc_ast::token::{self, CommentKind, Token, TokenKind};
+use rustc_ast::token::{self, CommentKind, Delimiter, Token, TokenKind};
 use rustc_ast::tokenstream::{Spacing, TokenStream};
 use rustc_ast::util::unicode::contains_text_flow_control_chars;
 use rustc_errors::{error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, PResult};
@@ -24,8 +24,8 @@
 
 #[derive(Clone, Debug)]
 pub struct UnmatchedBrace {
-    pub expected_delim: token::DelimToken,
-    pub found_delim: Option<token::DelimToken>,
+    pub expected_delim: Delimiter,
+    pub found_delim: Option<Delimiter>,
     pub found_span: Span,
     pub unclosed_span: Option<Span>,
     pub candidate_span: Option<Span>,
@@ -284,12 +284,12 @@ fn cook_lexer_token(&self, token: rustc_lexer::TokenKind, start: BytePos) -> Opt
             rustc_lexer::TokenKind::Semi => token::Semi,
             rustc_lexer::TokenKind::Comma => token::Comma,
             rustc_lexer::TokenKind::Dot => token::Dot,
-            rustc_lexer::TokenKind::OpenParen => token::OpenDelim(token::Paren),
-            rustc_lexer::TokenKind::CloseParen => token::CloseDelim(token::Paren),
-            rustc_lexer::TokenKind::OpenBrace => token::OpenDelim(token::Brace),
-            rustc_lexer::TokenKind::CloseBrace => token::CloseDelim(token::Brace),
-            rustc_lexer::TokenKind::OpenBracket => token::OpenDelim(token::Bracket),
-            rustc_lexer::TokenKind::CloseBracket => token::CloseDelim(token::Bracket),
+            rustc_lexer::TokenKind::OpenParen => token::OpenDelim(Delimiter::Parenthesis),
+            rustc_lexer::TokenKind::CloseParen => token::CloseDelim(Delimiter::Parenthesis),
+            rustc_lexer::TokenKind::OpenBrace => token::OpenDelim(Delimiter::Brace),
+            rustc_lexer::TokenKind::CloseBrace => token::CloseDelim(Delimiter::Brace),
+            rustc_lexer::TokenKind::OpenBracket => token::OpenDelim(Delimiter::Bracket),
+            rustc_lexer::TokenKind::CloseBracket => token::CloseDelim(Delimiter::Bracket),
             rustc_lexer::TokenKind::At => token::At,
             rustc_lexer::TokenKind::Pound => token::Pound,
             rustc_lexer::TokenKind::Tilde => token::Tilde,
@@ -612,14 +612,14 @@ fn report_unknown_prefix(&self, start: BytePos) {
                 err.span_suggestion_verbose(
                     prefix_span,
                     "use `br` for a raw byte string",
-                    "br".to_string(),
+                    "br",
                     Applicability::MaybeIncorrect,
                 );
             } else if expn_data.is_root() {
                 err.span_suggestion_verbose(
                     prefix_span.shrink_to_hi(),
                     "consider inserting whitespace here",
-                    " ".into(),
+                    " ",
                     Applicability::MaybeIncorrect,
                 );
             }
index 8318aec8726dc801a19d906ed84e259aebab00fe..ef84f95ec838010de72bb0b6c34067f62285eae7 100644 (file)
@@ -1,6 +1,6 @@
 use super::{StringReader, UnmatchedBrace};
 
-use rustc_ast::token::{self, DelimToken, Token};
+use rustc_ast::token::{self, Delimiter, Token};
 use rustc_ast::tokenstream::{
     DelimSpan,
     Spacing::{self, *},
@@ -32,15 +32,15 @@ struct TokenTreesReader<'a> {
     string_reader: StringReader<'a>,
     token: Token,
     /// Stack of open delimiters and their spans. Used for error message.
-    open_braces: Vec<(token::DelimToken, Span)>,
+    open_braces: Vec<(Delimiter, Span)>,
     unmatched_braces: Vec<UnmatchedBrace>,
     /// The type and spans for all braces
     ///
     /// Used only for error recovery when arriving to EOF with mismatched braces.
-    matching_delim_spans: Vec<(token::DelimToken, Span, Span)>,
+    matching_delim_spans: Vec<(Delimiter, Span, Span)>,
     last_unclosed_found_span: Option<Span>,
     /// Collect empty block spans that might have been auto-inserted by editors.
-    last_delim_empty_block_spans: FxHashMap<token::DelimToken, Span>,
+    last_delim_empty_block_spans: FxHashMap<Delimiter, Span>,
     /// Collect the spans of braces (Open, Close). Used only
     /// for detecting if blocks are empty and only braces.
     matching_block_spans: Vec<(Span, Span)>,
@@ -88,7 +88,7 @@ fn parse_token_tree(&mut self) -> PResult<'a, TreeAndSpacing> {
                 for &(_, sp) in &self.open_braces {
                     err.span_label(sp, "unclosed delimiter");
                     self.unmatched_braces.push(UnmatchedBrace {
-                        expected_delim: token::DelimToken::Brace,
+                        expected_delim: Delimiter::Brace,
                         found_delim: None,
                         found_span: self.token.span,
                         unclosed_span: Some(sp),
@@ -150,7 +150,7 @@ fn parse_token_tree(&mut self) -> PResult<'a, TreeAndSpacing> {
                         }
 
                         //only add braces
-                        if let (DelimToken::Brace, DelimToken::Brace) = (open_brace, delim) {
+                        if let (Delimiter::Brace, Delimiter::Brace) = (open_brace, delim) {
                             self.matching_block_spans.push((open_brace_span, close_brace_span));
                         }
 
index 1d63b79adc53a8a93040303b125378f40f132fcb..faa686c3e57a335f5211575bcb5d1d42f129be50 100644 (file)
@@ -2,7 +2,7 @@
 // https://www.unicode.org/Public/security/10.0.0/confusables.txt
 
 use super::StringReader;
-use crate::token;
+use crate::token::{self, Delimiter};
 use rustc_errors::{Applicability, Diagnostic};
 use rustc_span::{symbol::kw, BytePos, Pos, Span};
 
     ('!', "Exclamation Mark", Some(token::Not)),
     ('?', "Question Mark", Some(token::Question)),
     ('.', "Period", Some(token::Dot)),
-    ('(', "Left Parenthesis", Some(token::OpenDelim(token::Paren))),
-    (')', "Right Parenthesis", Some(token::CloseDelim(token::Paren))),
-    ('[', "Left Square Bracket", Some(token::OpenDelim(token::Bracket))),
-    (']', "Right Square Bracket", Some(token::CloseDelim(token::Bracket))),
-    ('{', "Left Curly Brace", Some(token::OpenDelim(token::Brace))),
-    ('}', "Right Curly Brace", Some(token::CloseDelim(token::Brace))),
+    ('(', "Left Parenthesis", Some(token::OpenDelim(Delimiter::Parenthesis))),
+    (')', "Right Parenthesis", Some(token::CloseDelim(Delimiter::Parenthesis))),
+    ('[', "Left Square Bracket", Some(token::OpenDelim(Delimiter::Bracket))),
+    (']', "Right Square Bracket", Some(token::CloseDelim(Delimiter::Bracket))),
+    ('{', "Left Curly Brace", Some(token::OpenDelim(Delimiter::Brace))),
+    ('}', "Right Curly Brace", Some(token::CloseDelim(Delimiter::Brace))),
     ('*', "Asterisk", Some(token::BinOp(token::Star))),
     ('/', "Slash", Some(token::BinOp(token::Slash))),
     ('\\', "Backslash", None),
@@ -338,9 +338,7 @@ pub(super) fn check_for_substitution<'a>(
     ch: char,
     err: &mut Diagnostic,
 ) -> Option<token::TokenKind> {
-    let Some(&(_u_char, u_name, ascii_char)) = UNICODE_ARRAY.iter().find(|&&(c, _, _)| c == ch) else {
-        return None;
-    };
+    let &(_u_char, u_name, ascii_char) = UNICODE_ARRAY.iter().find(|&&(c, _, _)| c == ch)?;
 
     let span = Span::with_root_ctxt(pos, pos + Pos::from_usize(ch.len_utf8()));
 
index 1724bab5caa430f7d64a34ccecf0190d2260c1bb..358b01df3b983523d00191c26fe7469ec4970881 100644 (file)
@@ -1,7 +1,7 @@
 use super::{AttrWrapper, Capturing, FnParseMode, ForceCollect, Parser, PathStyle};
 use rustc_ast as ast;
 use rustc_ast::attr;
-use rustc_ast::token::{self, Nonterminal};
+use rustc_ast::token::{self, Delimiter, Nonterminal};
 use rustc_ast_pretty::pprust;
 use rustc_errors::{error_code, Diagnostic, PResult};
 use rustc_span::{sym, BytePos, Span};
@@ -130,9 +130,9 @@ pub fn parse_attribute(
                     ast::AttrStyle::Outer
                 };
 
-                this.expect(&token::OpenDelim(token::Bracket))?;
+                this.expect(&token::OpenDelim(Delimiter::Bracket))?;
                 let item = this.parse_attr_item(false)?;
-                this.expect(&token::CloseDelim(token::Bracket))?;
+                this.expect(&token::CloseDelim(Delimiter::Bracket))?;
                 let attr_sp = lo.to(this.prev_token.span);
 
                 // Emit error if inner attribute is encountered and forbidden.
@@ -403,7 +403,7 @@ pub fn parse_meta_item(&mut self) -> PResult<'a, ast::MetaItem> {
     crate fn parse_meta_item_kind(&mut self) -> PResult<'a, ast::MetaItemKind> {
         Ok(if self.eat(&token::Eq) {
             ast::MetaItemKind::NameValue(self.parse_unsuffixed_lit()?)
-        } else if self.check(&token::OpenDelim(token::Paren)) {
+        } else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) {
             // Matches `meta_seq = ( COMMASEP(meta_item_inner) )`.
             let (list, _) = self.parse_paren_comma_seq(|p| p.parse_meta_item_inner())?;
             ast::MetaItemKind::List(list)
index 5ee9c339bb7aa9067c5d24726f65110b2a78fd8b..a12621564ab703e182a22d905127bf1d75b68860 100644 (file)
@@ -1,11 +1,11 @@
 use super::{Capturing, FlatToken, ForceCollect, Parser, ReplaceRange, TokenCursor, TrailingToken};
-use rustc_ast::token::{self, DelimToken, Token, TokenKind};
+use rustc_ast::token::{self, Delimiter, Token, TokenKind};
 use rustc_ast::tokenstream::{AttrAnnotatedTokenStream, AttributesData, CreateTokenStream};
 use rustc_ast::tokenstream::{AttrAnnotatedTokenTree, DelimSpan, LazyTokenStream, Spacing};
 use rustc_ast::{self as ast};
 use rustc_ast::{AstLike, AttrVec, Attribute};
 use rustc_errors::PResult;
-use rustc_span::{sym, Span, DUMMY_SP};
+use rustc_span::{sym, Span};
 
 use std::convert::TryInto;
 use std::ops::Range;
@@ -100,21 +100,16 @@ struct LazyTokenStreamImpl {
 
 impl CreateTokenStream for LazyTokenStreamImpl {
     fn create_token_stream(&self) -> AttrAnnotatedTokenStream {
-        // The token produced by the final call to `{,inlined_}next` or
-        // `{,inlined_}next_desugared` was not actually consumed by the
-        // callback. The combination of chaining the initial token and using
-        // `take` produces the desired result - we produce an empty
-        // `TokenStream` if no calls were made, and omit the final token
-        // otherwise.
+        // The token produced by the final call to `{,inlined_}next` was not
+        // actually consumed by the callback. The combination of chaining the
+        // initial token and using `take` produces the desired result - we
+        // produce an empty `TokenStream` if no calls were made, and omit the
+        // final token otherwise.
         let mut cursor_snapshot = self.cursor_snapshot.clone();
         let tokens =
             std::iter::once((FlatToken::Token(self.start_token.0.clone()), self.start_token.1))
                 .chain((0..self.num_calls).map(|_| {
-                    let token = if cursor_snapshot.desugar_doc_comments {
-                        cursor_snapshot.next_desugared()
-                    } else {
-                        cursor_snapshot.next()
-                    };
+                    let token = cursor_snapshot.next(cursor_snapshot.desugar_doc_comments);
                     (FlatToken::Token(token.0), token.1)
                 }))
                 .take(self.num_calls);
@@ -393,11 +388,11 @@ pub fn collect_tokens_trailing_token<R: AstLike>(
 /// Converts a flattened iterator of tokens (including open and close delimiter tokens)
 /// into a `TokenStream`, creating a `TokenTree::Delimited` for each matching pair
 /// of open and close delims.
-// FIXME(#67062): Currently, we don't parse `None`-delimited groups correctly,
-// which can cause us to end up with mismatched `None` delimiters in our
+// FIXME(#67062): Currently, we don't parse `Invisible`-delimited groups correctly,
+// which can cause us to end up with mismatched `Invisible` delimiters in our
 // captured tokens. This function contains several hacks to work around this -
-// essentially, we throw away mismatched `None` delimiters when we encounter them.
-// Once we properly parse `None` delimiters, they can be captured just like any
+// essentially, we throw away mismatched `Invisible` delimiters when we encounter them.
+// Once we properly parse `Invisible` delimiters, they can be captured just like any
 // other tokens, and these hacks can be removed.
 fn make_token_stream(
     mut iter: impl Iterator<Item = (FlatToken, Spacing)>,
@@ -405,24 +400,26 @@ fn make_token_stream(
 ) -> AttrAnnotatedTokenStream {
     #[derive(Debug)]
     struct FrameData {
-        open: Span,
-        open_delim: DelimToken,
+        // This is `None` for the first frame, `Some` for all others.
+        open_delim_sp: Option<(Delimiter, Span)>,
         inner: Vec<(AttrAnnotatedTokenTree, Spacing)>,
     }
-    let mut stack =
-        vec![FrameData { open: DUMMY_SP, open_delim: DelimToken::NoDelim, inner: vec![] }];
+    let mut stack = vec![FrameData { open_delim_sp: None, inner: vec![] }];
     let mut token_and_spacing = iter.next();
     while let Some((token, spacing)) = token_and_spacing {
         match token {
             FlatToken::Token(Token { kind: TokenKind::OpenDelim(delim), span }) => {
-                stack.push(FrameData { open: span, open_delim: delim, inner: vec![] });
+                stack.push(FrameData { open_delim_sp: Some((delim, span)), inner: vec![] });
             }
             FlatToken::Token(Token { kind: TokenKind::CloseDelim(delim), span }) => {
-                // HACK: If we encounter a mismatched `None` delimiter at the top
+                // HACK: If we encounter a mismatched `Invisible` delimiter at the top
                 // level, just ignore it.
-                if matches!(delim, DelimToken::NoDelim)
+                if matches!(delim, Delimiter::Invisible)
                     && (stack.len() == 1
-                        || !matches!(stack.last_mut().unwrap().open_delim, DelimToken::NoDelim))
+                        || !matches!(
+                            stack.last_mut().unwrap().open_delim_sp.unwrap().0,
+                            Delimiter::Invisible
+                        ))
                 {
                     token_and_spacing = iter.next();
                     continue;
@@ -431,11 +428,11 @@ struct FrameData {
                     .pop()
                     .unwrap_or_else(|| panic!("Token stack was empty for token: {:?}", token));
 
-                // HACK: If our current frame has a mismatched opening `None` delimiter,
+                // HACK: If our current frame has a mismatched opening `Invisible` delimiter,
                 // merge our current frame with the one above it. That is, transform
                 // `[ { < first second } third ]` into `[ { first second } third ]`
-                if !matches!(delim, DelimToken::NoDelim)
-                    && matches!(frame_data.open_delim, DelimToken::NoDelim)
+                if !matches!(delim, Delimiter::Invisible)
+                    && matches!(frame_data.open_delim_sp.unwrap().0, Delimiter::Invisible)
                 {
                     stack.last_mut().unwrap().inner.extend(frame_data.inner);
                     // Process our closing delimiter again, this time at the previous
@@ -444,12 +441,13 @@ struct FrameData {
                     continue;
                 }
 
+                let (open_delim, open_sp) = frame_data.open_delim_sp.unwrap();
                 assert_eq!(
-                    frame_data.open_delim, delim,
+                    open_delim, delim,
                     "Mismatched open/close delims: open={:?} close={:?}",
-                    frame_data.open, span
+                    open_delim, span
                 );
-                let dspan = DelimSpan::from_pair(frame_data.open, span);
+                let dspan = DelimSpan::from_pair(open_sp, span);
                 let stream = AttrAnnotatedTokenStream::new(frame_data.inner);
                 let delimited = AttrAnnotatedTokenTree::Delimited(dspan, delim, stream);
                 stack
@@ -474,10 +472,10 @@ struct FrameData {
         }
         token_and_spacing = iter.next();
     }
-    // HACK: If we don't have a closing `None` delimiter for our last
+    // HACK: If we don't have a closing `Invisible` delimiter for our last
     // frame, merge the frame with the top-level frame. That is,
     // turn `< first second` into `first second`
-    if stack.len() == 2 && stack[1].open_delim == DelimToken::NoDelim {
+    if stack.len() == 2 && stack[1].open_delim_sp.unwrap().0 == Delimiter::Invisible {
         let temp_buf = stack.pop().unwrap();
         stack.last_mut().unwrap().inner.extend(temp_buf.inner);
     }
index ed2640451705b6080e89b48cfc58e9b69dd2bd47..beffbdc5de4101c3bbd421f4e6433468df5e4f10 100644 (file)
@@ -8,7 +8,7 @@
 use crate::lexer::UnmatchedBrace;
 use rustc_ast as ast;
 use rustc_ast::ptr::P;
-use rustc_ast::token::{self, Lit, LitKind, TokenKind};
+use rustc_ast::token::{self, Delimiter, Lit, LitKind, TokenKind};
 use rustc_ast::util::parser::AssocOp;
 use rustc_ast::{
     AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec, BinOpKind, BindingMode, Block,
@@ -21,6 +21,7 @@
 use rustc_errors::{
     Applicability, DiagnosticBuilder, DiagnosticMessage, Handler, MultiSpan, PResult,
 };
+use rustc_macros::SessionDiagnostic;
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{kw, Ident};
 use rustc_span::{Span, SpanSnippetError, DUMMY_SP};
@@ -241,6 +242,16 @@ fn emit_many<G: EmissionGuarantee>(
         err.multipart_suggestions(msg, suggestions.map(|s| s.patches), applicability);
     }
 }
+
+#[derive(SessionDiagnostic)]
+#[error(slug = "parser-maybe-report-ambiguous-plus")]
+struct AmbiguousPlus {
+    pub sum_ty: String,
+    #[primary_span]
+    #[suggestion(code = "({sum_ty})")]
+    pub span: Span,
+}
+
 // SnapshotParser is used to create a snapshot of the parser
 // without causing duplicate errors being emitted when the `Parser`
 // is dropped.
@@ -326,10 +337,10 @@ pub(super) fn expected_ident_found(&self) -> DiagnosticBuilder<'a, ErrorGuarante
             TokenKind::Comma,
             TokenKind::Semi,
             TokenKind::ModSep,
-            TokenKind::OpenDelim(token::DelimToken::Brace),
-            TokenKind::OpenDelim(token::DelimToken::Paren),
-            TokenKind::CloseDelim(token::DelimToken::Brace),
-            TokenKind::CloseDelim(token::DelimToken::Paren),
+            TokenKind::OpenDelim(Delimiter::Brace),
+            TokenKind::OpenDelim(Delimiter::Parenthesis),
+            TokenKind::CloseDelim(Delimiter::Brace),
+            TokenKind::CloseDelim(Delimiter::Parenthesis),
         ];
         match self.token.ident() {
             Some((ident, false))
@@ -402,7 +413,7 @@ fn tokens_to_string(tokens: &[TokenType]) -> String {
             } else if !sm.is_multiline(self.prev_token.span.until(self.token.span)) {
                 // The current token is in the same line as the prior token, not recoverable.
             } else if [token::Comma, token::Colon].contains(&self.token.kind)
-                && self.prev_token.kind == token::CloseDelim(token::Paren)
+                && self.prev_token.kind == token::CloseDelim(Delimiter::Parenthesis)
             {
                 // Likely typo: The current token is on a new line and is expected to be
                 // `.`, `;`, `?`, or an operator after a close delimiter token.
@@ -413,7 +424,7 @@ fn tokens_to_string(tokens: &[TokenType]) -> String {
                 //         ^
                 // https://github.com/rust-lang/rust/issues/72253
             } else if self.look_ahead(1, |t| {
-                t == &token::CloseDelim(token::Brace)
+                t == &token::CloseDelim(Delimiter::Brace)
                     || t.can_begin_expr() && t.kind != token::Colon
             }) && [token::Comma, token::Colon].contains(&self.token.kind)
             {
@@ -430,11 +441,12 @@ fn tokens_to_string(tokens: &[TokenType]) -> String {
                     .emit();
                 return Ok(true);
             } else if self.look_ahead(0, |t| {
-                t == &token::CloseDelim(token::Brace)
-                    || (
-                        t.can_begin_expr() && t != &token::Semi && t != &token::Pound
-                        // Avoid triggering with too many trailing `#` in raw string.
-                    )
+                t == &token::CloseDelim(Delimiter::Brace)
+                    || (t.can_begin_expr() && t != &token::Semi && t != &token::Pound)
+                    // Avoid triggering with too many trailing `#` in raw string.
+                    || (sm.is_multiline(
+                        self.prev_token.span.shrink_to_hi().until(self.token.span.shrink_to_lo())
+                    ) && t == &token::Pound)
             }) {
                 // Missing semicolon typo. This is triggered if the next token could either start a
                 // new statement or is a block close. For example:
@@ -508,7 +520,12 @@ fn tokens_to_string(tokens: &[TokenType]) -> String {
         }
 
         if self.check_too_many_raw_str_terminators(&mut err) {
-            return Err(err);
+            if expected.contains(&TokenType::Token(token::Semi)) && self.eat(&token::Semi) {
+                err.emit();
+                return Ok(true);
+            } else {
+                return Err(err);
+            }
         }
 
         if self.prev_token.span == DUMMY_SP {
@@ -538,6 +555,7 @@ fn tokens_to_string(tokens: &[TokenType]) -> String {
     }
 
     fn check_too_many_raw_str_terminators(&mut self, err: &mut Diagnostic) -> bool {
+        let sm = self.sess.source_map();
         match (&self.prev_token.kind, &self.token.kind) {
             (
                 TokenKind::Literal(Lit {
@@ -545,15 +563,33 @@ fn check_too_many_raw_str_terminators(&mut self, err: &mut Diagnostic) -> bool {
                     ..
                 }),
                 TokenKind::Pound,
-            ) => {
+            ) if !sm.is_multiline(
+                self.prev_token.span.shrink_to_hi().until(self.token.span.shrink_to_lo()),
+            ) =>
+            {
+                let n_hashes: u8 = *n_hashes;
                 err.set_primary_message("too many `#` when terminating raw string");
+                let str_span = self.prev_token.span;
+                let mut span = self.token.span;
+                let mut count = 0;
+                while self.token.kind == TokenKind::Pound
+                    && !sm.is_multiline(span.shrink_to_hi().until(self.token.span.shrink_to_lo()))
+                {
+                    span = span.with_hi(self.token.span.hi());
+                    self.bump();
+                    count += 1;
+                }
+                err.set_span(span);
                 err.span_suggestion(
-                    self.token.span,
-                    "remove the extra `#`",
+                    span,
+                    &format!("remove the extra `#`{}", pluralize!(count)),
                     String::new(),
                     Applicability::MachineApplicable,
                 );
-                err.note(&format!("the raw string started with {n_hashes} `#`s"));
+                err.span_label(
+                    str_span,
+                    &format!("this raw string started with {n_hashes} `#`{}", pluralize!(n_hashes)),
+                );
                 true
             }
             _ => false,
@@ -619,7 +655,7 @@ pub fn maybe_suggest_struct_literal(
                 (Err(snapshot_err), Err(err)) => {
                     // We don't know what went wrong, emit the normal error.
                     snapshot_err.cancel();
-                    self.consume_block(token::Brace, ConsumeClosingDelim::Yes);
+                    self.consume_block(Delimiter::Brace, ConsumeClosingDelim::Yes);
                     Err(err)
                 }
                 (Ok(_), Ok(mut tail)) => {
@@ -830,7 +866,7 @@ pub(super) fn check_turbofish_missing_angle_brackets(&mut self, segment: &mut Pa
                         trailing_span = trailing_span.to(self.token.span);
                         self.bump();
                     }
-                    if self.token.kind == token::OpenDelim(token::Paren) {
+                    if self.token.kind == token::OpenDelim(Delimiter::Parenthesis) {
                         // Recover from bad turbofish: `foo.collect::Vec<_>()`.
                         let args = AngleBracketedArgs { args, span }.into();
                         segment.args = args;
@@ -1062,7 +1098,7 @@ pub(super) fn check_no_chained_comparison(
                             [(token::Lt, 1), (token::Gt, -1), (token::BinOp(token::Shr), -2)];
                         self.consume_tts(1, &modifiers);
 
-                        if !&[token::OpenDelim(token::Paren), token::ModSep]
+                        if !&[token::OpenDelim(Delimiter::Parenthesis), token::ModSep]
                             .contains(&self.token.kind)
                         {
                             // We don't have `foo< bar >(` or `foo< bar >::`, so we rewind the
@@ -1096,7 +1132,7 @@ pub(super) fn check_no_chained_comparison(
                                 Err(err)
                             }
                         }
-                    } else if token::OpenDelim(token::Paren) == self.token.kind {
+                    } else if token::OpenDelim(Delimiter::Parenthesis) == self.token.kind {
                         // We have high certainty that this was a bad turbofish at this point.
                         // `foo< bar >(`
                         suggest(&mut err);
@@ -1150,8 +1186,10 @@ fn consume_fn_args(&mut self) -> Result<(), ()> {
         self.bump(); // `(`
 
         // Consume the fn call arguments.
-        let modifiers =
-            [(token::OpenDelim(token::Paren), 1), (token::CloseDelim(token::Paren), -1)];
+        let modifiers = [
+            (token::OpenDelim(Delimiter::Parenthesis), 1),
+            (token::CloseDelim(Delimiter::Parenthesis), -1),
+        ];
         self.consume_tts(1, &modifiers);
 
         if self.token.kind == token::Eof {
@@ -1171,15 +1209,7 @@ pub(super) fn maybe_report_ambiguous_plus(
         ty: &Ty,
     ) {
         if matches!(allow_plus, AllowPlus::No) && impl_dyn_multi {
-            let sum_with_parens = format!("({})", pprust::ty_to_string(&ty));
-            self.struct_span_err(ty.span, "ambiguous `+` in a type")
-                .span_suggestion(
-                    ty.span,
-                    "use parentheses to disambiguate",
-                    sum_with_parens,
-                    Applicability::MachineApplicable,
-                )
-                .emit();
+            self.sess.emit_err(AmbiguousPlus { sum_ty: pprust::ty_to_string(&ty), span: ty.span });
         }
     }
 
@@ -1551,15 +1581,15 @@ pub(super) fn recover_incorrect_await_syntax(
 
     fn recover_await_macro(&mut self) -> PResult<'a, (Span, P<Expr>, bool)> {
         self.expect(&token::Not)?;
-        self.expect(&token::OpenDelim(token::Paren))?;
+        self.expect(&token::OpenDelim(Delimiter::Parenthesis))?;
         let expr = self.parse_expr()?;
-        self.expect(&token::CloseDelim(token::Paren))?;
+        self.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
         Ok((self.prev_token.span, expr, false))
     }
 
     fn recover_await_prefix(&mut self, await_sp: Span) -> PResult<'a, (Span, P<Expr>, bool)> {
         let is_question = self.eat(&token::Question); // Handle `await? <expr>`.
-        let expr = if self.token == token::OpenDelim(token::Brace) {
+        let expr = if self.token == token::OpenDelim(Delimiter::Brace) {
             // Handle `await { <expr> }`.
             // This needs to be handled separately from the next arm to avoid
             // interpreting `await { <expr> }?` as `<expr>?.await`.
@@ -1591,8 +1621,8 @@ fn error_on_incorrect_await(&self, lo: Span, hi: Span, expr: &Expr, is_question:
 
     /// If encountering `future.await()`, consumes and emits an error.
     pub(super) fn recover_from_await_method_call(&mut self) {
-        if self.token == token::OpenDelim(token::Paren)
-            && self.look_ahead(1, |t| t == &token::CloseDelim(token::Paren))
+        if self.token == token::OpenDelim(Delimiter::Parenthesis)
+            && self.look_ahead(1, |t| t == &token::CloseDelim(Delimiter::Parenthesis))
         {
             // future.await()
             let lo = self.token.span;
@@ -1613,7 +1643,7 @@ pub(super) fn recover_from_await_method_call(&mut self) {
     pub(super) fn try_macro_suggestion(&mut self) -> PResult<'a, P<Expr>> {
         let is_try = self.token.is_keyword(kw::Try);
         let is_questionmark = self.look_ahead(1, |t| t == &token::Not); //check for !
-        let is_open = self.look_ahead(2, |t| t == &token::OpenDelim(token::Paren)); //check for (
+        let is_open = self.look_ahead(2, |t| t == &token::OpenDelim(Delimiter::Parenthesis)); //check for (
 
         if is_try && is_questionmark && is_open {
             let lo = self.token.span;
@@ -1621,8 +1651,8 @@ pub(super) fn try_macro_suggestion(&mut self) -> PResult<'a, P<Expr>> {
             self.bump(); //remove !
             let try_span = lo.to(self.token.span); //we take the try!( span
             self.bump(); //remove (
-            let is_empty = self.token == token::CloseDelim(token::Paren); //check if the block is empty
-            self.consume_block(token::Paren, ConsumeClosingDelim::No); //eat the block
+            let is_empty = self.token == token::CloseDelim(Delimiter::Parenthesis); //check if the block is empty
+            self.consume_block(Delimiter::Parenthesis, ConsumeClosingDelim::No); //eat the block
             let hi = self.token.span;
             self.bump(); //remove )
             let mut err = self.struct_span_err(lo.to(hi), "use of deprecated `try` macro");
@@ -1653,7 +1683,7 @@ pub(super) fn recover_parens_around_for_head(
         begin_paren: Option<Span>,
     ) -> P<Pat> {
         match (&self.token.kind, begin_paren) {
-            (token::CloseDelim(token::Paren), Some(begin_par_sp)) => {
+            (token::CloseDelim(Delimiter::Parenthesis), Some(begin_par_sp)) => {
                 self.bump();
 
                 self.struct_span_err(
@@ -1686,8 +1716,8 @@ pub(super) fn could_ascription_be_path(&self, node: &ast::ExprKind) -> bool {
             || self.token.is_ident() &&
             matches!(node, ast::ExprKind::Path(..) | ast::ExprKind::Field(..)) &&
             !self.token.is_reserved_ident() &&           // v `foo:bar(baz)`
-            self.look_ahead(1, |t| t == &token::OpenDelim(token::Paren))
-            || self.look_ahead(1, |t| t == &token::OpenDelim(token::Brace)) // `foo:bar {`
+            self.look_ahead(1, |t| t == &token::OpenDelim(Delimiter::Parenthesis))
+            || self.look_ahead(1, |t| t == &token::OpenDelim(Delimiter::Brace)) // `foo:bar {`
             || self.look_ahead(1, |t| t == &token::Colon) &&     // `foo:bar::<baz`
             self.look_ahead(2, |t| t == &token::Lt) &&
             self.look_ahead(3, |t| t.is_ident())
@@ -1700,7 +1730,7 @@ pub(super) fn could_ascription_be_path(&self, node: &ast::ExprKind) -> bool {
 
     pub(super) fn recover_seq_parse_error(
         &mut self,
-        delim: token::DelimToken,
+        delim: Delimiter,
         lo: Span,
         result: PResult<'a, P<Expr>>,
     ) -> P<Expr> {
@@ -1817,7 +1847,7 @@ pub(super) fn recover_stmt_(
         loop {
             debug!("recover_stmt_ loop {:?}", self.token);
             match self.token.kind {
-                token::OpenDelim(token::DelimToken::Brace) => {
+                token::OpenDelim(Delimiter::Brace) => {
                     brace_depth += 1;
                     self.bump();
                     if break_on_block == BlockMode::Break && brace_depth == 1 && bracket_depth == 0
@@ -1825,11 +1855,11 @@ pub(super) fn recover_stmt_(
                         in_block = true;
                     }
                 }
-                token::OpenDelim(token::DelimToken::Bracket) => {
+                token::OpenDelim(Delimiter::Bracket) => {
                     bracket_depth += 1;
                     self.bump();
                 }
-                token::CloseDelim(token::DelimToken::Brace) => {
+                token::CloseDelim(Delimiter::Brace) => {
                     if brace_depth == 0 {
                         debug!("recover_stmt_ return - close delim {:?}", self.token);
                         break;
@@ -1841,7 +1871,7 @@ pub(super) fn recover_stmt_(
                         break;
                     }
                 }
-                token::CloseDelim(token::DelimToken::Bracket) => {
+                token::CloseDelim(Delimiter::Bracket) => {
                     bracket_depth -= 1;
                     if bracket_depth < 0 {
                         bracket_depth = 0;
@@ -1899,11 +1929,11 @@ pub(super) fn eat_incorrect_doc_comment_for_param_type(&mut self) {
             .emit();
             self.bump();
         } else if self.token == token::Pound
-            && self.look_ahead(1, |t| *t == token::OpenDelim(token::Bracket))
+            && self.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Bracket))
         {
             let lo = self.token.span;
             // Skip every token until next possible arg.
-            while self.token != token::CloseDelim(token::Bracket) {
+            while self.token != token::CloseDelim(Delimiter::Bracket) {
                 self.bump();
             }
             let sp = lo.to(self.token.span);
@@ -1924,7 +1954,9 @@ pub(super) fn parameter_without_type(
         // If we find a pattern followed by an identifier, it could be an (incorrect)
         // C-style parameter declaration.
         if self.check_ident()
-            && self.look_ahead(1, |t| *t == token::Comma || *t == token::CloseDelim(token::Paren))
+            && self.look_ahead(1, |t| {
+                *t == token::Comma || *t == token::CloseDelim(Delimiter::Parenthesis)
+            })
         {
             // `fn foo(String s) {}`
             let ident = self.parse_ident().unwrap();
@@ -1940,7 +1972,7 @@ pub(super) fn parameter_without_type(
         } else if require_name
             && (self.token == token::Comma
                 || self.token == token::Lt
-                || self.token == token::CloseDelim(token::Paren))
+                || self.token == token::CloseDelim(Delimiter::Parenthesis))
         {
             let rfc_note = "anonymous parameters are removed in the 2018 edition (see RFC 1685)";
 
@@ -2058,11 +2090,7 @@ pub(super) fn recover_bad_self_param(&mut self, mut param: Param) -> PResult<'a,
         Ok(param)
     }
 
-    pub(super) fn consume_block(
-        &mut self,
-        delim: token::DelimToken,
-        consume_close: ConsumeClosingDelim,
-    ) {
+    pub(super) fn consume_block(&mut self, delim: Delimiter, consume_close: ConsumeClosingDelim) {
         let mut brace_depth = 0;
         loop {
             if self.eat(&token::OpenDelim(delim)) {
@@ -2081,7 +2109,8 @@ pub(super) fn consume_block(
                     brace_depth -= 1;
                     continue;
                 }
-            } else if self.token == token::Eof || self.eat(&token::CloseDelim(token::NoDelim)) {
+            } else if self.token == token::Eof || self.eat(&token::CloseDelim(Delimiter::Invisible))
+            {
                 return;
             } else {
                 self.bump();
@@ -2527,7 +2556,7 @@ pub(super) fn incorrect_move_async_order_found(
 
     crate fn maybe_recover_unexpected_block_label(&mut self) -> bool {
         let Some(label) = self.eat_label().filter(|_| {
-            self.eat(&token::Colon) && self.token.kind == token::OpenDelim(token::Brace)
+            self.eat(&token::Colon) && self.token.kind == token::OpenDelim(Delimiter::Brace)
         }) else {
             return false;
         };
@@ -2624,7 +2653,7 @@ pub(super) fn incorrect_move_async_order_found(
     /// Parse and throw away a parenthesized comma separated
     /// sequence of patterns until `)` is reached.
     fn skip_pat_list(&mut self) -> PResult<'a, ()> {
-        while !self.check(&token::CloseDelim(token::Paren)) {
+        while !self.check(&token::CloseDelim(Delimiter::Parenthesis)) {
             self.parse_pat_no_top_alt(None)?;
             if !self.eat(&token::Comma) {
                 return Ok(());
index 7efc0ca2da234cb4132aed20f257d74c692bc09e..6114e7aaa7bd7bc784c84d5a82502c651763ebae 100644 (file)
@@ -7,9 +7,8 @@
 };
 use crate::maybe_recover_from_interpolated_ty_qpath;
 
-use ast::token::DelimToken;
 use rustc_ast::ptr::P;
-use rustc_ast::token::{self, Token, TokenKind};
+use rustc_ast::token::{self, Delimiter, Token, TokenKind};
 use rustc_ast::tokenstream::Spacing;
 use rustc_ast::util::classify;
 use rustc_ast::util::literal::LitError;
@@ -495,7 +494,7 @@ fn parse_range_expr(
     fn is_at_start_of_range_notation_rhs(&self) -> bool {
         if self.token.can_begin_expr() {
             // Parse `for i in 1.. { }` as infinite loop, not as `for i in (1..{})`.
-            if self.token == token::OpenDelim(token::Brace) {
+            if self.token == token::OpenDelim(Delimiter::Brace) {
                 return !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL);
             }
             true
@@ -992,8 +991,8 @@ fn parse_dot_or_call_expr_with_(&mut self, mut e: P<Expr>, lo: Span) -> PResult<
                 return Ok(e);
             }
             e = match self.token.kind {
-                token::OpenDelim(token::Paren) => self.parse_fn_call_expr(lo, e),
-                token::OpenDelim(token::Bracket) => self.parse_index_expr(lo, e)?,
+                token::OpenDelim(Delimiter::Parenthesis) => self.parse_fn_call_expr(lo, e),
+                token::OpenDelim(Delimiter::Bracket) => self.parse_index_expr(lo, e)?,
                 _ => return Ok(e),
             }
         }
@@ -1156,7 +1155,7 @@ fn parse_tuple_field_access_expr(
 
     /// Parse a function call expression, `expr(...)`.
     fn parse_fn_call_expr(&mut self, lo: Span, fun: P<Expr>) -> P<Expr> {
-        let snapshot = if self.token.kind == token::OpenDelim(token::Paren)
+        let snapshot = if self.token.kind == token::OpenDelim(Delimiter::Parenthesis)
             && self.look_ahead_type_ascription_as_field()
         {
             Some((self.create_snapshot_for_diagnostic(), fun.kind.clone()))
@@ -1173,7 +1172,7 @@ fn parse_fn_call_expr(&mut self, lo: Span, fun: P<Expr>) -> P<Expr> {
         {
             return expr;
         }
-        self.recover_seq_parse_error(token::Paren, lo, seq)
+        self.recover_seq_parse_error(Delimiter::Parenthesis, lo, seq)
     }
 
     /// If we encounter a parser state that looks like the user has written a `struct` literal with
@@ -1190,8 +1189,10 @@ fn maybe_recover_struct_lit_bad_delims(
             (Err(err), Some((mut snapshot, ExprKind::Path(None, path)))) => {
                 let name = pprust::path_to_string(&path);
                 snapshot.bump(); // `(`
-                match snapshot.parse_struct_fields(path, false, token::Paren) {
-                    Ok((fields, ..)) if snapshot.eat(&token::CloseDelim(token::Paren)) => {
+                match snapshot.parse_struct_fields(path, false, Delimiter::Parenthesis) {
+                    Ok((fields, ..))
+                        if snapshot.eat(&token::CloseDelim(Delimiter::Parenthesis)) =>
+                    {
                         // We are certain we have `Enum::Foo(a: 3, b: 4)`, suggest
                         // `Enum::Foo { a: 3, b: 4 }` or `Enum::Foo(3, 4)`.
                         self.restore_snapshot(snapshot);
@@ -1241,7 +1242,7 @@ fn maybe_recover_struct_lit_bad_delims(
     fn parse_index_expr(&mut self, lo: Span, base: P<Expr>) -> PResult<'a, P<Expr>> {
         self.bump(); // `[`
         let index = self.parse_expr()?;
-        self.expect(&token::CloseDelim(token::Bracket))?;
+        self.expect(&token::CloseDelim(Delimiter::Bracket))?;
         Ok(self.mk_expr(lo.to(self.prev_token.span), self.mk_index(base, index), AttrVec::new()))
     }
 
@@ -1253,10 +1254,10 @@ fn parse_dot_suffix(&mut self, self_arg: P<Expr>, lo: Span) -> PResult<'a, P<Exp
 
         let fn_span_lo = self.token.span;
         let mut segment = self.parse_path_segment(PathStyle::Expr, None)?;
-        self.check_trailing_angle_brackets(&segment, &[&token::OpenDelim(token::Paren)]);
+        self.check_trailing_angle_brackets(&segment, &[&token::OpenDelim(Delimiter::Parenthesis)]);
         self.check_turbofish_missing_angle_brackets(&mut segment);
 
-        if self.check(&token::OpenDelim(token::Paren)) {
+        if self.check(&token::OpenDelim(Delimiter::Parenthesis)) {
             // Method call `expr.f()`
             let mut args = self.parse_paren_expr_seq()?;
             args.insert(0, self_arg);
@@ -1302,9 +1303,9 @@ fn parse_bottom_expr(&mut self) -> PResult<'a, P<Expr>> {
             // could be removed without changing functionality, but it's faster
             // to have it here, especially for programs with large constants.
             self.parse_lit_expr(attrs)
-        } else if self.check(&token::OpenDelim(token::Paren)) {
+        } else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) {
             self.parse_tuple_parens_expr(attrs)
-        } else if self.check(&token::OpenDelim(token::Brace)) {
+        } else if self.check(&token::OpenDelim(Delimiter::Brace)) {
             self.parse_block_expr(None, lo, BlockCheckMode::Default, attrs)
         } else if self.check(&token::BinOp(token::Or)) || self.check(&token::OrOr) {
             self.parse_closure_expr(attrs).map_err(|mut err| {
@@ -1315,8 +1316,8 @@ fn parse_bottom_expr(&mut self) -> PResult<'a, P<Expr>> {
                 }
                 err
             })
-        } else if self.check(&token::OpenDelim(token::Bracket)) {
-            self.parse_array_or_repeat_expr(attrs, token::Bracket)
+        } else if self.check(&token::OpenDelim(Delimiter::Bracket)) {
+            self.parse_array_or_repeat_expr(attrs, Delimiter::Bracket)
         } else if self.check_path() {
             self.parse_path_start_expr(attrs)
         } else if self.check_keyword(kw::Move) || self.check_keyword(kw::Static) {
@@ -1373,6 +1374,8 @@ fn parse_bottom_expr(&mut self) -> PResult<'a, P<Expr>> {
             self.parse_break_expr(attrs)
         } else if self.eat_keyword(kw::Yield) {
             self.parse_yield_expr(attrs)
+        } else if self.is_do_yeet() {
+            self.parse_yeet_expr(attrs)
         } else if self.eat_keyword(kw::Let) {
             self.parse_let_expr(attrs)
         } else if self.eat_keyword(kw::Underscore) {
@@ -1422,14 +1425,16 @@ fn parse_lit_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
 
     fn parse_tuple_parens_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
         let lo = self.token.span;
-        self.expect(&token::OpenDelim(token::Paren))?;
+        self.expect(&token::OpenDelim(Delimiter::Parenthesis))?;
         let (es, trailing_comma) = match self.parse_seq_to_end(
-            &token::CloseDelim(token::Paren),
+            &token::CloseDelim(Delimiter::Parenthesis),
             SeqSep::trailing_allowed(token::Comma),
             |p| p.parse_expr_catch_underscore(),
         ) {
             Ok(x) => x,
-            Err(err) => return Ok(self.recover_seq_parse_error(token::Paren, lo, Err(err))),
+            Err(err) => {
+                return Ok(self.recover_seq_parse_error(Delimiter::Parenthesis, lo, Err(err)));
+            }
         };
         let kind = if es.len() == 1 && !trailing_comma {
             // `(e)` is parenthesized `e`.
@@ -1445,7 +1450,7 @@ fn parse_tuple_parens_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
     fn parse_array_or_repeat_expr(
         &mut self,
         attrs: AttrVec,
-        close_delim: token::DelimToken,
+        close_delim: Delimiter,
     ) -> PResult<'a, P<Expr>> {
         let lo = self.token.span;
         self.bump(); // `[` or other open delim
@@ -1500,7 +1505,7 @@ fn parse_path_start_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
                 prior_type_ascription: self.last_type_ascription,
             };
             (self.prev_token.span, ExprKind::MacCall(mac))
-        } else if self.check(&token::OpenDelim(token::Brace)) {
+        } else if self.check(&token::OpenDelim(Delimiter::Brace)) {
             if let Some(expr) = self.maybe_parse_struct_expr(qself.as_ref(), &path, &attrs) {
                 if qself.is_some() {
                     self.sess.gated_spans.gate(sym::more_qualified_paths, path.span);
@@ -1533,7 +1538,7 @@ fn parse_labeled_expr(
             self.parse_for_expr(label, lo, attrs)
         } else if self.eat_keyword(kw::Loop) {
             self.parse_loop_expr(label, lo, attrs)
-        } else if self.check(&token::OpenDelim(token::Brace)) || self.token.is_whole_block() {
+        } else if self.check(&token::OpenDelim(Delimiter::Brace)) || self.token.is_whole_block() {
             self.parse_block_expr(label, lo, BlockCheckMode::Default, attrs)
         } else if !ate_colon && (self.check(&TokenKind::Comma) || self.check(&TokenKind::Gt)) {
             // We're probably inside of a `Path<'a>` that needs a turbofish
@@ -1602,6 +1607,21 @@ fn parse_return_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
         self.maybe_recover_from_bad_qpath(expr, true)
     }
 
+    /// Parse `"do" "yeet" expr?`.
+    fn parse_yeet_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
+        let lo = self.token.span;
+
+        self.bump(); // `do`
+        self.bump(); // `yeet`
+
+        let kind = ExprKind::Yeet(self.parse_expr_opt()?);
+
+        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)
+    }
+
     /// Parse `"break" (('label (:? expr)?) | expr?)` with `"break"` token already eaten.
     /// If the label is followed immediately by a `:` token, the label and `:` are
     /// parsed as part of the expression (i.e. a labeled loop). The language team has
@@ -1631,7 +1651,7 @@ fn parse_break_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
             )
             .emit();
             Some(lexpr)
-        } else if self.token != token::OpenDelim(token::Brace)
+        } else if self.token != token::OpenDelim(Delimiter::Brace)
             || !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
         {
             let expr = self.parse_expr_opt()?;
@@ -1768,7 +1788,7 @@ fn error_float_lits_must_have_int_part(&self, token: &Token) {
             .span_suggestion(
                 token.span,
                 "must have an integer part",
-                pprust::token_to_string(token).into(),
+                pprust::token_to_string(token),
                 Applicability::MachineApplicable,
             )
             .emit();
@@ -1940,7 +1960,7 @@ fn maybe_suggest_brackets_instead_of_braces(
         attrs: AttrVec,
     ) -> Option<P<Expr>> {
         let mut snapshot = self.create_snapshot_for_diagnostic();
-        match snapshot.parse_array_or_repeat_expr(attrs, token::Brace) {
+        match snapshot.parse_array_or_repeat_expr(attrs, Delimiter::Brace) {
             Ok(arr) => {
                 let hi = snapshot.prev_token.span;
                 self.struct_span_err(arr.span, "this is a block expression, not an array")
@@ -2043,7 +2063,8 @@ fn parse_closure_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
             self.sess.gated_spans.gate(sym::async_closure, span);
         }
 
-        if self.token.kind == TokenKind::Semi && self.token_cursor.frame.delim == DelimToken::Paren
+        if self.token.kind == TokenKind::Semi
+            && matches!(self.token_cursor.frame.delim_sp, Some((Delimiter::Parenthesis, _)))
         {
             // It is likely that the closure body is a block but where the
             // braces have been removed. We will recover and eat the next
@@ -2157,7 +2178,7 @@ fn parse_if_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
             }
         } else {
             let attrs = self.parse_outer_attributes()?.take_for_recovery(); // For recovery.
-            let not_block = self.token != token::OpenDelim(token::Brace);
+            let not_block = self.token != token::OpenDelim(Delimiter::Brace);
             let block = self.parse_block().map_err(|err| {
                 if not_block {
                     self.error_missing_if_then_block(lo, Some(err), missing_then_block_binop_span())
@@ -2282,7 +2303,7 @@ fn parse_for_expr(
         // This is used below for recovery in case of `for ( $stuff ) $block`
         // in which case we will suggest `for $stuff $block`.
         let begin_paren = match self.token.kind {
-            token::OpenDelim(token::Paren) => Some(self.token.span),
+            token::OpenDelim(Delimiter::Parenthesis) => Some(self.token.span),
             _ => None,
         };
 
@@ -2320,7 +2341,7 @@ fn error_missing_in_for_loop(&mut self) {
             .span_suggestion_short(
                 span,
                 msg,
-                sugg.into(),
+                sugg,
                 // Has been misleading, at least in the past (closed Issue #48492).
                 Applicability::MaybeIncorrect,
             )
@@ -2371,7 +2392,7 @@ fn parse_match_expr(&mut self, mut attrs: AttrVec) -> PResult<'a, P<Expr>> {
         let match_span = self.prev_token.span;
         let lo = self.prev_token.span;
         let scrutinee = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
-        if let Err(mut e) = self.expect(&token::OpenDelim(token::Brace)) {
+        if let Err(mut e) = self.expect(&token::OpenDelim(Delimiter::Brace)) {
             if self.token == token::Semi {
                 e.span_suggestion_short(
                     match_span,
@@ -2390,7 +2411,7 @@ fn parse_match_expr(&mut self, mut attrs: AttrVec) -> PResult<'a, P<Expr>> {
         attrs.extend(self.parse_inner_attributes()?);
 
         let mut arms: Vec<Arm> = Vec::new();
-        while self.token != token::CloseDelim(token::Brace) {
+        while self.token != token::CloseDelim(Delimiter::Brace) {
             match self.parse_arm() {
                 Ok(arm) => arms.push(arm),
                 Err(mut e) => {
@@ -2398,7 +2419,7 @@ fn parse_match_expr(&mut self, mut attrs: AttrVec) -> PResult<'a, P<Expr>> {
                     e.emit();
                     self.recover_stmt();
                     let span = lo.to(self.token.span);
-                    if self.token == token::CloseDelim(token::Brace) {
+                    if self.token == token::CloseDelim(Delimiter::Brace) {
                         self.bump();
                     }
                     return Ok(self.mk_expr(span, ExprKind::Match(scrutinee, arms), attrs));
@@ -2462,7 +2483,7 @@ fn parse_arm_body_missing_braces(
         // We might have either a `,` -> `;` typo, or a block without braces. We need
         // a more subtle parsing strategy.
         loop {
-            if self.token.kind == token::CloseDelim(token::Brace) {
+            if self.token.kind == token::CloseDelim(Delimiter::Brace) {
                 // We have reached the closing brace of the `match` expression.
                 return Some(err(self, stmts));
             }
@@ -2570,7 +2591,7 @@ fn check_let_expr(expr: &Expr) -> (bool, bool) {
             })?;
 
             let require_comma = classify::expr_requires_semi_to_be_stmt(&expr)
-                && this.token != token::CloseDelim(token::Brace);
+                && this.token != token::CloseDelim(Delimiter::Brace);
 
             let hi = this.prev_token.span;
 
@@ -2591,8 +2612,8 @@ fn check_let_expr(expr: &Expr) -> (bool, bool) {
                         TrailingToken::None,
                     ));
                 }
-                this.expect_one_of(&[token::Comma], &[token::CloseDelim(token::Brace)]).map_err(
-                    |mut err| {
+                this.expect_one_of(&[token::Comma], &[token::CloseDelim(Delimiter::Brace)])
+                    .map_err(|mut err| {
                         match (sm.span_to_lines(expr.span), sm.span_to_lines(arm_start_span)) {
                             (Ok(ref expr_lines), Ok(ref arm_start_lines))
                                 if arm_start_lines.lines[0].end_col
@@ -2626,8 +2647,7 @@ fn check_let_expr(expr: &Expr) -> (bool, bool) {
                             }
                         }
                         err
-                    },
-                )?;
+                    })?;
             } else {
                 this.eat(&token::Comma);
             }
@@ -2669,13 +2689,17 @@ fn parse_try_block(&mut self, span_lo: Span, mut attrs: AttrVec) -> PResult<'a,
     fn is_do_catch_block(&self) -> bool {
         self.token.is_keyword(kw::Do)
             && self.is_keyword_ahead(1, &[kw::Catch])
-            && self.look_ahead(2, |t| *t == token::OpenDelim(token::Brace))
+            && self.look_ahead(2, |t| *t == token::OpenDelim(Delimiter::Brace))
             && !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
     }
 
+    fn is_do_yeet(&self) -> bool {
+        self.token.is_keyword(kw::Do) && self.is_keyword_ahead(1, &[kw::Yeet])
+    }
+
     fn is_try_block(&self) -> bool {
         self.token.is_keyword(kw::Try)
-            && self.look_ahead(1, |t| *t == token::OpenDelim(token::Brace))
+            && self.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace))
             && self.token.uninterpolated_span().rust_2018()
     }
 
@@ -2695,10 +2719,10 @@ fn is_async_block(&self) -> bool {
             && ((
                 // `async move {`
                 self.is_keyword_ahead(1, &[kw::Move])
-                    && self.look_ahead(2, |t| *t == token::OpenDelim(token::Brace))
+                    && self.look_ahead(2, |t| *t == token::OpenDelim(Delimiter::Brace))
             ) || (
                 // `async {`
-                self.look_ahead(1, |t| *t == token::OpenDelim(token::Brace))
+                self.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace))
             ))
     }
 
@@ -2725,7 +2749,7 @@ fn maybe_parse_struct_expr(
     ) -> Option<PResult<'a, P<Expr>>> {
         let struct_allowed = !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL);
         if struct_allowed || self.is_certainly_not_a_block() {
-            if let Err(err) = self.expect(&token::OpenDelim(token::Brace)) {
+            if let Err(err) = self.expect(&token::OpenDelim(Delimiter::Brace)) {
                 return Some(Err(err));
             }
             let expr = self.parse_struct_expr(qself.cloned(), path.clone(), attrs.clone(), true);
@@ -2752,7 +2776,7 @@ pub(super) fn parse_struct_fields(
         &mut self,
         pth: ast::Path,
         recover: bool,
-        close_delim: token::DelimToken,
+        close_delim: Delimiter,
     ) -> PResult<'a, (Vec<ExprField>, ast::StructRest, bool)> {
         let mut fields = Vec::new();
         let mut base = ast::StructRest::None;
@@ -2825,7 +2849,7 @@ pub(super) fn parse_struct_fields(
                             e.span_suggestion(
                                 self.prev_token.span.shrink_to_hi(),
                                 "try adding a comma",
-                                ",".into(),
+                                ",",
                                 Applicability::MachineApplicable,
                             );
                         }
@@ -2852,9 +2876,9 @@ pub(super) fn parse_struct_expr(
     ) -> PResult<'a, P<Expr>> {
         let lo = pth.span;
         let (fields, base, recover_async) =
-            self.parse_struct_fields(pth.clone(), recover, token::Brace)?;
+            self.parse_struct_fields(pth.clone(), recover, Delimiter::Brace)?;
         let span = lo.to(self.token.span);
-        self.expect(&token::CloseDelim(token::Brace))?;
+        self.expect(&token::CloseDelim(Delimiter::Brace))?;
         let expr = if recover_async {
             ExprKind::Err
         } else {
index 29fe2b761018e8fa40619f065e2e5bb884cb07f5..8081bac7cfd920a46155b7909557900e7ea0c630 100644 (file)
@@ -30,8 +30,10 @@ fn parse_ty_param(&mut self, preceding_attrs: Vec<Attribute>) -> PResult<'a, Gen
         let ident = self.parse_ident()?;
 
         // Parse optional colon and param bounds.
+        let mut colon_span = None;
         let bounds = if self.eat(&token::Colon) {
-            self.parse_generic_bounds(Some(self.prev_token.span))?
+            colon_span = Some(self.prev_token.span);
+            self.parse_generic_bounds(colon_span)?
         } else {
             Vec::new()
         };
@@ -45,6 +47,7 @@ fn parse_ty_param(&mut self, preceding_attrs: Vec<Attribute>) -> PResult<'a, Gen
             bounds,
             kind: GenericParamKind::Type { default },
             is_placeholder: false,
+            colon_span,
         })
     }
 
@@ -69,6 +72,7 @@ fn parse_ty_param(&mut self, preceding_attrs: Vec<Attribute>) -> PResult<'a, Gen
             bounds: Vec::new(),
             kind: GenericParamKind::Const { ty, kw_span: const_span, default },
             is_placeholder: false,
+            colon_span: None,
         })
     }
 
@@ -97,10 +101,10 @@ pub(super) fn parse_generic_params(&mut self) -> PResult<'a, Vec<ast::GenericPar
                     let param = if this.check_lifetime() {
                         let lifetime = this.expect_lifetime();
                         // Parse lifetime parameter.
-                        let bounds = if this.eat(&token::Colon) {
-                            this.parse_lt_param_bounds()
+                        let (colon_span, bounds) = if this.eat(&token::Colon) {
+                            (Some(this.prev_token.span), this.parse_lt_param_bounds())
                         } else {
-                            Vec::new()
+                            (None, Vec::new())
                         };
                         Some(ast::GenericParam {
                             ident: lifetime.ident,
@@ -109,6 +113,7 @@ pub(super) fn parse_generic_params(&mut self) -> PResult<'a, Vec<ast::GenericPar
                             bounds,
                             kind: ast::GenericParamKind::Lifetime,
                             is_placeholder: false,
+                            colon_span,
                         })
                     } else if this.check_keyword(kw::Const) {
                         // Parse const parameter.
index ca81921faedcccc3f25ff84f4063134ab0f3cd47..77a03428c166417048563860acae63db2ed63820 100644 (file)
@@ -4,7 +4,7 @@
 
 use rustc_ast::ast::*;
 use rustc_ast::ptr::P;
-use rustc_ast::token::{self, TokenKind};
+use rustc_ast::token::{self, Delimiter, TokenKind};
 use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree};
 use rustc_ast::{self as ast, AttrVec, Attribute, DUMMY_NODE_ID};
 use rustc_ast::{Async, Const, Defaultness, IsAuto, Mutability, Unsafe, UseTree, UseTreeKind};
@@ -39,9 +39,9 @@ fn parse_item_mod(&mut self, attrs: &mut Vec<Attribute>) -> PResult<'a, ItemInfo
         let mod_kind = if self.eat(&token::Semi) {
             ModKind::Unloaded
         } else {
-            self.expect(&token::OpenDelim(token::Brace))?;
+            self.expect(&token::OpenDelim(Delimiter::Brace))?;
             let (mut inner_attrs, items, inner_span) =
-                self.parse_mod(&token::CloseDelim(token::Brace))?;
+                self.parse_mod(&token::CloseDelim(Delimiter::Brace))?;
             attrs.append(&mut inner_attrs);
             ModKind::Loaded(items, Inline::Yes, inner_span)
         };
@@ -324,7 +324,7 @@ fn recover_missing_kw_before_item(&mut self) -> PResult<'a, ()> {
         let sp = self.prev_token.span.between(self.token.span);
         let full_sp = self.prev_token.span.to(self.token.span);
         let ident_sp = self.token.span;
-        if self.look_ahead(1, |t| *t == token::OpenDelim(token::Brace)) {
+        if self.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace)) {
             // possible public struct definition where `struct` was forgotten
             let ident = self.parse_ident().unwrap();
             let msg = format!("add `struct` here to parse `{ident}` as a public struct");
@@ -332,20 +332,20 @@ fn recover_missing_kw_before_item(&mut self) -> PResult<'a, ()> {
             err.span_suggestion_short(
                 sp,
                 &msg,
-                " struct ".into(),
+                " struct ",
                 Applicability::MaybeIncorrect, // speculative
             );
             Err(err)
-        } else if self.look_ahead(1, |t| *t == token::OpenDelim(token::Paren)) {
+        } else if self.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Parenthesis)) {
             let ident = self.parse_ident().unwrap();
             self.bump(); // `(`
             let kw_name = self.recover_first_param();
-            self.consume_block(token::Paren, ConsumeClosingDelim::Yes);
+            self.consume_block(Delimiter::Parenthesis, ConsumeClosingDelim::Yes);
             let (kw, kw_name, ambiguous) = if self.check(&token::RArrow) {
-                self.eat_to_tokens(&[&token::OpenDelim(token::Brace)]);
+                self.eat_to_tokens(&[&token::OpenDelim(Delimiter::Brace)]);
                 self.bump(); // `{`
                 ("fn", kw_name, false)
-            } else if self.check(&token::OpenDelim(token::Brace)) {
+            } else if self.check(&token::OpenDelim(Delimiter::Brace)) {
                 self.bump(); // `{`
                 ("fn", kw_name, false)
             } else if self.check(&token::Colon) {
@@ -358,7 +358,7 @@ fn recover_missing_kw_before_item(&mut self) -> PResult<'a, ()> {
             let msg = format!("missing `{kw}` for {kw_name} definition");
             let mut err = self.struct_span_err(sp, &msg);
             if !ambiguous {
-                self.consume_block(token::Brace, ConsumeClosingDelim::Yes);
+                self.consume_block(Delimiter::Brace, ConsumeClosingDelim::Yes);
                 let suggestion =
                     format!("add `{kw}` here to parse `{ident}` as a public {kw_name}");
                 err.span_suggestion_short(
@@ -386,9 +386,9 @@ fn recover_missing_kw_before_item(&mut self) -> PResult<'a, ()> {
             let ident = self.parse_ident().unwrap();
             self.eat_to_tokens(&[&token::Gt]);
             self.bump(); // `>`
-            let (kw, kw_name, ambiguous) = if self.eat(&token::OpenDelim(token::Paren)) {
+            let (kw, kw_name, ambiguous) = if self.eat(&token::OpenDelim(Delimiter::Parenthesis)) {
                 ("fn", self.recover_first_param(), false)
-            } else if self.check(&token::OpenDelim(token::Brace)) {
+            } else if self.check(&token::OpenDelim(Delimiter::Brace)) {
                 ("struct", "struct", false)
             } else {
                 ("fn` or `struct", "function or struct", true)
@@ -532,13 +532,13 @@ fn parse_item_impl(
                 .span_suggestion(
                     span,
                     "add a trait here",
-                    " Trait ".into(),
+                    " Trait ",
                     Applicability::HasPlaceholders,
                 )
                 .span_suggestion(
                     span.to(self.token.span),
                     "for an inherent impl, drop this `for`",
-                    "".into(),
+                    "",
                     Applicability::MaybeIncorrect,
                 )
                 .emit();
@@ -630,11 +630,11 @@ fn parse_item_list<T>(
         mut parse_item: impl FnMut(&mut Parser<'a>) -> PResult<'a, Option<Option<T>>>,
     ) -> PResult<'a, Vec<T>> {
         let open_brace_span = self.token.span;
-        self.expect(&token::OpenDelim(token::Brace))?;
+        self.expect(&token::OpenDelim(Delimiter::Brace))?;
         attrs.append(&mut self.parse_inner_attributes()?);
 
         let mut items = Vec::new();
-        while !self.eat(&token::CloseDelim(token::Brace)) {
+        while !self.eat(&token::CloseDelim(Delimiter::Brace)) {
             if self.recover_doc_comment_before_brace() {
                 continue;
             }
@@ -642,7 +642,7 @@ fn parse_item_list<T>(
                 Ok(None) => {
                     // We have to bail or we'll potentially never make progress.
                     let non_item_span = self.token.span;
-                    self.consume_block(token::Brace, ConsumeClosingDelim::Yes);
+                    self.consume_block(Delimiter::Brace, ConsumeClosingDelim::Yes);
                     self.struct_span_err(non_item_span, "non-item in item list")
                         .span_label(open_brace_span, "item list starts here")
                         .span_label(non_item_span, "non-item starts here")
@@ -652,7 +652,7 @@ fn parse_item_list<T>(
                 }
                 Ok(Some(item)) => items.extend(item),
                 Err(mut err) => {
-                    self.consume_block(token::Brace, ConsumeClosingDelim::Yes);
+                    self.consume_block(Delimiter::Brace, ConsumeClosingDelim::Yes);
                     err.span_label(open_brace_span, "while parsing this item list starting here")
                         .span_label(self.prev_token.span, "the item list ends here")
                         .emit();
@@ -666,7 +666,7 @@ fn parse_item_list<T>(
     /// Recover on a doc comment before `}`.
     fn recover_doc_comment_before_brace(&mut self) -> bool {
         if let token::DocComment(..) = self.token.kind {
-            if self.look_ahead(1, |tok| tok == &token::CloseDelim(token::Brace)) {
+            if self.look_ahead(1, |tok| tok == &token::CloseDelim(Delimiter::Brace)) {
                 struct_span_err!(
                     self.diagnostic(),
                     self.token.span,
@@ -866,7 +866,7 @@ fn parse_use_tree(&mut self) -> PResult<'a, UseTree> {
         let lo = self.token.span;
 
         let mut prefix = ast::Path { segments: Vec::new(), span: lo.shrink_to_lo(), tokens: None };
-        let kind = if self.check(&token::OpenDelim(token::Brace))
+        let kind = if self.check(&token::OpenDelim(Delimiter::Brace))
             || self.check(&token::BinOp(token::Star))
             || self.is_import_coupler()
         {
@@ -908,7 +908,7 @@ fn parse_use_tree_glob_or_nested(&mut self) -> PResult<'a, UseTreeKind> {
     /// USE_TREE_LIST = Ø | (USE_TREE `,`)* USE_TREE [`,`]
     /// ```
     fn parse_use_tree_list(&mut self) -> PResult<'a, Vec<(UseTree, ast::NodeId)>> {
-        self.parse_delim_comma_seq(token::Brace, |p| Ok((p.parse_use_tree()?, DUMMY_NODE_ID)))
+        self.parse_delim_comma_seq(Delimiter::Brace, |p| Ok((p.parse_use_tree()?, DUMMY_NODE_ID)))
             .map(|(r, _)| r)
     }
 
@@ -1020,7 +1020,7 @@ fn parse_item_foreign_mod(
                                 &format!("`{}` must come before `{}`", invalid_qual, current_qual),
                                 format!("{} {}", invalid_qual, current_qual),
                                 Applicability::MachineApplicable,
-                            ).note("keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`");
+                            ).note("keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`");
                     }
                 }
                 Err(err)
@@ -1077,7 +1077,7 @@ fn is_unsafe_foreign_mod(&self) -> bool {
             && self.is_keyword_ahead(1, &[kw::Extern])
             && self.look_ahead(
                 2 + self.look_ahead(2, |t| t.can_begin_literal_maybe_minus() as usize),
-                |t| t.kind == token::OpenDelim(token::Brace),
+                |t| t.kind == token::OpenDelim(Delimiter::Brace),
             )
     }
 
@@ -1204,8 +1204,9 @@ fn parse_item_enum(&mut self) -> PResult<'a, ItemInfo> {
         let mut generics = self.parse_generics()?;
         generics.where_clause = self.parse_where_clause()?;
 
-        let (variants, _) =
-            self.parse_delim_comma_seq(token::Brace, |p| p.parse_enum_variant()).map_err(|e| {
+        let (variants, _) = self
+            .parse_delim_comma_seq(Delimiter::Brace, |p| p.parse_enum_variant())
+            .map_err(|e| {
                 self.recover_stmt();
                 e
             })?;
@@ -1228,11 +1229,11 @@ fn parse_enum_variant(&mut self) -> PResult<'a, Option<Variant>> {
                 }
                 let ident = this.parse_field_ident("enum", vlo)?;
 
-                let struct_def = if this.check(&token::OpenDelim(token::Brace)) {
+                let struct_def = if this.check(&token::OpenDelim(Delimiter::Brace)) {
                     // Parse a struct variant.
                     let (fields, recovered) = this.parse_record_struct_body("struct", false)?;
                     VariantData::Struct(fields, recovered)
-                } else if this.check(&token::OpenDelim(token::Paren)) {
+                } else if this.check(&token::OpenDelim(Delimiter::Parenthesis)) {
                     VariantData::Tuple(this.parse_tuple_struct_body()?, DUMMY_NODE_ID)
                 } else {
                     VariantData::Unit(DUMMY_NODE_ID)
@@ -1292,12 +1293,12 @@ fn parse_item_struct(&mut self) -> PResult<'a, ItemInfo> {
         } else if self.eat(&token::Semi) {
             VariantData::Unit(DUMMY_NODE_ID)
         // Record-style struct definition
-        } else if self.token == token::OpenDelim(token::Brace) {
+        } else if self.token == token::OpenDelim(Delimiter::Brace) {
             let (fields, recovered) =
                 self.parse_record_struct_body("struct", generics.where_clause.has_where_token)?;
             VariantData::Struct(fields, recovered)
         // Tuple-style struct definition with optional where-clause.
-        } else if self.token == token::OpenDelim(token::Paren) {
+        } else if self.token == token::OpenDelim(Delimiter::Parenthesis) {
             let body = VariantData::Tuple(self.parse_tuple_struct_body()?, DUMMY_NODE_ID);
             generics.where_clause = self.parse_where_clause()?;
             self.expect_semi()?;
@@ -1326,7 +1327,7 @@ fn parse_item_union(&mut self) -> PResult<'a, ItemInfo> {
             let (fields, recovered) =
                 self.parse_record_struct_body("union", generics.where_clause.has_where_token)?;
             VariantData::Struct(fields, recovered)
-        } else if self.token == token::OpenDelim(token::Brace) {
+        } else if self.token == token::OpenDelim(Delimiter::Brace) {
             let (fields, recovered) =
                 self.parse_record_struct_body("union", generics.where_clause.has_where_token)?;
             VariantData::Struct(fields, recovered)
@@ -1348,10 +1349,10 @@ fn parse_record_struct_body(
     ) -> PResult<'a, (Vec<FieldDef>, /* recovered */ bool)> {
         let mut fields = Vec::new();
         let mut recovered = false;
-        if self.eat(&token::OpenDelim(token::Brace)) {
-            while self.token != token::CloseDelim(token::Brace) {
+        if self.eat(&token::OpenDelim(Delimiter::Brace)) {
+            while self.token != token::CloseDelim(Delimiter::Brace) {
                 let field = self.parse_field_def(adt_ty).map_err(|e| {
-                    self.consume_block(token::Brace, ConsumeClosingDelim::No);
+                    self.consume_block(Delimiter::Brace, ConsumeClosingDelim::No);
                     recovered = true;
                     e
                 });
@@ -1363,7 +1364,7 @@ fn parse_record_struct_body(
                     }
                 }
             }
-            self.eat(&token::CloseDelim(token::Brace));
+            self.eat(&token::CloseDelim(Delimiter::Brace));
         } else {
             let token_str = super::token_descr(&self.token);
             let msg = &format!(
@@ -1439,7 +1440,7 @@ fn parse_single_struct_field(
             token::Comma => {
                 self.bump();
             }
-            token::CloseDelim(token::Brace) => {}
+            token::CloseDelim(Delimiter::Brace) => {}
             token::DocComment(..) => {
                 let previous_span = self.prev_token.span;
                 let mut err = self.span_err(self.token.span, Error::UselessDocComment);
@@ -1450,7 +1451,7 @@ fn parse_single_struct_field(
                 if !seen_comma && comma_after_doc_seen {
                     seen_comma = true;
                 }
-                if comma_after_doc_seen || self.token == token::CloseDelim(token::Brace) {
+                if comma_after_doc_seen || self.token == token::CloseDelim(Delimiter::Brace) {
                     err.emit();
                 } else {
                     if !seen_comma {
@@ -1458,7 +1459,7 @@ fn parse_single_struct_field(
                         err.span_suggestion(
                             sp,
                             "missing comma here",
-                            ",".into(),
+                            ",",
                             Applicability::MachineApplicable,
                         );
                     }
@@ -1478,7 +1479,7 @@ fn parse_single_struct_field(
                     if let Some(last_segment) = segments.last() {
                         recovered = self.check_trailing_angle_brackets(
                             last_segment,
-                            &[&token::Comma, &token::CloseDelim(token::Brace)],
+                            &[&token::Comma, &token::CloseDelim(Delimiter::Brace)],
                         );
                         if recovered {
                             // Handle a case like `Vec<u8>>,` where we can continue parsing fields
@@ -1497,7 +1498,7 @@ fn parse_single_struct_field(
                     err.span_suggestion(
                         sp,
                         "try adding a comma",
-                        ",".into(),
+                        ",",
                         Applicability::MachineApplicable,
                     );
                     err.emit();
@@ -1636,12 +1637,12 @@ fn parse_field_ident(&mut self, adt_ty: &str, lo: Span) -> PResult<'a, Ident> {
     /// ```
     fn parse_item_decl_macro(&mut self, lo: Span) -> PResult<'a, ItemInfo> {
         let ident = self.parse_ident()?;
-        let body = if self.check(&token::OpenDelim(token::Brace)) {
+        let body = if self.check(&token::OpenDelim(Delimiter::Brace)) {
             self.parse_mac_args()? // `MacBody`
-        } else if self.check(&token::OpenDelim(token::Paren)) {
+        } else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) {
             let params = self.parse_token_tree(); // `MacParams`
             let pspan = params.span();
-            if !self.check(&token::OpenDelim(token::Brace)) {
+            if !self.check(&token::OpenDelim(Delimiter::Brace)) {
                 return self.unexpected();
             }
             let body = self.parse_token_tree(); // `MacBody`
@@ -1924,7 +1925,7 @@ fn parse_fn_body(
             self.expect_semi()?;
             *sig_hi = self.prev_token.span;
             (Vec::new(), None)
-        } else if self.check(&token::OpenDelim(token::Brace)) || self.token.is_whole_block() {
+        } else if self.check(&token::OpenDelim(Delimiter::Brace)) || self.token.is_whole_block() {
             self.parse_inner_attrs_and_block().map(|(attrs, body)| (attrs, Some(body)))?
         } else if self.token.kind == token::Eq {
             // Recover `fn foo() = $expr;`.
@@ -1943,12 +1944,12 @@ fn parse_fn_body(
             (Vec::new(), Some(self.mk_block_err(span)))
         } else {
             let expected = if req_body {
-                &[token::OpenDelim(token::Brace)][..]
+                &[token::OpenDelim(Delimiter::Brace)][..]
             } else {
-                &[token::Semi, token::OpenDelim(token::Brace)]
+                &[token::Semi, token::OpenDelim(Delimiter::Brace)]
             };
             if let Err(mut err) = self.expected_one_of_not_found(&[], &expected) {
-                if self.token.kind == token::CloseDelim(token::Brace) {
+                if self.token.kind == token::CloseDelim(Delimiter::Brace) {
                     // The enclosing `mod`, `trait` or `impl` is being closed, so keep the `fn` in
                     // the AST for typechecking.
                     err.span_label(ident.span, "while parsing this `fn`");
@@ -2085,7 +2086,7 @@ enum WrongKw {
                                     &format!("`{misplaced_qual}` must come before `{current_qual}`"),
                                     format!("{misplaced_qual} {current_qual}"),
                                     Applicability::MachineApplicable,
-                                ).note("keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`");
+                                ).note("keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`");
                         }
                     }
                     // Recover incorrect visibility order such as `async pub`
@@ -2164,7 +2165,7 @@ fn parse_fn_params(&mut self, req_name: ReqName) -> PResult<'a, Vec<Param>> {
                 e.emit();
                 let lo = p.prev_token.span;
                 // Skip every token until next possible arg or end.
-                p.eat_to_tokens(&[&token::Comma, &token::CloseDelim(token::Paren)]);
+                p.eat_to_tokens(&[&token::Comma, &token::CloseDelim(Delimiter::Parenthesis)]);
                 // Create a placeholder argument for proper arg count (issue #34264).
                 Ok(dummy_arg(Ident::new(kw::Empty, lo.to(p.prev_token.span))))
             });
@@ -2220,7 +2221,7 @@ fn parse_param_general(&mut self, req_name: ReqName, first_param: bool) -> PResu
                 let mut ty = this.parse_ty_for_param();
                 if ty.is_ok()
                     && this.token != token::Comma
-                    && this.token != token::CloseDelim(token::Paren)
+                    && this.token != token::CloseDelim(Delimiter::Parenthesis)
                 {
                     // This wasn't actually a type, but a pattern looking like a type,
                     // so we are going to rollback and re-parse for recovery.
index cb6be8f412cf54cf7cd9d2ddb4deecae119f9f14..cd61584a876620c7dddc3a624730599015d7db81 100644 (file)
@@ -19,7 +19,7 @@
 pub use path::PathStyle;
 
 use rustc_ast::ptr::P;
-use rustc_ast::token::{self, DelimToken, Nonterminal, Token, TokenKind};
+use rustc_ast::token::{self, Delimiter, Nonterminal, Token, TokenKind};
 use rustc_ast::tokenstream::AttributesData;
 use rustc_ast::tokenstream::{self, DelimSpan, Spacing};
 use rustc_ast::tokenstream::{TokenStream, TokenTree};
@@ -123,8 +123,8 @@ pub struct Parser<'a> {
     pub capture_cfg: bool,
     restrictions: Restrictions,
     expected_tokens: Vec<TokenType>,
-    // Important: This must only be advanced from `next_tok`
-    // to ensure that `token_cursor.num_next_calls` is updated properly
+    // Important: This must only be advanced from `bump` to ensure that
+    // `token_cursor.num_next_calls` is updated properly.
     token_cursor: TokenCursor,
     desugar_doc_comments: bool,
     /// This field is used to keep track of how many left angle brackets we have seen. This is
@@ -150,6 +150,11 @@ pub struct Parser<'a> {
     pub current_closure: Option<ClosureSpans>,
 }
 
+// This type is used a lot, e.g. it's cloned when matching many declarative macro rules. Make sure
+// it doesn't unintentionally get bigger.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+rustc_data_structures::static_assert_size!(Parser<'_>, 328);
+
 /// Stores span information about a closure.
 #[derive(Clone)]
 pub struct ClosureSpans {
@@ -203,12 +208,15 @@ fn drop(&mut self) {
 
 #[derive(Clone)]
 struct TokenCursor {
+    // The current (innermost) frame. `frame` and `stack` could be combined,
+    // but it's faster to have them separately to access `frame` directly
+    // rather than via something like `stack.last().unwrap()` or
+    // `stack[stack.len() - 1]`.
     frame: TokenCursorFrame,
+    // Additional frames that enclose `frame`.
     stack: Vec<TokenCursorFrame>,
     desugar_doc_comments: bool,
-    // Counts the number of calls to `{,inlined_}next` or
-    // `{,inlined_}next_desugared`, depending on whether
-    // `desugar_doc_comments` is set.
+    // Counts the number of calls to `{,inlined_}next`.
     num_next_calls: usize,
     // During parsing, we may sometimes need to 'unglue' a
     // glued token into two component tokens
@@ -236,75 +244,60 @@ struct TokenCursor {
 
 #[derive(Clone)]
 struct TokenCursorFrame {
-    delim: token::DelimToken,
-    span: DelimSpan,
-    open_delim: bool,
+    delim_sp: Option<(Delimiter, DelimSpan)>,
     tree_cursor: tokenstream::Cursor,
-    close_delim: bool,
 }
 
 impl TokenCursorFrame {
-    fn new(span: DelimSpan, delim: DelimToken, tts: TokenStream) -> Self {
-        TokenCursorFrame {
-            delim,
-            span,
-            open_delim: false,
-            tree_cursor: tts.into_trees(),
-            close_delim: false,
-        }
+    fn new(delim_sp: Option<(Delimiter, DelimSpan)>, tts: TokenStream) -> Self {
+        TokenCursorFrame { delim_sp, tree_cursor: tts.into_trees() }
     }
 }
 
 impl TokenCursor {
-    fn next(&mut self) -> (Token, Spacing) {
-        self.inlined_next()
+    fn next(&mut self, desugar_doc_comments: bool) -> (Token, Spacing) {
+        self.inlined_next(desugar_doc_comments)
     }
 
     /// This always-inlined version should only be used on hot code paths.
     #[inline(always)]
-    fn inlined_next(&mut self) -> (Token, Spacing) {
+    fn inlined_next(&mut self, desugar_doc_comments: bool) -> (Token, Spacing) {
         loop {
-            let (tree, spacing) = if !self.frame.open_delim {
-                self.frame.open_delim = true;
-                TokenTree::open_tt(self.frame.span, self.frame.delim).into()
-            } else if let Some(tree) = self.frame.tree_cursor.next_with_spacing() {
-                tree
-            } else if !self.frame.close_delim {
-                self.frame.close_delim = true;
-                TokenTree::close_tt(self.frame.span, self.frame.delim).into()
+            // FIXME: we currently don't return `Delimiter` open/close delims. To fix #67062 we will
+            // need to, whereupon the `delim != Delimiter::Invisible` conditions below can be
+            // removed.
+            if let Some((tree, spacing)) = self.frame.tree_cursor.next_with_spacing_ref() {
+                match tree {
+                    &TokenTree::Token(ref token) => match (desugar_doc_comments, token) {
+                        (true, &Token { kind: token::DocComment(_, attr_style, data), span }) => {
+                            return self.desugar(attr_style, data, span);
+                        }
+                        _ => return (token.clone(), *spacing),
+                    },
+                    &TokenTree::Delimited(sp, delim, ref tts) => {
+                        // Set `open_delim` to true here because we deal with it immediately.
+                        let frame = TokenCursorFrame::new(Some((delim, sp)), tts.clone());
+                        self.stack.push(mem::replace(&mut self.frame, frame));
+                        if delim != Delimiter::Invisible {
+                            return (Token::new(token::OpenDelim(delim), sp.open), Spacing::Alone);
+                        }
+                        // No open delimeter to return; continue on to the next iteration.
+                    }
+                };
             } else if let Some(frame) = self.stack.pop() {
+                if let Some((delim, span)) = self.frame.delim_sp && delim != Delimiter::Invisible {
+                    self.frame = frame;
+                    return (Token::new(token::CloseDelim(delim), span.close), Spacing::Alone);
+                }
                 self.frame = frame;
-                continue;
+                // No close delimiter to return; continue on to the next iteration.
             } else {
-                (TokenTree::Token(Token::new(token::Eof, DUMMY_SP)), Spacing::Alone)
-            };
-
-            match tree {
-                TokenTree::Token(token) => {
-                    return (token, spacing);
-                }
-                TokenTree::Delimited(sp, delim, tts) => {
-                    let frame = TokenCursorFrame::new(sp, delim, tts);
-                    self.stack.push(mem::replace(&mut self.frame, frame));
-                }
+                return (Token::new(token::Eof, DUMMY_SP), Spacing::Alone);
             }
         }
     }
 
-    fn next_desugared(&mut self) -> (Token, Spacing) {
-        self.inlined_next_desugared()
-    }
-
-    /// This always-inlined version should only be used on hot code paths.
-    #[inline(always)]
-    fn inlined_next_desugared(&mut self) -> (Token, Spacing) {
-        let (data, attr_style, sp) = match self.inlined_next() {
-            (Token { kind: token::DocComment(_, attr_style, data), span }, _) => {
-                (data, attr_style, span)
-            }
-            tok => return tok,
-        };
-
+    fn desugar(&mut self, attr_style: AttrStyle, data: Symbol, span: Span) -> (Token, Spacing) {
         // Searches for the occurrences of `"#*` and returns the minimum number of `#`s
         // required to wrap the text.
         let mut num_of_hashes = 0;
@@ -318,14 +311,14 @@ fn inlined_next_desugared(&mut self) -> (Token, Spacing) {
             num_of_hashes = cmp::max(num_of_hashes, count);
         }
 
-        let delim_span = DelimSpan::from_single(sp);
+        let delim_span = DelimSpan::from_single(span);
         let body = TokenTree::Delimited(
             delim_span,
-            token::Bracket,
+            Delimiter::Bracket,
             [
-                TokenTree::token(token::Ident(sym::doc, false), sp),
-                TokenTree::token(token::Eq, sp),
-                TokenTree::token(TokenKind::lit(token::StrRaw(num_of_hashes), data, None), sp),
+                TokenTree::token(token::Ident(sym::doc, false), span),
+                TokenTree::token(token::Eq, span),
+                TokenTree::token(TokenKind::lit(token::StrRaw(num_of_hashes), data, None), span),
             ]
             .iter()
             .cloned()
@@ -335,15 +328,14 @@ fn inlined_next_desugared(&mut self) -> (Token, Spacing) {
         self.stack.push(mem::replace(
             &mut self.frame,
             TokenCursorFrame::new(
-                delim_span,
-                token::NoDelim,
+                None,
                 if attr_style == AttrStyle::Inner {
-                    [TokenTree::token(token::Pound, sp), TokenTree::token(token::Not, sp), body]
+                    [TokenTree::token(token::Pound, span), TokenTree::token(token::Not, span), body]
                         .iter()
                         .cloned()
                         .collect::<TokenStream>()
                 } else {
-                    [TokenTree::token(token::Pound, sp), body]
+                    [TokenTree::token(token::Pound, span), body]
                         .iter()
                         .cloned()
                         .collect::<TokenStream>()
@@ -351,7 +343,7 @@ fn inlined_next_desugared(&mut self) -> (Token, Spacing) {
             ),
         ));
 
-        self.next()
+        self.next(/* desugar_doc_comments */ false)
     }
 }
 
@@ -436,10 +428,6 @@ pub fn new(
         desugar_doc_comments: bool,
         subparser_name: Option<&'static str>,
     ) -> Self {
-        let mut start_frame = TokenCursorFrame::new(DelimSpan::dummy(), token::NoDelim, tokens);
-        start_frame.open_delim = true;
-        start_frame.close_delim = true;
-
         let mut parser = Parser {
             sess,
             token: Token::dummy(),
@@ -449,7 +437,7 @@ pub fn new(
             restrictions: Restrictions::empty(),
             expected_tokens: Vec::new(),
             token_cursor: TokenCursor {
-                frame: start_frame,
+                frame: TokenCursorFrame::new(None, tokens),
                 stack: Vec::new(),
                 num_next_calls: 0,
                 desugar_doc_comments,
@@ -476,33 +464,6 @@ pub fn new(
         parser
     }
 
-    #[inline]
-    fn next_tok(&mut self, fallback_span: Span) -> (Token, Spacing) {
-        loop {
-            let (mut next, spacing) = if self.desugar_doc_comments {
-                self.token_cursor.inlined_next_desugared()
-            } else {
-                self.token_cursor.inlined_next()
-            };
-            self.token_cursor.num_next_calls += 1;
-            // We've retrieved an token from the underlying
-            // cursor, so we no longer need to worry about
-            // an unglued token. See `break_and_eat` for more details
-            self.token_cursor.break_last_token = false;
-            if next.span.is_dummy() {
-                // Tweak the location for better diagnostics, but keep syntactic context intact.
-                next.span = fallback_span.with_ctxt(next.span.ctxt());
-            }
-            if matches!(
-                next.kind,
-                token::OpenDelim(token::NoDelim) | token::CloseDelim(token::NoDelim)
-            ) {
-                continue;
-            }
-            return (next, spacing);
-        }
-    }
-
     pub fn unexpected<T>(&mut self) -> PResult<'a, T> {
         match self.expect_one_of(&[], &[]) {
             Err(e) => Err(e),
@@ -665,7 +626,7 @@ fn check_inline_const(&self, dist: usize) -> bool {
         self.is_keyword_ahead(dist, &[kw::Const])
             && self.look_ahead(dist + 1, |t| match t.kind {
                 token::Interpolated(ref nt) => matches!(**nt, token::NtBlock(..)),
-                token::OpenDelim(DelimToken::Brace) => true,
+                token::OpenDelim(Delimiter::Brace) => true,
                 _ => false,
             })
     }
@@ -697,7 +658,7 @@ fn break_and_eat(&mut self, expected: TokenKind) -> bool {
                 //
                 // If we consume any additional tokens, then this token
                 // is not needed (we'll capture the entire 'glued' token),
-                // and `next_tok` will set this field to `None`
+                // and `bump` will set this field to `None`
                 self.token_cursor.break_last_token = true;
                 // Use the spacing of the glued token as the spacing
                 // of the unglued second token.
@@ -841,7 +802,7 @@ fn parse_seq_to_before_tokens<T>(
                                     .span_suggestion_verbose(
                                         self.prev_token.span.shrink_to_hi().until(self.token.span),
                                         &msg,
-                                        " @ ".to_string(),
+                                        " @ ",
                                         Applicability::MaybeIncorrect,
                                     )
                                     .emit();
@@ -857,7 +818,7 @@ fn parse_seq_to_before_tokens<T>(
                                         .span_suggestion_short(
                                             sp,
                                             &format!("missing `{}`", token_str),
-                                            token_str.into(),
+                                            token_str,
                                             Applicability::MaybeIncorrect,
                                         )
                                         .emit();
@@ -993,7 +954,7 @@ fn parse_unspanned_seq<T>(
 
     fn parse_delim_comma_seq<T>(
         &mut self,
-        delim: DelimToken,
+        delim: Delimiter,
         f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
     ) -> PResult<'a, (Vec<T>, bool)> {
         self.parse_unspanned_seq(
@@ -1008,7 +969,7 @@ fn parse_paren_comma_seq<T>(
         &mut self,
         f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
     ) -> PResult<'a, (Vec<T>, bool)> {
-        self.parse_delim_comma_seq(token::Paren, f)
+        self.parse_delim_comma_seq(Delimiter::Parenthesis, f)
     }
 
     /// Advance the parser by one token using provided token as the next one.
@@ -1019,12 +980,6 @@ fn bump_with(&mut self, next: (Token, Spacing)) {
     /// This always-inlined version should only be used on hot code paths.
     #[inline(always)]
     fn inlined_bump_with(&mut self, (next_token, next_spacing): (Token, Spacing)) {
-        // Bumping after EOF is a bad sign, usually an infinite loop.
-        if self.prev_token.kind == TokenKind::Eof {
-            let msg = "attempted to bump the parser past EOF (may be stuck in a loop)";
-            self.span_bug(self.token.span, msg);
-        }
-
         // Update the current and previous tokens.
         self.prev_token = mem::replace(&mut self.token, next_token);
         self.token_spacing = next_spacing;
@@ -1035,8 +990,24 @@ fn inlined_bump_with(&mut self, (next_token, next_spacing): (Token, Spacing)) {
 
     /// Advance the parser by one token.
     pub fn bump(&mut self) {
-        let next_token = self.next_tok(self.token.span);
-        self.inlined_bump_with(next_token);
+        // Note: destructuring here would give nicer code, but it was found in #96210 to be slower
+        // than `.0`/`.1` access.
+        let mut next = self.token_cursor.inlined_next(self.desugar_doc_comments);
+        self.token_cursor.num_next_calls += 1;
+        // We've retrieved an token from the underlying
+        // cursor, so we no longer need to worry about
+        // an unglued token. See `break_and_eat` for more details
+        self.token_cursor.break_last_token = false;
+        if next.0.span.is_dummy() {
+            // Tweak the location for better diagnostics, but keep syntactic context intact.
+            let fallback_span = self.token.span;
+            next.0.span = fallback_span.with_ctxt(next.0.span.ctxt());
+        }
+        debug_assert!(!matches!(
+            next.0.kind,
+            token::OpenDelim(Delimiter::Invisible) | token::CloseDelim(Delimiter::Invisible)
+        ));
+        self.inlined_bump_with(next)
     }
 
     /// Look-ahead `dist` tokens of `self.token` and get access to that token there.
@@ -1047,10 +1018,10 @@ pub fn look_ahead<R>(&self, dist: usize, looker: impl FnOnce(&Token) -> R) -> R
         }
 
         let frame = &self.token_cursor.frame;
-        if frame.delim != DelimToken::NoDelim {
+        if let Some((delim, span)) = frame.delim_sp && delim != Delimiter::Invisible {
             let all_normal = (0..dist).all(|i| {
                 let token = frame.tree_cursor.look_ahead(i);
-                !matches!(token, Some(TokenTree::Delimited(_, DelimToken::NoDelim, _)))
+                !matches!(token, Some(TokenTree::Delimited(_, Delimiter::Invisible, _)))
             });
             if all_normal {
                 return match frame.tree_cursor.look_ahead(dist - 1) {
@@ -1060,7 +1031,7 @@ pub fn look_ahead<R>(&self, dist: usize, looker: impl FnOnce(&Token) -> R) -> R
                             looker(&Token::new(token::OpenDelim(*delim), dspan.open))
                         }
                     },
-                    None => looker(&Token::new(token::CloseDelim(frame.delim), frame.span.close)),
+                    None => looker(&Token::new(token::CloseDelim(delim), span.close)),
                 };
             }
         }
@@ -1069,10 +1040,10 @@ pub fn look_ahead<R>(&self, dist: usize, looker: impl FnOnce(&Token) -> R) -> R
         let mut i = 0;
         let mut token = Token::dummy();
         while i < dist {
-            token = cursor.next().0;
+            token = cursor.next(/* desugar_doc_comments */ false).0;
             if matches!(
                 token.kind,
-                token::OpenDelim(token::NoDelim) | token::CloseDelim(token::NoDelim)
+                token::OpenDelim(Delimiter::Invisible) | token::CloseDelim(Delimiter::Invisible)
             ) {
                 continue;
             }
@@ -1108,7 +1079,7 @@ fn parse_unsafety(&mut self) -> Unsafe {
     /// Parses constness: `const` or nothing.
     fn parse_constness(&mut self) -> Const {
         // Avoid const blocks to be parsed as const items
-        if self.look_ahead(1, |t| t != &token::OpenDelim(DelimToken::Brace))
+        if self.look_ahead(1, |t| t != &token::OpenDelim(Delimiter::Brace))
             && self.eat_keyword(kw::Const)
         {
             Const::Yes(self.prev_token.uninterpolated_span())
@@ -1171,9 +1142,9 @@ fn parse_attr_args(&mut self) -> PResult<'a, MacArgs> {
 
     fn parse_mac_args_common(&mut self, delimited_only: bool) -> PResult<'a, MacArgs> {
         Ok(
-            if self.check(&token::OpenDelim(DelimToken::Paren))
-                || self.check(&token::OpenDelim(DelimToken::Bracket))
-                || self.check(&token::OpenDelim(DelimToken::Brace))
+            if self.check(&token::OpenDelim(Delimiter::Parenthesis))
+                || self.check(&token::OpenDelim(Delimiter::Bracket))
+                || self.check(&token::OpenDelim(Delimiter::Brace))
             {
                 match self.parse_token_tree() {
                     TokenTree::Delimited(dspan, delim, tokens) =>
@@ -1217,24 +1188,27 @@ fn parse_or_use_outer_attributes(
     pub(crate) fn parse_token_tree(&mut self) -> TokenTree {
         match self.token.kind {
             token::OpenDelim(..) => {
-                let depth = self.token_cursor.stack.len();
-
-                // We keep advancing the token cursor until we hit
-                // the matching `CloseDelim` token.
-                while !(depth == self.token_cursor.stack.len()
-                    && matches!(self.token.kind, token::CloseDelim(_)))
-                {
+                // Grab the tokens from this frame.
+                let frame = &self.token_cursor.frame;
+                let stream = frame.tree_cursor.stream.clone();
+                let (delim, span) = frame.delim_sp.unwrap();
+
+                // Advance the token cursor through the entire delimited
+                // sequence. After getting the `OpenDelim` we are *within* the
+                // delimited sequence, i.e. at depth `d`. After getting the
+                // matching `CloseDelim` we are *after* the delimited sequence,
+                // i.e. at depth `d - 1`.
+                let target_depth = self.token_cursor.stack.len() - 1;
+                loop {
                     // Advance one token at a time, so `TokenCursor::next()`
                     // can capture these tokens if necessary.
                     self.bump();
+                    if self.token_cursor.stack.len() == target_depth {
+                        debug_assert!(matches!(self.token.kind, token::CloseDelim(_)));
+                        break;
+                    }
                 }
-                // We are still inside the frame corresponding
-                // to the delimited stream we captured, so grab
-                // the tokens from this frame.
-                let frame = &self.token_cursor.frame;
-                let stream = frame.tree_cursor.stream.clone();
-                let span = frame.span;
-                let delim = frame.delim;
+
                 // Consume close delimiter
                 self.bump();
                 TokenTree::Delimited(span, delim, stream)
@@ -1314,7 +1288,7 @@ pub fn parse_visibility(&mut self, fbt: FollowedByType) -> PResult<'a, Visibilit
         }
         let lo = self.prev_token.span;
 
-        if self.check(&token::OpenDelim(token::Paren)) {
+        if self.check(&token::OpenDelim(Delimiter::Parenthesis)) {
             // We don't `self.bump()` the `(` yet because this might be a struct definition where
             // `()` or a tuple might be allowed. For example, `struct Struct(pub (), pub (usize));`.
             // Because of this, we only `bump` the `(` if we're assured it is appropriate to do so
@@ -1325,7 +1299,7 @@ pub fn parse_visibility(&mut self, fbt: FollowedByType) -> PResult<'a, Visibilit
                 // Parse `pub(crate)`.
                 self.bump(); // `(`
                 self.bump(); // `crate`
-                self.expect(&token::CloseDelim(token::Paren))?; // `)`
+                self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; // `)`
                 let vis = VisibilityKind::Crate(CrateSugar::PubCrate);
                 return Ok(Visibility {
                     span: lo.to(self.prev_token.span),
@@ -1337,20 +1311,20 @@ pub fn parse_visibility(&mut self, fbt: FollowedByType) -> PResult<'a, Visibilit
                 self.bump(); // `(`
                 self.bump(); // `in`
                 let path = self.parse_path(PathStyle::Mod)?; // `path`
-                self.expect(&token::CloseDelim(token::Paren))?; // `)`
+                self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; // `)`
                 let vis = VisibilityKind::Restricted { path: P(path), id: ast::DUMMY_NODE_ID };
                 return Ok(Visibility {
                     span: lo.to(self.prev_token.span),
                     kind: vis,
                     tokens: None,
                 });
-            } else if self.look_ahead(2, |t| t == &token::CloseDelim(token::Paren))
+            } else if self.look_ahead(2, |t| t == &token::CloseDelim(Delimiter::Parenthesis))
                 && self.is_keyword_ahead(1, &[kw::Super, kw::SelfLower])
             {
                 // Parse `pub(self)` or `pub(super)`.
                 self.bump(); // `(`
                 let path = self.parse_path(PathStyle::Mod)?; // `super`/`self`
-                self.expect(&token::CloseDelim(token::Paren))?; // `)`
+                self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; // `)`
                 let vis = VisibilityKind::Restricted { path: P(path), id: ast::DUMMY_NODE_ID };
                 return Ok(Visibility {
                     span: lo.to(self.prev_token.span),
@@ -1372,7 +1346,7 @@ pub fn parse_visibility(&mut self, fbt: FollowedByType) -> PResult<'a, Visibilit
     fn recover_incorrect_vis_restriction(&mut self) -> PResult<'a, ()> {
         self.bump(); // `(`
         let path = self.parse_path(PathStyle::Mod)?;
-        self.expect(&token::CloseDelim(token::Paren))?; // `)`
+        self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; // `)`
 
         let msg = "incorrect visibility restriction";
         let suggestion = r##"some possible visibility restrictions are:
@@ -1439,7 +1413,7 @@ pub fn collect_tokens_no_attrs<R: AstLike>(
     fn is_import_coupler(&mut self) -> bool {
         self.check(&token::ModSep)
             && self.look_ahead(1, |t| {
-                *t == token::OpenDelim(token::Brace) || *t == token::BinOp(token::Star)
+                *t == token::OpenDelim(Delimiter::Brace) || *t == token::BinOp(token::Star)
             })
     }
 
index b45bca3d2e024acf169d5a34411a32d9430b07d7..6974f318f9498542de1683663afdcdb147e3c11d 100644 (file)
@@ -1,5 +1,5 @@
 use rustc_ast::ptr::P;
-use rustc_ast::token::{self, NonterminalKind, Token};
+use rustc_ast::token::{self, Delimiter, NonterminalKind, Token};
 use rustc_ast::AstLike;
 use rustc_ast_pretty::pprust;
 use rustc_errors::PResult;
 impl<'a> Parser<'a> {
     /// Checks whether a non-terminal may begin with a particular token.
     ///
-    /// Returning `false` is a *stability guarantee* that such a matcher will *never* begin with that
-    /// token. Be conservative (return true) if not sure.
+    /// Returning `false` is a *stability guarantee* that such a matcher will *never* begin with
+    /// that token. Be conservative (return true) if not sure. Inlined because it has a single call
+    /// site.
+    #[inline]
     pub fn nonterminal_may_begin_with(kind: NonterminalKind, token: &Token) -> bool {
         /// Checks whether the non-terminal may contain a single (non-keyword) identifier.
         fn may_be_ident(nt: &token::Nonterminal) -> bool {
@@ -41,7 +43,7 @@ fn may_be_ident(nt: &token::Nonterminal) -> bool {
                 _ => token.can_begin_type(),
             },
             NonterminalKind::Block => match token.kind {
-                token::OpenDelim(token::Brace) => true,
+                token::OpenDelim(Delimiter::Brace) => true,
                 token::Interpolated(ref nt) => !matches!(
                     **nt,
                     token::NtItem(_)
@@ -65,8 +67,8 @@ fn may_be_ident(nt: &token::Nonterminal) -> bool {
             NonterminalKind::PatParam { .. } | NonterminalKind::PatWithOr { .. } => {
                 match token.kind {
                 token::Ident(..) |                  // box, ref, mut, and other identifiers (can stricten)
-                token::OpenDelim(token::Paren) |    // tuple pattern
-                token::OpenDelim(token::Bracket) |  // slice pattern
+                token::OpenDelim(Delimiter::Parenthesis) |    // tuple pattern
+                token::OpenDelim(Delimiter::Bracket) |  // slice pattern
                 token::BinOp(token::And) |          // reference
                 token::BinOp(token::Minus) |        // negative literal
                 token::AndAnd |                     // double reference
@@ -95,7 +97,9 @@ fn may_be_ident(nt: &token::Nonterminal) -> bool {
         }
     }
 
-    /// Parse a non-terminal (e.g. MBE `:pat` or `:ident`).
+    /// Parse a non-terminal (e.g. MBE `:pat` or `:ident`). Inlined because there is only one call
+    /// site.
+    #[inline]
     pub fn parse_nonterminal(&mut self, kind: NonterminalKind) -> PResult<'a, NtOrTt> {
         // Any `Nonterminal` which stores its tokens (currently `NtItem` and `NtExpr`)
         // needs to have them force-captured here.
index 67bbbf249369da56d017609aaad1e7b374000b8d..8019c5fb67cb9b46f255e6141e4b468d3b364c6e 100644 (file)
@@ -2,7 +2,7 @@
 use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
 use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor};
 use rustc_ast::ptr::P;
-use rustc_ast::token;
+use rustc_ast::token::{self, Delimiter};
 use rustc_ast::{
     self as ast, AttrVec, Attribute, BindingMode, Expr, ExprKind, MacCall, Mutability, Pat,
     PatField, PatKind, Path, QSelf, RangeEnd, RangeSyntax,
@@ -260,9 +260,9 @@ fn recover_trailing_vert(&mut self, lo: Option<Span>) -> bool {
                 | token::Semi // e.g. `let a |;`.
                 | token::Colon // e.g. `let a | :`.
                 | token::Comma // e.g. `let (a |,)`.
-                | token::CloseDelim(token::Bracket) // e.g. `let [a | ]`.
-                | token::CloseDelim(token::Paren) // e.g. `let (a | )`.
-                | token::CloseDelim(token::Brace) // e.g. `let A { f: a | }`.
+                | token::CloseDelim(Delimiter::Bracket) // e.g. `let [a | ]`.
+                | token::CloseDelim(Delimiter::Parenthesis) // e.g. `let (a | )`.
+                | token::CloseDelim(Delimiter::Brace) // e.g. `let A { f: a | }`.
             )
         });
         match (is_end_ahead, &self.token.kind) {
@@ -323,11 +323,11 @@ fn parse_pat_with_range_pat(
 
         let pat = if self.check(&token::BinOp(token::And)) || self.token.kind == token::AndAnd {
             self.parse_pat_deref(expected)?
-        } else if self.check(&token::OpenDelim(token::Paren)) {
+        } else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) {
             self.parse_pat_tuple_or_parens()?
-        } else if self.check(&token::OpenDelim(token::Bracket)) {
+        } else if self.check(&token::OpenDelim(Delimiter::Bracket)) {
             // Parse `[pat, pat,...]` as a slice pattern.
-            let (pats, _) = self.parse_delim_comma_seq(token::Bracket, |p| {
+            let (pats, _) = self.parse_delim_comma_seq(Delimiter::Bracket, |p| {
                 p.parse_pat_allow_top_alt(
                     None,
                     RecoverComma::No,
@@ -389,9 +389,9 @@ fn parse_pat_with_range_pat(
             } else if let Some(form) = self.parse_range_end() {
                 let begin = self.mk_expr(span, ExprKind::Path(qself, path), AttrVec::new());
                 self.parse_pat_range_begin_with(begin, form)?
-            } else if self.check(&token::OpenDelim(token::Brace)) {
+            } else if self.check(&token::OpenDelim(Delimiter::Brace)) {
                 self.parse_pat_struct(qself, path)?
-            } else if self.check(&token::OpenDelim(token::Paren)) {
+            } else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) {
                 self.parse_pat_tuple_struct(qself, path)?
             } else {
                 PatKind::Path(qself, path)
@@ -606,7 +606,7 @@ fn recover_mut_ref_ident(&mut self, lo: Span) -> PResult<'a, PatKind> {
             .span_suggestion(
                 mutref_span,
                 "try switching the order",
-                "ref mut".into(),
+                "ref mut",
                 Applicability::MachineApplicable,
             )
             .emit();
@@ -845,8 +845,8 @@ fn can_be_ident_pat(&mut self) -> bool {
         // Avoid `in`. Due to recovery in the list parser this messes with `for ( $pat in $expr )`.
         && !self.token.is_keyword(kw::In)
         // Try to do something more complex?
-        && self.look_ahead(1, |t| !matches!(t.kind, token::OpenDelim(token::Paren) // A tuple struct pattern.
-            | token::OpenDelim(token::Brace) // A struct pattern.
+        && self.look_ahead(1, |t| !matches!(t.kind, token::OpenDelim(Delimiter::Parenthesis) // A tuple struct pattern.
+            | token::OpenDelim(Delimiter::Brace) // A struct pattern.
             | token::DotDotDot | token::DotDotEq | token::DotDot // A range pattern.
             | token::ModSep // A tuple / struct variant pattern.
             | token::Not)) // A macro expanding to a pattern.
@@ -868,7 +868,7 @@ fn parse_pat_ident(&mut self, binding_mode: BindingMode) -> PResult<'a, PatKind>
         // This shortly leads to a parse error. Note that if there is no explicit
         // binding mode then we do not end up here, because the lookahead
         // will direct us over to `parse_enum_variant()`.
-        if self.token == token::OpenDelim(token::Paren) {
+        if self.token == token::OpenDelim(Delimiter::Parenthesis) {
             return Err(self
                 .struct_span_err(self.prev_token.span, "expected identifier, found enum pattern"));
         }
@@ -917,7 +917,7 @@ fn parse_pat_fields(&mut self) -> PResult<'a, (Vec<PatField>, bool)> {
         let mut delayed_err: Option<DiagnosticBuilder<'a, ErrorGuaranteed>> = None;
         let mut etc_span = None;
 
-        while self.token != token::CloseDelim(token::Brace) {
+        while self.token != token::CloseDelim(Delimiter::Brace) {
             let attrs = match self.parse_outer_attributes() {
                 Ok(attrs) => attrs,
                 Err(err) => {
@@ -946,7 +946,7 @@ fn parse_pat_fields(&mut self) -> PResult<'a, (Vec<PatField>, bool)> {
                 self.recover_one_fewer_dotdot();
                 self.bump(); // `..` || `...`
 
-                if self.token == token::CloseDelim(token::Brace) {
+                if self.token == token::CloseDelim(Delimiter::Brace) {
                     etc_span = Some(etc_sp);
                     break;
                 }
@@ -970,7 +970,7 @@ fn parse_pat_fields(&mut self) -> PResult<'a, (Vec<PatField>, bool)> {
                 }
 
                 etc_span = Some(etc_sp.until(self.token.span));
-                if self.token == token::CloseDelim(token::Brace) {
+                if self.token == token::CloseDelim(Delimiter::Brace) {
                     // If the struct looks otherwise well formed, recover and continue.
                     if let Some(sp) = comma_sp {
                         err.span_suggestion_short(
index b9e3adaac03a42bfd43114da1605eac9c6c7934f..5c6fb376cd41a0d51051b4c8a6b27917e5029ce1 100644 (file)
@@ -2,7 +2,7 @@
 use super::{Parser, Restrictions, TokenType};
 use crate::maybe_whole;
 use rustc_ast::ptr::P;
-use rustc_ast::token::{self, Token};
+use rustc_ast::token::{self, Delimiter, Token};
 use rustc_ast::{
     self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AssocConstraint,
     AssocConstraintKind, BlockCheckMode, GenericArg, GenericArgs, Generics, ParenthesizedArgs,
@@ -236,14 +236,14 @@ pub(super) fn parse_path_segment(
                 token.kind,
                 token::Lt
                     | token::BinOp(token::Shl)
-                    | token::OpenDelim(token::Paren)
+                    | token::OpenDelim(Delimiter::Parenthesis)
                     | token::LArrow
             )
         };
         let check_args_start = |this: &mut Self| {
             this.expected_tokens.extend_from_slice(&[
                 TokenType::Token(token::Lt),
-                TokenType::Token(token::OpenDelim(token::Paren)),
+                TokenType::Token(token::OpenDelim(Delimiter::Parenthesis)),
             ]);
             is_args_start(&this.token)
         };
@@ -639,7 +639,7 @@ pub(super) fn expr_is_valid_const_arg(&self, expr: &P<rustc_ast::Expr>) -> bool
     /// the caller.
     pub(super) fn parse_const_arg(&mut self) -> PResult<'a, AnonConst> {
         // Parse const argument.
-        let value = if let token::OpenDelim(token::Brace) = self.token.kind {
+        let value = if let token::OpenDelim(Delimiter::Brace) = self.token.kind {
             self.parse_block_expr(
                 None,
                 self.token.span,
@@ -667,7 +667,8 @@ pub(super) fn parse_generic_arg(
             GenericArg::Const(self.parse_const_arg()?)
         } else if self.check_type() {
             // Parse type argument.
-            let is_const_fn = self.look_ahead(1, |t| t.kind == token::OpenDelim(token::Paren));
+            let is_const_fn =
+                self.look_ahead(1, |t| t.kind == token::OpenDelim(Delimiter::Parenthesis));
             let mut snapshot = self.create_snapshot_for_diagnostic();
             match self.parse_ty() {
                 Ok(ty) => GenericArg::Type(ty),
index 5b7ae5f7a7b822f106aa7084543c19db28e9d85f..ac693597662e6e55c27ca68c7fbabcfa5cd958bf 100644 (file)
@@ -11,7 +11,7 @@
 
 use rustc_ast as ast;
 use rustc_ast::ptr::P;
-use rustc_ast::token::{self, TokenKind};
+use rustc_ast::token::{self, Delimiter, TokenKind};
 use rustc_ast::util::classify;
 use rustc_ast::{
     AstLike, AttrStyle, AttrVec, Attribute, LocalKind, MacCall, MacCallStmt, MacStmtStyle,
@@ -92,7 +92,7 @@ pub fn parse_stmt(&mut self, force_collect: ForceCollect) -> PResult<'a, Option<
             // Do not attempt to parse an expression if we're done here.
             self.error_outer_attrs(&attrs.take_for_recovery());
             self.mk_stmt(lo, StmtKind::Empty)
-        } else if self.token != token::CloseDelim(token::Brace) {
+        } else if self.token != token::CloseDelim(Delimiter::Brace) {
             // Remainder are line-expr stmts.
             let e = if force_collect == ForceCollect::Yes {
                 self.collect_tokens_no_attrs(|this| {
@@ -131,7 +131,7 @@ fn parse_stmt_path_start(&mut self, lo: Span, attrs: AttrWrapper) -> PResult<'a,
                 }
             }
 
-            let expr = if this.eat(&token::OpenDelim(token::Brace)) {
+            let expr = if this.eat(&token::OpenDelim(Delimiter::Brace)) {
                 this.parse_struct_expr(None, path, AttrVec::new(), true)?
             } else {
                 let hi = this.prev_token.span;
@@ -164,25 +164,29 @@ fn parse_stmt_mac(&mut self, lo: Span, attrs: AttrVec, path: ast::Path) -> PResu
         let delim = args.delim();
         let hi = self.prev_token.span;
 
-        let style =
-            if delim == token::Brace { MacStmtStyle::Braces } else { MacStmtStyle::NoBraces };
+        let style = match delim {
+            Some(Delimiter::Brace) => MacStmtStyle::Braces,
+            Some(_) => MacStmtStyle::NoBraces,
+            None => unreachable!(),
+        };
 
         let mac = MacCall { path, args, prior_type_ascription: self.last_type_ascription };
 
-        let kind =
-            if (delim == token::Brace && self.token != token::Dot && self.token != token::Question)
-                || self.token == token::Semi
-                || self.token == token::Eof
-            {
-                StmtKind::MacCall(P(MacCallStmt { mac, style, attrs, tokens: None }))
-            } 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.parse_dot_or_call_expr_with(e, lo, attrs.into())?;
-                let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?;
-                StmtKind::Expr(e)
-            };
+        let kind = if (style == MacStmtStyle::Braces
+            && self.token != token::Dot
+            && self.token != token::Question)
+            || self.token == token::Semi
+            || self.token == token::Eof
+        {
+            StmtKind::MacCall(P(MacCallStmt { mac, style, attrs, tokens: None }))
+        } 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.parse_dot_or_call_expr_with(e, lo, attrs.into())?;
+            let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?;
+            StmtKind::Expr(e)
+        };
         Ok(self.mk_stmt(lo.to(hi), kind))
     }
 
@@ -430,7 +434,7 @@ fn error_block_no_opening_brace_msg(
             // If the next token is an open brace (e.g., `if a b {`), the place-
             // inside-a-block suggestion would be more likely wrong than right.
             Ok(Some(_))
-                if self.look_ahead(1, |t| t == &token::OpenDelim(token::Brace))
+                if self.look_ahead(1, |t| t == &token::OpenDelim(Delimiter::Brace))
                     || do_not_suggest_help => {}
             // Do not suggest `if foo println!("") {;}` (as would be seen in test for #46836).
             Ok(Some(Stmt { kind: StmtKind::Empty, .. })) => {}
@@ -484,7 +488,7 @@ pub(super) fn parse_block_common(
         maybe_whole!(self, NtBlock, |x| (Vec::new(), x));
 
         self.maybe_recover_unexpected_block_label();
-        if !self.eat(&token::OpenDelim(token::Brace)) {
+        if !self.eat(&token::OpenDelim(Delimiter::Brace)) {
             return self.error_block_no_opening_brace();
         }
 
@@ -505,7 +509,7 @@ pub(super) fn parse_block_common(
         recover: AttemptLocalParseRecovery,
     ) -> PResult<'a, P<Block>> {
         let mut stmts = vec![];
-        while !self.eat(&token::CloseDelim(token::Brace)) {
+        while !self.eat(&token::CloseDelim(Delimiter::Brace)) {
             if self.token == token::Eof {
                 break;
             }
@@ -549,7 +553,7 @@ pub fn parse_full_stmt(
             {
                 // Just check for errors and recover; do not eat semicolon yet.
                 if let Err(mut e) =
-                    self.expect_one_of(&[], &[token::Semi, token::CloseDelim(token::Brace)])
+                    self.expect_one_of(&[], &[token::Semi, token::CloseDelim(Delimiter::Brace)])
                 {
                     if let TokenKind::DocComment(..) = self.token.kind {
                         if let Ok(snippet) = self.span_to_snippet(self.token.span) {
index bb387064e27fe0e583c16f63a565cf8e96d94383..9e771a8af1a4e0a3368b4c4b5a7409fa05fafa00 100644 (file)
@@ -3,7 +3,7 @@
 use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
 
 use rustc_ast::ptr::P;
-use rustc_ast::token::{self, Token, TokenKind};
+use rustc_ast::token::{self, Delimiter, Token, TokenKind};
 use rustc_ast::{
     self as ast, BareFnTy, FnRetTy, GenericBound, GenericBounds, GenericParam, Generics, Lifetime,
     MacCall, MutTy, Mutability, PolyTraitRef, TraitBoundModifier, TraitObjectSyntax, Ty, TyKind,
@@ -249,14 +249,14 @@ fn parse_ty_common(
 
         let lo = self.token.span;
         let mut impl_dyn_multi = false;
-        let kind = if self.check(&token::OpenDelim(token::Paren)) {
+        let kind = if self.check(&token::OpenDelim(Delimiter::Parenthesis)) {
             self.parse_ty_tuple_or_parens(lo, allow_plus)?
         } else if self.eat(&token::Not) {
             // Never type `!`
             TyKind::Never
         } else if self.eat(&token::BinOp(token::Star)) {
             self.parse_ty_ptr()?
-        } else if self.eat(&token::OpenDelim(token::Bracket)) {
+        } else if self.eat(&token::OpenDelim(Delimiter::Bracket)) {
             self.parse_array_or_slice_ty()?
         } else if self.check(&token::BinOp(token::And)) || self.check(&token::AndAnd) {
             // Reference
@@ -409,7 +409,7 @@ fn parse_array_or_slice_ty(&mut self) -> PResult<'a, TyKind> {
         let elt_ty = match self.parse_ty() {
             Ok(ty) => ty,
             Err(mut err)
-                if self.look_ahead(1, |t| t.kind == token::CloseDelim(token::Bracket))
+                if self.look_ahead(1, |t| t.kind == token::CloseDelim(Delimiter::Bracket))
                     | self.look_ahead(1, |t| t.kind == token::Semi) =>
             {
                 // Recover from `[LIT; EXPR]` and `[LIT]`
@@ -422,14 +422,14 @@ fn parse_array_or_slice_ty(&mut self) -> PResult<'a, TyKind> {
 
         let ty = if self.eat(&token::Semi) {
             let mut length = self.parse_anon_const_expr()?;
-            if let Err(e) = self.expect(&token::CloseDelim(token::Bracket)) {
+            if let Err(e) = self.expect(&token::CloseDelim(Delimiter::Bracket)) {
                 // Try to recover from `X<Y, ...>` when `X::<Y, ...>` works
                 self.check_mistyped_turbofish_with_multiple_type_params(e, &mut length.value)?;
-                self.expect(&token::CloseDelim(token::Bracket))?;
+                self.expect(&token::CloseDelim(Delimiter::Bracket))?;
             }
             TyKind::Array(elt_ty, length)
         } else {
-            self.expect(&token::CloseDelim(token::Bracket))?;
+            self.expect(&token::CloseDelim(Delimiter::Bracket))?;
             TyKind::Slice(elt_ty)
         };
 
@@ -492,9 +492,9 @@ fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> {
     // Parses the `typeof(EXPR)`.
     // To avoid ambiguity, the type is surrounded by parentheses.
     fn parse_typeof_ty(&mut self) -> PResult<'a, TyKind> {
-        self.expect(&token::OpenDelim(token::Paren))?;
+        self.expect(&token::OpenDelim(Delimiter::Parenthesis))?;
         let expr = self.parse_anon_const_expr()?;
-        self.expect(&token::CloseDelim(token::Paren))?;
+        self.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
         Ok(TyKind::Typeof(expr))
     }
 
@@ -672,7 +672,7 @@ fn can_begin_bound(&mut self) -> bool {
         || self.check(&token::Question)
         || self.check(&token::Tilde)
         || self.check_keyword(kw::For)
-        || self.check(&token::OpenDelim(token::Paren))
+        || self.check(&token::OpenDelim(Delimiter::Parenthesis))
     }
 
     fn error_negative_bounds(
@@ -713,7 +713,7 @@ fn error_negative_bounds(
     fn parse_generic_bound(&mut self) -> PResult<'a, Result<GenericBound, Span>> {
         let anchor_lo = self.prev_token.span;
         let lo = self.token.span;
-        let has_parens = self.eat(&token::OpenDelim(token::Paren));
+        let has_parens = self.eat(&token::OpenDelim(Delimiter::Parenthesis));
         let inner_lo = self.token.span;
         let is_negative = self.eat(&token::Not);
 
@@ -766,7 +766,7 @@ fn error_lt_bound_with_modifiers(&self, modifiers: BoundModifiers) {
     /// Recover on `('lifetime)` with `(` already eaten.
     fn recover_paren_lifetime(&mut self, lo: Span, inner_lo: Span) -> PResult<'a, ()> {
         let inner_span = inner_lo.to(self.prev_token.span);
-        self.expect(&token::CloseDelim(token::Paren))?;
+        self.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
         let mut err = self.struct_span_err(
             lo.to(self.prev_token.span),
             "parenthesized lifetime bounds are not supported",
@@ -829,7 +829,7 @@ fn parse_generic_ty_bound(
                 // suggestion is given.
                 let bounds = vec![];
                 self.parse_remaining_bounds(bounds, true)?;
-                self.expect(&token::CloseDelim(token::Paren))?;
+                self.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
                 let sp = vec![lo, self.prev_token.span];
                 let sugg: Vec<_> = sp.iter().map(|sp| (*sp, String::new())).collect();
                 self.struct_span_err(sp, "incorrect braces around trait bounds")
@@ -840,7 +840,7 @@ fn parse_generic_ty_bound(
                     )
                     .emit();
             } else {
-                self.expect(&token::CloseDelim(token::Paren))?;
+                self.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
             }
         }
 
index 261ea0b4deb4a18bb164838bfaee63e8110f1405..991d0d45546285601cb3caf45a10598ad2b618ba 100644 (file)
@@ -45,8 +45,6 @@ struct MarkSymbolVisitor<'tcx> {
     live_symbols: FxHashSet<LocalDefId>,
     repr_has_repr_c: bool,
     in_pat: bool,
-    inherited_pub_visibility: bool,
-    pub_visibility: bool,
     ignore_variant_stack: Vec<DefId>,
     // maps from tuple struct constructors to tuple struct items
     struct_constructors: FxHashMap<LocalDefId, LocalDefId>,
@@ -90,15 +88,15 @@ fn handle_res(&mut self, res: Res) {
             _ if self.in_pat => {}
             Res::PrimTy(..) | Res::SelfCtor(..) | Res::Local(..) => {}
             Res::Def(DefKind::Ctor(CtorOf::Variant, ..), ctor_def_id) => {
-                let variant_id = self.tcx.parent(ctor_def_id).unwrap();
-                let enum_id = self.tcx.parent(variant_id).unwrap();
+                let variant_id = self.tcx.parent(ctor_def_id);
+                let enum_id = self.tcx.parent(variant_id);
                 self.check_def_id(enum_id);
                 if !self.ignore_variant_stack.contains(&ctor_def_id) {
                     self.check_def_id(variant_id);
                 }
             }
             Res::Def(DefKind::Variant, variant_id) => {
-                let enum_id = self.tcx.parent(variant_id).unwrap();
+                let enum_id = self.tcx.parent(variant_id);
                 self.check_def_id(enum_id);
                 if !self.ignore_variant_stack.contains(&variant_id) {
                     self.check_def_id(variant_id);
@@ -284,33 +282,23 @@ fn visit_node(&mut self, node: Node<'tcx>) {
         }
 
         let had_repr_c = self.repr_has_repr_c;
-        let had_inherited_pub_visibility = self.inherited_pub_visibility;
-        let had_pub_visibility = self.pub_visibility;
         self.repr_has_repr_c = false;
-        self.inherited_pub_visibility = false;
-        self.pub_visibility = false;
         match node {
-            Node::Item(item) => {
-                self.pub_visibility = item.vis.node.is_pub();
+            Node::Item(item) => match item.kind {
+                hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) => {
+                    let def = self.tcx.adt_def(item.def_id);
+                    self.repr_has_repr_c = def.repr().c();
 
-                match item.kind {
-                    hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) => {
-                        let def = self.tcx.adt_def(item.def_id);
-                        self.repr_has_repr_c = def.repr().c();
-
-                        intravisit::walk_item(self, &item);
-                    }
-                    hir::ItemKind::Enum(..) => {
-                        self.inherited_pub_visibility = self.pub_visibility;
-
-                        intravisit::walk_item(self, &item);
-                    }
-                    hir::ItemKind::ForeignMod { .. } => {}
-                    _ => {
-                        intravisit::walk_item(self, &item);
-                    }
+                    intravisit::walk_item(self, &item);
                 }
-            }
+                hir::ItemKind::Enum(..) => {
+                    intravisit::walk_item(self, &item);
+                }
+                hir::ItemKind::ForeignMod { .. } => {}
+                _ => {
+                    intravisit::walk_item(self, &item);
+                }
+            },
             Node::TraitItem(trait_item) => {
                 intravisit::walk_trait_item(self, trait_item);
             }
@@ -322,8 +310,6 @@ fn visit_node(&mut self, node: Node<'tcx>) {
             }
             _ => {}
         }
-        self.pub_visibility = had_pub_visibility;
-        self.inherited_pub_visibility = had_inherited_pub_visibility;
         self.repr_has_repr_c = had_repr_c;
     }
 
@@ -354,14 +340,19 @@ fn visit_variant_data(
         _: hir::HirId,
         _: rustc_span::Span,
     ) {
+        let tcx = self.tcx;
         let has_repr_c = self.repr_has_repr_c;
-        let inherited_pub_visibility = self.inherited_pub_visibility;
-        let pub_visibility = self.pub_visibility;
-        let live_fields = def.fields().iter().filter(|f| {
-            has_repr_c || (pub_visibility && (inherited_pub_visibility || f.vis.node.is_pub()))
+        let live_fields = def.fields().iter().filter_map(|f| {
+            let def_id = tcx.hir().local_def_id(f.hir_id);
+            if has_repr_c {
+                return Some(def_id);
+            }
+            if !tcx.visibility(f.hir_id.owner).is_public() {
+                return None;
+            }
+            if tcx.visibility(def_id).is_public() { Some(def_id) } else { None }
         });
-        let hir = self.tcx.hir();
-        self.live_symbols.extend(live_fields.map(|f| hir.local_def_id(f.hir_id)));
+        self.live_symbols.extend(live_fields);
 
         intravisit::walk_struct_def(self, def);
     }
@@ -521,7 +512,7 @@ fn visit_item(&mut self, item: &hir::Item<'_>) {
                 if of_trait.is_some() {
                     self.worklist.push(item.def_id);
                 }
-                for impl_item_ref in items {
+                for impl_item_ref in *items {
                     let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
                     if of_trait.is_some()
                         || has_allow_dead_code_or_lang_attr(self.tcx, impl_item.hir_id())
@@ -602,8 +593,6 @@ fn live_symbols_and_ignored_derived_traits<'tcx>(
         live_symbols: Default::default(),
         repr_has_repr_c: false,
         in_pat: false,
-        inherited_pub_visibility: false,
-        pub_visibility: false,
         ignore_variant_stack: vec![],
         struct_constructors,
         ignored_derived_traits: FxHashMap::default(),
index db083d0453bc05d7cc9a6924a3a3e3ca845eca8c..f84b848e08d1ec1b9b2162ae4beb4ead3297a3e7 100644 (file)
@@ -27,7 +27,7 @@ struct EntryContext<'tcx> {
 
 impl<'tcx> ItemLikeVisitor<'tcx> for EntryContext<'tcx> {
     fn visit_item(&mut self, item: &'tcx Item<'tcx>) {
-        let at_root = self.tcx.local_parent(item.def_id) == Some(CRATE_DEF_ID);
+        let at_root = self.tcx.opt_local_parent(item.def_id) == Some(CRATE_DEF_ID);
         find_item(item, self, at_root);
     }
 
index 6cf1aa480d298e1d64eefeb00cc95b23fe913fab..237a8abfabe7e918feb33896f8cde5d6956f6297 100644 (file)
@@ -3,6 +3,7 @@
 // completely accurate (some things might be counted twice, others missed).
 
 use rustc_ast::visit as ast_visit;
+use rustc_ast::visit::BoundKind;
 use rustc_ast::{self as ast, AttrId, NodeId};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir as hir;
@@ -302,7 +303,7 @@ fn visit_assoc_item(&mut self, item: &'v ast::AssocItem, ctxt: ast_visit::AssocC
         ast_visit::walk_assoc_item(self, item, ctxt);
     }
 
-    fn visit_param_bound(&mut self, bounds: &'v ast::GenericBound) {
+    fn visit_param_bound(&mut self, bounds: &'v ast::GenericBound, _ctxt: BoundKind) {
         self.record("GenericBound", Id::None, bounds);
         ast_visit::walk_param_bound(self, bounds)
     }
index 99ea73fe2fe10bdb9304dbf8e2f60a13d8f8b464..9eba7fb0811c6200eff5d4ac7333f4f2040a9a8e 100644 (file)
@@ -332,9 +332,9 @@ fn visit_body(&mut self, body: &'tcx hir::Body<'tcx>) {
         let def_id = local_def_id.to_def_id();
 
         // Don't run unused pass for #[derive()]
-        if let Some(parent) = self.tcx.parent(def_id)
-            && let DefKind::Impl = self.tcx.def_kind(parent.expect_local())
-            && self.tcx.has_attr(parent, sym::automatically_derived)
+        let parent = self.tcx.local_parent(local_def_id);
+        if let DefKind::Impl = self.tcx.def_kind(parent)
+            && self.tcx.has_attr(parent.to_def_id(), sym::automatically_derived)
         {
             return;
         }
index b520e5d04eab98650b09844bc56e0df77bb4302e..b603352a9beba57ecdbe3ea4d8aeade7f8ccb50e 100644 (file)
@@ -280,8 +280,7 @@ fn propagate_node(&mut self, node: &Node<'tcx>, search_item: LocalDefId) {
                     self.visit_nested_body(body);
                 }
                 hir::ImplItemKind::Fn(_, body) => {
-                    let impl_def_id =
-                        self.tcx.parent(search_item.to_def_id()).unwrap().expect_local();
+                    let impl_def_id = self.tcx.local_parent(search_item);
                     if method_might_be_inlined(self.tcx, impl_item, impl_def_id) {
                         self.visit_nested_body(body)
                     }
@@ -333,6 +332,11 @@ fn push_to_worklist_if_has_custom_linkage(&mut self, def_id: LocalDefId) {
         let codegen_attrs = self.tcx.codegen_fn_attrs(def_id);
         if codegen_attrs.contains_extern_indicator()
             || codegen_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL)
+            // FIXME(nbdd0121): `#[used]` are marked as reachable here so it's picked up by
+            // `linked_symbols` in cg_ssa. They won't be exported in binary or cdylib due to their
+            // `SymbolExportLevel::Rust` export level but may end up being exported in dylibs.
+            || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED)
+            || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
         {
             self.worklist.push(def_id);
         }
index 35a858cb86c3f1851f40e4b266c2571bf0fc5342..10dc587be6e48a9304ba5e18c746e7864b820b63 100644 (file)
@@ -737,7 +737,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
                     }
                 }
 
-                for impl_item_ref in items {
+                for impl_item_ref in *items {
                     let impl_item = self.tcx.associated_item(impl_item_ref.id.def_id);
 
                     if let Some(def_id) = impl_item.trait_item_def_id {
index 0ce97de413496db7146557dd8e4681183a3acbb6..ee459d9c129d37d2126c6dcb5e499d1cca671a55 100644 (file)
@@ -24,7 +24,8 @@
 use rustc_middle::ty::fold::TypeVisitor;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::subst::InternalSubsts;
-use rustc_middle::ty::{self, Const, GenericParamDefKind, TraitRef, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, Const, DefIdTree, GenericParamDefKind};
+use rustc_middle::ty::{TraitRef, Ty, TyCtxt, TypeFoldable};
 use rustc_session::lint;
 use rustc_span::hygiene::Transparency;
 use rustc_span::symbol::{kw, Ident};
@@ -295,28 +296,6 @@ fn min(vis1: ty::Visibility, vis2: ty::Visibility, tcx: TyCtxt<'_>) -> ty::Visib
     if vis1.is_at_least(vis2, tcx) { vis2 } else { vis1 }
 }
 
-////////////////////////////////////////////////////////////////////////////////
-/// Visitor used to determine if pub(restricted) is used anywhere in the crate.
-///
-/// This is done so that `private_in_public` warnings can be turned into hard errors
-/// in crates that have been updated to use pub(restricted).
-////////////////////////////////////////////////////////////////////////////////
-struct PubRestrictedVisitor<'tcx> {
-    tcx: TyCtxt<'tcx>,
-    has_pub_restricted: bool,
-}
-
-impl<'tcx> Visitor<'tcx> for PubRestrictedVisitor<'tcx> {
-    type NestedFilter = nested_filter::All;
-
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.tcx.hir()
-    }
-    fn visit_vis(&mut self, vis: &'tcx hir::Visibility<'tcx>) {
-        self.has_pub_restricted = self.has_pub_restricted || vis.node.is_pub_restricted();
-    }
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 /// Visitor used to determine impl visibility and reachability.
 ////////////////////////////////////////////////////////////////////////////////
@@ -478,9 +457,7 @@ fn update_reachability_from_macro(&mut self, local_def_id: LocalDefId, md: &Macr
             return;
         }
 
-        let item_def_id = local_def_id.to_def_id();
-        let macro_module_def_id =
-            ty::DefIdTree::parent(self.tcx, item_def_id).unwrap().expect_local();
+        let macro_module_def_id = self.tcx.local_parent(local_def_id);
         if self.tcx.hir().opt_def_kind(macro_module_def_id) != Some(DefKind::Mod) {
             // The macro's parent doesn't correspond to a `mod`, return early (#63164, #65252).
             return;
@@ -499,8 +476,7 @@ fn update_reachability_from_macro(&mut self, local_def_id: LocalDefId, md: &Macr
             if changed_reachability || module_def_id == CRATE_DEF_ID {
                 break;
             }
-            module_def_id =
-                ty::DefIdTree::parent(self.tcx, module_def_id.to_def_id()).unwrap().expect_local();
+            module_def_id = self.tcx.local_parent(module_def_id);
         }
     }
 
@@ -682,7 +658,9 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
                     self.update_with_hir_id(ctor_hir_id, item_level);
                 }
                 for field in def.fields() {
-                    if field.vis.node.is_pub() {
+                    let def_id = self.tcx.hir().local_def_id(field.hir_id);
+                    let vis = self.tcx.visibility(def_id);
+                    if vis.is_public() {
                         self.update_with_hir_id(field.hir_id, item_level);
                     }
                 }
@@ -1361,7 +1339,7 @@ fn path_is_private_type(&self, path: &hir::Path<'_>) -> bool {
             // .. and it corresponds to a private type in the AST (this returns
             // `None` for type parameters).
             match self.tcx.hir().find(self.tcx.hir().local_def_id_to_hir_id(did)) {
-                Some(Node::Item(item)) => !item.vis.node.is_pub(),
+                Some(Node::Item(_)) => !self.tcx.visibility(did).is_public(),
                 Some(_) | None => false,
             }
         } else {
@@ -1383,8 +1361,8 @@ fn check_generic_bound(&mut self, bound: &hir::GenericBound<'_>) {
         }
     }
 
-    fn item_is_public(&self, def_id: LocalDefId, vis: &hir::Visibility<'_>) -> bool {
-        self.access_levels.is_reachable(def_id) || vis.node.is_pub()
+    fn item_is_public(&self, def_id: LocalDefId) -> bool {
+        self.access_levels.is_reachable(def_id) || self.tcx.visibility(def_id).is_public()
     }
 }
 
@@ -1519,8 +1497,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
                                 let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
                                 match impl_item.kind {
                                     hir::ImplItemKind::Const(..) | hir::ImplItemKind::Fn(..)
-                                        if self
-                                            .item_is_public(impl_item.def_id, &impl_item.vis) =>
+                                        if self.item_is_public(impl_item.def_id) =>
                                     {
                                         intravisit::walk_impl_item(self, impl_item)
                                     }
@@ -1591,7 +1568,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
             hir::ItemKind::TyAlias(..) => return,
 
             // Not at all public, so we don't care.
-            _ if !self.item_is_public(item.def_id, &item.vis) => {
+            _ if !self.item_is_public(item.def_id) => {
                 return;
             }
 
@@ -1606,12 +1583,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
     }
 
     fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) {
-        for param in generics.params {
-            for bound in param.bounds {
-                self.check_generic_bound(bound);
-            }
-        }
-        for predicate in generics.where_clause.predicates {
+        for predicate in generics.predicates {
             match predicate {
                 hir::WherePredicate::BoundPredicate(bound_pred) => {
                     for bound in bound_pred.bounds.iter() {
@@ -1655,7 +1627,9 @@ fn visit_variant(
     }
 
     fn visit_field_def(&mut self, s: &'tcx hir::FieldDef<'tcx>) {
-        if s.vis.node.is_pub() || self.in_variant {
+        let def_id = self.tcx.hir().local_def_id(s.hir_id);
+        let vis = self.tcx.visibility(def_id);
+        if vis.is_public() || self.in_variant {
             intravisit::walk_field_def(self, s);
         }
     }
@@ -1680,7 +1654,6 @@ struct SearchInterfaceForPrivateItemsVisitor<'tcx> {
     item_def_id: LocalDefId,
     /// The visitor checks that each component type is at least this visible.
     required_visibility: ty::Visibility,
-    has_pub_restricted: bool,
     has_old_errors: bool,
     in_assoc_ty: bool,
 }
@@ -1769,7 +1742,10 @@ fn check_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display)
             };
             let make_msg = || format!("{} {} `{}` in public interface", vis_descr, kind, descr);
             let span = self.tcx.def_span(self.item_def_id.to_def_id());
-            if self.has_pub_restricted || self.has_old_errors || self.in_assoc_ty {
+            if self.has_old_errors
+                || self.in_assoc_ty
+                || self.tcx.resolutions(()).has_pub_restricted
+            {
                 let mut err = if kind == "trait" {
                     struct_span_err!(self.tcx.sess, span, E0445, "{}", make_msg())
                 } else {
@@ -1828,7 +1804,6 @@ fn visit_def_id(
 
 struct PrivateItemsInPublicInterfacesVisitor<'tcx> {
     tcx: TyCtxt<'tcx>,
-    has_pub_restricted: bool,
     old_error_set_ancestry: LocalDefIdSet,
 }
 
@@ -1842,7 +1817,6 @@ fn check(
             tcx: self.tcx,
             item_def_id: def_id,
             required_visibility,
-            has_pub_restricted: self.has_pub_restricted,
             has_old_errors: self.old_error_set_ancestry.contains(&def_id),
             in_assoc_ty: false,
         }
@@ -1994,19 +1968,16 @@ fn visibility(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Visibility {
             match tcx.hir().get(hir_id) {
                 // Unique types created for closures participate in type privacy checking.
                 // They have visibilities inherited from the module they are defined in.
-                Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(..), .. }) => {
-                    ty::Visibility::Restricted(tcx.parent_module(hir_id).to_def_id())
-                }
-                // - AST lowering may clone `use` items and the clones don't
+                Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(..), .. })
+                // - AST lowering creates dummy `use` items which don't
                 //   get their entries in the resolver's visibility table.
                 // - AST lowering also creates opaque type items with inherited visibilities.
                 //   Visibility on them should have no effect, but to avoid the visibility
                 //   query failing on some items, we provide it for opaque types as well.
-                Node::Item(hir::Item {
-                    vis,
-                    kind: hir::ItemKind::Use(..) | hir::ItemKind::OpaqueTy(..),
+                | Node::Item(hir::Item {
+                    kind: hir::ItemKind::Use(_, hir::UseKind::ListStem) | hir::ItemKind::OpaqueTy(..),
                     ..
-                }) => ty::Visibility::from_hir(vis, hir_id, tcx),
+                }) => ty::Visibility::Restricted(tcx.parent_module(hir_id).to_def_id()),
                 // Visibilities of trait impl items are inherited from their traits
                 // and are not filled in resolve.
                 Node::ImplItem(impl_item) => {
@@ -2083,12 +2054,6 @@ fn check_private_in_public(tcx: TyCtxt<'_>, (): ()) {
     };
     tcx.hir().walk_toplevel_module(&mut visitor);
 
-    let has_pub_restricted = {
-        let mut pub_restricted_visitor = PubRestrictedVisitor { tcx, has_pub_restricted: false };
-        tcx.hir().walk_toplevel_module(&mut pub_restricted_visitor);
-        pub_restricted_visitor.has_pub_restricted
-    };
-
     let mut old_error_set_ancestry = HirIdSet::default();
     for mut id in visitor.old_error_set.iter().copied() {
         loop {
@@ -2106,7 +2071,6 @@ fn check_private_in_public(tcx: TyCtxt<'_>, (): ()) {
     // Check for private types and traits in public interfaces.
     let mut visitor = PrivateItemsInPublicInterfacesVisitor {
         tcx,
-        has_pub_restricted,
         // Only definition IDs are ever searched in `old_error_set_ancestry`,
         // so we can filter away all non-definition IDs at this point.
         old_error_set_ancestry: old_error_set_ancestry
index f1f83a7299c4d97740c2997e02055dcf466759bb..3f0f856b5dd7c16f2dca8f2075625ce49c13a5ba 100644 (file)
@@ -502,3 +502,14 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
         self.0.default_span(tcx)
     }
 }
+
+impl<'tcx> Key for (Ty<'tcx>, ty::ValTree<'tcx>) {
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        true
+    }
+
+    fn default_span(&self, _: TyCtxt<'_>) -> Span {
+        DUMMY_SP
+    }
+}
index d97d9199b77eed1f4c7b6bd3d8bf700697095973..783ff5a3f915cd63a5f998533b1d01ca183e6216 100644 (file)
@@ -265,6 +265,8 @@ fn try_resolve_visibility<'ast>(
                 })
             }
             ast::VisibilityKind::Restricted { ref path, id, .. } => {
+                // Make `PRIVATE_IN_PUBLIC` lint a hard error.
+                self.r.has_pub_restricted = true;
                 // For visibilities we are not ready to provide correct implementation of "uniform
                 // paths" right now, so on 2018 edition we only allow module-relative paths for now.
                 // On 2015 edition visibilities are resolved as crate-relative by default,
@@ -296,7 +298,7 @@ fn try_resolve_visibility<'ast>(
                     &segments,
                     Some(TypeNS),
                     parent_scope,
-                    if finalize { Finalize::SimplePath(id, path.span) } else { Finalize::No },
+                    finalize.then(|| Finalize::new(id, path.span)),
                     None,
                 ) {
                     PathResult::Module(ModuleOrUniformRoot::Module(module)) => {
@@ -458,6 +460,14 @@ fn build_reduced_graph_for_use_tree(
                 let mut source = module_path.pop().unwrap();
                 let mut type_ns_only = false;
 
+                self.r.visibilities.insert(self.r.local_def_id(id), vis);
+                if id1 != ast::DUMMY_NODE_ID {
+                    self.r.visibilities.insert(self.r.local_def_id(id1), vis);
+                }
+                if id2 != ast::DUMMY_NODE_ID {
+                    self.r.visibilities.insert(self.r.local_def_id(id2), vis);
+                }
+
                 if nested {
                     // Correctly handle `self`
                     if source.ident.name == kw::SelfLower {
@@ -580,6 +590,7 @@ fn build_reduced_graph_for_use_tree(
                     is_prelude: self.r.session.contains_name(&item.attrs, sym::prelude_import),
                     max_vis: Cell::new(ty::Visibility::Invisible),
                 };
+                self.r.visibilities.insert(self.r.local_def_id(id), vis);
                 self.add_import(prefix, kind, use_tree.span, id, item, root_span, item.id, vis);
             }
             ast::UseTreeKind::Nested(ref items) => {
@@ -840,7 +851,7 @@ fn build_reduced_graph_for_extern_crate(
                 .span_suggestion(
                     item.span,
                     "rename the `self` crate to be able to import it",
-                    "extern crate self as name;".into(),
+                    "extern crate self as name;",
                     Applicability::HasPlaceholders,
                 )
                 .emit();
@@ -1256,13 +1267,15 @@ fn define_macro(&mut self, item: &ast::Item) -> MacroRulesScopeRef<'a> {
                 self.insert_unused_macro(ident, def_id, item.id);
             }
             self.r.visibilities.insert(def_id, vis);
-            self.r.arenas.alloc_macro_rules_scope(MacroRulesScope::Binding(
+            let scope = self.r.arenas.alloc_macro_rules_scope(MacroRulesScope::Binding(
                 self.r.arenas.alloc_macro_rules_binding(MacroRulesBinding {
                     parent_macro_rules_scope: parent_scope.macro_rules,
                     binding,
                     ident,
                 }),
-            ))
+            ));
+            self.r.macro_rules_scopes.insert(def_id, scope);
+            scope
         } else {
             let module = parent_scope.module;
             let vis = match item.kind {
@@ -1377,7 +1390,7 @@ fn visit_assoc_item(&mut self, item: &'b AssocItem, ctxt: AssocCtxt) {
             && self
                 .r
                 .trait_impl_items
-                .contains(&ty::DefIdTree::parent(&*self.r, def_id).unwrap().expect_local()))
+                .contains(&ty::DefIdTree::local_parent(&*self.r, local_def_id)))
         {
             // Trait impl item visibility is inherited from its trait when not specified
             // explicitly. In that case we cannot determine it here in early resolve,
index 899980a4c08872a103877052297b4c8fbb79537a..aef9fb57a6a7c5a08ddbdf7b9e7f08ac19810ee9 100644 (file)
@@ -123,7 +123,7 @@ fn report_with_use_injections(&mut self, krate: &Crate) {
             let (span, found_use) = if let Some(def_id) = def_id.as_local() {
                 UsePlacementFinder::check(krate, self.def_id_to_node_id[def_id])
             } else {
-                (None, false)
+                (None, FoundUse::No)
             };
             if !candidates.is_empty() {
                 show_candidates(
@@ -132,8 +132,9 @@ fn report_with_use_injections(&mut self, krate: &Crate) {
                     &mut err,
                     span,
                     &candidates,
-                    instead,
+                    if instead { Instead::Yes } else { Instead::No },
                     found_use,
+                    IsPattern::No,
                 );
             } else if let Some((span, msg, sugg, appl)) = suggestion {
                 err.span_suggestion(span, msg, sugg, appl);
@@ -416,15 +417,12 @@ fn add_suggestion_for_duplicate_nested_use(
 
     crate fn lint_if_path_starts_with_module(
         &mut self,
-        finalize: Finalize,
+        finalize: Option<Finalize>,
         path: &[Segment],
         second_binding: Option<&NameBinding<'_>>,
     ) {
-        let (diag_id, diag_span) = match finalize {
-            Finalize::No => return,
-            Finalize::SimplePath(id, path_span) => (id, path_span),
-            Finalize::UsePath { root_id, root_span, .. } => (root_id, root_span),
-            Finalize::QPathTrait { qpath_id, qpath_span, .. } => (qpath_id, qpath_span),
+        let Some(Finalize { node_id, root_span, .. }) = finalize else {
+            return;
         };
 
         let first_name = match path.get(0) {
@@ -462,11 +460,11 @@ fn add_suggestion_for_duplicate_nested_use(
             }
         }
 
-        let diag = BuiltinLintDiagnostics::AbsPathWithModule(diag_span);
+        let diag = BuiltinLintDiagnostics::AbsPathWithModule(root_span);
         self.lint_buffer.buffer_lint_with_diagnostic(
             ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE,
-            diag_id,
-            diag_span,
+            node_id,
+            root_span,
             "absolute paths must start with `self`, `super`, \
              `crate`, or an external crate name in the 2018 edition",
             diag,
@@ -493,14 +491,14 @@ fn add_suggestion_for_duplicate_nested_use(
     ///
     /// This takes the error provided, combines it with the span and any additional spans inside the
     /// error and emits it.
-    crate fn report_error(&self, span: Span, resolution_error: ResolutionError<'_>) {
+    crate fn report_error(&mut self, span: Span, resolution_error: ResolutionError<'a>) {
         self.into_struct_error(span, resolution_error).emit();
     }
 
     crate fn into_struct_error(
-        &self,
+        &mut self,
         span: Span,
-        resolution_error: ResolutionError<'_>,
+        resolution_error: ResolutionError<'a>,
     ) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
         match resolution_error {
             ResolutionError::GenericParamsFromOuterFunction(outer_res, has_generic_params) => {
@@ -650,7 +648,7 @@ fn add_suggestion_for_duplicate_nested_use(
                 }
                 err
             }
-            ResolutionError::VariableNotBoundInPattern(binding_error) => {
+            ResolutionError::VariableNotBoundInPattern(binding_error, parent_scope) => {
                 let BindingError { name, target, origin, could_be_path } = binding_error;
 
                 let target_sp = target.iter().copied().collect::<Vec<_>>();
@@ -670,13 +668,41 @@ fn add_suggestion_for_duplicate_nested_use(
                 for sp in origin_sp {
                     err.span_label(sp, "variable not in all patterns");
                 }
-                if *could_be_path {
-                    let help_msg = format!(
-                        "if you meant to match on a variant or a `const` item, consider \
-                         making the path in the pattern qualified: `?::{}`",
-                        name,
+                if could_be_path {
+                    let import_suggestions = self.lookup_import_candidates(
+                        Ident::with_dummy_span(name),
+                        Namespace::ValueNS,
+                        &parent_scope,
+                        &|res: Res| match res {
+                            Res::Def(
+                                DefKind::Ctor(CtorOf::Variant, CtorKind::Const)
+                                | DefKind::Ctor(CtorOf::Struct, CtorKind::Const)
+                                | DefKind::Const
+                                | DefKind::AssocConst,
+                                _,
+                            ) => true,
+                            _ => false,
+                        },
+                    );
+
+                    if import_suggestions.is_empty() {
+                        let help_msg = format!(
+                            "if you meant to match on a variant or a `const` item, consider \
+                             making the path in the pattern qualified: `path::to::ModOrType::{}`",
+                            name,
+                        );
+                        err.span_help(span, &help_msg);
+                    }
+                    show_candidates(
+                        &self.definitions,
+                        self.session,
+                        &mut err,
+                        Some(span),
+                        &import_suggestions,
+                        Instead::No,
+                        FoundUse::Yes,
+                        IsPattern::Yes,
                     );
-                    err.span_help(span, &help_msg);
                 }
                 err
             }
@@ -1014,7 +1040,7 @@ fn add_suggestion_for_duplicate_nested_use(
             }
             ResolutionError::InvalidAsmSym => {
                 let mut err = self.session.struct_span_err(span, "invalid `sym` operand");
-                err.span_label(span, &format!("is a local variable"));
+                err.span_label(span, "is a local variable");
                 err.help("`sym` operands must refer to either a function or a static");
                 err
             }
@@ -1022,7 +1048,7 @@ fn add_suggestion_for_duplicate_nested_use(
     }
 
     crate fn report_vis_error(
-        &self,
+        &mut self,
         vis_resolution_error: VisResolutionError<'_>,
     ) -> ErrorGuaranteed {
         match vis_resolution_error {
@@ -1295,7 +1321,7 @@ fn lookup_import_candidates_from_module<FilterFn>(
                         segms.push(ast::PathSegment::from_ident(ident));
                         let path = Path { span: name_binding.span, segments: segms, tokens: None };
                         let did = match res {
-                            Res::Def(DefKind::Ctor(..), did) => this.parent(did),
+                            Res::Def(DefKind::Ctor(..), did) => this.opt_parent(did),
                             _ => res.opt_def_id(),
                         };
 
@@ -1453,8 +1479,9 @@ fn lookup_import_candidates_from_module<FilterFn>(
             err,
             None,
             &import_suggestions,
-            false,
-            true,
+            Instead::No,
+            FoundUse::Yes,
+            IsPattern::No,
         );
 
         if macro_kind == MacroKind::Derive && (ident.name == sym::Send || ident.name == sym::Sync) {
@@ -1473,7 +1500,6 @@ fn lookup_import_candidates_from_module<FilterFn>(
                 &parent_scope,
                 None,
                 false,
-                false,
                 None,
             ) {
                 let desc = match binding.res() {
@@ -1681,7 +1707,7 @@ fn ctor_fields_span(&self, binding: &NameBinding<'_>) -> Option<Span> {
             _,
         ) = binding.kind
         {
-            let def_id = self.parent(ctor_def_id).expect("no parent for a constructor");
+            let def_id = self.parent(ctor_def_id);
             let fields = self.field_names.get(&def_id)?;
             return fields.iter().map(|name| name.span).reduce(Span::to); // None for `struct Foo()`
         }
@@ -1781,7 +1807,7 @@ fn report_privacy_error(&self, privacy_error: &PrivacyError<'_>) {
         opt_ns: Option<Namespace>, // `None` indicates a module path in import
         parent_scope: &ParentScope<'a>,
         ribs: Option<&PerNS<Vec<Rib<'a>>>>,
-        unusable_binding: Option<&'a NameBinding<'a>>,
+        ignore_binding: Option<&'a NameBinding<'a>>,
         module: Option<ModuleOrUniformRoot<'a>>,
         i: usize,
         ident: Ident,
@@ -1833,8 +1859,7 @@ fn report_privacy_error(&self, privacy_error: &PrivacyError<'_>) {
                         ns_to_try,
                         parent_scope,
                         None,
-                        false,
-                        unusable_binding,
+                        ignore_binding,
                     ).ok()
                 } else if let Some(ribs) = ribs
                     && let Some(TypeNS | ValueNS) = opt_ns
@@ -1843,9 +1868,9 @@ fn report_privacy_error(&self, privacy_error: &PrivacyError<'_>) {
                         ident,
                         ns_to_try,
                         parent_scope,
-                        Finalize::No,
+                        None,
                         &ribs[ns_to_try],
-                        unusable_binding,
+                        ignore_binding,
                     ) {
                         // we found a locally-imported or available item/module
                         Some(LexicalScopeBinding::Item(binding)) => Some(binding),
@@ -1859,8 +1884,7 @@ fn report_privacy_error(&self, privacy_error: &PrivacyError<'_>) {
                         parent_scope,
                         None,
                         false,
-                        false,
-                        unusable_binding,
+                        ignore_binding,
                     ).ok()
                 };
                 if let Some(binding) = binding {
@@ -1891,9 +1915,9 @@ fn report_privacy_error(&self, privacy_error: &PrivacyError<'_>) {
                     ident,
                     ValueNS,
                     parent_scope,
-                    Finalize::No,
+                    None,
                     &ribs[ValueNS],
-                    unusable_binding,
+                    ignore_binding,
                 )
             } else {
                 None
@@ -2390,6 +2414,27 @@ fn find_span_immediately_after_crate_name(
     (next_left_bracket == after_second_colon, from_second_colon)
 }
 
+/// A suggestion has already been emitted, change the wording slightly to clarify that both are
+/// independent options.
+enum Instead {
+    Yes,
+    No,
+}
+
+/// Whether an existing place with an `use` item was found.
+enum FoundUse {
+    Yes,
+    No,
+}
+
+/// Whether a binding is part of a pattern or an expression. Used for diagnostics.
+enum IsPattern {
+    /// The binding is part of a pattern
+    Yes,
+    /// The binding is part of an expression
+    No,
+}
+
 /// When an entity with a given name is not available in scope, we search for
 /// entities with that name in all crates. This method allows outputting the
 /// results of this search in a programmer-friendly way
@@ -2400,8 +2445,9 @@ fn show_candidates(
     // This is `None` if all placement locations are inside expansions
     use_placement_span: Option<Span>,
     candidates: &[ImportSuggestion],
-    instead: bool,
-    found_use: bool,
+    instead: Instead,
+    found_use: FoundUse,
+    is_pattern: IsPattern,
 ) {
     if candidates.is_empty() {
         return;
@@ -2428,24 +2474,38 @@ fn show_candidates(
     }
 
     if !accessible_path_strings.is_empty() {
-        let (determiner, kind) = if accessible_path_strings.len() == 1 {
-            ("this", accessible_path_strings[0].1)
+        let (determiner, kind, name) = if accessible_path_strings.len() == 1 {
+            ("this", accessible_path_strings[0].1, format!(" `{}`", accessible_path_strings[0].0))
         } else {
-            ("one of these", "items")
+            ("one of these", "items", String::new())
         };
 
-        let instead = if instead { " instead" } else { "" };
-        let mut msg = format!("consider importing {} {}{}", determiner, kind, instead);
+        let instead = if let Instead::Yes = instead { " instead" } else { "" };
+        let mut msg = if let IsPattern::Yes = is_pattern {
+            format!(
+                "if you meant to match on {}{}{}, use the full path in the pattern",
+                kind, instead, name
+            )
+        } else {
+            format!("consider importing {} {}{}", determiner, kind, instead)
+        };
 
         for note in accessible_path_strings.iter().flat_map(|cand| cand.3.as_ref()) {
             err.note(note);
         }
 
-        if let Some(span) = use_placement_span {
+        if let (IsPattern::Yes, Some(span)) = (is_pattern, use_placement_span) {
+            err.span_suggestions(
+                span,
+                &msg,
+                accessible_path_strings.into_iter().map(|a| a.0),
+                Applicability::MaybeIncorrect,
+            );
+        } else if let Some(span) = use_placement_span {
             for candidate in &mut accessible_path_strings {
                 // produce an additional newline to separate the new use statement
                 // from the directly following item.
-                let additional_newline = if found_use { "" } else { "\n" };
+                let additional_newline = if let FoundUse::Yes = found_use { "" } else { "\n" };
                 candidate.0 = format!("use {};\n{}", &candidate.0, additional_newline);
             }
 
@@ -2453,7 +2513,7 @@ fn show_candidates(
                 span,
                 &msg,
                 accessible_path_strings.into_iter().map(|a| a.0),
-                Applicability::Unspecified,
+                Applicability::MaybeIncorrect,
             );
         } else {
             msg.push(':');
@@ -2468,9 +2528,17 @@ fn show_candidates(
     } else {
         assert!(!inaccessible_path_strings.is_empty());
 
+        let prefix =
+            if let IsPattern::Yes = is_pattern { "you might have meant to match on " } else { "" };
         if inaccessible_path_strings.len() == 1 {
             let (name, descr, def_id, note) = &inaccessible_path_strings[0];
-            let msg = format!("{} `{}` exists but is inaccessible", descr, name);
+            let msg = format!(
+                "{}{} `{}`{} exists but is inaccessible",
+                prefix,
+                descr,
+                name,
+                if let IsPattern::Yes = is_pattern { ", which" } else { "" }
+            );
 
             if let Some(local_def_id) = def_id.and_then(|did| did.as_local()) {
                 let span = definitions.def_span(local_def_id);
@@ -2496,7 +2564,7 @@ fn show_candidates(
                 "item".to_string()
             };
 
-            let mut msg = format!("these {}s exist but are inaccessible", descr);
+            let mut msg = format!("{}these {}s exist but are inaccessible", prefix, descr);
             let mut has_colon = false;
 
             let mut spans = Vec::new();
@@ -2537,14 +2605,14 @@ struct UsePlacementFinder {
 }
 
 impl UsePlacementFinder {
-    fn check(krate: &Crate, target_module: NodeId) -> (Option<Span>, bool) {
+    fn check(krate: &Crate, target_module: NodeId) -> (Option<Span>, FoundUse) {
         let mut finder =
             UsePlacementFinder { target_module, first_legal_span: None, first_use_span: None };
         finder.visit_crate(krate);
         if let Some(use_span) = finder.first_use_span {
-            (Some(use_span), true)
+            (Some(use_span), FoundUse::Yes)
         } else {
-            (finder.first_legal_span, false)
+            (finder.first_legal_span, FoundUse::No)
         }
     }
 }
index 84fe0ec83d26c3c075dc332a7b7982f03d8e655a..baaab33d71f50feff18adcdf53f8b340e97c9ac4 100644 (file)
@@ -279,9 +279,9 @@ fn hygienic_lexical_parent(
         mut ident: Ident,
         ns: Namespace,
         parent_scope: &ParentScope<'a>,
-        finalize_full: Finalize,
+        finalize: Option<Finalize>,
         ribs: &[Rib<'a>],
-        unusable_binding: Option<&'a NameBinding<'a>>,
+        ignore_binding: Option<&'a NameBinding<'a>>,
     ) -> Option<LexicalScopeBinding<'a>> {
         assert!(ns == TypeNS || ns == ValueNS);
         let orig_ident = ident;
@@ -302,7 +302,6 @@ fn hygienic_lexical_parent(
         let normalized_ident = Ident { span: normalized_span, ..ident };
 
         // Walk backwards up the ribs in scope.
-        let finalize = finalize_full.path_span();
         let mut module = self.graph_root;
         for i in (0..ribs.len()).rev() {
             debug!("walk rib\n{:?}", ribs[i].bindings);
@@ -316,7 +315,7 @@ fn hygienic_lexical_parent(
                     i,
                     rib_ident,
                     *res,
-                    finalize,
+                    finalize.map(|finalize| finalize.path_span),
                     *original_rib_ident_def,
                     ribs,
                 )));
@@ -344,8 +343,7 @@ fn hygienic_lexical_parent(
                 ns,
                 parent_scope,
                 finalize,
-                false,
-                unusable_binding,
+                ignore_binding,
             );
             if let Ok(binding) = item {
                 // The ident resolves to an item.
@@ -354,12 +352,11 @@ fn hygienic_lexical_parent(
         }
         self.early_resolve_ident_in_lexical_scope(
             orig_ident,
-            ScopeSet::Late(ns, module, finalize_full.node_id()),
+            ScopeSet::Late(ns, module, finalize.map(|finalize| finalize.node_id)),
             parent_scope,
             finalize,
             finalize.is_some(),
-            false,
-            unusable_binding,
+            ignore_binding,
         )
         .ok()
         .map(LexicalScopeBinding::Item)
@@ -376,10 +373,9 @@ fn hygienic_lexical_parent(
         orig_ident: Ident,
         scope_set: ScopeSet<'a>,
         parent_scope: &ParentScope<'a>,
-        finalize: Option<Span>,
+        finalize: Option<Finalize>,
         force: bool,
-        last_import_segment: bool,
-        unusable_binding: Option<&'a NameBinding<'a>>,
+        ignore_binding: Option<&'a NameBinding<'a>>,
     ) -> Result<&'a NameBinding<'a>, Determinacy> {
         bitflags::bitflags! {
             struct Flags: u8 {
@@ -499,8 +495,7 @@ struct Flags: u8 {
                             ns,
                             parent_scope,
                             finalize,
-                            last_import_segment,
-                            unusable_binding,
+                            ignore_binding,
                         );
                         match binding {
                             Ok(binding) => Ok((binding, Flags::MODULE | Flags::MISC_SUGGEST_CRATE)),
@@ -522,8 +517,7 @@ struct Flags: u8 {
                             adjusted_parent_scope,
                             !matches!(scope_set, ScopeSet::Late(..)),
                             finalize,
-                            last_import_segment,
-                            unusable_binding,
+                            ignore_binding,
                         );
                         match binding {
                             Ok(binding) => {
@@ -608,8 +602,7 @@ struct Flags: u8 {
                                 ns,
                                 parent_scope,
                                 None,
-                                last_import_segment,
-                                unusable_binding,
+                                ignore_binding,
                             ) {
                                 if use_prelude || this.is_builtin_macro(binding.res()) {
                                     result = Ok((binding, Flags::MISC_FROM_PRELUDE));
@@ -731,7 +724,7 @@ struct Flags: u8 {
         ns: Namespace,
         parent_scope: &ParentScope<'a>,
     ) -> Result<&'a NameBinding<'a>, Determinacy> {
-        self.resolve_ident_in_module_ext(module, ident, ns, parent_scope, None, false, None)
+        self.resolve_ident_in_module_ext(module, ident, ns, parent_scope, None, None)
             .map_err(|(determinacy, _)| determinacy)
     }
 
@@ -742,23 +735,11 @@ struct Flags: u8 {
         ident: Ident,
         ns: Namespace,
         parent_scope: &ParentScope<'a>,
-        finalize: Option<Span>,
-        // We are resolving a last import segment during import validation.
-        last_import_segment: bool,
-        // This binding should be ignored during in-module resolution, so that we don't get
-        // "self-confirming" import resolutions during import validation.
-        unusable_binding: Option<&'a NameBinding<'a>>,
+        finalize: Option<Finalize>,
+        ignore_binding: Option<&'a NameBinding<'a>>,
     ) -> Result<&'a NameBinding<'a>, Determinacy> {
-        self.resolve_ident_in_module_ext(
-            module,
-            ident,
-            ns,
-            parent_scope,
-            finalize,
-            last_import_segment,
-            unusable_binding,
-        )
-        .map_err(|(determinacy, _)| determinacy)
+        self.resolve_ident_in_module_ext(module, ident, ns, parent_scope, finalize, ignore_binding)
+            .map_err(|(determinacy, _)| determinacy)
     }
 
     #[tracing::instrument(level = "debug", skip(self))]
@@ -768,9 +749,8 @@ fn resolve_ident_in_module_ext(
         mut ident: Ident,
         ns: Namespace,
         parent_scope: &ParentScope<'a>,
-        finalize: Option<Span>,
-        last_import_segment: bool,
-        unusable_binding: Option<&'a NameBinding<'a>>,
+        finalize: Option<Finalize>,
+        ignore_binding: Option<&'a NameBinding<'a>>,
     ) -> Result<&'a NameBinding<'a>, (Determinacy, Weak)> {
         let tmp_parent_scope;
         let mut adjusted_parent_scope = parent_scope;
@@ -796,8 +776,7 @@ fn resolve_ident_in_module_ext(
             adjusted_parent_scope,
             false,
             finalize,
-            last_import_segment,
-            unusable_binding,
+            ignore_binding,
         )
     }
 
@@ -808,9 +787,8 @@ fn resolve_ident_in_module_unadjusted(
         ident: Ident,
         ns: Namespace,
         parent_scope: &ParentScope<'a>,
-        finalize: Option<Span>,
-        last_import_segment: bool,
-        unusable_binding: Option<&'a NameBinding<'a>>,
+        finalize: Option<Finalize>,
+        ignore_binding: Option<&'a NameBinding<'a>>,
     ) -> Result<&'a NameBinding<'a>, Determinacy> {
         self.resolve_ident_in_module_unadjusted_ext(
             module,
@@ -819,8 +797,7 @@ fn resolve_ident_in_module_unadjusted(
             parent_scope,
             false,
             finalize,
-            last_import_segment,
-            unusable_binding,
+            ignore_binding,
         )
         .map_err(|(determinacy, _)| determinacy)
     }
@@ -835,9 +812,10 @@ fn resolve_ident_in_module_unadjusted_ext(
         ns: Namespace,
         parent_scope: &ParentScope<'a>,
         restricted_shadowing: bool,
-        finalize: Option<Span>,
-        last_import_segment: bool,
-        unusable_binding: Option<&'a NameBinding<'a>>,
+        finalize: Option<Finalize>,
+        // This binding should be ignored during in-module resolution, so that we don't get
+        // "self-confirming" import resolutions during import validation and checking.
+        ignore_binding: Option<&'a NameBinding<'a>>,
     ) -> Result<&'a NameBinding<'a>, (Determinacy, Weak)> {
         let module = match module {
             ModuleOrUniformRoot::Module(module) => module,
@@ -849,8 +827,7 @@ fn resolve_ident_in_module_unadjusted_ext(
                     parent_scope,
                     finalize,
                     finalize.is_some(),
-                    last_import_segment,
-                    unusable_binding,
+                    ignore_binding,
                 );
                 return binding.map_err(|determinacy| (determinacy, Weak::No));
             }
@@ -890,8 +867,7 @@ fn resolve_ident_in_module_unadjusted_ext(
                     parent_scope,
                     finalize,
                     finalize.is_some(),
-                    last_import_segment,
-                    unusable_binding,
+                    ignore_binding,
                 );
                 return binding.map_err(|determinacy| (determinacy, Weak::No));
             }
@@ -901,19 +877,15 @@ fn resolve_ident_in_module_unadjusted_ext(
         let resolution =
             self.resolution(module, key).try_borrow_mut().map_err(|_| (Determined, Weak::No))?; // This happens when there is a cycle of imports.
 
-        if let Some(path_span) = finalize {
+        if let Some(Finalize { path_span, report_private, .. }) = finalize {
             // If the primary binding is unusable, search further and return the shadowed glob
             // binding if it exists. What we really want here is having two separate scopes in
             // a module - one for non-globs and one for globs, but until that's done use this
             // hack to avoid inconsistent resolution ICEs during import validation.
             let binding = [resolution.binding, resolution.shadowed_glob]
                 .into_iter()
-                .filter_map(|binding| match (binding, unusable_binding) {
-                    (Some(binding), Some(unusable_binding))
-                        if ptr::eq(binding, unusable_binding) =>
-                    {
-                        None
-                    }
+                .filter_map(|binding| match (binding, ignore_binding) {
+                    (Some(binding), Some(ignored)) if ptr::eq(binding, ignored) => None,
                     _ => binding,
                 })
                 .next();
@@ -922,14 +894,14 @@ fn resolve_ident_in_module_unadjusted_ext(
             };
 
             if !self.is_accessible_from(binding.vis, parent_scope.module) {
-                if last_import_segment {
-                    return Err((Determined, Weak::No));
-                } else {
+                if report_private {
                     self.privacy_errors.push(PrivacyError {
                         ident,
                         binding,
                         dedup_span: path_span,
                     });
+                } else {
+                    return Err((Determined, Weak::No));
                 }
             }
 
@@ -960,10 +932,8 @@ fn resolve_ident_in_module_unadjusted_ext(
         }
 
         let check_usable = |this: &mut Self, binding: &'a NameBinding<'a>| {
-            if let Some(unusable_binding) = unusable_binding {
-                if ptr::eq(binding, unusable_binding) {
-                    return Err((Determined, Weak::No));
-                }
+            if let Some(ignored) = ignore_binding && ptr::eq(binding, ignored) {
+                return Err((Determined, Weak::No));
             }
             let usable = this.is_accessible_from(binding.vis, parent_scope.module);
             if usable { Ok(binding) } else { Err((Determined, Weak::No)) }
@@ -996,8 +966,7 @@ fn resolve_ident_in_module_unadjusted_ext(
                 ns,
                 &single_import.parent_scope,
                 None,
-                last_import_segment,
-                unusable_binding,
+                ignore_binding,
             ) {
                 Err(Determined) => continue,
                 Ok(binding)
@@ -1073,8 +1042,7 @@ fn resolve_ident_in_module_unadjusted_ext(
                 ns,
                 adjusted_parent_scope,
                 None,
-                last_import_segment,
-                unusable_binding,
+                ignore_binding,
             );
 
             match result {
@@ -1211,7 +1179,7 @@ fn validate_res_from_ribs(
                         ConstantItemRibKind(trivial, _) => {
                             let features = self.session.features_untracked();
                             // HACK(min_const_generics): We currently only allow `N` or `{ N }`.
-                            if !(trivial || features.generic_const_exprs) {
+                            if !(trivial == HasGenericParams::Yes || features.generic_const_exprs) {
                                 // HACK(min_const_generics): If we encounter `Self` in an anonymous constant
                                 // we can't easily tell if it's generic at this stage, so we instead remember
                                 // this and then enforce the self type to be concrete later on.
@@ -1299,7 +1267,7 @@ fn validate_res_from_ribs(
                         ConstantItemRibKind(trivial, _) => {
                             let features = self.session.features_untracked();
                             // HACK(min_const_generics): We currently only allow `N` or `{ N }`.
-                            if !(trivial || features.generic_const_exprs) {
+                            if !(trivial == HasGenericParams::Yes || features.generic_const_exprs) {
                                 if let Some(span) = finalize {
                                     self.report_error(
                                         span,
@@ -1371,7 +1339,7 @@ fn validate_res_from_ribs(
         opt_ns: Option<Namespace>, // `None` indicates a module path in import
         parent_scope: &ParentScope<'a>,
     ) -> PathResult<'a> {
-        self.resolve_path_with_ribs(path, opt_ns, parent_scope, Finalize::No, None, None)
+        self.resolve_path_with_ribs(path, opt_ns, parent_scope, None, None, None)
     }
 
     #[tracing::instrument(level = "debug", skip(self))]
@@ -1380,10 +1348,10 @@ fn validate_res_from_ribs(
         path: &[Segment],
         opt_ns: Option<Namespace>, // `None` indicates a module path in import
         parent_scope: &ParentScope<'a>,
-        finalize: Finalize,
-        unusable_binding: Option<&'a NameBinding<'a>>,
+        finalize: Option<Finalize>,
+        ignore_binding: Option<&'a NameBinding<'a>>,
     ) -> PathResult<'a> {
-        self.resolve_path_with_ribs(path, opt_ns, parent_scope, finalize, None, unusable_binding)
+        self.resolve_path_with_ribs(path, opt_ns, parent_scope, finalize, None, ignore_binding)
     }
 
     crate fn resolve_path_with_ribs(
@@ -1391,13 +1359,12 @@ fn validate_res_from_ribs(
         path: &[Segment],
         opt_ns: Option<Namespace>, // `None` indicates a module path in import
         parent_scope: &ParentScope<'a>,
-        finalize_full: Finalize,
+        finalize: Option<Finalize>,
         ribs: Option<&PerNS<Vec<Rib<'a>>>>,
-        unusable_binding: Option<&'a NameBinding<'a>>,
+        ignore_binding: Option<&'a NameBinding<'a>>,
     ) -> PathResult<'a> {
-        debug!("resolve_path(path={:?}, opt_ns={:?}, finalize={:?})", path, opt_ns, finalize_full);
+        debug!("resolve_path(path={:?}, opt_ns={:?}, finalize={:?})", path, opt_ns, finalize);
 
-        let finalize = finalize_full.path_span();
         let mut module = None;
         let mut allow_super = true;
         let mut second_binding = None;
@@ -1497,8 +1464,7 @@ enum FindBindingResult<'a> {
                         ns,
                         parent_scope,
                         finalize,
-                        false,
-                        unusable_binding,
+                        ignore_binding,
                     )
                 } else if let Some(ribs) = ribs
                     && let Some(TypeNS | ValueNS) = opt_ns
@@ -1507,9 +1473,9 @@ enum FindBindingResult<'a> {
                         ident,
                         ns,
                         parent_scope,
-                        finalize_full,
+                        finalize,
                         &ribs[ns],
-                        unusable_binding,
+                        ignore_binding,
                     ) {
                         // we found a locally-imported or available item/module
                         Some(LexicalScopeBinding::Item(binding)) => Ok(binding),
@@ -1525,8 +1491,7 @@ enum FindBindingResult<'a> {
                         parent_scope,
                         finalize,
                         finalize.is_some(),
-                        false,
-                        unusable_binding,
+                        ignore_binding,
                     )
                 };
                 FindBindingResult::Binding(binding)
@@ -1566,7 +1531,7 @@ enum FindBindingResult<'a> {
                     } else if res == Res::Err {
                         return PathResult::NonModule(PartialRes::new(Res::Err));
                     } else if opt_ns.is_some() && (is_last || maybe_assoc) {
-                        self.lint_if_path_starts_with_module(finalize_full, path, second_binding);
+                        self.lint_if_path_starts_with_module(finalize, path, second_binding);
                         return PathResult::NonModule(PartialRes::with_unresolved_segments(
                             res,
                             path.len() - i - 1,
@@ -1599,7 +1564,7 @@ enum FindBindingResult<'a> {
                             opt_ns,
                             parent_scope,
                             ribs,
-                            unusable_binding,
+                            ignore_binding,
                             module,
                             i,
                             ident,
@@ -1609,7 +1574,7 @@ enum FindBindingResult<'a> {
             }
         }
 
-        self.lint_if_path_starts_with_module(finalize_full, path, second_binding);
+        self.lint_if_path_starts_with_module(finalize, path, second_binding);
 
         PathResult::Module(match module {
             Some(module) => module,
index 01dc727737a5a53e2c0891b11b2aa19ae2da5978..3d0e2b9921d00e17a1602608ba1229fb9c23f39f 100644 (file)
@@ -13,7 +13,6 @@
 use rustc_data_structures::intern::Interned;
 use rustc_errors::{pluralize, struct_span_err, Applicability, MultiSpan};
 use rustc_hir::def::{self, PartialRes};
-use rustc_hir::def_id::DefId;
 use rustc_middle::metadata::ModChild;
 use rustc_middle::span_bug;
 use rustc_middle::ty;
@@ -345,12 +344,6 @@ pub struct ImportResolver<'a, 'b> {
     pub r: &'a mut Resolver<'b>,
 }
 
-impl<'a, 'b> ty::DefIdTree for &'a ImportResolver<'a, 'b> {
-    fn parent(self, id: DefId) -> Option<DefId> {
-        self.r.parent(id)
-    }
-}
-
 impl<'a, 'b> ImportResolver<'a, 'b> {
     // Import resolution
     //
@@ -545,7 +538,6 @@ fn resolve_import(&mut self, import: &'b Import<'b>) -> bool {
                         ns,
                         &import.parent_scope,
                         None,
-                        false,
                         None,
                     );
                     import.vis.set(orig_vis);
@@ -589,22 +581,18 @@ fn resolve_import(&mut self, import: &'b Import<'b>) -> bool {
     /// consolidate multiple unresolved import errors into a single diagnostic.
     fn finalize_import(&mut self, import: &'b Import<'b>) -> Option<UnresolvedImportError> {
         let orig_vis = import.vis.replace(ty::Visibility::Invisible);
-        let unusable_binding = match &import.kind {
+        let ignore_binding = match &import.kind {
             ImportKind::Single { target_bindings, .. } => target_bindings[TypeNS].get(),
             _ => None,
         };
         let prev_ambiguity_errors_len = self.r.ambiguity_errors.len();
-        let finalize = Finalize::UsePath {
-            root_id: import.root_id,
-            root_span: import.root_span,
-            path_span: import.span,
-        };
+        let finalize = Finalize::with_root_span(import.root_id, import.span, import.root_span);
         let path_res = self.r.resolve_path(
             &import.module_path,
             None,
             &import.parent_scope,
-            finalize,
-            unusable_binding,
+            Some(finalize),
+            ignore_binding,
         );
         let no_ambiguity = self.r.ambiguity_errors.len() == prev_ambiguity_errors_len;
         import.vis.set(orig_vis);
@@ -685,7 +673,7 @@ fn finalize_import(&mut self, import: &'b Import<'b>) -> Option<UnresolvedImport
                     // 2 segments, so the `resolve_path` above won't trigger it.
                     let mut full_path = import.module_path.clone();
                     full_path.push(Segment::from_ident(Ident::empty()));
-                    self.r.lint_if_path_starts_with_module(finalize, &full_path, None);
+                    self.r.lint_if_path_starts_with_module(Some(finalize), &full_path, None);
                 }
 
                 if let ModuleOrUniformRoot::Module(module) = module {
@@ -701,7 +689,7 @@ fn finalize_import(&mut self, import: &'b Import<'b>) -> Option<UnresolvedImport
                 }
                 if !is_prelude &&
                    max_vis.get() != ty::Visibility::Invisible && // Allow empty globs.
-                   !max_vis.get().is_at_least(import.vis.get(), &*self)
+                   !max_vis.get().is_at_least(import.vis.get(), &*self.r)
                 {
                     let msg = "glob import doesn't reexport anything because no candidate is public enough";
                     self.r.lint_buffer.buffer_lint(UNUSED_IMPORTS, import.id, import.span, msg);
@@ -720,8 +708,7 @@ fn finalize_import(&mut self, import: &'b Import<'b>) -> Option<UnresolvedImport
                     ident,
                     ns,
                     &import.parent_scope,
-                    Some(import.span),
-                    true,
+                    Some(Finalize { report_private: false, ..finalize }),
                     target_bindings[ns].get(),
                 );
                 import.vis.set(orig_vis);
@@ -781,8 +768,7 @@ fn finalize_import(&mut self, import: &'b Import<'b>) -> Option<UnresolvedImport
                         ident,
                         ns,
                         &import.parent_scope,
-                        Some(import.span),
-                        false,
+                        Some(finalize),
                         None,
                     );
                     if binding.is_ok() {
@@ -948,7 +934,7 @@ fn finalize_import(&mut self, import: &'b Import<'b>) -> Option<UnresolvedImport
             full_path.push(Segment::from_ident(ident));
             self.r.per_ns(|this, ns| {
                 if let Ok(binding) = source_bindings[ns].get() {
-                    this.lint_if_path_starts_with_module(finalize, &full_path, Some(binding));
+                    this.lint_if_path_starts_with_module(Some(finalize), &full_path, Some(binding));
                 }
             });
         }
@@ -1003,7 +989,6 @@ fn check_for_redundant_imports(
                     &import.parent_scope,
                     None,
                     false,
-                    false,
                     target_bindings[ns].get(),
                 ) {
                     Ok(other_binding) => {
index 591bad70840a4ec7009eb274f7c3a5b17fda1c8b..ab353128cbcced62dc7b0071de6a11845b58b3ac 100644 (file)
 use crate::{ResolutionError, Resolver, Segment, UseError};
 
 use rustc_ast::ptr::P;
-use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
+use rustc_ast::visit::{self, AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor};
 use rustc_ast::*;
-use rustc_ast_lowering::ResolverAstLowering;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_ast_lowering::{LifetimeRes, ResolverAstLowering};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
 use rustc_errors::DiagnosticId;
 use rustc_hir::def::Namespace::{self, *};
 use rustc_hir::def::{self, CtorKind, DefKind, PartialRes, PerNS};
 use rustc_hir::def_id::{DefId, CRATE_DEF_ID};
+use rustc_hir::definitions::DefPathData;
 use rustc_hir::{PrimTy, TraitCandidate};
+use rustc_index::vec::Idx;
 use rustc_middle::ty::DefIdTree;
 use rustc_middle::{bug, span_bug};
 use rustc_session::lint;
@@ -92,6 +94,12 @@ enum PatBoundCtx {
     No,
 }
 
+impl HasGenericParams {
+    fn force_yes_if(self, b: bool) -> Self {
+        if b { Self::Yes } else { self }
+    }
+}
+
 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
 crate enum ConstantItemKind {
     Const,
@@ -123,9 +131,9 @@ enum PatBoundCtx {
 
     /// We're in a constant item. Can't refer to dynamic stuff.
     ///
-    /// The `bool` indicates if this constant may reference generic parameters
-    /// and is used to only allow generic parameters to be used in trivial constant expressions.
-    ConstantItemRibKind(bool, Option<(Ident, ConstantItemKind)>),
+    /// The item may reference generic parameters in trivial constant expressions.
+    /// All other constants aren't allowed to use generic params at all.
+    ConstantItemRibKind(HasGenericParams, Option<(Ident, ConstantItemKind)>),
 
     /// We passed through a module.
     ModuleRibKind(Module<'a>),
@@ -195,7 +203,17 @@ enum LifetimeRibKind {
     Item,
 
     /// This rib declares generic parameters.
-    Generics { span: Span, kind: LifetimeBinderKind },
+    Generics { parent: NodeId, span: Span, kind: LifetimeBinderKind },
+
+    /// FIXME(const_generics): This patches over an ICE caused by non-'static lifetimes in const
+    /// generics. We are disallowing this until we can decide on how we want to handle non-'static
+    /// lifetimes in const generics. See issue #74052 for discussion.
+    ConstGeneric,
+
+    /// Non-static lifetimes are prohibited in anonymous constants under `min_const_generics`.
+    /// This function will emit an error if `generic_const_exprs` is not enabled, the body identified by
+    /// `body_id` is an anonymous constant and `lifetime_ref` is non-static.
+    AnonConst,
 
     /// For **Modern** cases, create a new anonymous region parameter
     /// and reference that.
@@ -204,7 +222,7 @@ enum LifetimeRibKind {
     /// `resolve_lifetime` code.
     ///
     /// For **Deprecated** cases, report an error.
-    AnonymousCreateParameter,
+    AnonymousCreateParameter(NodeId),
 
     /// Give a hard error when either `&` or `'_` is written. Used to
     /// rule out things like `where T: Foo<'_>`. Does not imply an
@@ -212,7 +230,7 @@ enum LifetimeRibKind {
     AnonymousReportError,
 
     /// Pass responsibility to `resolve_lifetime` code for all cases.
-    AnonymousPassThrough,
+    AnonymousPassThrough(NodeId),
 }
 
 #[derive(Copy, Clone, Debug)]
@@ -242,7 +260,8 @@ fn descr(self) -> &'static str {
 #[derive(Debug)]
 struct LifetimeRib {
     kind: LifetimeRibKind,
-    bindings: IdentMap<()>,
+    // We need to preserve insertion order for async fns.
+    bindings: FxIndexMap<Ident, (NodeId, LifetimeRes)>,
 }
 
 impl LifetimeRib {
@@ -524,7 +543,9 @@ fn visit_block(&mut self, block: &'ast Block) {
     }
     fn visit_anon_const(&mut self, constant: &'ast AnonConst) {
         // We deal with repeat expressions explicitly in `resolve_expr`.
-        self.resolve_anon_const(constant, IsRepeatExpr::No);
+        self.with_lifetime_rib(LifetimeRibKind::AnonConst, |this| {
+            this.resolve_anon_const(constant, IsRepeatExpr::No);
+        })
     }
     fn visit_expr(&mut self, expr: &'ast Expr) {
         self.resolve_expr(expr, None);
@@ -563,7 +584,7 @@ fn visit_ty(&mut self, ty: &'ast Ty) {
                     .resolve_ident_in_lexical_scope(
                         self_ty,
                         TypeNS,
-                        Finalize::SimplePath(ty.id, ty.span),
+                        Some(Finalize::new(ty.id, ty.span)),
                         None,
                     )
                     .map_or(Res::Err, |d| d.res());
@@ -581,12 +602,19 @@ fn visit_ty(&mut self, ty: &'ast Ty) {
                 self.with_generic_param_rib(
                     &bare_fn.generic_params,
                     NormalRibKind,
-                    LifetimeRibKind::Generics { kind: LifetimeBinderKind::BareFnType, span },
+                    LifetimeRibKind::Generics {
+                        parent: ty.id,
+                        kind: LifetimeBinderKind::BareFnType,
+                        span,
+                    },
                     |this| {
-                        this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough, |this| {
-                            this.visit_generic_param_vec(&bare_fn.generic_params, false);
-                            visit::walk_fn_decl(this, &bare_fn.decl);
-                        });
+                        this.with_lifetime_rib(
+                            LifetimeRibKind::AnonymousPassThrough(ty.id),
+                            |this| {
+                                this.visit_generic_param_vec(&bare_fn.generic_params, false);
+                                visit::walk_fn_decl(this, &bare_fn.decl);
+                            },
+                        );
                     },
                 );
                 self.diagnostic_metadata.current_trait_object = prev;
@@ -604,7 +632,11 @@ fn visit_poly_trait_ref(&mut self, tref: &'ast PolyTraitRef, _: &'ast TraitBound
         self.with_generic_param_rib(
             &tref.bound_generic_params,
             NormalRibKind,
-            LifetimeRibKind::Generics { kind: LifetimeBinderKind::PolyTrait, span },
+            LifetimeRibKind::Generics {
+                parent: tref.trait_ref.ref_id,
+                kind: LifetimeBinderKind::PolyTrait,
+                span,
+            },
             |this| {
                 this.visit_generic_param_vec(&tref.bound_generic_params, false);
                 this.smart_resolve_path(
@@ -625,6 +657,7 @@ fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) {
                         &generics.params,
                         ItemRibKind(HasGenericParams::Yes),
                         LifetimeRibKind::Generics {
+                            parent: foreign_item.id,
                             kind: LifetimeBinderKind::Item,
                             span: generics.span,
                         },
@@ -638,6 +671,7 @@ fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) {
                         &generics.params,
                         ItemRibKind(HasGenericParams::Yes),
                         LifetimeRibKind::Generics {
+                            parent: foreign_item.id,
                             kind: LifetimeBinderKind::Function,
                             span: generics.span,
                         },
@@ -655,13 +689,13 @@ fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) {
             }
         }
     }
-    fn visit_fn(&mut self, fn_kind: FnKind<'ast>, sp: Span, _: NodeId) {
+    fn visit_fn(&mut self, fn_kind: FnKind<'ast>, sp: Span, fn_id: NodeId) {
         let rib_kind = match fn_kind {
             // Bail if the function is foreign, and thus cannot validly have
             // a body, or if there's no body for some other reason.
             FnKind::Fn(FnCtxt::Foreign, _, sig, _, generics, _)
             | FnKind::Fn(_, _, sig, _, generics, None) => {
-                self.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough, |this| {
+                self.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough(fn_id), |this| {
                     // We don't need to deal with patterns in parameters, because
                     // they are not possible for foreign or bodiless functions.
                     this.visit_fn_header(&sig.header);
@@ -691,20 +725,50 @@ fn visit_fn(&mut self, fn_kind: FnKind<'ast>, sp: Span, _: NodeId) {
                     this.visit_generics(generics);
                 }
 
-                if async_node_id.is_some() {
+                if let Some(async_node_id) = async_node_id {
                     // In `async fn`, argument-position elided lifetimes
                     // must be transformed into fresh generic parameters so that
                     // they can be applied to the opaque `impl Trait` return type.
-                    this.with_lifetime_rib(LifetimeRibKind::AnonymousCreateParameter, |this| {
-                        // Add each argument to the rib.
-                        this.resolve_params(&declaration.inputs)
-                    });
+                    this.with_lifetime_rib(
+                        LifetimeRibKind::AnonymousCreateParameter(fn_id),
+                        |this| {
+                            // Add each argument to the rib.
+                            this.resolve_params(&declaration.inputs)
+                        },
+                    );
 
-                    this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough, |this| {
-                        visit::walk_fn_ret_ty(this, &declaration.output)
-                    });
+                    // Construct the list of in-scope lifetime parameters for async lowering.
+                    // We include all lifetime parameters, either named or "Fresh".
+                    // The order of those parameters does not matter, as long as it is
+                    // deterministic.
+                    let mut extra_lifetime_params =
+                        this.r.extra_lifetime_params_map.get(&fn_id).cloned().unwrap_or_default();
+                    for rib in this.lifetime_ribs.iter().rev() {
+                        extra_lifetime_params.extend(
+                            rib.bindings
+                                .iter()
+                                .map(|(&ident, &(node_id, res))| (ident, node_id, res)),
+                        );
+                        match rib.kind {
+                            LifetimeRibKind::Item => break,
+                            LifetimeRibKind::AnonymousCreateParameter(id) => {
+                                if let Some(earlier_fresh) =
+                                    this.r.extra_lifetime_params_map.get(&id)
+                                {
+                                    extra_lifetime_params.extend(earlier_fresh);
+                                }
+                            }
+                            _ => {}
+                        }
+                    }
+                    this.r.extra_lifetime_params_map.insert(async_node_id, extra_lifetime_params);
+
+                    this.with_lifetime_rib(
+                        LifetimeRibKind::AnonymousPassThrough(async_node_id),
+                        |this| visit::walk_fn_ret_ty(this, &declaration.output),
+                    );
                 } else {
-                    this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough, |this| {
+                    this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough(fn_id), |this| {
                         // Add each argument to the rib.
                         this.resolve_params(&declaration.inputs);
 
@@ -716,13 +780,12 @@ fn visit_fn(&mut self, fn_kind: FnKind<'ast>, sp: Span, _: NodeId) {
                 // Be sure not to set this until the function signature has been resolved.
                 let previous_state = replace(&mut this.in_func_body, true);
                 // Resolve the function body, potentially inside the body of an async closure
-                this.with_lifetime_rib(
-                    LifetimeRibKind::AnonymousPassThrough,
-                    |this| match fn_kind {
+                this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough(fn_id), |this| {
+                    match fn_kind {
                         FnKind::Fn(.., body) => walk_list!(this, visit_block, body),
                         FnKind::Closure(_, body) => this.visit_expr(body),
-                    },
-                );
+                    }
+                });
 
                 debug!("(resolving function) leaving function");
                 this.in_func_body = previous_state;
@@ -769,19 +832,24 @@ fn visit_generic_arg(&mut self, arg: &'ast GenericArg) {
                             // Note that we might not be inside of an repeat expression here,
                             // but considering that `IsRepeatExpr` is only relevant for
                             // non-trivial constants this is doesn't matter.
-                            self.with_constant_rib(IsRepeatExpr::No, true, None, |this| {
-                                this.smart_resolve_path(
-                                    ty.id,
-                                    qself.as_ref(),
-                                    path,
-                                    PathSource::Expr(None),
-                                );
-
-                                if let Some(ref qself) = *qself {
-                                    this.visit_ty(&qself.ty);
-                                }
-                                this.visit_path(path, ty.id);
-                            });
+                            self.with_constant_rib(
+                                IsRepeatExpr::No,
+                                HasGenericParams::Yes,
+                                None,
+                                |this| {
+                                    this.smart_resolve_path(
+                                        ty.id,
+                                        qself.as_ref(),
+                                        path,
+                                        PathSource::Expr(None),
+                                    );
+
+                                    if let Some(ref qself) = *qself {
+                                        this.visit_ty(&qself.ty);
+                                    }
+                                    this.visit_path(path, ty.id);
+                                },
+                            );
 
                             self.diagnostic_metadata.currently_processing_generics = prev;
                             return;
@@ -801,10 +869,10 @@ fn visit_path_segment(&mut self, path_span: Span, path_segment: &'ast PathSegmen
         if let Some(ref args) = path_segment.args {
             match &**args {
                 GenericArgs::AngleBracketed(..) => visit::walk_generic_args(self, path_span, args),
-                GenericArgs::Parenthesized(..) => self
-                    .with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough, |this| {
-                        visit::walk_generic_args(this, path_span, args)
-                    }),
+                GenericArgs::Parenthesized(..) => self.with_lifetime_rib(
+                    LifetimeRibKind::AnonymousPassThrough(path_segment.id),
+                    |this| visit::walk_generic_args(this, path_span, args),
+                ),
             }
         }
     }
@@ -830,12 +898,16 @@ fn visit_where_predicate(&mut self, p: &'ast WherePredicate) {
                 this.with_generic_param_rib(
                     &bound_generic_params,
                     NormalRibKind,
-                    LifetimeRibKind::Generics { kind: LifetimeBinderKind::WhereBound, span },
+                    LifetimeRibKind::Generics {
+                        parent: bounded_ty.id,
+                        kind: LifetimeBinderKind::WhereBound,
+                        span,
+                    },
                     |this| {
                         this.visit_generic_param_vec(&bound_generic_params, false);
                         this.visit_ty(bounded_ty);
                         for bound in bounds {
-                            this.visit_param_bound(bound)
+                            this.visit_param_bound(bound, BoundKind::Bound)
                         }
                     },
                 );
@@ -897,7 +969,7 @@ fn maybe_resolve_ident_in_lexical_scope(
             ident,
             ns,
             &self.parent_scope,
-            Finalize::No,
+            None,
             &self.ribs[ns],
             None,
         )
@@ -907,8 +979,8 @@ fn resolve_ident_in_lexical_scope(
         &mut self,
         ident: Ident,
         ns: Namespace,
-        finalize: Finalize,
-        unusable_binding: Option<&'a NameBinding<'a>>,
+        finalize: Option<Finalize>,
+        ignore_binding: Option<&'a NameBinding<'a>>,
     ) -> Option<LexicalScopeBinding<'a>> {
         self.r.resolve_ident_in_lexical_scope(
             ident,
@@ -916,7 +988,7 @@ fn resolve_ident_in_lexical_scope(
             &self.parent_scope,
             finalize,
             &self.ribs[ns],
-            unusable_binding,
+            ignore_binding,
         )
     }
 
@@ -924,7 +996,7 @@ fn resolve_path(
         &mut self,
         path: &[Segment],
         opt_ns: Option<Namespace>, // `None` indicates a module path in import
-        finalize: Finalize,
+        finalize: Option<Finalize>,
     ) -> PathResult<'a> {
         self.r.resolve_path_with_ribs(
             path,
@@ -1026,12 +1098,12 @@ fn visit_generic_param_vec(&mut self, params: &'ast Vec<GenericParam>, add_self_
                 match param.kind {
                     GenericParamKind::Lifetime => {
                         for bound in &param.bounds {
-                            this.visit_param_bound(bound);
+                            this.visit_param_bound(bound, BoundKind::Bound);
                         }
                     }
                     GenericParamKind::Type { ref default } => {
                         for bound in &param.bounds {
-                            this.visit_param_bound(bound);
+                            this.visit_param_bound(bound, BoundKind::Bound);
                         }
 
                         if let Some(ref ty) = default {
@@ -1053,14 +1125,18 @@ fn visit_generic_param_vec(&mut self, params: &'ast Vec<GenericParam>, add_self_
 
                         this.ribs[TypeNS].push(Rib::new(ConstParamTyRibKind));
                         this.ribs[ValueNS].push(Rib::new(ConstParamTyRibKind));
-                        this.visit_ty(ty);
+                        this.with_lifetime_rib(LifetimeRibKind::ConstGeneric, |this| {
+                            this.visit_ty(ty)
+                        });
                         this.ribs[TypeNS].pop().unwrap();
                         this.ribs[ValueNS].pop().unwrap();
 
                         if let Some(ref expr) = default {
                             this.ribs[TypeNS].push(forward_ty_ban_rib);
                             this.ribs[ValueNS].push(forward_const_ban_rib);
-                            this.visit_anon_const(expr);
+                            this.with_lifetime_rib(LifetimeRibKind::ConstGeneric, |this| {
+                                this.resolve_anon_const(expr, IsRepeatExpr::No)
+                            });
                             forward_const_ban_rib = this.ribs[ValueNS].pop().unwrap();
                             forward_ty_ban_rib = this.ribs[TypeNS].pop().unwrap();
                         }
@@ -1092,6 +1168,7 @@ fn resolve_lifetime(&mut self, lifetime: &'ast Lifetime) {
         let ident = lifetime.ident;
 
         if ident.name == kw::StaticLifetime {
+            self.record_lifetime_res(lifetime.id, LifetimeRes::Static);
             return;
         }
 
@@ -1103,12 +1180,24 @@ fn resolve_lifetime(&mut self, lifetime: &'ast Lifetime) {
         for i in &mut indices {
             let rib = &self.lifetime_ribs[i];
             let normalized_ident = ident.normalize_to_macros_2_0();
-            if let Some(_) = rib.bindings.get_key_value(&normalized_ident) {
+            if let Some(&(_, region)) = rib.bindings.get(&normalized_ident) {
+                self.record_lifetime_res(lifetime.id, region);
                 return;
             }
 
-            if let LifetimeRibKind::Item = rib.kind {
-                break;
+            match rib.kind {
+                LifetimeRibKind::Item => break,
+                LifetimeRibKind::ConstGeneric => {
+                    self.emit_non_static_lt_in_const_generic_error(lifetime);
+                    self.r.lifetimes_res_map.insert(lifetime.id, LifetimeRes::Error);
+                    return;
+                }
+                LifetimeRibKind::AnonConst => {
+                    self.maybe_emit_forbidden_non_static_lifetime_error(lifetime);
+                    self.r.lifetimes_res_map.insert(lifetime.id, LifetimeRes::Error);
+                    return;
+                }
+                _ => {}
             }
         }
 
@@ -1123,6 +1212,7 @@ fn resolve_lifetime(&mut self, lifetime: &'ast Lifetime) {
         }
 
         self.emit_undeclared_lifetime_error(lifetime, outer_res);
+        self.record_lifetime_res(lifetime.id, LifetimeRes::Error);
     }
 
     #[tracing::instrument(level = "debug", skip(self))]
@@ -1132,6 +1222,10 @@ fn resolve_anonymous_lifetime(&mut self, lifetime: &Lifetime, elided: bool) {
         for i in (0..self.lifetime_ribs.len()).rev() {
             let rib = &mut self.lifetime_ribs[i];
             match rib.kind {
+                LifetimeRibKind::AnonymousCreateParameter(item_node_id) => {
+                    self.create_fresh_lifetime(lifetime.id, lifetime.ident, item_node_id);
+                    return;
+                }
                 LifetimeRibKind::AnonymousReportError => {
                     let (msg, note) = if elided {
                         (
@@ -1151,23 +1245,64 @@ fn resolve_anonymous_lifetime(&mut self, lifetime: &Lifetime, elided: bool) {
                     .span_label(lifetime.ident.span, note)
                     .emit();
 
+                    self.record_lifetime_res(lifetime.id, LifetimeRes::Error);
                     return;
                 }
-                LifetimeRibKind::AnonymousCreateParameter
-                | LifetimeRibKind::AnonymousPassThrough
-                | LifetimeRibKind::Item => return,
+                LifetimeRibKind::AnonymousPassThrough(node_id) => {
+                    self.record_lifetime_res(
+                        lifetime.id,
+                        LifetimeRes::Anonymous { binder: node_id, elided },
+                    );
+                    return;
+                }
+                LifetimeRibKind::Item => break,
                 _ => {}
             }
         }
+        // This resolution is wrong, it passes the work to HIR lifetime resolution.
+        // We cannot use `LifetimeRes::Error` because we do not emit a diagnostic.
+        self.record_lifetime_res(
+            lifetime.id,
+            LifetimeRes::Anonymous { binder: DUMMY_NODE_ID, elided },
+        );
     }
 
     #[tracing::instrument(level = "debug", skip(self))]
     fn resolve_elided_lifetime(&mut self, anchor_id: NodeId, span: Span) {
         let id = self.r.next_node_id();
+        self.record_lifetime_res(
+            anchor_id,
+            LifetimeRes::ElidedAnchor { start: id, end: NodeId::from_u32(id.as_u32() + 1) },
+        );
+
         let lt = Lifetime { id, ident: Ident::new(kw::UnderscoreLifetime, span) };
         self.resolve_anonymous_lifetime(&lt, true);
     }
 
+    #[tracing::instrument(level = "debug", skip(self))]
+    fn create_fresh_lifetime(&mut self, id: NodeId, ident: Ident, item_node_id: NodeId) {
+        debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
+        debug!(?ident.span);
+        let item_def_id = self.r.local_def_id(item_node_id);
+        let def_node_id = self.r.next_node_id();
+        let def_id = self.r.create_def(
+            item_def_id,
+            def_node_id,
+            DefPathData::LifetimeNs(kw::UnderscoreLifetime),
+            self.parent_scope.expansion.to_expn_id(),
+            ident.span,
+        );
+        debug!(?def_id);
+
+        let region = LifetimeRes::Fresh { param: def_id, binder: item_node_id };
+        self.record_lifetime_res(id, region);
+        self.r.extra_lifetime_params_map.entry(item_node_id).or_insert_with(Vec::new).push((
+            ident,
+            def_node_id,
+            region,
+        ));
+    }
+
     #[tracing::instrument(level = "debug", skip(self))]
     fn resolve_elided_lifetimes_in_path(
         &mut self,
@@ -1175,11 +1310,8 @@ fn resolve_elided_lifetimes_in_path(
         partial_res: PartialRes,
         path: &[Segment],
         source: PathSource<'_>,
-        finalize: Finalize,
+        path_span: Span,
     ) {
-        let Some(path_span) = finalize.path_span() else {
-            return;
-        };
         let proj_start = path.len() - partial_res.unresolved_segments();
         for (i, segment) in path.iter().enumerate() {
             if segment.has_lifetime_args {
@@ -1192,12 +1324,8 @@ fn resolve_elided_lifetimes_in_path(
             // Figure out if this is a type/trait segment,
             // which may need lifetime elision performed.
             let type_def_id = match partial_res.base_res() {
-                Res::Def(DefKind::AssocTy, def_id) if i + 2 == proj_start => {
-                    self.r.parent(def_id).unwrap()
-                }
-                Res::Def(DefKind::Variant, def_id) if i + 1 == proj_start => {
-                    self.r.parent(def_id).unwrap()
-                }
+                Res::Def(DefKind::AssocTy, def_id) if i + 2 == proj_start => self.r.parent(def_id),
+                Res::Def(DefKind::Variant, def_id) if i + 1 == proj_start => self.r.parent(def_id),
                 Res::Def(DefKind::Struct, def_id)
                 | Res::Def(DefKind::Union, def_id)
                 | Res::Def(DefKind::Enum, def_id)
@@ -1222,7 +1350,7 @@ fn resolve_elided_lifetimes_in_path(
                 | PathSource::Struct
                 | PathSource::TupleStruct(..) => false,
             };
-            let mut error = false;
+            let mut res = LifetimeRes::Error;
             for rib in self.lifetime_ribs.iter().rev() {
                 match rib.kind {
                     // In create-parameter mode we error here because we don't want to support
@@ -1231,8 +1359,7 @@ fn resolve_elided_lifetimes_in_path(
                     //
                     //     impl Foo for std::cell::Ref<u32> // note lack of '_
                     //     async fn foo(_: std::cell::Ref<u32>) { ... }
-                    LifetimeRibKind::AnonymousCreateParameter => {
-                        error = true;
+                    LifetimeRibKind::AnonymousCreateParameter(_) => {
                         break;
                     }
                     // `PassThrough` is the normal case.
@@ -1241,13 +1368,31 @@ fn resolve_elided_lifetimes_in_path(
                     // `PathSegment`, for which there is no associated `'_` or `&T` with no explicit
                     // lifetime. Instead, we simply create an implicit lifetime, which will be checked
                     // later, at which point a suitable error will be emitted.
-                    LifetimeRibKind::AnonymousPassThrough
-                    | LifetimeRibKind::AnonymousReportError
-                    | LifetimeRibKind::Item => break,
+                    LifetimeRibKind::AnonymousPassThrough(binder) => {
+                        res = LifetimeRes::Anonymous { binder, elided: true };
+                        break;
+                    }
+                    LifetimeRibKind::AnonymousReportError | LifetimeRibKind::Item => {
+                        // FIXME(cjgillot) This resolution is wrong, but this does not matter
+                        // since these cases are erroneous anyway.  Lifetime resolution should
+                        // emit a "missing lifetime specifier" diagnostic.
+                        res = LifetimeRes::Anonymous { binder: DUMMY_NODE_ID, elided: true };
+                        break;
+                    }
                     _ => {}
                 }
             }
 
+            let node_ids = self.r.next_node_ids(expected_lifetimes);
+            self.record_lifetime_res(
+                segment_id,
+                LifetimeRes::ElidedAnchor { start: node_ids.start, end: node_ids.end },
+            );
+            for i in 0..expected_lifetimes {
+                let id = node_ids.start.plus(i);
+                self.record_lifetime_res(id, res);
+            }
+
             if !missing {
                 continue;
             }
@@ -1261,7 +1406,7 @@ fn resolve_elided_lifetimes_in_path(
                 // originating from macros, since the segment's span might be from a macro arg.
                 segment.ident.span.find_ancestor_inside(path_span).unwrap_or(path_span)
             };
-            if error {
+            if let LifetimeRes::Error = res {
                 let sess = self.r.session;
                 let mut err = rustc_errors::struct_span_err!(
                     sess,
@@ -1296,9 +1441,19 @@ fn resolve_elided_lifetimes_in_path(
         }
     }
 
+    #[tracing::instrument(level = "debug", skip(self))]
+    fn record_lifetime_res(&mut self, id: NodeId, res: LifetimeRes) {
+        if let Some(prev_res) = self.r.lifetimes_res_map.insert(id, res) {
+            panic!(
+                "lifetime {:?} resolved multiple times ({:?} before, {:?} now)",
+                id, prev_res, res
+            )
+        }
+    }
+
     /// 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(&self, mut label: Ident) -> Option<NodeId> {
+    fn resolve_label(&mut self, mut label: Ident) -> Option<NodeId> {
         let mut suggestion = None;
 
         // Preserve the original span so that errors contain "in this macro invocation"
@@ -1318,6 +1473,7 @@ fn resolve_label(&self, mut label: Ident) -> Option<NodeId> {
 
             let ident = label.normalize_to_macro_rules();
             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)
                 } else {
@@ -1325,7 +1481,7 @@ fn resolve_label(&self, mut label: Ident) -> Option<NodeId> {
                         original_span,
                         ResolutionError::UnreachableLabel {
                             name: label.name,
-                            definition_span: ident.span,
+                            definition_span,
                             suggestion,
                         },
                     );
@@ -1379,7 +1535,11 @@ fn resolve_adt(&mut self, item: &'ast Item, generics: &'ast Generics) {
             this.with_generic_param_rib(
                 &generics.params,
                 ItemRibKind(HasGenericParams::Yes),
-                LifetimeRibKind::Generics { kind: LifetimeBinderKind::Item, span: generics.span },
+                LifetimeRibKind::Generics {
+                    parent: item.id,
+                    kind: LifetimeBinderKind::Item,
+                    span: generics.span,
+                },
                 |this| {
                     let item_def_id = this.r.local_def_id(item.id).to_def_id();
                     this.with_self_rib(
@@ -1420,8 +1580,8 @@ fn future_proof_import(&mut self, use_tree: &UseTree) {
                         report_error(self, ns);
                     }
                     Some(LexicalScopeBinding::Item(binding)) => {
-                        if let Some(LexicalScopeBinding::Res(..)) = self
-                            .resolve_ident_in_lexical_scope(ident, ns, Finalize::No, Some(binding))
+                        if let Some(LexicalScopeBinding::Res(..)) =
+                            self.resolve_ident_in_lexical_scope(ident, ns, None, Some(binding))
                         {
                             report_error(self, ns);
                         }
@@ -1446,6 +1606,7 @@ fn resolve_item(&mut self, item: &'ast Item) {
                     &generics.params,
                     ItemRibKind(HasGenericParams::Yes),
                     LifetimeRibKind::Generics {
+                        parent: item.id,
                         kind: LifetimeBinderKind::Item,
                         span: generics.span,
                     },
@@ -1458,6 +1619,7 @@ fn resolve_item(&mut self, item: &'ast Item) {
                     &generics.params,
                     ItemRibKind(HasGenericParams::Yes),
                     LifetimeRibKind::Generics {
+                        parent: item.id,
                         kind: LifetimeBinderKind::Function,
                         span: generics.span,
                     },
@@ -1487,6 +1649,7 @@ fn resolve_item(&mut self, item: &'ast Item) {
                     &generics.params,
                     ItemRibKind(HasGenericParams::Yes),
                     LifetimeRibKind::Generics {
+                        parent: item.id,
                         kind: LifetimeBinderKind::Item,
                         span: generics.span,
                     },
@@ -1496,7 +1659,7 @@ fn resolve_item(&mut self, item: &'ast Item) {
                             Res::SelfTy { trait_: Some(local_def_id), alias_to: None },
                             |this| {
                                 this.visit_generics(generics);
-                                walk_list!(this, visit_param_bound, bounds);
+                                walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits);
 
                                 let walk_assoc_item =
                                     |this: &mut Self,
@@ -1506,7 +1669,11 @@ fn resolve_item(&mut self, item: &'ast Item) {
                                         this.with_generic_param_rib(
                                             &generics.params,
                                             AssocItemRibKind,
-                                            LifetimeRibKind::Generics { span: generics.span, kind },
+                                            LifetimeRibKind::Generics {
+                                                parent: item.id,
+                                                span: generics.span,
+                                                kind,
+                                            },
                                             |this| {
                                                 visit::walk_assoc_item(this, item, AssocCtxt::Trait)
                                             },
@@ -1528,7 +1695,7 @@ fn resolve_item(&mut self, item: &'ast Item) {
                                                     // not used as part of the type system, this is far less surprising.
                                                     this.with_constant_rib(
                                                         IsRepeatExpr::No,
-                                                        true,
+                                                        HasGenericParams::Yes,
                                                         None,
                                                         |this| this.visit_expr(expr),
                                                     );
@@ -1571,6 +1738,7 @@ fn resolve_item(&mut self, item: &'ast Item) {
                     &generics.params,
                     ItemRibKind(HasGenericParams::Yes),
                     LifetimeRibKind::Generics {
+                        parent: item.id,
                         kind: LifetimeBinderKind::Item,
                         span: generics.span,
                     },
@@ -1580,7 +1748,7 @@ fn resolve_item(&mut self, item: &'ast Item) {
                             Res::SelfTy { trait_: Some(local_def_id), alias_to: None },
                             |this| {
                                 this.visit_generics(generics);
-                                walk_list!(this, visit_param_bound, bounds);
+                                walk_list!(this, visit_param_bound, bounds, BoundKind::Bound);
                             },
                         );
                     },
@@ -1606,7 +1774,7 @@ fn resolve_item(&mut self, item: &'ast Item) {
                         // so it doesn't matter whether this is a trivial constant.
                         this.with_constant_rib(
                             IsRepeatExpr::No,
-                            true,
+                            HasGenericParams::Yes,
                             Some((item.ident, constant_item_kind)),
                             |this| this.visit_expr(expr),
                         );
@@ -1696,7 +1864,7 @@ fn with_generic_param_rib<'c, F>(
                     "invalid lifetime parameter name: `{}`",
                     param.ident,
                 )
-                .span_label(param.ident.span, format!("'static is a reserved lifetime name"))
+                .span_label(param.ident.span, "'static is a reserved lifetime name")
                 .emit();
                 continue;
             }
@@ -1708,7 +1876,10 @@ fn with_generic_param_rib<'c, F>(
                 GenericParamKind::Type { .. } => (&mut function_type_rib, DefKind::TyParam),
                 GenericParamKind::Const { .. } => (&mut function_value_rib, DefKind::ConstParam),
                 GenericParamKind::Lifetime => {
-                    function_lifetime_rib.bindings.insert(ident, ());
+                    let LifetimeRibKind::Generics { parent, .. } = lifetime_kind else { panic!() };
+                    let res = LifetimeRes::Param { param: def_id, binder: parent };
+                    self.record_lifetime_res(param.id, res);
+                    function_lifetime_rib.bindings.insert(ident, (param.id, res));
                     continue;
                 }
             };
@@ -1749,20 +1920,23 @@ fn with_item_rib(&mut self, f: impl FnOnce(&mut Self)) {
     // Note that we intentionally still forbid `[0; N + 1]` during
     // name resolution so that we don't extend the future
     // compat lint to new cases.
+    #[instrument(level = "debug", skip(self, f))]
     fn with_constant_rib(
         &mut self,
         is_repeat: IsRepeatExpr,
-        is_trivial: bool,
+        may_use_generics: HasGenericParams,
         item: Option<(Ident, ConstantItemKind)>,
         f: impl FnOnce(&mut Self),
     ) {
-        debug!("with_constant_rib: is_repeat={:?} is_trivial={}", is_repeat, is_trivial);
-        self.with_rib(ValueNS, ConstantItemRibKind(is_trivial, item), |this| {
+        self.with_rib(ValueNS, ConstantItemRibKind(may_use_generics, item), |this| {
             this.with_rib(
                 TypeNS,
-                ConstantItemRibKind(is_repeat == IsRepeatExpr::Yes || is_trivial, item),
+                ConstantItemRibKind(
+                    may_use_generics.force_yes_if(is_repeat == IsRepeatExpr::Yes),
+                    item,
+                ),
                 |this| {
-                    this.with_label_rib(ConstantItemRibKind(is_trivial, item), f);
+                    this.with_label_rib(ConstantItemRibKind(may_use_generics, item), f);
                 },
             )
         });
@@ -1812,7 +1986,7 @@ fn with_optional_trait_ref<T>(
                 None,
                 &path,
                 PathSource::Trait(AliasPossibility::No),
-                Finalize::SimplePath(trait_ref.ref_id, trait_ref.path.span),
+                Finalize::new(trait_ref.ref_id, trait_ref.path.span),
             );
             if let Some(def_id) = res.base_res().opt_def_id() {
                 new_id = Some(def_id);
@@ -1849,10 +2023,10 @@ fn resolve_implementation(
     ) {
         debug!("resolve_implementation");
         // If applicable, create a rib for the type parameters.
-        self.with_generic_param_rib(&generics.params, ItemRibKind(HasGenericParams::Yes), LifetimeRibKind::Generics { span: generics.span, kind: LifetimeBinderKind::ImplBlock }, |this| {
+        self.with_generic_param_rib(&generics.params, ItemRibKind(HasGenericParams::Yes), LifetimeRibKind::Generics { span: generics.span, parent: item_id, kind: LifetimeBinderKind::ImplBlock }, |this| {
             // Dummy self type for better errors if `Self` is used in the trait path.
             this.with_self_rib(Res::SelfTy { trait_: None, alias_to: None }, |this| {
-                this.with_lifetime_rib(LifetimeRibKind::AnonymousCreateParameter, |this| {
+                this.with_lifetime_rib(LifetimeRibKind::AnonymousCreateParameter(item_id), |this| {
                     // Resolve the trait reference, if necessary.
                     this.with_optional_trait_ref(opt_trait_reference.as_ref(), |this, trait_id| {
                         let item_def_id = this.r.local_def_id(item_id);
@@ -1876,7 +2050,7 @@ fn resolve_implementation(
                             this.visit_generics(generics);
 
                             // Resolve the items within the impl.
-                            this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough,
+                            this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough(item_id),
                                 |this| {
                                     this.with_current_self_type(self_type, |this| {
                                         this.with_self_rib_ns(ValueNS, Res::SelfCtor(item_def_id), |this| {
@@ -1904,7 +2078,7 @@ fn resolve_implementation(
                                                         // not used as part of the type system, this is far less surprising.
                                                         this.with_constant_rib(
                                                             IsRepeatExpr::No,
-                                                            true,
+                                                            HasGenericParams::Yes,
                                                             None,
                                                             |this| {
                                                                 visit::walk_assoc_item(
@@ -1921,7 +2095,7 @@ fn resolve_implementation(
                                                         this.with_generic_param_rib(
                                                             &generics.params,
                                                             AssocItemRibKind,
-                                                            LifetimeRibKind::Generics { span: generics.span, kind: LifetimeBinderKind::Function },
+                                                            LifetimeRibKind::Generics { parent: item.id, span: generics.span, kind: LifetimeBinderKind::Function },
                                                             |this| {
                                                                 // If this is a trait impl, ensure the method
                                                                 // exists in trait
@@ -1950,7 +2124,7 @@ fn resolve_implementation(
                                                         this.with_generic_param_rib(
                                                             &generics.params,
                                                             AssocItemRibKind,
-                                                            LifetimeRibKind::Generics { span: generics.span, kind: LifetimeBinderKind::Item },
+                                                            LifetimeRibKind::Generics { parent: item.id, span: generics.span, kind: LifetimeBinderKind::Item },
                                                             |this| {
                                                                 // If this is a trait impl, ensure the type
                                                                 // exists in trait
@@ -1996,7 +2170,7 @@ fn check_trait_item<F>(
         span: Span,
         err: F,
     ) where
-        F: FnOnce(Ident, &str, Option<Symbol>) -> ResolutionError<'_>,
+        F: FnOnce(Ident, String, Option<Symbol>) -> ResolutionError<'a>,
     {
         // If there is a TraitRef in scope for an impl, then the method must be in the trait.
         let Some((module, _)) = &self.current_trait_ref else { return; };
@@ -2020,7 +2194,8 @@ fn check_trait_item<F>(
             // We could not find the method: report an error.
             let candidate = self.find_similarly_named_assoc_item(ident.name, kind);
             let path = &self.current_trait_ref.as_ref().unwrap().1.path;
-            self.report_error(span, err(ident, &path_names_to_string(path), candidate));
+            let path_names = path_names_to_string(path);
+            self.report_error(span, err(ident, path_names, candidate));
             return;
         };
 
@@ -2044,13 +2219,14 @@ fn check_trait_item<F>(
             AssocItemKind::TyAlias(..) => (rustc_errors::error_code!(E0325), "type"),
             AssocItemKind::MacCall(..) => span_bug!(span, "unexpanded macro"),
         };
+        let trait_path = path_names_to_string(path);
         self.report_error(
             span,
             ResolutionError::TraitImplMismatch {
                 name: ident.name,
                 kind,
                 code,
-                trait_path: path_names_to_string(path),
+                trait_path,
                 trait_item_span: binding.span,
             },
         );
@@ -2165,16 +2341,16 @@ fn check_consistent_bindings(&mut self, pats: &[P<Pat>]) -> Vec<BindingMap> {
         }
 
         // 3) Report all missing variables we found.
-        let mut missing_vars = missing_vars.iter_mut().collect::<Vec<_>>();
-        missing_vars.sort_by_key(|(sym, _err)| sym.as_str());
+        let mut missing_vars = missing_vars.into_iter().collect::<Vec<_>>();
+        missing_vars.sort_by_key(|&(sym, ref _err)| sym);
 
-        for (name, mut v) in missing_vars {
-            if inconsistent_vars.contains_key(name) {
+        for (name, mut v) in missing_vars.into_iter() {
+            if inconsistent_vars.contains_key(&name) {
                 v.could_be_path = false;
             }
             self.report_error(
                 *v.origin.iter().next().unwrap(),
-                ResolutionError::VariableNotBoundInPattern(v),
+                ResolutionError::VariableNotBoundInPattern(v, self.parent_scope),
             );
         }
 
@@ -2484,7 +2660,7 @@ fn smart_resolve_path(
             qself,
             &Segment::from_path(path),
             source,
-            Finalize::SimplePath(id, path.span),
+            Finalize::new(id, path.span),
         );
     }
 
@@ -2503,8 +2679,7 @@ fn smart_resolve_path_fragment(
         );
         let ns = source.namespace();
 
-        let (id, path_span) =
-            finalize.node_id_and_path_span().expect("unexpected speculative resolution");
+        let Finalize { node_id, path_span, .. } = finalize;
         let report_errors = |this: &mut Self, res: Option<Res>| {
             if this.should_report_errs() {
                 let (err, candidates) =
@@ -2618,7 +2793,7 @@ fn smart_resolve_path_fragment(
                 if ns == ValueNS {
                     let item_name = path.last().unwrap().ident;
                     let traits = self.traits_in_scope(item_name, ns);
-                    self.r.trait_map.insert(id, traits);
+                    self.r.trait_map.insert(node_id, traits);
                 }
 
                 if PrimTy::from_name(path[0].ident.name).is_some() {
@@ -2627,7 +2802,7 @@ fn smart_resolve_path_fragment(
                     std_path.push(Segment::from_ident(Ident::with_dummy_span(sym::std)));
                     std_path.extend(path);
                     if let PathResult::Module(_) | PathResult::NonModule(_) =
-                        self.resolve_path(&std_path, Some(ns), Finalize::No)
+                        self.resolve_path(&std_path, Some(ns), None)
                     {
                         // Check if we wrote `str::from_utf8` instead of `std::str::from_utf8`
                         let item_span =
@@ -2654,10 +2829,10 @@ fn smart_resolve_path_fragment(
 
         if !matches!(source, PathSource::TraitItem(..)) {
             // Avoid recording definition of `A::B` in `<T as A>::B::C`.
-            self.r.record_partial_res(id, partial_res);
+            self.r.record_partial_res(node_id, partial_res);
+            self.resolve_elided_lifetimes_in_path(node_id, partial_res, path, source, path_span);
         }
 
-        self.resolve_elided_lifetimes_in_path(id, partial_res, path, source, finalize);
         partial_res
     }
 
@@ -2676,7 +2851,7 @@ fn self_value_is_available(&mut self, self_span: Span) -> bool {
     /// A wrapper around [`Resolver::report_error`].
     ///
     /// This doesn't emit errors for function bodies if this is rustdoc.
-    fn report_error(&self, span: Span, resolution_error: ResolutionError<'_>) {
+    fn report_error(&mut self, span: Span, resolution_error: ResolutionError<'a>) {
         if self.should_report_errs() {
             self.r.report_error(span, resolution_error);
         }
@@ -2763,21 +2938,12 @@ fn resolve_qpath(
             // the trait (the slice upto and including
             // `qself.position`). And then we recursively resolve that,
             // but with `qself` set to `None`.
-            //
-            // However, setting `qself` to none (but not changing the
-            // span) loses the information about where this path
-            // *actually* appears, so for the purposes of the crate
-            // lint we pass along information that this is the trait
-            // name from a fully qualified path, and this also
-            // contains the full span (the `Finalize::QPathTrait`).
             let ns = if qself.position + 1 == path.len() { ns } else { TypeNS };
             let partial_res = self.smart_resolve_path_fragment(
                 None,
                 &path[..=qself.position],
                 PathSource::TraitItem(ns),
-                finalize.node_id_and_path_span().map_or(Finalize::No, |(qpath_id, path_span)| {
-                    Finalize::QPathTrait { qpath_id, qpath_span: qself.path_span, path_span }
-                }),
+                Finalize::with_root_span(finalize.node_id, finalize.path_span, qself.path_span),
             );
 
             // The remaining segments (the `C` in our example) will
@@ -2789,7 +2955,7 @@ fn resolve_qpath(
             )));
         }
 
-        let result = match self.resolve_path(&path, Some(ns), finalize) {
+        let result = match self.resolve_path(&path, Some(ns), Some(finalize)) {
             PathResult::NonModule(path_res) => path_res,
             PathResult::Module(ModuleOrUniformRoot::Module(module)) if !module.is_normal() => {
                 PartialRes::new(module.res().unwrap())
@@ -2827,10 +2993,9 @@ fn resolve_qpath(
             && result.base_res() != Res::Err
             && path[0].ident.name != kw::PathRoot
             && path[0].ident.name != kw::DollarCrate
-            && let Some((id, path_span)) = finalize.node_id_and_path_span()
         {
             let unqualified_result = {
-                match self.resolve_path(&[*path.last().unwrap()], Some(ns), Finalize::No) {
+                match self.resolve_path(&[*path.last().unwrap()], Some(ns), None) {
                     PathResult::NonModule(path_res) => path_res.base_res(),
                     PathResult::Module(ModuleOrUniformRoot::Module(module)) => {
                         module.res().unwrap()
@@ -2840,7 +3005,12 @@ fn resolve_qpath(
             };
             if result.base_res() == unqualified_result {
                 let lint = lint::builtin::UNUSED_QUALIFICATIONS;
-                self.r.lint_buffer.buffer_lint(lint, id, path_span, "unnecessary qualification")
+                self.r.lint_buffer.buffer_lint(
+                    lint,
+                    finalize.node_id,
+                    finalize.path_span,
+                    "unnecessary qualification",
+                )
             }
         }
 
@@ -2921,11 +3091,13 @@ fn resolve_anon_const(&mut self, constant: &'ast AnonConst, is_repeat: IsRepeatE
         debug!("resolve_anon_const {:?} is_repeat: {:?}", constant, is_repeat);
         self.with_constant_rib(
             is_repeat,
-            constant.value.is_potential_trivial_const_param(),
-            None,
-            |this| {
-                visit::walk_anon_const(this, constant);
+            if constant.value.is_potential_trivial_const_param() {
+                HasGenericParams::Yes
+            } else {
+                HasGenericParams::No
             },
+            None,
+            |this| visit::walk_anon_const(this, constant),
         );
     }
 
@@ -3026,7 +3198,11 @@ fn resolve_expr(&mut self, expr: &'ast Expr, parent: Option<&'ast Expr>) {
                     if const_args.contains(&idx) {
                         self.with_constant_rib(
                             IsRepeatExpr::No,
-                            argument.is_potential_trivial_const_param(),
+                            if argument.is_potential_trivial_const_param() {
+                                HasGenericParams::Yes
+                            } else {
+                                HasGenericParams::No
+                            },
                             None,
                             |this| {
                                 this.resolve_expr(argument, None);
@@ -3076,7 +3252,12 @@ fn resolve_expr(&mut self, expr: &'ast Expr, parent: Option<&'ast Expr>) {
             }
             ExprKind::Repeat(ref elem, ref ct) => {
                 self.visit_expr(elem);
-                self.resolve_anon_const(ct, IsRepeatExpr::Yes);
+                self.with_lifetime_rib(LifetimeRibKind::AnonConst, |this| {
+                    this.resolve_anon_const(ct, IsRepeatExpr::Yes)
+                });
+            }
+            ExprKind::ConstBlock(ref ct) => {
+                self.resolve_anon_const(ct, IsRepeatExpr::No);
             }
             ExprKind::Index(ref elem, ref idx) => {
                 self.resolve_expr(elem, Some(expr));
index d77cc917e2f9a2035c05fd4d3b7b303c4c19db7c..3076cc1131700d8df6f0f4707f37023d54fffe95 100644 (file)
@@ -3,7 +3,7 @@
 use crate::late::{AliasPossibility, LateResolutionVisitor, RibKind};
 use crate::late::{LifetimeBinderKind, LifetimeRibKind};
 use crate::path_names_to_string;
-use crate::{Finalize, Module, ModuleKind, ModuleOrUniformRoot};
+use crate::{Module, ModuleKind, ModuleOrUniformRoot};
 use crate::{PathResult, PathSource, Segment};
 
 use rustc_ast::visit::FnKind;
@@ -86,7 +86,7 @@ impl ForLifetimeSpanType {
     }
 }
 
-impl<'tcx> Into<MissingLifetimeSpot<'tcx>> for &'tcx hir::Generics<'tcx> {
+impl<'tcx> Into<MissingLifetimeSpot<'tcx>> for &&'tcx hir::Generics<'tcx> {
     fn into(self) -> MissingLifetimeSpot<'tcx> {
         MissingLifetimeSpot::Generics(self)
     }
@@ -189,7 +189,7 @@ pub(crate) fn smart_resolve_report_errors(
                 (String::new(), "the crate root".to_string())
             } else {
                 let mod_path = &path[..path.len() - 1];
-                let mod_prefix = match self.resolve_path(mod_path, Some(TypeNS), Finalize::No) {
+                let mod_prefix = match self.resolve_path(mod_path, Some(TypeNS), None) {
                     PathResult::Module(ModuleOrUniformRoot::Module(module)) => module.res(),
                     _ => None,
                 }
@@ -648,7 +648,7 @@ fn get_single_associated_item(
         if let crate::PathSource::TraitItem(_) = source {
             let mod_path = &path[..path.len() - 1];
             if let PathResult::Module(ModuleOrUniformRoot::Module(module)) =
-                self.resolve_path(mod_path, None, Finalize::No)
+                self.resolve_path(mod_path, None, None)
             {
                 let resolutions = self.r.resolutions(module).borrow();
                 let targets: Vec<_> =
@@ -1183,9 +1183,7 @@ fn smart_resolve_context_dependent_help(
         ident: Symbol,
         kind: &AssocItemKind,
     ) -> Option<Symbol> {
-        let Some((module, _)) = &self.current_trait_ref else {
-            return None;
-        };
+        let (module, _) = self.current_trait_ref.as_ref()?;
         if ident == kw::Underscore {
             // We do nothing for `_`.
             return None;
@@ -1364,7 +1362,7 @@ fn lookup_typo_candidate(
             // Search in module.
             let mod_path = &path[..path.len() - 1];
             if let PathResult::Module(ModuleOrUniformRoot::Module(module)) =
-                self.resolve_path(mod_path, Some(TypeNS), Finalize::No)
+                self.resolve_path(mod_path, Some(TypeNS), None)
             {
                 self.r.add_module_candidates(module, &mut names, &filter_fn);
             }
@@ -1824,7 +1822,7 @@ fn suggest_using_enum_variant(
 
         for rib in self.lifetime_ribs.iter().rev() {
             match rib.kind {
-                LifetimeRibKind::Generics { span, kind } => {
+                LifetimeRibKind::Generics { parent: _, span, kind } => {
                     if !span.can_be_used_for_suggestions() && suggest_note {
                         suggest_note = false; // Avoid displaying the same help multiple times.
                         err.span_label(
@@ -1888,6 +1886,37 @@ fn suggest_using_enum_variant(
 
         err.emit();
     }
+
+    crate fn emit_non_static_lt_in_const_generic_error(&self, lifetime_ref: &ast::Lifetime) {
+        struct_span_err!(
+            self.r.session,
+            lifetime_ref.ident.span,
+            E0771,
+            "use of non-static lifetime `{}` in const generic",
+            lifetime_ref.ident
+        )
+        .note(
+            "for more information, see issue #74052 \
+            <https://github.com/rust-lang/rust/issues/74052>",
+        )
+        .emit();
+    }
+
+    /// Non-static lifetimes are prohibited in anonymous constants under `min_const_generics`.
+    /// This function will emit an error if `generic_const_exprs` is not enabled, the body identified by
+    /// `body_id` is an anonymous constant and `lifetime_ref` is non-static.
+    crate fn maybe_emit_forbidden_non_static_lifetime_error(&self, lifetime_ref: &ast::Lifetime) {
+        let feature_active = self.r.session.features_untracked().generic_const_exprs;
+        if !feature_active {
+            feature_err(
+                &self.r.session.parse_sess,
+                sym::generic_const_exprs,
+                lifetime_ref.ident.span,
+                "a non-static lifetime is not allowed in a `const`",
+            )
+            .emit();
+        }
+    }
 }
 
 impl<'tcx> LifetimeContext<'_, 'tcx> {
@@ -1984,24 +2013,6 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
         }
     }
 
-    // FIXME(const_generics): This patches over an ICE caused by non-'static lifetimes in const
-    // generics. We are disallowing this until we can decide on how we want to handle non-'static
-    // lifetimes in const generics. See issue #74052 for discussion.
-    crate fn emit_non_static_lt_in_const_generic_error(&self, lifetime_ref: &hir::Lifetime) {
-        let mut err = struct_span_err!(
-            self.tcx.sess,
-            lifetime_ref.span,
-            E0771,
-            "use of non-static lifetime `{}` in const generic",
-            lifetime_ref
-        );
-        err.note(
-            "for more information, see issue #74052 \
-            <https://github.com/rust-lang/rust/issues/74052>",
-        );
-        err.emit();
-    }
-
     crate fn is_trait_ref_fn_scope(&mut self, trait_ref: &'tcx hir::PolyTraitRef<'tcx>) -> bool {
         if let def::Res::Def(_, did) = trait_ref.trait_ref.path.res {
             if [
@@ -2403,32 +2414,4 @@ fn span_underscore_borrow(&self) -> Span {
             _ => unreachable!(),
         }
     }
-
-    /// Non-static lifetimes are prohibited in anonymous constants under `min_const_generics`.
-    /// This function will emit an error if `generic_const_exprs` is not enabled, the body identified by
-    /// `body_id` is an anonymous constant and `lifetime_ref` is non-static.
-    crate fn maybe_emit_forbidden_non_static_lifetime_error(
-        &self,
-        body_id: hir::BodyId,
-        lifetime_ref: &'tcx hir::Lifetime,
-    ) {
-        let is_anon_const = matches!(
-            self.tcx.def_kind(self.tcx.hir().body_owner_def_id(body_id)),
-            hir::def::DefKind::AnonConst
-        );
-        let is_allowed_lifetime = matches!(
-            lifetime_ref.name,
-            hir::LifetimeName::Implicit | hir::LifetimeName::Static | hir::LifetimeName::Underscore
-        );
-
-        if !self.tcx.lazy_normalization() && is_anon_const && !is_allowed_lifetime {
-            feature_err(
-                &self.tcx.sess.parse_sess,
-                sym::generic_const_exprs,
-                lifetime_ref.span,
-                "a non-static lifetime is not allowed in a `const`",
-            )
-            .emit();
-        }
-    }
 }
index d5f2e2db1e39b1851754fbbc0fed7d35c36b81fb..50428811fff253ce9ad0f66c0db887bbb0be69ce 100644 (file)
@@ -164,8 +164,6 @@ struct NamedRegionMap {
     map: &'a mut NamedRegionMap,
     scope: ScopeRef<'a>,
 
-    is_in_const_generic: bool,
-
     /// Indicates that we only care about the definition of a trait. This should
     /// be false if the `Item` we are resolving lifetimes for is not a trait or
     /// we eventually need lifetimes resolve for trait items.
@@ -452,7 +450,6 @@ fn do_resolve(
         tcx,
         map: &mut named_region_map,
         scope: ROOT_SCOPE,
-        is_in_const_generic: false,
         trait_definition_only,
         labels_in_fn: vec![],
         xcrate_object_lifetime_defaults: Default::default(),
@@ -537,21 +534,17 @@ fn is_late_bound_map<'tcx>(
 ) -> Option<(LocalDefId, &'tcx FxHashSet<LocalDefId>)> {
     match tcx.def_kind(def_id) {
         DefKind::AnonConst | DefKind::InlineConst => {
-            let mut def_id = tcx
-                .parent(def_id.to_def_id())
-                .unwrap_or_else(|| bug!("anon const or closure without a parent"));
+            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) {
-                def_id = tcx
-                    .parent(def_id)
-                    .unwrap_or_else(|| bug!("anon const or closure without a parent"));
+            while tcx.is_closure(def_id.to_def_id()) {
+                def_id = tcx.local_parent(def_id);
             }
 
-            tcx.is_late_bound_map(def_id.expect_local())
+            tcx.is_late_bound_map(def_id)
         }
         _ => resolve_lifetimes_for(tcx, def_id).late_bound.get(&def_id).map(|lt| (def_id, lt)),
     }
@@ -685,8 +678,8 @@ fn visit_fn(
         hir_id: hir::HirId,
     ) {
         let name = match fk {
-            intravisit::FnKind::ItemFn(id, _, _, _) => id.name,
-            intravisit::FnKind::Method(id, _, _) => id.name,
+            intravisit::FnKind::ItemFn(id, _, _) => id.name,
+            intravisit::FnKind::Method(id, _) => id.name,
             intravisit::FnKind::Closure => sym::closure,
         };
         let name = name.as_str();
@@ -1266,10 +1259,6 @@ fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
             self.insert_lifetime(lifetime_ref, Region::Static);
             return;
         }
-        if self.is_in_const_generic && lifetime_ref.name != LifetimeName::Error {
-            self.emit_non_static_lt_in_const_generic_error(lifetime_ref);
-            return;
-        }
         self.resolve_lifetime_ref(lifetime_ref);
     }
 
@@ -1335,24 +1324,19 @@ fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) {
                 match param.kind {
                     GenericParamKind::Lifetime { .. } => {}
                     GenericParamKind::Type { ref default, .. } => {
-                        walk_list!(this, visit_param_bound, param.bounds);
                         if let Some(ref ty) = default {
                             this.visit_ty(&ty);
                         }
                     }
                     GenericParamKind::Const { ref ty, default } => {
-                        let was_in_const_generic = this.is_in_const_generic;
-                        this.is_in_const_generic = true;
-                        walk_list!(this, visit_param_bound, param.bounds);
                         this.visit_ty(&ty);
                         if let Some(default) = default {
                             this.visit_body(this.tcx.hir().body(default.body));
                         }
-                        this.is_in_const_generic = was_in_const_generic;
                     }
                 }
             }
-            for predicate in generics.where_clause.predicates {
+            for predicate in generics.predicates {
                 match predicate {
                     &hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
                         ref bounded_ty,
@@ -1403,6 +1387,32 @@ fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) {
                     }) => {
                         this.visit_lifetime(lifetime);
                         walk_list!(this, visit_param_bound, bounds);
+
+                        if lifetime.name != hir::LifetimeName::Static {
+                            for bound in bounds {
+                                let hir::GenericBound::Outlives(ref lt) = bound else {
+                                    continue;
+                                };
+                                if lt.name != hir::LifetimeName::Static {
+                                    continue;
+                                }
+                                this.insert_lifetime(lt, Region::Static);
+                                this.tcx
+                                    .sess
+                                    .struct_span_warn(
+                                        lifetime.span,
+                                        &format!(
+                                            "unnecessary lifetime parameter `{}`",
+                                            lifetime.name.ident(),
+                                        ),
+                                    )
+                                    .help(&format!(
+                                        "you can use the `'static` lifetime directly, in place of `{}`",
+                                        lifetime.name.ident(),
+                                    ))
+                                    .emit();
+                            }
+                        }
                     }
                     &hir::WherePredicate::EqPredicate(hir::WhereEqPredicate {
                         ref lhs_ty,
@@ -1724,10 +1734,8 @@ fn add_bounds(set: &mut Set1<hir::LifetimeName>, bounds: &[hir::GenericBound<'_>
         GenericParamKind::Type { .. } => {
             let mut set = Set1::Empty;
 
-            add_bounds(&mut set, &param.bounds);
-
             let param_def_id = tcx.hir().local_def_id(param.hir_id);
-            for predicate in generics.where_clause.predicates {
+            for predicate in generics.predicates {
                 // Look for `type: ...` where clauses.
                 let hir::WherePredicate::BoundPredicate(ref data) = *predicate else { continue };
 
@@ -1798,7 +1806,6 @@ fn with<F>(&mut self, wrap_scope: Scope<'_>, f: F)
             tcx: *tcx,
             map,
             scope: &wrap_scope,
-            is_in_const_generic: self.is_in_const_generic,
             trait_definition_only: self.trait_definition_only,
             labels_in_fn,
             xcrate_object_lifetime_defaults,
@@ -1853,7 +1860,7 @@ fn suggest_eliding_single_use_lifetime(
         let remove_decl = self
             .tcx
             .parent(def_id)
-            .and_then(|parent_def_id| parent_def_id.as_local())
+            .as_local()
             .and_then(|parent_def_id| self.tcx.hir().get_generics(parent_def_id))
             .and_then(|generics| self.lifetime_deletion_span(name, generics));
 
@@ -1992,37 +1999,36 @@ fn check_uses_for_lifetimes_defined_by_scope(&mut self) {
                             continue;
                         }
 
-                        if let Some(parent_def_id) = self.tcx.parent(def_id) {
-                            if let Some(def_id) = parent_def_id.as_local() {
-                                // lifetimes in `derive` expansions don't count (Issue #53738)
-                                if self
-                                    .tcx
-                                    .get_attrs(def_id.to_def_id())
-                                    .iter()
-                                    .any(|attr| attr.has_name(sym::automatically_derived))
-                                {
-                                    continue;
-                                }
+                        let parent_def_id = self.tcx.parent(def_id);
+                        if let Some(def_id) = parent_def_id.as_local() {
+                            // lifetimes in `derive` expansions don't count (Issue #53738)
+                            if self
+                                .tcx
+                                .get_attrs(def_id.to_def_id())
+                                .iter()
+                                .any(|attr| attr.has_name(sym::automatically_derived))
+                            {
+                                continue;
+                            }
 
-                                // opaque types generated when desugaring an async function can have a single
-                                // use lifetime even if it is explicitly denied (Issue #77175)
-                                if let hir::Node::Item(hir::Item {
-                                    kind: hir::ItemKind::OpaqueTy(ref opaque),
-                                    ..
-                                }) = self.tcx.hir().get_by_def_id(def_id)
-                                {
-                                    if !matches!(opaque.origin, hir::OpaqueTyOrigin::AsyncFn(..)) {
+                            // opaque types generated when desugaring an async function can have a single
+                            // use lifetime even if it is explicitly denied (Issue #77175)
+                            if let hir::Node::Item(hir::Item {
+                                kind: hir::ItemKind::OpaqueTy(ref opaque),
+                                ..
+                            }) = self.tcx.hir().get_by_def_id(def_id)
+                            {
+                                if !matches!(opaque.origin, hir::OpaqueTyOrigin::AsyncFn(..)) {
+                                    continue 'lifetimes;
+                                }
+                                // We want to do this only if the lifetime identifier is already defined
+                                // in the async function that generated this. Otherwise it could be
+                                // an opaque type defined by the developer and we still want this
+                                // lint to fail compilation
+                                for p in opaque.generics.params {
+                                    if defined_by.contains_key(&p.name) {
                                         continue 'lifetimes;
                                     }
-                                    // We want to do this only if the lifetime identifier is already defined
-                                    // in the async function that generated this. Otherwise it could be
-                                    // an opaque type defined by the developer and we still want this
-                                    // lint to fail compilation
-                                    for p in opaque.generics.params {
-                                        if defined_by.contains_key(&p.name) {
-                                            continue 'lifetimes;
-                                        }
-                                    }
                                 }
                             }
                         }
@@ -2076,20 +2082,19 @@ fn check_uses_for_lifetimes_defined_by_scope(&mut self) {
                             |lint| {
                                 let mut err = lint
                                     .build(&format!("lifetime parameter `{}` never used", name));
-                                if let Some(parent_def_id) = self.tcx.parent(def_id) {
-                                    if let Some(generics) =
-                                        self.tcx.hir().get_generics(parent_def_id.expect_local())
-                                    {
-                                        let unused_lt_span =
-                                            self.lifetime_deletion_span(name, generics);
-                                        if let Some(span) = unused_lt_span {
-                                            err.span_suggestion(
-                                                span,
-                                                "elide the unused lifetime",
-                                                String::new(),
-                                                Applicability::MachineApplicable,
-                                            );
-                                        }
+                                let parent_def_id = self.tcx.parent(def_id);
+                                if let Some(generics) =
+                                    self.tcx.hir().get_generics(parent_def_id.expect_local())
+                                {
+                                    let unused_lt_span =
+                                        self.lifetime_deletion_span(name, generics);
+                                    if let Some(span) = unused_lt_span {
+                                        err.span_suggestion(
+                                            span,
+                                            "elide the unused lifetime",
+                                            String::new(),
+                                            Applicability::MachineApplicable,
+                                        );
                                     }
                                 }
                                 err.emit();
@@ -2254,10 +2259,6 @@ fn resolve_lifetime_ref(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
         let result = loop {
             match *scope {
                 Scope::Body { id, s } => {
-                    // Non-static lifetimes are prohibited in anonymous constants without
-                    // `generic_const_exprs`.
-                    self.maybe_emit_forbidden_non_static_lifetime_error(id, lifetime_ref);
-
                     outermost_body = Some(id);
                     scope = s;
                 }
@@ -3139,50 +3140,6 @@ fn check_lifetime_params(
 
             // It is a soft error to shadow a lifetime within a parent scope.
             self.check_lifetime_param_for_shadowing(old_scope, &lifetime_i);
-
-            for bound in lifetime_i.bounds {
-                match bound {
-                    hir::GenericBound::Outlives(ref lt) => match lt.name {
-                        hir::LifetimeName::Underscore => {
-                            self.tcx.sess.delay_span_bug(
-                                lt.span,
-                                "use of `'_` in illegal place, but not caught by lowering",
-                            );
-                        }
-                        hir::LifetimeName::Static => {
-                            self.insert_lifetime(lt, Region::Static);
-                            self.tcx
-                                .sess
-                                .struct_span_warn(
-                                    lifetime_i.span.to(lt.span),
-                                    &format!(
-                                        "unnecessary lifetime parameter `{}`",
-                                        lifetime_i.name.ident(),
-                                    ),
-                                )
-                                .help(&format!(
-                                    "you can use the `'static` lifetime directly, in place of `{}`",
-                                    lifetime_i.name.ident(),
-                                ))
-                                .emit();
-                        }
-                        hir::LifetimeName::Param(_) | hir::LifetimeName::Implicit => {
-                            self.resolve_lifetime_ref(lt);
-                        }
-                        hir::LifetimeName::ImplicitObjectLifetimeDefault => {
-                            self.tcx.sess.delay_span_bug(
-                                lt.span,
-                                "lowering generated `ImplicitObjectLifetimeDefault` \
-                                 outside of an object type",
-                            );
-                        }
-                        hir::LifetimeName::Error => {
-                            // No need to do anything, error already reported.
-                        }
-                    },
-                    _ => bug!(),
-                }
-            }
         }
     }
 
@@ -3341,18 +3298,6 @@ fn insert_late_bound_lifetimes(
     // ignore binders here and scrape up all names we see.
     let mut appears_in_where_clause = AllCollector::default();
     appears_in_where_clause.visit_generics(generics);
-
-    for param in generics.params {
-        if let hir::GenericParamKind::Lifetime { .. } = param.kind {
-            if !param.bounds.is_empty() {
-                // `'a: 'b` means both `'a` and `'b` are referenced
-                appears_in_where_clause
-                    .regions
-                    .insert(hir::LifetimeName::Param(param.name.normalize_to_macros_2_0()));
-            }
-        }
-    }
-
     debug!(?appears_in_where_clause.regions);
 
     // Late bound regions are those that:
index 4dfb7aef86f5a7f01c63e52e7b751777edd3df71..f6109b1dc1a1af17f89ea10afcbda9e707d20976 100644 (file)
@@ -29,7 +29,7 @@
 use rustc_ast::node_id::NodeMap;
 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::ResolverAstLowering;
+use rustc_ast_lowering::{LifetimeRes, ResolverAstLowering};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
 use rustc_data_structures::intern::Interned;
 use rustc_data_structures::sync::Lrc;
@@ -143,9 +143,9 @@ enum ScopeSet<'a> {
 /// but not for late resolution yet.
 #[derive(Clone, Copy, Debug)]
 pub struct ParentScope<'a> {
-    module: Module<'a>,
+    pub module: Module<'a>,
     expansion: LocalExpnId,
-    macro_rules: MacroRulesScopeRef<'a>,
+    pub macro_rules: MacroRulesScopeRef<'a>,
     derives: &'a [ast::Path],
 }
 
@@ -201,13 +201,13 @@ enum ResolutionError<'a> {
     /// parameter list.
     NameAlreadyUsedInParameterList(Symbol, Span),
     /// Error E0407: method is not a member of trait.
-    MethodNotMemberOfTrait(Ident, &'a str, Option<Symbol>),
+    MethodNotMemberOfTrait(Ident, String, Option<Symbol>),
     /// Error E0437: type is not a member of trait.
-    TypeNotMemberOfTrait(Ident, &'a str, Option<Symbol>),
+    TypeNotMemberOfTrait(Ident, String, Option<Symbol>),
     /// Error E0438: const is not a member of trait.
-    ConstNotMemberOfTrait(Ident, &'a str, Option<Symbol>),
+    ConstNotMemberOfTrait(Ident, String, Option<Symbol>),
     /// Error E0408: variable `{}` is not bound in all patterns.
-    VariableNotBoundInPattern(&'a BindingError),
+    VariableNotBoundInPattern(BindingError, ParentScope<'a>),
     /// Error E0409: variable `{}` is bound in inconsistent ways within the same match arm.
     VariableBoundWithDifferentMode(Symbol, Span),
     /// Error E0415: identifier is bound more than once in this parameter list.
@@ -901,6 +901,10 @@ pub struct Resolver<'a> {
     import_res_map: NodeMap<PerNS<Option<Res>>>,
     /// Resolutions for labels (node IDs of their corresponding blocks or loops).
     label_res_map: NodeMap<NodeId>,
+    /// Resolutions for lifetimes.
+    lifetimes_res_map: NodeMap<LifetimeRes>,
+    /// Lifetime parameters that lowering will have to introduce.
+    extra_lifetime_params_map: NodeMap<Vec<(Ident, NodeId, LifetimeRes)>>,
 
     /// `CrateNum` resolutions of `extern crate` items.
     extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
@@ -934,6 +938,7 @@ pub struct Resolver<'a> {
     glob_map: FxHashMap<LocalDefId, FxHashSet<Symbol>>,
     /// Visibilities in "lowered" form, for all entities that have them.
     visibilities: FxHashMap<LocalDefId, ty::Visibility>,
+    has_pub_restricted: bool,
     used_imports: FxHashSet<NodeId>,
     maybe_unused_trait_imports: FxHashSet<LocalDefId>,
     maybe_unused_extern_crates: Vec<(LocalDefId, Span)>,
@@ -985,6 +990,8 @@ pub struct Resolver<'a> {
     /// `macro_rules` scopes *produced* by expanding the macro invocations,
     /// include all the `macro_rules` items and other invocations generated by them.
     output_macro_rules_scopes: FxHashMap<LocalExpnId, MacroRulesScopeRef<'a>>,
+    /// `macro_rules` scopes produced by `macro_rules` item definitions.
+    macro_rules_scopes: FxHashMap<LocalDefId, MacroRulesScopeRef<'a>>,
     /// Helper attributes that are in scope for the given expansion.
     helper_attrs: FxHashMap<LocalExpnId, Vec<Ident>>,
     /// Ready or in-progress results of resolving paths inside the `#[derive(...)]` attribute
@@ -1104,7 +1111,8 @@ fn as_mut(&mut self) -> &mut Resolver<'a> {
 }
 
 impl<'a, 'b> DefIdTree for &'a Resolver<'b> {
-    fn parent(self, id: DefId) -> Option<DefId> {
+    #[inline]
+    fn opt_parent(self, id: DefId) -> Option<DefId> {
         match id.as_local() {
             Some(id) => self.definitions.def_key(id).parent,
             None => self.cstore().def_key(id).parent,
@@ -1153,6 +1161,14 @@ fn get_label_res(&self, id: NodeId) -> Option<NodeId> {
         self.label_res_map.get(&id).cloned()
     }
 
+    fn get_lifetime_res(&self, id: NodeId) -> Option<LifetimeRes> {
+        self.lifetimes_res_map.get(&id).copied()
+    }
+
+    fn take_extra_lifetime_params(&mut self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)> {
+        self.extra_lifetime_params_map.remove(&id).unwrap_or_default()
+    }
+
     fn create_stable_hashing_context(&self) -> StableHashingContext<'_> {
         StableHashingContext::new(self.session, &self.definitions, self.crate_loader.cstore())
     }
@@ -1301,6 +1317,8 @@ pub fn new(
             partial_res_map: Default::default(),
             import_res_map: Default::default(),
             label_res_map: Default::default(),
+            lifetimes_res_map: Default::default(),
+            extra_lifetime_params_map: Default::default(),
             extern_crate_map: Default::default(),
             reexport_map: FxHashMap::default(),
             trait_map: NodeMap::default(),
@@ -1313,6 +1331,7 @@ pub fn new(
 
             glob_map: Default::default(),
             visibilities,
+            has_pub_restricted: false,
             used_imports: FxHashSet::default(),
             maybe_unused_trait_imports: Default::default(),
             maybe_unused_extern_crates: Vec::new(),
@@ -1345,6 +1364,7 @@ pub fn new(
             non_macro_attr: Lrc::new(SyntaxExtension::non_macro_attr(session.edition())),
             invocation_parent_scopes: Default::default(),
             output_macro_rules_scopes: Default::default(),
+            macro_rules_scopes: Default::default(),
             helper_attrs: Default::default(),
             derive_data: Default::default(),
             local_macro_def_scopes: FxHashMap::default(),
@@ -1423,6 +1443,7 @@ pub fn into_outputs(self) -> ResolverOutputs {
         let proc_macros = self.proc_macros.iter().map(|id| self.local_def_id(*id)).collect();
         let definitions = self.definitions;
         let visibilities = self.visibilities;
+        let has_pub_restricted = self.has_pub_restricted;
         let extern_crate_map = self.extern_crate_map;
         let reexport_map = self.reexport_map;
         let maybe_unused_trait_imports = self.maybe_unused_trait_imports;
@@ -1435,6 +1456,7 @@ pub fn into_outputs(self) -> ResolverOutputs {
             definitions,
             cstore: Box::new(self.crate_loader.into_cstore()),
             visibilities,
+            has_pub_restricted,
             access_levels,
             extern_crate_map,
             reexport_map,
@@ -1461,6 +1483,7 @@ pub fn clone_outputs(&self) -> ResolverOutputs {
             access_levels: self.access_levels.clone(),
             cstore: Box::new(self.cstore().clone()),
             visibilities: self.visibilities.clone(),
+            has_pub_restricted: self.has_pub_restricted,
             extern_crate_map: self.extern_crate_map.clone(),
             reexport_map: self.reexport_map.clone(),
             glob_map: self.glob_map.clone(),
@@ -1855,25 +1878,25 @@ pub fn resolve_rustdoc_path(
         &mut self,
         path_str: &str,
         ns: Namespace,
-        mut module_id: DefId,
+        mut parent_scope: ParentScope<'a>,
     ) -> Option<Res> {
         let mut segments =
             Vec::from_iter(path_str.split("::").map(Ident::from_str).map(Segment::from_ident));
         if let Some(segment) = segments.first_mut() {
             if segment.ident.name == kw::Crate {
                 // FIXME: `resolve_path` always resolves `crate` to the current crate root, but
-                // rustdoc wants it to resolve to the `module_id`'s crate root. This trick of
+                // rustdoc wants it to resolve to the `parent_scope`'s crate root. This trick of
                 // replacing `crate` with `self` and changing the current module should achieve
                 // the same effect.
                 segment.ident.name = kw::SelfLower;
-                module_id = module_id.krate.as_def_id();
+                parent_scope.module =
+                    self.expect_module(parent_scope.module.def_id().krate.as_def_id());
             } else if segment.ident.name == kw::Empty {
                 segment.ident.name = kw::PathRoot;
             }
         }
 
-        let module = self.expect_module(module_id);
-        match self.maybe_resolve_path(&segments, Some(ns), &ParentScope::module(module, self)) {
+        match self.maybe_resolve_path(&segments, Some(ns), &parent_scope) {
             PathResult::Module(ModuleOrUniformRoot::Module(module)) => Some(module.res().unwrap()),
             PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => {
                 Some(path_res.base_res())
@@ -1885,11 +1908,6 @@ pub fn resolve_rustdoc_path(
         }
     }
 
-    // For rustdoc.
-    pub fn graph_root(&self) -> Module<'a> {
-        self.graph_root
-    }
-
     // For rustdoc.
     pub fn take_all_macro_rules(&mut self) -> FxHashMap<Symbol, Res> {
         mem::take(&mut self.all_macro_rules)
@@ -1905,6 +1923,11 @@ pub fn module_children_or_reexports(&self, def_id: DefId) -> Vec<ModChild> {
         }
     }
 
+    /// For rustdoc.
+    pub fn macro_rules_scope(&self, def_id: LocalDefId) -> MacroRulesScopeRef<'a> {
+        *self.macro_rules_scopes.get(&def_id).expect("not a `macro_rules` item")
+    }
+
     /// Retrieves the span of the given `DefId` if `DefId` is in the local crate.
     #[inline]
     pub fn opt_span(&self, def_id: DefId) -> Option<Span> {
@@ -2025,42 +2048,27 @@ fn collect_mod(names: &mut Vec<Symbol>, module: Module<'_>) {
 }
 
 #[derive(Copy, Clone, Debug)]
-enum Finalize {
-    /// Do not issue the lint.
-    No,
-
-    /// This lint applies to some arbitrary path; e.g., `impl ::foo::Bar`.
-    /// In this case, we can take the span of that path.
-    SimplePath(NodeId, Span),
-
-    /// This lint comes from a `use` statement. In this case, what we
-    /// care about really is the *root* `use` statement; e.g., if we
-    /// have nested things like `use a::{b, c}`, we care about the
-    /// `use a` part.
-    UsePath { root_id: NodeId, root_span: Span, path_span: Span },
-
-    /// This is the "trait item" from a fully qualified path. For example,
-    /// we might be resolving  `X::Y::Z` from a path like `<T as X::Y>::Z`.
-    /// The `path_span` is the span of the to the trait itself (`X::Y`).
-    QPathTrait { qpath_id: NodeId, qpath_span: Span, path_span: Span },
+struct Finalize {
+    /// Node ID for linting.
+    node_id: NodeId,
+    /// Span of the whole path or some its characteristic fragment.
+    /// E.g. span of `b` in `foo::{a, b, c}`, or full span for regular paths.
+    path_span: Span,
+    /// Span of the path start, suitable for prepending something to to it.
+    /// E.g. span of `foo` in `foo::{a, b, c}`, or full span for regular paths.
+    root_span: Span,
+    /// Whether to report privacy errors or silently return "no resolution" for them,
+    /// similarly to speculative resolution.
+    report_private: bool,
 }
 
 impl Finalize {
-    fn node_id_and_path_span(&self) -> Option<(NodeId, Span)> {
-        match *self {
-            Finalize::No => None,
-            Finalize::SimplePath(id, path_span)
-            | Finalize::UsePath { root_id: id, path_span, .. }
-            | Finalize::QPathTrait { qpath_id: id, path_span, .. } => Some((id, path_span)),
-        }
-    }
-
-    fn node_id(&self) -> Option<NodeId> {
-        self.node_id_and_path_span().map(|(id, _)| id)
+    fn new(node_id: NodeId, path_span: Span) -> Finalize {
+        Finalize::with_root_span(node_id, path_span, path_span)
     }
 
-    fn path_span(&self) -> Option<Span> {
-        self.node_id_and_path_span().map(|(_, path_span)| path_span)
+    fn with_root_span(node_id: NodeId, path_span: Span, root_span: Span) -> Finalize {
+        Finalize { node_id, path_span, root_span, report_private: true }
     }
 }
 
index 01f0b11f1ac3beb0030649a55e360f50bb7d09c9..19a9c1b99fc47f897d2701fc90d0be3312b4b442 100644 (file)
@@ -604,7 +604,6 @@ pub fn resolve_macro_path(
                 parent_scope,
                 None,
                 force,
-                false,
                 None,
             );
             if let Err(Determinacy::Undetermined) = binding {
@@ -673,7 +672,7 @@ pub fn resolve_macro_path(
                 &path,
                 Some(MacroNS),
                 &parent_scope,
-                Finalize::SimplePath(ast::CRATE_NODE_ID, path_span),
+                Some(Finalize::new(ast::CRATE_NODE_ID, path_span)),
                 None,
             ) {
                 PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => {
@@ -708,9 +707,8 @@ pub fn resolve_macro_path(
                 ident,
                 ScopeSet::Macro(kind),
                 &parent_scope,
-                Some(ident.span),
+                Some(Finalize::new(ast::CRATE_NODE_ID, ident.span)),
                 true,
-                false,
                 None,
             ) {
                 Ok(binding) => {
@@ -751,9 +749,8 @@ pub fn resolve_macro_path(
                 ident,
                 ScopeSet::Macro(MacroKind::Attr),
                 &parent_scope,
-                Some(ident.span),
+                Some(Finalize::new(ast::CRATE_NODE_ID, ident.span)),
                 true,
-                false,
                 None,
             );
         }
index 22d0a20395ec7d77b62a9811f14049940e55f1a2..e1c9ecc055f6ad52b11b30c0d03e75cccccb123a 100644 (file)
@@ -25,7 +25,6 @@
 use rustc_middle::span_bug;
 use rustc_middle::ty::{self, DefIdTree, TyCtxt};
 use rustc_session::config::Input;
-use rustc_span::source_map::respan;
 use rustc_span::symbol::Ident;
 use rustc_span::*;
 
@@ -57,20 +56,14 @@ macro_rules! down_cast_data {
 }
 
 macro_rules! access_from {
-    ($save_ctxt:expr, $item:expr, $id:expr) => {
+    ($save_ctxt:expr, $id:expr) => {
         Access {
-            public: $item.vis.node.is_pub(),
+            public: $save_ctxt.tcx.visibility($id).is_public(),
             reachable: $save_ctxt.access_levels.is_reachable($id),
         }
     };
 }
 
-macro_rules! access_from_vis {
-    ($save_ctxt:expr, $vis:expr, $id:expr) => {
-        Access { public: $vis.node.is_pub(), reachable: $save_ctxt.access_levels.is_reachable($id) }
-    };
-}
-
 pub struct DumpVisitor<'tcx> {
     pub save_ctxt: SaveContext<'tcx>,
     tcx: TyCtxt<'tcx>,
@@ -257,7 +250,6 @@ fn process_method(
         def_id: LocalDefId,
         ident: Ident,
         generics: &'tcx hir::Generics<'tcx>,
-        vis: &hir::Visibility<'tcx>,
         span: Span,
     ) {
         debug!("process_method: {:?}:{}", def_id, ident);
@@ -272,10 +264,10 @@ fn process_method(
                 v.process_generic_params(&generics, &method_data.qualname, hir_id);
 
                 method_data.value =
-                    fn_to_string(sig.decl, sig.header, Some(ident.name), generics, vis, &[], None);
+                    fn_to_string(sig.decl, sig.header, Some(ident.name), generics, &[], None);
                 method_data.sig = sig::method_signature(hir_id, ident, generics, sig, &v.save_ctxt);
 
-                v.dumper.dump_def(&access_from_vis!(v.save_ctxt, vis, def_id), method_data);
+                v.dumper.dump_def(&access_from!(v.save_ctxt, def_id), method_data);
             }
 
             // walk arg and return types
@@ -302,7 +294,7 @@ fn process_struct_field_def(
         let field_data = self.save_ctxt.get_field_data(field, parent_id);
         if let Some(field_data) = field_data {
             self.dumper.dump_def(
-                &access_from!(self.save_ctxt, field, self.tcx.hir().local_def_id(field.hir_id)),
+                &access_from!(self.save_ctxt, self.tcx.hir().local_def_id(field.hir_id)),
                 field_data,
             );
         }
@@ -369,7 +361,7 @@ fn process_fn(
                 v.process_formals(body.params, &fn_data.qualname);
                 v.process_generic_params(ty_params, &fn_data.qualname, item.hir_id());
 
-                v.dumper.dump_def(&access_from!(v.save_ctxt, item, item.def_id), fn_data);
+                v.dumper.dump_def(&access_from!(v.save_ctxt, item.def_id), fn_data);
             }
 
             for arg in decl.inputs {
@@ -393,7 +385,7 @@ fn process_static_or_const_item(
         self.nest_typeck_results(item.def_id, |v| {
             if let Some(var_data) = v.save_ctxt.get_item_data(item) {
                 down_cast_data!(var_data, DefData, item.span);
-                v.dumper.dump_def(&access_from!(v.save_ctxt, item, item.def_id), var_data);
+                v.dumper.dump_def(&access_from!(v.save_ctxt, item.def_id), var_data);
             }
             v.visit_ty(&typ);
             v.visit_expr(expr);
@@ -407,7 +399,6 @@ fn process_assoc_const(
         typ: &'tcx hir::Ty<'tcx>,
         expr: Option<&'tcx hir::Expr<'tcx>>,
         parent_id: DefId,
-        vis: &hir::Visibility<'tcx>,
         attrs: &'tcx [ast::Attribute],
     ) {
         let qualname = format!("::{}", self.tcx.def_path_str(def_id.to_def_id()));
@@ -418,7 +409,7 @@ fn process_assoc_const(
             let span = self.span_from_span(ident.span);
 
             self.dumper.dump_def(
-                &access_from_vis!(self.save_ctxt, vis, def_id),
+                &access_from!(self.save_ctxt, def_id),
                 Def {
                     kind: DefKind::Const,
                     id: id_from_hir_id(hir_id, &self.save_ctxt),
@@ -469,7 +460,11 @@ fn process_struct(
                 let fields_str = fields
                     .iter()
                     .filter_map(|f| {
-                        if include_priv_fields || f.vis.node.is_pub() {
+                        if include_priv_fields {
+                            return Some(f.ident.to_string());
+                        }
+                        let def_id = self.save_ctxt.tcx.hir().local_def_id(f.hir_id);
+                        if self.save_ctxt.tcx.visibility(def_id).is_public() {
                             Some(f.ident.to_string())
                         } else {
                             None
@@ -487,7 +482,7 @@ fn process_struct(
             let span = self.span_from_span(item.ident.span);
             let attrs = self.tcx.hir().attrs(item.hir_id());
             self.dumper.dump_def(
-                &access_from!(self.save_ctxt, item, item.def_id),
+                &access_from!(self.save_ctxt, item.def_id),
                 Def {
                     kind,
                     id: id_from_def_id(item.def_id.to_def_id()),
@@ -527,7 +522,7 @@ fn process_enum(
         };
         down_cast_data!(enum_data, DefData, item.span);
 
-        let access = access_from!(self.save_ctxt, item, item.def_id);
+        let access = access_from!(self.save_ctxt, item.def_id);
 
         for variant in enum_definition.variants {
             let name = variant.ident.name.to_string();
@@ -662,7 +657,7 @@ fn process_trait(
                 methods.iter().map(|i| id_from_def_id(i.id.def_id.to_def_id())).collect();
             let attrs = self.tcx.hir().attrs(item.hir_id());
             self.dumper.dump_def(
-                &access_from!(self.save_ctxt, item, item.def_id),
+                &access_from!(self.save_ctxt, item.def_id),
                 Def {
                     kind: DefKind::Trait,
                     id,
@@ -724,7 +719,7 @@ fn process_trait(
     fn process_mod(&mut self, item: &'tcx hir::Item<'tcx>) {
         if let Some(mod_data) = self.save_ctxt.get_item_data(item) {
             down_cast_data!(mod_data, DefData, item.span);
-            self.dumper.dump_def(&access_from!(self.save_ctxt, item, item.def_id), mod_data);
+            self.dumper.dump_def(&access_from!(self.save_ctxt, item.def_id), mod_data);
         }
     }
 
@@ -979,11 +974,9 @@ fn process_macro_use(&mut self, _span: Span) {
 
     fn process_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>, trait_id: DefId) {
         self.process_macro_use(trait_item.span);
-        let vis_span = trait_item.span.shrink_to_lo();
         match trait_item.kind {
             hir::TraitItemKind::Const(ref ty, body) => {
                 let body = body.map(|b| &self.tcx.hir().body(b).value);
-                let respan = respan(vis_span, hir::VisibilityKind::Public);
                 let attrs = self.tcx.hir().attrs(trait_item.hir_id());
                 self.process_assoc_const(
                     trait_item.def_id,
@@ -991,21 +984,18 @@ fn process_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>, trait_i
                     &ty,
                     body,
                     trait_id,
-                    &respan,
                     attrs,
                 );
             }
             hir::TraitItemKind::Fn(ref sig, ref trait_fn) => {
                 let body =
                     if let hir::TraitFn::Provided(body) = trait_fn { Some(*body) } else { None };
-                let respan = respan(vis_span, hir::VisibilityKind::Public);
                 self.process_method(
                     sig,
                     body,
                     trait_item.def_id,
                     trait_item.ident,
                     &trait_item.generics,
-                    &respan,
                     trait_item.span,
                 );
             }
@@ -1064,7 +1054,6 @@ fn process_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>, impl_id: D
                     &ty,
                     Some(&body.value),
                     impl_id,
-                    &impl_item.vis,
                     attrs,
                 );
             }
@@ -1075,7 +1064,6 @@ fn process_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>, impl_id: D
                     impl_item.def_id,
                     impl_item.ident,
                     &impl_item.generics,
-                    &impl_item.vis,
                     impl_item.span,
                 );
             }
@@ -1147,11 +1135,10 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
             hir::ItemKind::Use(path, hir::UseKind::Single) => {
                 let sub_span = path.segments.last().unwrap().ident.span;
                 if !self.span.filter_generated(sub_span) {
-                    let access = access_from!(self.save_ctxt, item, item.def_id);
+                    let access = access_from!(self.save_ctxt, item.def_id);
                     let ref_id = self.lookup_def_id(item.hir_id()).map(id_from_def_id);
                     let span = self.span_from_span(sub_span);
-                    let parent =
-                        self.save_ctxt.tcx.parent(item.def_id.to_def_id()).map(id_from_def_id);
+                    let parent = self.save_ctxt.tcx.local_parent(item.def_id);
                     self.dumper.import(
                         &access,
                         Import {
@@ -1161,7 +1148,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
                             alias_span: None,
                             name: item.ident.to_string(),
                             value: String::new(),
-                            parent,
+                            parent: Some(id_from_def_id(parent.to_def_id())),
                         },
                     );
                     self.write_sub_paths_truncated(&path);
@@ -1176,10 +1163,9 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
                 // we don't want to track anyway, since it's probably macro-internal `use`
                 if let Some(sub_span) = self.span.sub_span_of_star(item.span) {
                     if !self.span.filter_generated(item.span) {
-                        let access = access_from!(self.save_ctxt, item, item.def_id);
+                        let access = access_from!(self.save_ctxt, item.def_id);
                         let span = self.span_from_span(sub_span);
-                        let parent =
-                            self.save_ctxt.tcx.parent(item.def_id.to_def_id()).map(id_from_def_id);
+                        let parent = self.save_ctxt.tcx.local_parent(item.def_id);
                         self.dumper.import(
                             &access,
                             Import {
@@ -1189,7 +1175,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
                                 alias_span: None,
                                 name: "*".to_owned(),
                                 value: names.join(", "),
-                                parent,
+                                parent: Some(id_from_def_id(parent.to_def_id())),
                             },
                         );
                         self.write_sub_paths(&path);
@@ -1200,8 +1186,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
                 let name_span = item.ident.span;
                 if !self.span.filter_generated(name_span) {
                     let span = self.span_from_span(name_span);
-                    let parent =
-                        self.save_ctxt.tcx.parent(item.def_id.to_def_id()).map(id_from_def_id);
+                    let parent = self.save_ctxt.tcx.local_parent(item.def_id);
                     self.dumper.import(
                         &Access { public: false, reachable: false },
                         Import {
@@ -1211,7 +1196,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
                             alias_span: None,
                             name: item.ident.to_string(),
                             value: String::new(),
-                            parent,
+                            parent: Some(id_from_def_id(parent.to_def_id())),
                         },
                     );
                 }
@@ -1249,7 +1234,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
                     let attrs = self.tcx.hir().attrs(item.hir_id());
 
                     self.dumper.dump_def(
-                        &access_from!(self.save_ctxt, item, item.def_id),
+                        &access_from!(self.save_ctxt, item.def_id),
                         Def {
                             kind: DefKind::Type,
                             id,
@@ -1279,13 +1264,11 @@ fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) {
             match param.kind {
                 hir::GenericParamKind::Lifetime { .. } => {}
                 hir::GenericParamKind::Type { ref default, .. } => {
-                    self.process_bounds(param.bounds);
                     if let Some(ref ty) = default {
                         self.visit_ty(ty);
                     }
                 }
                 hir::GenericParamKind::Const { ref ty, ref default } => {
-                    self.process_bounds(param.bounds);
                     self.visit_ty(ty);
                     if let Some(default) = default {
                         self.visit_anon_const(default);
@@ -1293,7 +1276,7 @@ fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) {
                 }
             }
         }
-        for pred in generics.where_clause.predicates {
+        for pred in generics.predicates {
             if let hir::WherePredicate::BoundPredicate(ref wbp) = *pred {
                 self.process_bounds(wbp.bounds);
                 self.visit_ty(wbp.bounded_ty);
@@ -1443,7 +1426,7 @@ fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) {
     }
 
     fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) {
-        let access = access_from!(self.save_ctxt, item, item.def_id);
+        let access = access_from!(self.save_ctxt, item.def_id);
 
         match item.kind {
             hir::ForeignItemKind::Fn(decl, _, ref generics) => {
index 102268c6ca3524b1b7e39c51bb02217f6925f148..5d94884e0f618487238adf118de24450c666476f 100644 (file)
@@ -27,7 +27,6 @@
 use rustc_session::config::{CrateType, Input, OutputType};
 use rustc_session::cstore::ExternCrate;
 use rustc_session::output::{filename_for_metadata, out_filename};
-use rustc_span::source_map::Spanned;
 use rustc_span::symbol::Ident;
 use rustc_span::*;
 
@@ -165,7 +164,6 @@ pub fn get_extern_item_data(&self, item: &hir::ForeignItem<'_>) -> Option<Data>
                         },
                         Some(item.ident.name),
                         generics,
-                        &item.vis,
                         arg_names,
                         None,
                     ),
@@ -221,7 +219,6 @@ pub fn get_item_data(&self, item: &hir::Item<'_>) -> Option<Data> {
                         sig.header,
                         Some(item.ident.name),
                         generics,
-                        &item.vis,
                         &[],
                         None,
                     ),
@@ -310,7 +307,7 @@ pub fn get_item_data(&self, item: &hir::Item<'_>) -> Option<Data> {
                 let qualname = format!("::{}", self.tcx.def_path_str(def_id));
                 filter!(self.span_utils, item.ident.span);
                 let value =
-                    enum_def_to_string(def, generics, item.ident.name, item.span, &item.vis);
+                    enum_def_to_string(def, generics, item.ident.name, item.span);
                 Some(Data::DefData(Def {
                     kind: DefKind::Enum,
                     id: id_from_def_id(def_id),
@@ -595,11 +592,6 @@ pub fn get_path_res(&self, hir_id: hir::HirId) -> Res {
             Node::TraitRef(tr) => tr.path.res,
 
             Node::Item(&hir::Item { kind: hir::ItemKind::Use(path, _), .. }) => path.res,
-            Node::Visibility(&Spanned {
-                node: hir::VisibilityKind::Restricted { ref path, .. },
-                ..
-            }) => path.res,
-
             Node::PathSegment(seg) => match seg.res {
                 Some(res) if res != Res::Err => res,
                 _ => {
@@ -698,7 +690,7 @@ fn fn_type(seg: &hir::PathSegment<'_>) -> bool {
                 // This is a reference to a tuple struct or an enum variant where the def_id points
                 // to an invisible constructor function. That is not a very useful
                 // def, so adjust to point to the tuple struct or enum variant itself.
-                let parent_def_id = self.tcx.parent(def_id).unwrap();
+                let parent_def_id = self.tcx.parent(def_id);
                 Some(Ref { kind: RefKind::Type, span, ref_id: id_from_def_id(parent_def_id) })
             }
             Res::Def(HirDefKind::Static(_) | HirDefKind::Const | HirDefKind::AssocConst, _) => {
index 8f50f44571953fb0b7a89ae8f2c6bbec6d00eab6..d1286c9b8b0dfeb083a4e2585f57aa3d4d8eb1a5 100644 (file)
@@ -630,31 +630,6 @@ fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<
                     param_text.push_str(&id_to_string(&scx.tcx.hir(), default.hir_id));
                 }
             }
-            if !param.bounds.is_empty() {
-                param_text.push_str(": ");
-                match param.kind {
-                    hir::GenericParamKind::Lifetime { .. } => {
-                        let bounds = param
-                            .bounds
-                            .iter()
-                            .map(|bound| match bound {
-                                hir::GenericBound::Outlives(lt) => lt.name.ident().to_string(),
-                                _ => panic!(),
-                            })
-                            .collect::<Vec<_>>()
-                            .join(" + ");
-                        param_text.push_str(&bounds);
-                        // FIXME add lifetime bounds refs.
-                    }
-                    hir::GenericParamKind::Type { .. } => {
-                        param_text.push_str(&bounds_to_string(param.bounds));
-                        // FIXME descend properly into bounds.
-                    }
-                    hir::GenericParamKind::Const { .. } => {
-                        // Const generics cannot contain bounds.
-                    }
-                }
-            }
             text.push_str(&param_text);
             text.push(',');
         }
index d5053034ed88298a0c885e6da5410e4b80c39a10..7d6b8c760ff6a4e3fde8b1c60691e0322388bc3d 100644 (file)
@@ -498,7 +498,6 @@ macro_rules! peel {
 /// 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 {
-    ()                     => (0usize);
     ($one:tt)              => (1usize);
     ($($pairs:tt $_p:tt)*) => (count!($($pairs)*) << 1usize);
     ($odd:tt $($rest:tt)*) => (count!($($rest)*) | 1usize);
index 12c5c4445d46f333c9437fd7270a81afac91692a..530c1a06f8f47d451e0e843c12031366512acc3e 100644 (file)
@@ -474,6 +474,11 @@ pub struct ExternEntry {
     /// This can be disabled with the `noprelude` option like
     /// `--extern noprelude:name`.
     pub add_prelude: bool,
+    /// The extern entry shouldn't be considered for unused dependency warnings.
+    ///
+    /// `--extern nounused:std=/path/to/lib/libstd.rlib`. This is used to
+    /// suppress `unused-crate-dependencies` warnings.
+    pub nounused_dep: bool,
 }
 
 #[derive(Clone, Debug)]
@@ -512,7 +517,7 @@ pub fn len(&self) -> usize {
 
 impl ExternEntry {
     fn new(location: ExternLocation) -> ExternEntry {
-        ExternEntry { location, is_private_dep: false, add_prelude: false }
+        ExternEntry { location, is_private_dep: false, add_prelude: false, nounused_dep: false }
     }
 
     pub fn files(&self) -> Option<impl Iterator<Item = &CanonicalizedPath>> {
@@ -752,7 +757,7 @@ fn default() -> Options {
             real_rust_source_base_dir: None,
             edition: DEFAULT_EDITION,
             json_artifact_notifications: false,
-            json_unused_externs: false,
+            json_unused_externs: JsonUnusedExterns::No,
             json_future_incompat: false,
             pretty: None,
             working_dir: RealFileName::LocalPath(std::env::current_dir().unwrap()),
@@ -1038,6 +1043,7 @@ fn fill_well_known_names(&mut self) {
             sym::target_has_atomic_load_store,
             sym::target_has_atomic,
             sym::target_has_atomic_equal_alignment,
+            sym::target_feature,
             sym::panic,
             sym::sanitize,
             sym::debug_assertions,
@@ -1081,6 +1087,10 @@ fn fill_well_known_values(&mut self) {
             .into_iter()
             .map(|sanitizer| Symbol::intern(sanitizer.as_str().unwrap()));
 
+        // Unknown possible values:
+        //  - `feature`
+        //  - `target_feature`
+
         // No-values
         for name in [
             sym::doc,
@@ -1488,10 +1498,37 @@ pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
 pub struct JsonConfig {
     pub json_rendered: HumanReadableErrorType,
     pub json_artifact_notifications: bool,
-    pub json_unused_externs: bool,
+    pub json_unused_externs: JsonUnusedExterns,
     pub json_future_incompat: bool,
 }
 
+/// Report unused externs in event stream
+#[derive(Copy, Clone)]
+pub enum JsonUnusedExterns {
+    /// Do not
+    No,
+    /// Report, but do not exit with failure status for deny/forbid
+    Silent,
+    /// Report, and also exit with failure status for deny/forbid
+    Loud,
+}
+
+impl JsonUnusedExterns {
+    pub fn is_enabled(&self) -> bool {
+        match self {
+            JsonUnusedExterns::No => false,
+            JsonUnusedExterns::Loud | JsonUnusedExterns::Silent => true,
+        }
+    }
+
+    pub fn is_loud(&self) -> bool {
+        match self {
+            JsonUnusedExterns::No | JsonUnusedExterns::Silent => false,
+            JsonUnusedExterns::Loud => true,
+        }
+    }
+}
+
 /// Parse the `--json` flag.
 ///
 /// The first value returned is how to render JSON diagnostics, and the second
@@ -1501,7 +1538,7 @@ pub fn parse_json(matches: &getopts::Matches) -> JsonConfig {
         HumanReadableErrorType::Default;
     let mut json_color = ColorConfig::Never;
     let mut json_artifact_notifications = false;
-    let mut json_unused_externs = false;
+    let mut json_unused_externs = JsonUnusedExterns::No;
     let mut json_future_incompat = false;
     for option in matches.opt_strs("json") {
         // For now conservatively forbid `--color` with `--json` since `--json`
@@ -1519,7 +1556,8 @@ pub fn parse_json(matches: &getopts::Matches) -> JsonConfig {
                 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
                 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
                 "artifacts" => json_artifact_notifications = true,
-                "unused-externs" => json_unused_externs = true,
+                "unused-externs" => json_unused_externs = JsonUnusedExterns::Loud,
+                "unused-externs-silent" => json_unused_externs = JsonUnusedExterns::Silent,
                 "future-incompat" => json_future_incompat = true,
                 s => early_error(
                     ErrorOutputType::default(),
@@ -2131,6 +2169,7 @@ pub fn parse_externs(
 
         let mut is_private_dep = false;
         let mut add_prelude = true;
+        let mut nounused_dep = false;
         if let Some(opts) = options {
             if !is_unstable_enabled {
                 early_error(
@@ -2152,6 +2191,7 @@ pub fn parse_externs(
                             );
                         }
                     }
+                    "nounused" => nounused_dep = true,
                     _ => early_error(error_format, &format!("unknown --extern option `{opt}`")),
                 }
             }
@@ -2160,6 +2200,8 @@ pub fn parse_externs(
         // Crates start out being not private, and go to being private `priv`
         // is specified.
         entry.is_private_dep |= is_private_dep;
+        // likewise `nounused`
+        entry.nounused_dep |= nounused_dep;
         // If any flag is missing `noprelude`, then add to the prelude.
         entry.add_prelude |= add_prelude;
     }
@@ -2215,7 +2257,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
 
     check_debug_option_stability(&debugging_opts, error_format, json_rendered);
 
-    if !debugging_opts.unstable_options && json_unused_externs {
+    if !debugging_opts.unstable_options && json_unused_externs.is_enabled() {
         early_error(
             error_format,
             "the `-Z unstable-options` flag must also be passed to enable \
index df65409a8a063b1c7e87994b5d2a0ed31f93f939..14e918660dd39f47341ef76851ab35e5993ddbe3 100644 (file)
@@ -221,7 +221,7 @@ pub struct Options {
         json_artifact_notifications: bool [TRACKED],
 
         /// `true` if we're emitting a JSON blob containing the unused externs
-        json_unused_externs: bool [UNTRACKED],
+        json_unused_externs: JsonUnusedExterns [UNTRACKED],
 
         /// `true` if we're emitting a JSON job containing a future-incompat report for lints
         json_future_incompat: bool [TRACKED],
@@ -368,6 +368,8 @@ mod desc {
     pub const parse_opt_langid: &str = "a language identifier";
     pub const parse_opt_pathbuf: &str = "a path";
     pub const parse_list: &str = "a space-separated list of strings";
+    pub const parse_list_with_polarity: &str =
+        "a comma-separated list of strings, with elements beginning with + or -";
     pub const parse_opt_comma_list: &str = "a comma-separated list of strings";
     pub const parse_number: &str = "a number";
     pub const parse_opt_number: &str = parse_number;
@@ -529,6 +531,19 @@ mod parse {
         }
     }
 
+    crate fn parse_list_with_polarity(slot: &mut Vec<(String, bool)>, v: Option<&str>) -> bool {
+        match v {
+            Some(s) => {
+                for s in s.split(",") {
+                    let Some(pass_name) = s.strip_prefix(&['+', '-'][..]) else { return false };
+                    slot.push((pass_name.to_string(), &s[..1] == "+"));
+                }
+                true
+            }
+            None => false,
+        }
+    }
+
     crate fn parse_location_detail(ld: &mut LocationDetail, v: Option<&str>) -> bool {
         if let Some(v) = v {
             ld.line = false;
@@ -1318,6 +1333,10 @@ mod parse {
     mir_emit_retag: bool = (false, parse_bool, [TRACKED],
         "emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 \
         (default: no)"),
+    mir_enable_passes: Vec<(String, bool)> = (Vec::new(), parse_list_with_polarity, [TRACKED],
+        "use like `-Zmir-enable-passes=+DestProp,-InstCombine`. Forces the specified passes to be \
+        enabled, overriding all other checks. Passes that are not specified are enabled or \
+        disabled by other flags as usual."),
     mir_opt_level: Option<usize> = (None, parse_opt_number, [TRACKED],
         "MIR optimization level (0-4; default: 1 in non optimized builds and 2 in optimized builds)"),
     move_size_limit: Option<usize> = (None, parse_opt_number, [TRACKED],
index 6a36ae63c6834ad6ef2224f4a545d2d1312922e2..e933fe1cb2412c31fef8715cf6b03109248988d6 100644 (file)
@@ -3,13 +3,14 @@
 
 use crate::config::CheckCfg;
 use crate::lint::{BufferedEarlyLint, BuiltinLintDiagnostics, Lint, LintId};
+use crate::SessionDiagnostic;
 use rustc_ast::node_id::NodeId;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::sync::{Lock, Lrc};
 use rustc_errors::{emitter::SilentEmitter, ColorConfig, Handler};
 use rustc_errors::{
     error_code, fallback_fluent_bundle, Applicability, Diagnostic, DiagnosticBuilder,
-    ErrorGuaranteed, MultiSpan,
+    DiagnosticMessage, ErrorGuaranteed, MultiSpan,
 };
 use rustc_feature::{find_feature_issue, GateIssue, UnstableFeatures};
 use rustc_span::edition::Edition;
@@ -287,4 +288,23 @@ pub fn save_proc_macro_span(&self, span: Span) -> usize {
     pub fn proc_macro_quoted_spans(&self) -> Vec<Span> {
         self.proc_macro_quoted_spans.lock().clone()
     }
+
+    pub fn emit_err<'a>(&'a self, err: impl SessionDiagnostic<'a>) -> ErrorGuaranteed {
+        err.into_diagnostic(self).emit()
+    }
+
+    pub fn emit_warning<'a>(&'a self, warning: impl SessionDiagnostic<'a, ()>) {
+        warning.into_diagnostic(self).emit()
+    }
+
+    pub fn struct_err(
+        &self,
+        msg: impl Into<DiagnosticMessage>,
+    ) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
+        self.span_diagnostic.struct_err(msg)
+    }
+
+    pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
+        self.span_diagnostic.struct_warn(msg)
+    }
 }
index b4548129689b1e90f718d7737ce28c48131170a1..e8279f6fed24f378369f12ef018ffbd6c8b7e131 100644 (file)
@@ -212,7 +212,7 @@ pub struct PerfStats {
 pub trait SessionDiagnostic<'a, T: EmissionGuarantee = ErrorGuaranteed> {
     /// Write out as a diagnostic out of `sess`.
     #[must_use]
-    fn into_diagnostic(self, sess: &'a Session) -> DiagnosticBuilder<'a, T>;
+    fn into_diagnostic(self, sess: &'a ParseSess) -> DiagnosticBuilder<'a, T>;
 }
 
 impl Session {
@@ -334,7 +334,7 @@ pub fn struct_err(
         &self,
         msg: impl Into<DiagnosticMessage>,
     ) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
-        self.diagnostic().struct_err(msg)
+        self.parse_sess.struct_err(msg)
     }
     pub fn struct_err_with_code(
         &self,
@@ -414,10 +414,10 @@ pub fn err(&self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed {
         self.diagnostic().err(msg)
     }
     pub fn emit_err<'a>(&'a self, err: impl SessionDiagnostic<'a>) -> ErrorGuaranteed {
-        err.into_diagnostic(self).emit()
+        self.parse_sess.emit_err(err)
     }
     pub fn emit_warning<'a>(&'a self, warning: impl SessionDiagnostic<'a, ()>) {
-        warning.into_diagnostic(self).emit()
+        self.parse_sess.emit_warning(warning)
     }
     #[inline]
     pub fn err_count(&self) -> usize {
index 8064c217457bb561bc66185b27d75822f0fbce1e..db755ccd1d5155fc0ce1ed4999a48fcde6caa54f 100644 (file)
@@ -1,6 +1,6 @@
 use crate::parse::ParseSess;
 use crate::session::Session;
-use rustc_ast::token::{self, DelimToken, Nonterminal, Token};
+use rustc_ast::token::{self, Delimiter, Nonterminal, Token};
 use rustc_ast::tokenstream::CanSynthesizeMissingTokens;
 use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree};
 use rustc_data_structures::profiling::VerboseTimingGuard;
@@ -137,7 +137,7 @@ pub fn process_token(&mut self, token: Token) -> TokenStream {
                 let tts = (self.nt_to_tokenstream)(&nt, self.parse_sess, self.synthesize_tokens);
                 TokenTree::Delimited(
                     DelimSpan::from_single(token.span),
-                    DelimToken::NoDelim,
+                    Delimiter::Invisible,
                     self.process_token_stream(tts),
                 )
                 .into()
index 3889639b50f454bf232b430c17bbf9ff86397db1..447b73fa3c3ce484b5274a7ebaeaf14451b6b89b 100644 (file)
@@ -1132,6 +1132,7 @@ pub enum DesugaringKind {
     CondTemporary,
     QuestionMark,
     TryBlock,
+    YeetExpr,
     /// Desugaring of an `impl Trait` in return type position
     /// to an `type Foo = impl Trait;` and replacing the
     /// `impl Trait` with `Foo`.
@@ -1152,6 +1153,7 @@ pub fn descr(self) -> &'static str {
             DesugaringKind::Await => "`await` expression",
             DesugaringKind::QuestionMark => "operator `?`",
             DesugaringKind::TryBlock => "`try` block",
+            DesugaringKind::YeetExpr => "`do yeet` expression",
             DesugaringKind::OpaqueTy => "`impl Trait`",
             DesugaringKind::ForLoop => "`for` loop",
             DesugaringKind::LetElse => "`let...else`",
index b0307cc20d174f39645a81d5a8f7646ff515eda9..f22faef2580a56c6482570ba083e44fc790eb548 100644 (file)
@@ -59,6 +59,8 @@
 mod analyze_source_file;
 pub mod fatal_error;
 
+pub mod profiling;
+
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::sync::{Lock, Lrc};
 
diff --git a/compiler/rustc_span/src/profiling.rs b/compiler/rustc_span/src/profiling.rs
new file mode 100644 (file)
index 0000000..f169007
--- /dev/null
@@ -0,0 +1,35 @@
+use std::borrow::Borrow;
+
+use rustc_data_structures::profiling::EventArgRecorder;
+
+/// Extension trait for self-profiling purposes: allows to record spans within a generic activity's
+/// event arguments.
+pub trait SpannedEventArgRecorder {
+    /// Records the following event arguments within the current generic activity being profiled:
+    /// - the provided `event_arg`
+    /// - a string representation of the provided `span`
+    ///
+    /// Note: when self-profiling with costly event arguments, at least one argument
+    /// needs to be recorded. A panic will be triggered if that doesn't happen.
+    fn record_arg_with_span<A>(&mut self, event_arg: A, span: crate::Span)
+    where
+        A: Borrow<str> + Into<String>;
+}
+
+impl SpannedEventArgRecorder for EventArgRecorder<'_> {
+    fn record_arg_with_span<A>(&mut self, event_arg: A, span: crate::Span)
+    where
+        A: Borrow<str> + Into<String>,
+    {
+        self.record_arg(event_arg);
+
+        let span_arg = crate::with_session_globals(|session_globals| {
+            if let Some(source_map) = &*session_globals.source_map.borrow() {
+                source_map.span_to_embeddable_string(span)
+            } else {
+                format!("{:?}", span)
+            }
+        });
+        self.record_arg(span_arg);
+    }
+}
index 95177102dcf8678df118ab6d58cc65750219d8be..460b5c18fc1b4838089ef11fe9d422e95ef44bf9 100644 (file)
@@ -1102,7 +1102,19 @@ pub fn map_prefix(&self, path: PathBuf) -> (PathBuf, bool) {
         //       take precedence.
         for &(ref from, ref to) in self.mapping.iter().rev() {
             if let Ok(rest) = path.strip_prefix(from) {
-                return (to.join(rest), true);
+                let remapped = if rest.as_os_str().is_empty() {
+                    // This is subtle, joining an empty path onto e.g. `foo/bar` will
+                    // result in `foo/bar/`, that is, there'll be an additional directory
+                    // separator at the end. This can lead to duplicated directory separators
+                    // in remapped paths down the line.
+                    // So, if we have an exact match, we just return that without a call
+                    // to `Path::join()`.
+                    to.clone()
+                } else {
+                    to.join(rest)
+                };
+
+                return (remapped, true);
             }
         }
 
index f13979941abee7ded0399227f2ee1222a8591227..481e015c66c25ce3c6a8881974f93f2fc17cb1c2 100644 (file)
@@ -312,3 +312,83 @@ fn span_substr(
         }
     }
 }
+
+fn map_path_prefix(mapping: &FilePathMapping, path: &str) -> String {
+    // It's important that we convert to a string here because that's what
+    // later stages do too (e.g. in the backend), and comparing `Path` values
+    // won't catch some differences at the string level, e.g. "abc" and "abc/"
+    // compare as equal.
+    mapping.map_prefix(path.into()).0.to_string_lossy().to_string()
+}
+
+#[cfg(unix)]
+#[test]
+fn path_prefix_remapping() {
+    // Relative to relative
+    {
+        let mapping = &FilePathMapping::new(vec![("abc/def".into(), "foo".into())]);
+
+        assert_eq!(map_path_prefix(mapping, "abc/def/src/main.rs"), "foo/src/main.rs");
+        assert_eq!(map_path_prefix(mapping, "abc/def"), "foo");
+    }
+
+    // Relative to absolute
+    {
+        let mapping = &FilePathMapping::new(vec![("abc/def".into(), "/foo".into())]);
+
+        assert_eq!(map_path_prefix(mapping, "abc/def/src/main.rs"), "/foo/src/main.rs");
+        assert_eq!(map_path_prefix(mapping, "abc/def"), "/foo");
+    }
+
+    // Absolute to relative
+    {
+        let mapping = &FilePathMapping::new(vec![("/abc/def".into(), "foo".into())]);
+
+        assert_eq!(map_path_prefix(mapping, "/abc/def/src/main.rs"), "foo/src/main.rs");
+        assert_eq!(map_path_prefix(mapping, "/abc/def"), "foo");
+    }
+
+    // Absolute to absolute
+    {
+        let mapping = &FilePathMapping::new(vec![("/abc/def".into(), "/foo".into())]);
+
+        assert_eq!(map_path_prefix(mapping, "/abc/def/src/main.rs"), "/foo/src/main.rs");
+        assert_eq!(map_path_prefix(mapping, "/abc/def"), "/foo");
+    }
+}
+
+#[cfg(windows)]
+#[test]
+fn path_prefix_remapping_from_relative2() {
+    // Relative to relative
+    {
+        let mapping = &FilePathMapping::new(vec![("abc\\def".into(), "foo".into())]);
+
+        assert_eq!(map_path_prefix(mapping, "abc\\def\\src\\main.rs"), "foo\\src\\main.rs");
+        assert_eq!(map_path_prefix(mapping, "abc\\def"), "foo");
+    }
+
+    // Relative to absolute
+    {
+        let mapping = &FilePathMapping::new(vec![("abc\\def".into(), "X:\\foo".into())]);
+
+        assert_eq!(map_path_prefix(mapping, "abc\\def\\src\\main.rs"), "X:\\foo\\src\\main.rs");
+        assert_eq!(map_path_prefix(mapping, "abc\\def"), "X:\\foo");
+    }
+
+    // Absolute to relative
+    {
+        let mapping = &FilePathMapping::new(vec![("X:\\abc\\def".into(), "foo".into())]);
+
+        assert_eq!(map_path_prefix(mapping, "X:\\abc\\def\\src\\main.rs"), "foo\\src\\main.rs");
+        assert_eq!(map_path_prefix(mapping, "X:\\abc\\def"), "foo");
+    }
+
+    // Absolute to absolute
+    {
+        let mapping = &FilePathMapping::new(vec![("X:\\abc\\def".into(), "X:\\foo".into())]);
+
+        assert_eq!(map_path_prefix(mapping, "X:\\abc\\def\\src\\main.rs"), "X:\\foo\\src\\main.rs");
+        assert_eq!(map_path_prefix(mapping, "X:\\abc\\def"), "X:\\foo");
+    }
+}
index e3ce8105a8b47a825ccb5499944993015f4bea92..c1299c94c4bb395395f04632dd0edc9ed4c3c222 100644 (file)
         MacroRules:         "macro_rules",
         Raw:                "raw",
         Union:              "union",
+        Yeet:               "yeet",
     }
 
     // Pre-interned symbols that can be referred to with `rustc_span::sym::*`.
         from_residual,
         from_size_align_unchecked,
         from_usize,
+        from_yeet,
         fsub_fast,
         fundamental,
         future,
         x87_reg,
         xer,
         xmm_reg,
+        yeet_desugar_details,
+        yeet_expr,
         ymm_reg,
         zmm_reg,
     }
index ce564d1455bfc05d3ee3016f2f5e4255cd2454d9..afce10ff1cbe8f36510626fd4696e1e46c22874c 100644 (file)
@@ -696,7 +696,13 @@ pub fn adjust_for_foreign_abi<C>(
             "sparc" => sparc::compute_abi_info(cx, self),
             "sparc64" => sparc64::compute_abi_info(cx, self),
             "nvptx" => nvptx::compute_abi_info(self),
-            "nvptx64" => nvptx64::compute_abi_info(self),
+            "nvptx64" => {
+                if cx.target_spec().adjust_abi(abi) == spec::abi::Abi::PtxKernel {
+                    nvptx64::compute_ptx_kernel_abi_info(cx, self)
+                } else {
+                    nvptx64::compute_abi_info(self)
+                }
+            }
             "hexagon" => hexagon::compute_abi_info(self),
             "riscv32" | "riscv64" => riscv::compute_abi_info(cx, self),
             "wasm32" | "wasm64" => {
index 16f331b16d5619b5e0c7263c99d92e8a7f8c4cc8..fc16f1c97a4522dc45d1e3680c66ac35728886bc 100644 (file)
@@ -1,21 +1,35 @@
-// Reference: PTX Writer's Guide to Interoperability
-// https://docs.nvidia.com/cuda/ptx-writers-guide-to-interoperability
-
-use crate::abi::call::{ArgAbi, FnAbi};
+use crate::abi::call::{ArgAbi, FnAbi, PassMode, Reg, Size, Uniform};
+use crate::abi::{HasDataLayout, TyAbiInterface};
 
 fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
     if ret.layout.is_aggregate() && ret.layout.size.bits() > 64 {
         ret.make_indirect();
-    } else {
-        ret.extend_integer_width_to(64);
     }
 }
 
 fn classify_arg<Ty>(arg: &mut ArgAbi<'_, Ty>) {
     if arg.layout.is_aggregate() && arg.layout.size.bits() > 64 {
         arg.make_indirect();
-    } else {
-        arg.extend_integer_width_to(64);
+    }
+}
+
+fn classify_arg_kernel<'a, Ty, C>(_cx: &C, arg: &mut ArgAbi<'a, Ty>)
+where
+    Ty: TyAbiInterface<'a, C> + Copy,
+    C: HasDataLayout,
+{
+    if matches!(arg.mode, PassMode::Pair(..)) && (arg.layout.is_adt() || arg.layout.is_tuple()) {
+        let align_bytes = arg.layout.align.abi.bytes();
+
+        let unit = match align_bytes {
+            1 => Reg::i8(),
+            2 => Reg::i16(),
+            4 => Reg::i32(),
+            8 => Reg::i64(),
+            16 => Reg::i128(),
+            _ => unreachable!("Align is given as power of 2 no larger than 16 bytes"),
+        };
+        arg.cast_to(Uniform { unit, total: Size::from_bytes(2 * align_bytes) });
     }
 }
 
@@ -31,3 +45,20 @@ pub fn compute_abi_info<Ty>(fn_abi: &mut FnAbi<'_, Ty>) {
         classify_arg(arg);
     }
 }
+
+pub fn compute_ptx_kernel_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
+where
+    Ty: TyAbiInterface<'a, C> + Copy,
+    C: HasDataLayout,
+{
+    if !fn_abi.ret.layout.is_unit() && !fn_abi.ret.layout.is_never() {
+        panic!("Kernels should not return anything other than () or !");
+    }
+
+    for arg in &mut fn_abi.args {
+        if arg.is_ignore() {
+            continue;
+        }
+        classify_arg_kernel(cx, arg);
+    }
+}
index 169167f69bf8c6eea720579f272aca9911fec50c..0e8fd9cc93fd120d97da310d45135688e0e01270 100644 (file)
@@ -1355,6 +1355,10 @@ fn ty_and_layout_pointee_info_at(
         cx: &C,
         offset: Size,
     ) -> Option<PointeeInfo>;
+    fn is_adt(this: TyAndLayout<'a, Self>) -> bool;
+    fn is_never(this: TyAndLayout<'a, Self>) -> bool;
+    fn is_tuple(this: TyAndLayout<'a, Self>) -> bool;
+    fn is_unit(this: TyAndLayout<'a, Self>) -> bool;
 }
 
 impl<'a, Ty> TyAndLayout<'a, Ty> {
@@ -1396,6 +1400,34 @@ pub fn is_single_fp_element<C>(self, cx: &C) -> bool
             _ => false,
         }
     }
+
+    pub fn is_adt<C>(self) -> bool
+    where
+        Ty: TyAbiInterface<'a, C>,
+    {
+        Ty::is_adt(self)
+    }
+
+    pub fn is_never<C>(self) -> bool
+    where
+        Ty: TyAbiInterface<'a, C>,
+    {
+        Ty::is_never(self)
+    }
+
+    pub fn is_tuple<C>(self) -> bool
+    where
+        Ty: TyAbiInterface<'a, C>,
+    {
+        Ty::is_tuple(self)
+    }
+
+    pub fn is_unit<C>(self) -> bool
+    where
+        Ty: TyAbiInterface<'a, C>,
+    {
+        Ty::is_unit(self)
+    }
 }
 
 impl<'a, Ty> TyAndLayout<'a, Ty> {
index b1e8737b52b90a45d0ecc3d49615d0f292518697..4e7c2eb1bf88e65c39bd8c71d307d4ebd9197f28 100644 (file)
@@ -43,7 +43,8 @@ pub fn supported_types(
     }
 }
 
-// The reserved registers are somewhat taken from <https://git.io/JUR1k#L150>.
+// The reserved registers are somewhat taken from
+// <https://github.com/llvm/llvm-project/blob/deb8f8bcf31540c657716ea5242183b0792702a1/llvm/lib/Target/Mips/MipsRegisterInfo.cpp#L150>.
 def_regs! {
     Mips MipsInlineAsmReg MipsInlineAsmRegClass {
         r2: reg = ["$2"],
index bd5b712c143c5047c133fb62db6771b447c98eec..965a3c109832ba2cfa79b7a1075955f03a04bc7d 100644 (file)
@@ -2249,10 +2249,6 @@ macro_rules! target_val {
                 let name = (stringify!($attr)).replace("_", "-");
                 d.insert(name, self.$attr.to_json());
             }};
-            ($attr:ident, $key_name:expr) => {{
-                let name = $key_name;
-                d.insert(name.into(), self.$attr.to_json());
-            }};
         }
 
         macro_rules! target_option_val {
index 609b7d42e43a11ae007e1944b92a515bb2378a61..6826c0ac62b3ab48ac82195e303b1ac44ad763f9 100644 (file)
@@ -36,7 +36,7 @@ pub fn target() -> Target {
     Target {
         llvm_target: "wasm64-unknown-unknown".into(),
         pointer_width: 64,
-        data_layout: "e-m:e-p:64:64-i64:64-n32:64-S128-ni:1:10:20".into(),
+        data_layout: "e-m:e-p:64:64-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20".into(),
         arch: "wasm64".into(),
         options,
     }
index 50e4fafdd6c829c44fe8212e244993f5689a0b3b..7a3579eb1cc853193bbda3e3ecdb74c3c5d65cf6 100644 (file)
@@ -1727,6 +1727,7 @@ fn type_category(tcx: TyCtxt<'_>, t: Ty<'_>) -> Option<u32> {
         } else if cat_a == cat_b {
             match (a.kind(), b.kind()) {
                 (ty::Adt(def_a, _), ty::Adt(def_b, _)) => def_a == def_b,
+                (ty::Foreign(def_a), ty::Foreign(def_b)) => def_a == def_b,
                 // Matching on references results in a lot of unhelpful
                 // suggestions, so let's just not do that for now.
                 //
@@ -2418,26 +2419,15 @@ fn maybe_suggest_unsized_generics<'hir>(
         };
         let sized_trait = self.tcx.lang_items().sized_trait();
         debug!("maybe_suggest_unsized_generics: generics.params={:?}", generics.params);
-        debug!("maybe_suggest_unsized_generics: generics.where_clause={:?}", generics.where_clause);
-        let param = generics.params.iter().filter(|param| param.span == span).find(|param| {
-            // Check that none of the explicit trait bounds is `Sized`. Assume that an explicit
-            // `Sized` bound is there intentionally and we don't need to suggest relaxing it.
-            param
-                .bounds
-                .iter()
-                .all(|bound| bound.trait_ref().and_then(|tr| tr.trait_def_id()) != sized_trait)
-        });
-        let Some(param) = param else {
+        debug!("maybe_suggest_unsized_generics: generics.predicates={:?}", generics.predicates);
+        let Some(param) = generics.params.iter().find(|param| param.span == span) else {
             return;
         };
-        let param_def_id = self.tcx.hir().local_def_id(param.hir_id).to_def_id();
-        let preds = generics.where_clause.predicates.iter();
-        let explicitly_sized = preds
-            .filter_map(|pred| match pred {
-                hir::WherePredicate::BoundPredicate(bp) => Some(bp),
-                _ => None,
-            })
-            .filter(|bp| bp.is_param_bound(param_def_id))
+        let param_def_id = self.tcx.hir().local_def_id(param.hir_id);
+        // Check that none of the explicit trait bounds is `Sized`. Assume that an explicit
+        // `Sized` bound is there intentionally and we don't need to suggest relaxing it.
+        let explicitly_sized = generics
+            .bounds_for_param(param_def_id)
             .flat_map(|bp| bp.bounds)
             .any(|bound| bound.trait_ref().and_then(|tr| tr.trait_def_id()) == sized_trait);
         if explicitly_sized {
@@ -2460,9 +2450,11 @@ fn maybe_suggest_unsized_generics<'hir>(
             _ => {}
         };
         // Didn't add an indirection suggestion, so add a general suggestion to relax `Sized`.
-        let (span, separator) = match param.bounds {
-            [] => (span.shrink_to_hi(), ":"),
-            [.., bound] => (bound.span().shrink_to_hi(), " +"),
+        let (span, separator) = if let Some(s) = generics.bounds_span_for_suggestions(param_def_id)
+        {
+            (s, " +")
+        } else {
+            (span.shrink_to_hi(), ":")
         };
         err.span_suggestion_verbose(
             span,
index 31b92d52bebc8d08a8690b60d7d283ecb516e6f4..9e9c230aebb85b2a597cf5dad201e09aa02eda42 100644 (file)
@@ -217,22 +217,42 @@ fn on_unimplemented_note(
                 flags.push((sym::_Self, Some(shortname.to_owned())));
             }
 
+            // Slices give us `[]`, `[{ty}]`
+            if let ty::Slice(aty) = self_ty.kind() {
+                flags.push((sym::_Self, Some("[]".to_string())));
+                if let Some(def) = aty.ty_adt_def() {
+                    // We also want to be able to select the slice's type's original
+                    // signature with no type arguments resolved
+                    let type_string = self.tcx.type_of(def.did()).to_string();
+                    flags.push((sym::_Self, Some(format!("[{type_string}]"))));
+                }
+                if aty.is_integral() {
+                    flags.push((sym::_Self, Some("[{integral}]".to_string())));
+                }
+            }
+
+            // Arrays give us `[]`, `[{ty}; _]` and `[{ty}; N]`
             if let ty::Array(aty, len) = self_ty.kind() {
-                flags.push((sym::_Self, Some("[]".to_owned())));
-                flags.push((sym::_Self, Some(format!("[{}]", aty))));
+                flags.push((sym::_Self, Some("[]".to_string())));
+                let len = len.val().try_to_value().and_then(|v| v.try_to_machine_usize(self.tcx));
+                flags.push((sym::_Self, Some(format!("[{}; _]", aty))));
+                if let Some(n) = len {
+                    flags.push((sym::_Self, Some(format!("[{}; {}]", aty, n))));
+                }
                 if let Some(def) = aty.ty_adt_def() {
                     // We also want to be able to select the array's type's original
                     // signature with no type arguments resolved
                     let type_string = self.tcx.type_of(def.did()).to_string();
-                    flags.push((sym::_Self, Some(format!("[{}]", type_string))));
-
-                    let len =
-                        len.val().try_to_value().and_then(|v| v.try_to_machine_usize(self.tcx));
-                    let string = match len {
-                        Some(n) => format!("[{}; {}]", type_string, n),
-                        None => format!("[{}; _]", type_string),
-                    };
-                    flags.push((sym::_Self, Some(string)));
+                    flags.push((sym::_Self, Some(format!("[{type_string}; _]"))));
+                    if let Some(n) = len {
+                        flags.push((sym::_Self, Some(format!("[{type_string}; {n}]"))));
+                    }
+                }
+                if aty.is_integral() {
+                    flags.push((sym::_Self, Some("[{integral}; _]".to_string())));
+                    if let Some(n) = len {
+                        flags.push((sym::_Self, Some(format!("[{{integral}}; {n}]"))));
+                    }
                 }
             }
             if let ty::Dynamic(traits, _) = self_ty.kind() {
index 0c1ca65c48f6adb9230785eb5e494973c04cc70c..a3d3c7c0cf3aa9f445141f9068826bfcd10caf98 100644 (file)
@@ -319,12 +319,8 @@ fn suggest_derive(
 
 fn predicate_constraint(generics: &hir::Generics<'_>, pred: String) -> (Span, String) {
     (
-        generics.where_clause.tail_span_for_suggestion(),
-        format!(
-            "{} {}",
-            if !generics.where_clause.predicates.is_empty() { "," } else { " where" },
-            pred,
-        ),
+        generics.tail_span_for_predicate_suggestion(),
+        format!("{} {}", if generics.has_where_clause { "," } else { " where" }, pred,),
     )
 }
 
@@ -346,7 +342,7 @@ fn suggest_restriction<'tcx>(
     //              -  ^^^^^^^^^ GenericBounds
     //              |
     //              &Ident
-    let span = generics.where_clause.span_for_predicates_or_empty_place();
+    let span = generics.span_for_predicates_or_empty_place();
     if span.from_expansion() || span.desugaring_kind().is_some() {
         return;
     }
@@ -396,21 +392,10 @@ fn suggest_restriction<'tcx>(
         let pred = trait_pred.to_predicate(tcx).to_string();
         let pred = pred.replace(&impl_trait_str, &type_param_name);
         let mut sugg = vec![
-            // Find the last of the generic parameters contained within the span of
-            // the generics
-            match generics
-                .params
-                .iter()
-                .map(|p| p.bounds_span_for_suggestions().unwrap_or(p.span.shrink_to_hi()))
-                .filter(|&span| generics.span.contains(span) && span.can_be_used_for_suggestions())
-                .max_by_key(|span| span.hi())
-            {
-                // `fn foo(t: impl Trait)`
-                //        ^ suggest `<T: Trait>` here
-                None => (generics.span, format!("<{}>", type_param)),
-                // `fn foo<A>(t: impl Trait)`
-                //        ^^^ suggest `<A, T: Trait>` here
-                Some(span) => (span, format!(", {}", type_param)),
+            if let Some(span) = generics.span_for_param_suggestion() {
+                (span, format!(", {}", type_param))
+            } else {
+                (generics.span, format!("<{}>", type_param))
             },
             // `fn foo(t: impl Trait)`
             //                       ^ suggest `where <T as Trait>::A: Bound`
@@ -1921,7 +1906,7 @@ fn note_obligation_cause_for_async_await(
                         GeneratorKind::Async(AsyncGeneratorKind::Fn) => self
                             .tcx
                             .parent(generator_did)
-                            .and_then(|parent_did| parent_did.as_local())
+                            .as_local()
                             .map(|parent_did| hir.local_def_id_to_hir_id(parent_did))
                             .and_then(|parent_hir_id| hir.opt_name(parent_hir_id))
                             .map(|name| {
@@ -2227,7 +2212,7 @@ fn note_obligation_cause_code<T>(
             }
             ObligationCauseCode::RepeatElementCopy { is_const_fn } => {
                 err.note(
-                    "the `Copy` trait is required because the repeated element will be copied",
+                    "the `Copy` trait is required because this value will be copied for each element of the array",
                 );
 
                 if is_const_fn {
index 84958136cac97b98dadea1239e44162882d4fd63..b39310d12942d752979f2d78b3ff464ff8e146df 100644 (file)
@@ -221,7 +221,6 @@ fn sized_trait_bound_spans<'tcx>(
                 ..
             }) => Some(
                 generics
-                    .where_clause
                     .predicates
                     .iter()
                     .filter_map(|pred| {
@@ -399,8 +398,8 @@ fn virtual_call_violation_for_method<'tcx>(
         // We'll attempt to provide a structured suggestion for `Self: Sized`.
         let sugg =
             tcx.hir().get_if_local(method.def_id).as_ref().and_then(|node| node.generics()).map(
-                |generics| match generics.where_clause.predicates {
-                    [] => (" where Self: Sized", generics.where_clause.span),
+                |generics| match generics.predicates {
+                    [] => (" where Self: Sized", generics.where_clause_span),
                     [.., pred] => (", Self: Sized", pred.span().shrink_to_hi()),
                 },
             );
index 8ba390c71db97b1bfc517a270386e9139cd71f87..c7a61cbe25a1aed118e1a7441ab08b2bace4d540 100644 (file)
@@ -1519,18 +1519,22 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
                 // Any type with multiple potential metadata types is therefore not eligible.
                 let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty());
 
-                let tail = selcx.tcx().struct_tail_with_normalize(self_ty, |ty| {
-                    // We throw away any obligations we get from this, since we normalize
-                    // and confirm these obligations once again during confirmation
-                    normalize_with_depth(
-                        selcx,
-                        obligation.param_env,
-                        obligation.cause.clone(),
-                        obligation.recursion_depth + 1,
-                        ty,
-                    )
-                    .value
-                });
+                let tail = selcx.tcx().struct_tail_with_normalize(
+                    self_ty,
+                    |ty| {
+                        // We throw away any obligations we get from this, since we normalize
+                        // and confirm these obligations once again during confirmation
+                        normalize_with_depth(
+                            selcx,
+                            obligation.param_env,
+                            obligation.cause.clone(),
+                            obligation.recursion_depth + 1,
+                            ty,
+                        )
+                        .value
+                    },
+                    || {},
+                );
 
                 match tail.kind() {
                     ty::Bool
index 5f5b81b892475b198b62a6feb7c90905464a8583..794e711b6c83106940755fd831f3d6aed117eb2a 100644 (file)
@@ -86,7 +86,7 @@ fn generic_arg_mismatch_err(
                         let param_type = tcx.infer_ctxt().enter(|infcx| {
                             infcx.resolve_numeric_literals_with_default(tcx.type_of(param.def_id))
                         });
-                        if param_type.is_suggestable() {
+                        if param_type.is_suggestable(tcx) {
                             err.span_suggestion(
                                 tcx.def_span(src_def_id),
                                 "consider changing this type parameter to be a `const` generic",
index 6bae0f2eac9545b5cb1c92d4a6bf84f4526d2e9e..fd1b7bfa0b1b0952cdb6321af62647657c297176 100644 (file)
@@ -924,14 +924,9 @@ pub(crate) fn add_implicitly_sized<'hir>(
             let self_ty_def_id = tcx.hir().local_def_id(self_ty).to_def_id();
             for clause in where_clause {
                 if let hir::WherePredicate::BoundPredicate(pred) = clause {
-                    match pred.bounded_ty.kind {
-                        hir::TyKind::Path(hir::QPath::Resolved(_, path)) => match path.res {
-                            Res::Def(DefKind::TyParam, def_id) if def_id == self_ty_def_id => {}
-                            _ => continue,
-                        },
-                        _ => continue,
+                    if pred.is_param_bound(self_ty_def_id) {
+                        search_bounds(pred.bounds);
                     }
-                    search_bounds(pred.bounds);
                 }
             }
         }
@@ -1957,7 +1952,7 @@ fn qpath_to_ty(
     ) -> Ty<'tcx> {
         let tcx = self.tcx();
 
-        let trait_def_id = tcx.parent(item_def_id).unwrap();
+        let trait_def_id = tcx.parent(item_def_id);
 
         debug!("qpath_to_ty: trait_def_id={:?}", trait_def_id);
 
@@ -2164,11 +2159,11 @@ pub fn def_ids_for_value_path_segments(
 
                     // `DefKind::Ctor` -> `DefKind::Variant`
                     if let DefKind::Ctor(..) = kind {
-                        def_id = tcx.parent(def_id).unwrap()
+                        def_id = tcx.parent(def_id);
                     }
 
                     // `DefKind::Variant` -> `DefKind::Enum`
-                    let enum_def_id = tcx.parent(def_id).unwrap();
+                    let enum_def_id = tcx.parent(def_id);
                     (enum_def_id, last - 1)
                 } else {
                     // FIXME: lint here recommending `Enum::<...>::Variant` form
@@ -2389,7 +2384,6 @@ fn ast_ty_to_ty_inner(&self, ast_ty: &hir::Ty<'_>, borrowed: bool, in_path: bool
                     bf.unsafety,
                     bf.abi,
                     bf.decl,
-                    &hir::Generics::empty(),
                     None,
                     Some(ast_ty),
                 ))
@@ -2466,7 +2460,7 @@ fn ast_ty_to_ty_inner(&self, ast_ty: &hir::Ty<'_>, borrowed: bool, in_path: bool
                     span,
                     ty,
                     opt_sugg: Some((span, Applicability::MachineApplicable))
-                        .filter(|_| ty.is_suggestable()),
+                        .filter(|_| ty.is_suggestable(tcx)),
                 });
 
                 ty
@@ -2551,8 +2545,7 @@ pub fn ty_of_fn(
         unsafety: hir::Unsafety,
         abi: abi::Abi,
         decl: &hir::FnDecl<'_>,
-        generics: &hir::Generics<'_>,
-        ident_span: Option<Span>,
+        generics: Option<&hir::Generics<'_>>,
         hir_ty: Option<&hir::Ty<'_>>,
     ) -> ty::PolyFnSig<'tcx> {
         debug!("ty_of_fn");
@@ -2563,40 +2556,78 @@ pub fn ty_of_fn(
 
         // We proactively collect all the inferred type params to emit a single error per fn def.
         let mut visitor = HirPlaceholderCollector::default();
-        for ty in decl.inputs {
-            visitor.visit_ty(ty);
+        let mut infer_replacements = vec![];
+
+        if let Some(generics) = generics {
+            walk_generics(&mut visitor, generics);
         }
-        walk_generics(&mut visitor, generics);
 
-        let input_tys = decl.inputs.iter().map(|a| self.ty_of_arg(a, None));
+        let input_tys: Vec<_> = decl
+            .inputs
+            .iter()
+            .enumerate()
+            .map(|(i, a)| {
+                if let hir::TyKind::Infer = a.kind && !self.allow_ty_infer() {
+                    if let Some(suggested_ty) =
+                        self.suggest_trait_fn_ty_for_impl_fn_infer(hir_id, Some(i))
+                    {
+                        infer_replacements.push((a.span, suggested_ty.to_string()));
+                        return suggested_ty;
+                    }
+                }
+
+                // Only visit the type looking for `_` if we didn't fix the type above
+                visitor.visit_ty(a);
+                self.ty_of_arg(a, None)
+            })
+            .collect();
+
         let output_ty = match decl.output {
             hir::FnRetTy::Return(output) => {
-                visitor.visit_ty(output);
-                self.ast_ty_to_ty(output)
+                if let hir::TyKind::Infer = output.kind
+                    && !self.allow_ty_infer()
+                    && let Some(suggested_ty) =
+                        self.suggest_trait_fn_ty_for_impl_fn_infer(hir_id, None)
+                {
+                    infer_replacements.push((output.span, suggested_ty.to_string()));
+                    suggested_ty
+                } else {
+                    visitor.visit_ty(output);
+                    self.ast_ty_to_ty(output)
+                }
             }
             hir::FnRetTy::DefaultReturn(..) => tcx.mk_unit(),
         };
 
         debug!("ty_of_fn: output_ty={:?}", output_ty);
 
-        let fn_ty = tcx.mk_fn_sig(input_tys, output_ty, decl.c_variadic, unsafety, abi);
+        let fn_ty = tcx.mk_fn_sig(input_tys.into_iter(), output_ty, decl.c_variadic, unsafety, abi);
         let bare_fn_ty = ty::Binder::bind_with_vars(fn_ty, bound_vars);
 
-        if !self.allow_ty_infer() {
+        if !self.allow_ty_infer() && !(visitor.0.is_empty() && infer_replacements.is_empty()) {
             // We always collect the spans for placeholder types when evaluating `fn`s, but we
             // only want to emit an error complaining about them if infer types (`_`) are not
             // allowed. `allow_ty_infer` gates this behavior. We check for the presence of
             // `ident_span` to not emit an error twice when we have `fn foo(_: fn() -> _)`.
 
-            crate::collect::placeholder_type_error(
+            let mut diag = crate::collect::placeholder_type_error_diag(
                 tcx,
-                ident_span.map(|sp| sp.shrink_to_hi()),
-                generics.params,
+                generics,
                 visitor.0,
+                infer_replacements.iter().map(|(s, _)| *s).collect(),
                 true,
                 hir_ty,
                 "function",
             );
+
+            if !infer_replacements.is_empty() {
+                diag.multipart_suggestion(&format!(
+                    "try replacing `_` with the type{} in the corresponding trait method signature",
+                    rustc_errors::pluralize!(infer_replacements.len()),
+                ), infer_replacements, Applicability::MachineApplicable);
+            }
+
+            diag.emit();
         }
 
         // Find any late-bound regions declared in return type that do
@@ -2624,6 +2655,43 @@ pub fn ty_of_fn(
         bare_fn_ty
     }
 
+    /// Given a fn_hir_id for a impl function, suggest the type that is found on the
+    /// corresponding function in the trait that the impl implements, if it exists.
+    /// If arg_idx is Some, then it corresponds to an input type index, otherwise it
+    /// corresponds to the return type.
+    fn suggest_trait_fn_ty_for_impl_fn_infer(
+        &self,
+        fn_hir_id: hir::HirId,
+        arg_idx: Option<usize>,
+    ) -> Option<Ty<'tcx>> {
+        let tcx = self.tcx();
+        let hir = tcx.hir();
+
+        let hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), ident, .. }) =
+            hir.get(fn_hir_id) else { return None };
+        let hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(i), .. }) =
+                hir.get(hir.get_parent_node(fn_hir_id)) else { bug!("ImplItem should have Impl parent") };
+
+        let trait_ref =
+            self.instantiate_mono_trait_ref(i.of_trait.as_ref()?, self.ast_ty_to_ty(i.self_ty));
+
+        let assoc = tcx.associated_items(trait_ref.def_id).find_by_name_and_kind(
+            tcx,
+            *ident,
+            ty::AssocKind::Fn,
+            trait_ref.def_id,
+        )?;
+
+        let fn_sig = tcx.fn_sig(assoc.def_id).subst(
+            tcx,
+            trait_ref.substs.extend_to(tcx, assoc.def_id, |param, _| tcx.mk_param_from_def(param)),
+        );
+
+        let ty = if let Some(arg_idx) = arg_idx { fn_sig.input(arg_idx) } else { fn_sig.output() };
+
+        Some(tcx.liberate_late_bound_regions(fn_hir_id.expect_owner().to_def_id(), ty))
+    }
+
     fn validate_late_bound_regions(
         &self,
         constrained_regions: FxHashSet<ty::BoundRegionKind>,
index 314236b1cdfbcbeec787166b1aac931aee4b9c5b..6a4c0c2091e92dc230219b6683f46bba9d5de84d 100644 (file)
@@ -102,6 +102,12 @@ pub(super) fn check_fn<'a, 'tcx>(
             DUMMY_SP,
             param_env,
         ));
+    // HACK(oli-obk): we rewrite the declared return type, too, so that we don't end up inferring all
+    // unconstrained RPIT to have `()` as their hidden type. This would happen because further down we
+    // compare the ret_coercion with declared_ret_ty, and anything uninferred would be inferred to the
+    // opaque type itself. That again would cause writeback to assume we have a recursive call site
+    // and do the sadly stabilized fallback to `()`.
+    let declared_ret_ty = ret_ty;
     fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(ret_ty)));
     fcx.ret_type_span = Some(decl.output.span());
 
index 4ab6f2cdafbc7ee7140b29442a81bd03a7069c02..6d78a863d54cf97bdf0911899899684441f1e1d7 100644 (file)
@@ -804,7 +804,8 @@ fn compare_synthetic_generics<'tcx>(
         iter::zip(impl_m_type_params, trait_m_type_params)
     {
         if impl_synthetic != trait_synthetic {
-            let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_def_id.expect_local());
+            let impl_def_id = impl_def_id.expect_local();
+            let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_def_id);
             let impl_span = tcx.hir().span(impl_hir_id);
             let trait_span = tcx.def_span(trait_def_id);
             let mut err = struct_span_err!(
@@ -868,14 +869,14 @@ fn compare_synthetic_generics<'tcx>(
                             hir::ImplItemKind::Fn(ref sig, _) => sig.decl.inputs,
                             _ => unreachable!(),
                         };
-                        struct Visitor(Option<Span>, hir::def_id::DefId);
+                        struct Visitor(Option<Span>, hir::def_id::LocalDefId);
                         impl<'v> intravisit::Visitor<'v> for Visitor {
                             fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
                                 intravisit::walk_ty(self, ty);
                                 if let hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) =
                                     ty.kind
                                     && let Res::Def(DefKind::TyParam, def_id) = path.res
-                                    && def_id == self.1
+                                    && def_id == self.1.to_def_id()
                                 {
                                     self.0 = Some(ty.span);
                                 }
@@ -887,17 +888,7 @@ fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
                         }
                         let span = visitor.0?;
 
-                        let bounds =
-                            impl_m.generics.params.iter().find_map(|param| match param.kind {
-                                GenericParamKind::Lifetime { .. } => None,
-                                GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
-                                    if param.hir_id == impl_hir_id {
-                                        Some(&param.bounds)
-                                    } else {
-                                        None
-                                    }
-                                }
-                            })?;
+                        let bounds = impl_m.generics.bounds_for_param(impl_def_id).next()?.bounds;
                         let bounds = bounds.first()?.span().to(bounds.last()?.span());
                         let bounds = tcx.sess.source_map().span_to_snippet(bounds).ok()?;
 
index e88082dbb9744e36c57a8b3c7f558c0a37333a16..a1e8d2040dd80d82429fa9b4984a656fb3145ef6 100644 (file)
 };
 use crate::type_error_struct;
 
+use super::suggest_call_constructor;
 use crate::errors::{AddressOfTemporaryTaken, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive};
 use rustc_ast as ast;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_errors::Diagnostic;
+use rustc_errors::EmissionGuarantee;
 use rustc_errors::ErrorGuaranteed;
 use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, DiagnosticId};
 use rustc_hir as hir;
@@ -78,10 +80,18 @@ fn check_expr_meets_expectation_or_error(
         // While we don't allow *arbitrary* coercions here, we *do* allow
         // coercions from ! to `expected`.
         if ty.is_never() {
-            assert!(
-                !self.typeck_results.borrow().adjustments().contains_key(expr.hir_id),
-                "expression with never type wound up being adjusted"
-            );
+            if let Some(adjustments) = self.typeck_results.borrow().adjustments().get(expr.hir_id) {
+                self.tcx().sess.delay_span_bug(
+                    expr.span,
+                    "expression with never type wound up being adjusted",
+                );
+                return if let [Adjustment { kind: Adjust::NeverToAny, target }] = &adjustments[..] {
+                    target.to_owned()
+                } else {
+                    self.tcx().ty_error()
+                };
+            }
+
             let adj_ty = self.next_ty_var(TypeVariableOrigin {
                 kind: TypeVariableOriginKind::AdjustmentType,
                 span: expr.span,
@@ -1282,9 +1292,49 @@ fn check_expr_repeat(
             return tcx.ty_error();
         }
 
+        self.check_repeat_element_needs_copy_bound(element, count, element_ty);
+
         tcx.mk_ty(ty::Array(t, count))
     }
 
+    fn check_repeat_element_needs_copy_bound(
+        &self,
+        element: &hir::Expr<'_>,
+        count: ty::Const<'tcx>,
+        element_ty: Ty<'tcx>,
+    ) {
+        let tcx = self.tcx;
+        // Actual constants as the repeat element get inserted repeatedly instead of getting copied via Copy.
+        match &element.kind {
+            hir::ExprKind::ConstBlock(..) => return,
+            hir::ExprKind::Path(qpath) => {
+                let res = self.typeck_results.borrow().qpath_res(qpath, element.hir_id);
+                if let Res::Def(DefKind::Const | DefKind::AssocConst | DefKind::AnonConst, _) = res
+                {
+                    return;
+                }
+            }
+            _ => {}
+        }
+        // If someone calls a const fn, they can extract that call out into a separate constant (or a const
+        // block in the future), so we check that to tell them that in the diagnostic. Does not affect typeck.
+        let is_const_fn = match element.kind {
+            hir::ExprKind::Call(func, _args) => match *self.node_ty(func.hir_id).kind() {
+                ty::FnDef(def_id, _) => tcx.is_const_fn(def_id),
+                _ => false,
+            },
+            _ => false,
+        };
+
+        // If the length is 0, we don't create any elements, so we don't copy any. If the length is 1, we
+        // don't copy that one element, we move it. Only check for Copy if the length is larger.
+        if count.try_eval_usize(tcx, self.param_env).map_or(true, |len| len > 1) {
+            let lang_item = self.tcx.require_lang_item(LangItem::Copy, None);
+            let code = traits::ObligationCauseCode::RepeatElementCopy { is_const_fn };
+            self.require_type_meets(element_ty, element.span, code, lang_item);
+        }
+    }
+
     fn check_expr_tuple(
         &self,
         elts: &'tcx [hir::Expr<'tcx>],
@@ -1978,6 +2028,26 @@ fn check_field(
         self.tcx().ty_error()
     }
 
+    fn check_call_constructor<G: EmissionGuarantee>(
+        &self,
+        err: &mut DiagnosticBuilder<'_, G>,
+        base: &'tcx hir::Expr<'tcx>,
+        def_id: DefId,
+    ) {
+        let local_id = def_id.expect_local();
+        let hir_id = self.tcx.hir().local_def_id_to_hir_id(local_id);
+        let node = self.tcx.hir().get(hir_id);
+
+        if let Some(fields) = node.tuple_fields() {
+            let kind = match self.tcx.opt_def_kind(local_id) {
+                Some(DefKind::Ctor(of, _)) => of,
+                _ => return,
+            };
+
+            suggest_call_constructor(base.span, kind, fields.len(), err);
+        }
+    }
+
     fn suggest_await_on_field_access(
         &self,
         err: &mut Diagnostic,
@@ -2047,6 +2117,9 @@ fn ban_nonexisting_field(
             ty::Opaque(_, _) => {
                 self.suggest_await_on_field_access(&mut err, field, base, expr_t.peel_refs());
             }
+            ty::FnDef(def_id, _) => {
+                self.check_call_constructor(&mut err, base, def_id);
+            }
             _ => {}
         }
 
@@ -2277,14 +2350,17 @@ fn no_such_field_err(
         // try to add a suggestion in case the field is a nested field of a field of the Adt
         if let Some((fields, substs)) = self.get_field_candidates(span, expr_t) {
             for candidate_field in fields.iter() {
-                if let Some(field_path) = self.check_for_nested_field(
+                if let Some(mut field_path) = self.check_for_nested_field_satisfying(
                     span,
-                    field,
+                    &|candidate_field, _| candidate_field.ident(self.tcx()) == field,
                     candidate_field,
                     substs,
                     vec![],
                     self.tcx.parent_module(id).to_def_id(),
                 ) {
+                    // field_path includes `field` that we're looking for, so pop it.
+                    field_path.pop();
+
                     let field_path_str = field_path
                         .iter()
                         .map(|id| id.name.to_ident_string())
@@ -2304,7 +2380,7 @@ fn no_such_field_err(
         err
     }
 
-    fn get_field_candidates(
+    crate fn get_field_candidates(
         &self,
         span: Span,
         base_t: Ty<'tcx>,
@@ -2329,49 +2405,42 @@ fn get_field_candidates(
 
     /// This method is called after we have encountered a missing field error to recursively
     /// search for the field
-    fn check_for_nested_field(
+    crate fn check_for_nested_field_satisfying(
         &self,
         span: Span,
-        target_field: Ident,
+        matches: &impl Fn(&ty::FieldDef, Ty<'tcx>) -> bool,
         candidate_field: &ty::FieldDef,
         subst: SubstsRef<'tcx>,
         mut field_path: Vec<Ident>,
         id: DefId,
     ) -> Option<Vec<Ident>> {
         debug!(
-            "check_for_nested_field(span: {:?}, candidate_field: {:?}, field_path: {:?}",
+            "check_for_nested_field_satisfying(span: {:?}, candidate_field: {:?}, field_path: {:?}",
             span, candidate_field, field_path
         );
 
-        if candidate_field.ident(self.tcx) == target_field {
-            Some(field_path)
-        } else if field_path.len() > 3 {
+        if field_path.len() > 3 {
             // For compile-time reasons and to avoid infinite recursion we only check for fields
             // up to a depth of three
             None
         } else {
             // recursively search fields of `candidate_field` if it's a ty::Adt
-
             field_path.push(candidate_field.ident(self.tcx).normalize_to_macros_2_0());
             let field_ty = candidate_field.ty(self.tcx, subst);
             if let Some((nested_fields, subst)) = self.get_field_candidates(span, field_ty) {
                 for field in nested_fields.iter() {
-                    let accessible = field.vis.is_accessible_from(id, self.tcx);
-                    if accessible {
-                        let ident = field.ident(self.tcx).normalize_to_macros_2_0();
-                        if ident == target_field {
+                    if field.vis.is_accessible_from(id, self.tcx) {
+                        if matches(candidate_field, field_ty) {
                             return Some(field_path);
-                        }
-                        let field_path = field_path.clone();
-                        if let Some(path) = self.check_for_nested_field(
+                        } else if let Some(field_path) = self.check_for_nested_field_satisfying(
                             span,
-                            target_field,
+                            matches,
                             field,
                             subst,
-                            field_path,
+                            field_path.clone(),
                             id,
                         ) {
-                            return Some(path);
+                            return Some(field_path);
                         }
                     }
                 }
index 152be4bd5382906b728fb6d67fa9eb2f606bd640..93b0edb84c0547860b7b3e589e24315d3935b1c7 100644 (file)
@@ -757,7 +757,7 @@ pub(in super::super) fn expected_inputs_for_expected_output(
         formal_args: &[Ty<'tcx>],
     ) -> Option<Vec<Ty<'tcx>>> {
         let formal_ret = self.resolve_vars_with_obligations(formal_ret);
-        let Some(ret_ty) = expected_ret.only_has_type(self) else { return None };
+        let ret_ty = expected_ret.only_has_type(self)?;
 
         // HACK(oli-obk): This is a hack to keep RPIT and TAIT in sync wrt their behaviour.
         // Without it, the inference
@@ -838,7 +838,7 @@ pub(in super::super) fn resolve_lang_item_path(
         let def_kind = self.tcx.def_kind(def_id);
 
         let item_ty = if let DefKind::Variant = def_kind {
-            self.tcx.type_of(self.tcx.parent(def_id).expect("variant w/out parent"))
+            self.tcx.type_of(self.tcx.parent(def_id))
         } else {
             self.tcx.type_of(def_id)
         };
index 80f6190732ac2a273fba37ba057898525803ccfb..75976ebdf2822b3c6fd8e0f1cccd1fd75c4ac920 100644 (file)
@@ -429,9 +429,9 @@ pub(in super::super) fn check_argument_types(
             errors.drain_filter(|error| {
                 let Error::Invalid(input_idx, Compatibility::Incompatible(error)) = error else { return false };
                 let expected_ty = expected_input_tys[*input_idx];
-                let provided_ty = final_arg_types[*input_idx].map(|ty| ty.0).unwrap();
+                let Some(Some((provided_ty, _))) = final_arg_types.get(*input_idx) else { return false };
                 let cause = &self.misc(provided_args[*input_idx].span);
-                let trace = TypeTrace::types(cause, true, expected_ty, provided_ty);
+                let trace = TypeTrace::types(cause, true, expected_ty, *provided_ty);
                 if let Some(e) = error {
                     if !matches!(trace.cause.as_failure_code(e), FailureCode::Error0308(_)) {
                         self.report_and_explain_type_error(trace, e).emit();
@@ -679,8 +679,14 @@ enum SuggestionText {
                     Error::Invalid(input_idx, compatibility) => {
                         let expected_ty = expected_input_tys[input_idx];
                         if let Compatibility::Incompatible(error) = &compatibility {
-                            let provided_ty = final_arg_types[input_idx].map(|ty| ty.0).unwrap();
-                            let cause = &self.misc(provided_args[input_idx].span);
+                            let provided_ty = final_arg_types
+                                .get(input_idx)
+                                .and_then(|x| x.as_ref())
+                                .map(|ty| ty.0)
+                                .unwrap_or(tcx.ty_error());
+                            let cause = &self.misc(
+                                provided_args.get(input_idx).map(|i| i.span).unwrap_or(call_span),
+                            );
                             let trace = TypeTrace::types(cause, true, expected_ty, provided_ty);
                             if let Some(e) = error {
                                 self.note_type_err(
@@ -695,14 +701,16 @@ enum SuggestionText {
                             }
                         }
 
-                        self.emit_coerce_suggestions(
-                            &mut err,
-                            &provided_args[input_idx],
-                            final_arg_types[input_idx].map(|ty| ty.0).unwrap(),
-                            final_arg_types[input_idx].map(|ty| ty.1).unwrap(),
-                            None,
-                            None,
-                        );
+                        if let Some(expr) = provided_args.get(input_idx) {
+                            self.emit_coerce_suggestions(
+                                &mut err,
+                                &expr,
+                                final_arg_types[input_idx].map(|ty| ty.0).unwrap(),
+                                final_arg_types[input_idx].map(|ty| ty.1).unwrap(),
+                                None,
+                                None,
+                            );
+                        }
                     }
                     Error::Extra(arg_idx) => {
                         let arg_type = if let Some((_, ty)) = final_arg_types[arg_idx] {
@@ -968,9 +976,9 @@ enum SuggestionText {
                 SuggestionText::Remove(plural) => {
                     Some(format!("remove the extra argument{}", if plural { "s" } else { "" }))
                 }
-                SuggestionText::Swap => Some(format!("swap these arguments")),
-                SuggestionText::Reorder => Some(format!("reorder these arguments")),
-                SuggestionText::DidYouMean => Some(format!("did you mean")),
+                SuggestionText::Swap => Some("swap these arguments".to_string()),
+                SuggestionText::Reorder => Some("reorder these arguments".to_string()),
+                SuggestionText::DidYouMean => Some("did you mean".to_string()),
             };
             if let Some(suggestion_text) = suggestion_text {
                 let source_map = self.sess().source_map();
@@ -980,7 +988,7 @@ enum SuggestionText {
                 );
                 for (idx, arg) in matched_inputs.iter().enumerate() {
                     let suggestion_text = if let Some(arg) = arg {
-                        let arg_span = provided_args[*arg].span;
+                        let arg_span = provided_args[*arg].span.source_callsite();
                         let arg_text = source_map.span_to_snippet(arg_span).unwrap();
                         arg_text
                     } else {
index 62518408b8b3097d3003936e6ccc6ced2322ace7..681d1e37f86f1317486616e91aa7b887a29f7ca8 100644 (file)
@@ -1,5 +1,6 @@
 use super::FnCtxt;
 use crate::astconv::AstConv;
+use crate::errors::{AddReturnTypeSuggestion, ExpectedReturnTypeLabel};
 
 use rustc_ast::util::parser::ExprPrecedence;
 use rustc_errors::{Applicability, Diagnostic, MultiSpan};
@@ -525,30 +526,20 @@ pub(in super::super) fn suggest_missing_return_type(
             self.resolve_numeric_literals_with_default(self.resolve_vars_if_possible(found));
         // Only suggest changing the return type for methods that
         // haven't set a return type at all (and aren't `fn main()` or an impl).
-        match (&fn_decl.output, found.is_suggestable(), can_suggest, expected.is_unit()) {
+        match (&fn_decl.output, found.is_suggestable(self.tcx), can_suggest, expected.is_unit()) {
             (&hir::FnRetTy::DefaultReturn(span), true, true, true) => {
-                err.span_suggestion(
-                    span,
-                    "try adding a return type",
-                    format!("-> {} ", found),
-                    Applicability::MachineApplicable,
-                );
+                err.subdiagnostic(AddReturnTypeSuggestion::Add { span, found });
                 true
             }
             (&hir::FnRetTy::DefaultReturn(span), false, true, true) => {
                 // FIXME: if `found` could be `impl Iterator` or `impl Fn*`, we should suggest
                 // that.
-                err.span_suggestion(
-                    span,
-                    "a return type might be missing here",
-                    "-> _ ".to_string(),
-                    Applicability::HasPlaceholders,
-                );
+                err.subdiagnostic(AddReturnTypeSuggestion::MissingHere { span });
                 true
             }
             (&hir::FnRetTy::DefaultReturn(span), _, false, true) => {
                 // `fn main()` must return `()`, do not suggest changing return type
-                err.span_label(span, "expected `()` because of default return type");
+                err.subdiagnostic(ExpectedReturnTypeLabel::Unit { span });
                 true
             }
             // expectation was caused by something else, not the default return
@@ -557,16 +548,16 @@ pub(in super::super) fn suggest_missing_return_type(
                 // Only point to return type if the expected type is the return type, as if they
                 // are not, the expectation must have been caused by something else.
                 debug!("suggest_missing_return_type: return type {:?} node {:?}", ty, ty.kind);
-                let sp = ty.span;
+                let span = ty.span;
                 let ty = <dyn AstConv<'_>>::ast_ty_to_ty(self, ty);
                 debug!("suggest_missing_return_type: return type {:?}", ty);
                 debug!("suggest_missing_return_type: expected type {:?}", ty);
                 let bound_vars = self.tcx.late_bound_vars(fn_id);
                 let ty = Binder::bind_with_vars(ty, bound_vars);
-                let ty = self.normalize_associated_types_in(sp, ty);
+                let ty = self.normalize_associated_types_in(span, ty);
                 let ty = self.tcx.erase_late_bound_regions(ty);
                 if self.can_coerce(expected, ty) {
-                    err.span_label(sp, format!("expected `{}` because of return type", expected));
+                    err.subdiagnostic(ExpectedReturnTypeLabel::Other { span, expected });
                     self.try_suggest_return_impl_trait(err, expected, ty, fn_id);
                     return true;
                 }
@@ -608,17 +599,18 @@ fn try_suggest_return_impl_trait(
             kind:
                 hir::ItemKind::Fn(
                     hir::FnSig { decl: hir::FnDecl { inputs: fn_parameters, output: fn_return, .. }, .. },
-                    hir::Generics { params, where_clause, .. },
+                    hir::Generics { params, predicates, .. },
                     _body_id,
                 ),
             ..
         })) = fn_node else { return };
 
-        let Some(expected_generic_param) = params.get(expected_ty_as_param.index as usize) else { return };
+        if params.get(expected_ty_as_param.index as usize).is_none() {
+            return;
+        };
 
         // get all where BoundPredicates here, because they are used in to cases below
-        let where_predicates = where_clause
-            .predicates
+        let where_predicates = predicates
             .iter()
             .filter_map(|p| match p {
                 WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
@@ -649,10 +641,7 @@ fn try_suggest_return_impl_trait(
             where_predicates.iter().flatten().flat_map(|bounds| bounds.iter());
 
         // extract all bounds from the source code using their spans
-        let all_matching_bounds_strs = expected_generic_param
-            .bounds
-            .iter()
-            .chain(predicates_from_where)
+        let all_matching_bounds_strs = predicates_from_where
             .filter_map(|bound| match bound {
                 GenericBound::Trait(_, _) => {
                     self.tcx.sess.source_map().span_to_snippet(bound.span()).ok()
index 75a8ad8a159b52c658f829c03ab4030a11316e10..721f251650f54656a68497be907d8abfa01561b0 100644 (file)
@@ -257,7 +257,6 @@ fn find_target_expression_from_destination(
                 | hir::Node::Ctor(..)
                 | hir::Node::Lifetime(..)
                 | hir::Node::GenericParam(..)
-                | hir::Node::Visibility(..)
                 | hir::Node::Crate(..)
                 | hir::Node::Infer(..) => bug!("Unsupported branch target: {:?}", node),
             }
index 2921176ca4b38e02e7acd0d2211fac3e0bc49152..634ba2baf96678df57813ce777b659da9e341c14 100644 (file)
@@ -8,6 +8,7 @@
     MultiSpan,
 };
 use rustc_hir as hir;
+use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{ExprKind, Node, QPath};
@@ -28,8 +29,8 @@
 use std::cmp::Ordering;
 use std::iter;
 
-use super::probe::Mode;
-use super::{CandidateSource, MethodError, NoMatchData};
+use super::probe::{Mode, ProbeScope};
+use super::{super::suggest_call_constructor, CandidateSource, MethodError, NoMatchData};
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     fn is_fn_ty(&self, ty: Ty<'tcx>, span: Span) -> bool {
@@ -271,205 +272,82 @@ pub fn report_method_error(
                         (None, true) => "variant",
                     }
                 };
-                // FIXME(eddyb) this indentation is probably unnecessary.
-                let mut err = {
-                    // Suggest clamping down the type if the method that is being attempted to
-                    // be used exists at all, and the type is an ambiguous numeric type
-                    // ({integer}/{float}).
-                    let mut candidates = all_traits(self.tcx)
-                        .into_iter()
-                        .filter_map(|info| self.associated_value(info.def_id, item_name));
-                    // There are methods that are defined on the primitive types and won't be
-                    // found when exploring `all_traits`, but we also need them to be accurate on
-                    // our suggestions (#47759).
-                    let found_assoc = |ty: Ty<'tcx>| {
-                        simplify_type(tcx, ty, TreatParams::AsPlaceholders)
-                            .and_then(|simp| {
-                                tcx.incoherent_impls(simp)
-                                    .iter()
-                                    .find_map(|&id| self.associated_value(id, item_name))
-                            })
-                            .is_some()
-                    };
-                    let found_candidate = candidates.next().is_some()
-                        || found_assoc(tcx.types.i8)
-                        || found_assoc(tcx.types.i16)
-                        || found_assoc(tcx.types.i32)
-                        || found_assoc(tcx.types.i64)
-                        || found_assoc(tcx.types.i128)
-                        || found_assoc(tcx.types.u8)
-                        || found_assoc(tcx.types.u16)
-                        || found_assoc(tcx.types.u32)
-                        || found_assoc(tcx.types.u64)
-                        || found_assoc(tcx.types.u128)
-                        || found_assoc(tcx.types.f32)
-                        || found_assoc(tcx.types.f32);
-                    if let (true, false, SelfSource::MethodCall(expr), true) = (
-                        actual.is_numeric(),
-                        actual.has_concrete_skeleton(),
-                        source,
-                        found_candidate,
-                    ) {
-                        let mut err = struct_span_err!(
-                            tcx.sess,
-                            span,
-                            E0689,
-                            "can't call {} `{}` on ambiguous numeric type `{}`",
-                            item_kind,
-                            item_name,
-                            ty_str
-                        );
-                        let concrete_type = if actual.is_integral() { "i32" } else { "f32" };
-                        match expr.kind {
-                            ExprKind::Lit(ref lit) => {
-                                // numeric literal
-                                let snippet = tcx
-                                    .sess
-                                    .source_map()
-                                    .span_to_snippet(lit.span)
-                                    .unwrap_or_else(|_| "<numeric literal>".to_owned());
-
-                                // If this is a floating point literal that ends with '.',
-                                // get rid of it to stop this from becoming a member access.
-                                let snippet = snippet.strip_suffix('.').unwrap_or(&snippet);
 
-                                err.span_suggestion(
-                                    lit.span,
-                                    &format!(
-                                        "you must specify a concrete type for this numeric value, \
-                                         like `{}`",
-                                        concrete_type
-                                    ),
-                                    format!("{snippet}_{concrete_type}"),
-                                    Applicability::MaybeIncorrect,
-                                );
-                            }
-                            ExprKind::Path(QPath::Resolved(_, path)) => {
-                                // local binding
-                                if let hir::def::Res::Local(hir_id) = path.res {
-                                    let span = tcx.hir().span(hir_id);
-                                    let snippet = tcx.sess.source_map().span_to_snippet(span);
-                                    let filename = tcx.sess.source_map().span_to_filename(span);
-
-                                    let parent_node =
-                                        self.tcx.hir().get(self.tcx.hir().get_parent_node(hir_id));
-                                    let msg = format!(
-                                        "you must specify a type for this binding, like `{}`",
-                                        concrete_type,
-                                    );
-
-                                    match (filename, parent_node, snippet) {
-                                        (
-                                            FileName::Real(_),
-                                            Node::Local(hir::Local {
-                                                source: hir::LocalSource::Normal,
-                                                ty,
-                                                ..
-                                            }),
-                                            Ok(ref snippet),
-                                        ) => {
-                                            err.span_suggestion(
-                                                // account for `let x: _ = 42;`
-                                                //                  ^^^^
-                                                span.to(ty
-                                                    .as_ref()
-                                                    .map(|ty| ty.span)
-                                                    .unwrap_or(span)),
-                                                &msg,
-                                                format!("{}: {}", snippet, concrete_type),
-                                                Applicability::MaybeIncorrect,
-                                            );
-                                        }
-                                        _ => {
-                                            err.span_label(span, msg);
-                                        }
-                                    }
-                                }
+                if self.suggest_constraining_numerical_ty(
+                    tcx, actual, source, span, item_kind, item_name, &ty_str,
+                ) {
+                    return None;
+                }
+
+                span = item_name.span;
+
+                // Don't show generic arguments when the method can't be found in any implementation (#81576).
+                let mut ty_str_reported = ty_str.clone();
+                if let ty::Adt(_, generics) = actual.kind() {
+                    if generics.len() > 0 {
+                        let mut autoderef = self.autoderef(span, actual);
+                        let candidate_found = autoderef.any(|(ty, _)| {
+                            if let ty::Adt(adt_deref, _) = ty.kind() {
+                                self.tcx
+                                    .inherent_impls(adt_deref.did())
+                                    .iter()
+                                    .filter_map(|def_id| self.associated_value(*def_id, item_name))
+                                    .count()
+                                    >= 1
+                            } else {
+                                false
                             }
-                            _ => {}
-                        }
-                        err.emit();
-                        return None;
-                    } else {
-                        span = item_name.span;
-
-                        // Don't show generic arguments when the method can't be found in any implementation (#81576).
-                        let mut ty_str_reported = ty_str.clone();
-                        if let ty::Adt(_, generics) = actual.kind() {
-                            if generics.len() > 0 {
-                                let mut autoderef = self.autoderef(span, actual);
-                                let candidate_found = autoderef.any(|(ty, _)| {
-                                    if let ty::Adt(adt_deref, _) = ty.kind() {
-                                        self.tcx
-                                            .inherent_impls(adt_deref.did())
-                                            .iter()
-                                            .filter_map(|def_id| {
-                                                self.associated_value(*def_id, item_name)
-                                            })
-                                            .count()
-                                            >= 1
-                                    } else {
-                                        false
-                                    }
-                                });
-                                let has_deref = autoderef.step_count() > 0;
-                                if !candidate_found
-                                    && !has_deref
-                                    && unsatisfied_predicates.is_empty()
-                                {
-                                    if let Some((path_string, _)) = ty_str.split_once('<') {
-                                        ty_str_reported = path_string.to_string();
-                                    }
-                                }
+                        });
+                        let has_deref = autoderef.step_count() > 0;
+                        if !candidate_found && !has_deref && unsatisfied_predicates.is_empty() {
+                            if let Some((path_string, _)) = ty_str.split_once('<') {
+                                ty_str_reported = path_string.to_string();
                             }
                         }
+                    }
+                }
 
-                        let mut err = struct_span_err!(
-                            tcx.sess,
-                            span,
-                            E0599,
-                            "no {} named `{}` found for {} `{}` in the current scope",
-                            item_kind,
-                            item_name,
-                            actual.prefix_string(self.tcx),
-                            ty_str_reported,
-                        );
-                        if let Mode::MethodCall = mode && let SelfSource::MethodCall(cal) = source {
-                            self.suggest_await_before_method(
-                                &mut err, item_name, actual, cal, span,
-                            );
-                        }
-                        if let Some(span) =
-                            tcx.resolutions(()).confused_type_with_std_module.get(&span)
-                        {
-                            if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(*span) {
-                                err.span_suggestion(
-                                    *span,
-                                    "you are looking for the module in `std`, \
+                let mut err = struct_span_err!(
+                    tcx.sess,
+                    span,
+                    E0599,
+                    "no {} named `{}` found for {} `{}` in the current scope",
+                    item_kind,
+                    item_name,
+                    actual.prefix_string(self.tcx),
+                    ty_str_reported,
+                );
+                if actual.references_error() {
+                    err.downgrade_to_delayed_bug();
+                }
+
+                if let Mode::MethodCall = mode && let SelfSource::MethodCall(cal) = source {
+                    self.suggest_await_before_method(
+                        &mut err, item_name, actual, cal, span,
+                    );
+                }
+                if let Some(span) = tcx.resolutions(()).confused_type_with_std_module.get(&span) {
+                    if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(*span) {
+                        err.span_suggestion(
+                            *span,
+                            "you are looking for the module in `std`, \
                                      not the primitive type",
-                                    format!("std::{}", snippet),
-                                    Applicability::MachineApplicable,
-                                );
-                            }
-                        }
-                        if let ty::RawPtr(_) = &actual.kind() {
-                            err.note(
-                                "try using `<*const T>::as_ref()` to get a reference to the \
+                            format!("std::{}", snippet),
+                            Applicability::MachineApplicable,
+                        );
+                    }
+                }
+                if let ty::RawPtr(_) = &actual.kind() {
+                    err.note(
+                        "try using `<*const T>::as_ref()` to get a reference to the \
                                       type behind the pointer: https://doc.rust-lang.org/std/\
                                       primitive.pointer.html#method.as_ref",
-                            );
-                            err.note(
-                                "using `<*const T>::as_ref()` on a pointer \
+                    );
+                    err.note(
+                        "using `<*const T>::as_ref()` on a pointer \
                                       which is unaligned or points to invalid \
                                       or uninitialized memory is undefined behavior",
-                            );
-                        }
-                        err
-                    }
-                };
-
-                if actual.references_error() {
-                    err.downgrade_to_delayed_bug();
+                    );
                 }
 
                 if let Some(def) = actual.ty_adt_def() {
@@ -488,19 +366,32 @@ pub fn report_method_error(
                 }
 
                 if self.is_fn_ty(rcvr_ty, span) {
-                    fn report_function<T: std::fmt::Display>(err: &mut Diagnostic, name: T) {
-                        err.note(
-                            &format!("`{}` is a function, perhaps you wish to call it", name,),
-                        );
-                    }
-
                     if let SelfSource::MethodCall(expr) = source {
-                        if let Ok(expr_string) = tcx.sess.source_map().span_to_snippet(expr.span) {
-                            report_function(&mut err, expr_string);
-                        } else if let ExprKind::Path(QPath::Resolved(_, path)) = expr.kind {
-                            if let Some(segment) = path.segments.last() {
-                                report_function(&mut err, segment.ident);
+                        let suggest = if let ty::FnDef(def_id, _) = rcvr_ty.kind() {
+                            let local_id = def_id.expect_local();
+                            let hir_id = tcx.hir().local_def_id_to_hir_id(local_id);
+                            let node = tcx.hir().get(hir_id);
+                            let fields = node.tuple_fields();
+
+                            if let Some(fields) = fields
+                                && let Some(DefKind::Ctor(of, _)) = self.tcx.opt_def_kind(local_id) {
+                                    Some((fields, of))
+                            } else {
+                                None
                             }
+                        } else {
+                            None
+                        };
+
+                        // If the function is a tuple constructor, we recommend that they call it
+                        if let Some((fields, kind)) = suggest {
+                            suggest_call_constructor(expr.span, kind, fields.len(), &mut err);
+                        } else {
+                            // General case
+                            err.span_label(
+                                expr.span,
+                                "this is a function, perhaps you wish to call it",
+                            );
                         }
                     }
                 }
@@ -642,12 +533,9 @@ fn report_function<T: std::fmt::Display>(err: &mut Diagnostic, name: T) {
                                 };
                                 if let Some(hir::Node::Item(hir::Item { kind, .. })) = node {
                                     if let Some(g) = kind.generics() {
-                                        let key = match g.where_clause.predicates {
+                                        let key = match g.predicates {
                                             [.., pred] => (pred.span().shrink_to_hi(), false),
-                                            [] => (
-                                                g.where_clause.span_for_predicates_or_empty_place(),
-                                                true,
-                                            ),
+                                            [] => (g.span_for_predicates_or_empty_place(), true),
                                         };
                                         type_params
                                             .entry(key)
@@ -985,7 +873,7 @@ trait bound{s}",
                     }
                 }
 
-                let mut label_span_not_found = || {
+                let label_span_not_found = |err: &mut DiagnosticBuilder<'_, _>| {
                     if unsatisfied_predicates.is_empty() {
                         err.span_label(span, format!("{item_kind} not found in `{ty_str}`"));
                         let is_string_or_ref_str = match actual.kind() {
@@ -1071,62 +959,54 @@ trait bound{s}",
                 // If the method name is the name of a field with a function or closure type,
                 // give a helping note that it has to be called as `(x.f)(...)`.
                 if let SelfSource::MethodCall(expr) = source {
-                    let field_receiver =
-                        self.autoderef(span, rcvr_ty).find_map(|(ty, _)| match ty.kind() {
-                            ty::Adt(def, substs) if !def.is_enum() => {
-                                let variant = &def.non_enum_variant();
-                                self.tcx.find_field_index(item_name, variant).map(|index| {
-                                    let field = &variant.fields[index];
-                                    let field_ty = field.ty(tcx, substs);
-                                    (field, field_ty)
-                                })
-                            }
-                            _ => None,
-                        });
+                    if !self.suggest_field_call(span, rcvr_ty, expr, item_name, &mut err)
+                        && lev_candidate.is_none()
+                        && !custom_span_label
+                    {
+                        label_span_not_found(&mut err);
+                    }
+                } else if !custom_span_label {
+                    label_span_not_found(&mut err);
+                }
 
-                    if let Some((field, field_ty)) = field_receiver {
-                        let scope = self.tcx.parent_module(self.body_id).to_def_id();
-                        let is_accessible = field.vis.is_accessible_from(scope, self.tcx);
+                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);
 
-                        if is_accessible {
-                            if self.is_fn_ty(field_ty, span) {
-                                let expr_span = expr.span.to(item_name.span);
-                                err.multipart_suggestion(
-                                    &format!(
-                                        "to call the function stored in `{}`, \
-                                         surround the field access with parentheses",
-                                        item_name,
-                                    ),
-                                    vec![
-                                        (expr_span.shrink_to_lo(), '('.to_string()),
-                                        (expr_span.shrink_to_hi(), ')'.to_string()),
-                                    ],
-                                    Applicability::MachineApplicable,
-                                );
-                            } else {
-                                let call_expr = self
-                                    .tcx
-                                    .hir()
-                                    .expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
-
-                                if let Some(span) = call_expr.span.trim_start(item_name.span) {
-                                    err.span_suggestion(
-                                        span,
-                                        "remove the arguments",
-                                        String::new(),
-                                        Applicability::MaybeIncorrect,
-                                    );
-                                }
-                            }
+                            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,
+                            );
                         }
-
-                        let field_kind = if is_accessible { "field" } else { "private field" };
-                        err.span_label(item_name.span, format!("{}, not a method", field_kind));
-                    } else if lev_candidate.is_none() && !custom_span_label {
-                        label_span_not_found();
                     }
-                } else if !custom_span_label {
-                    label_span_not_found();
                 }
 
                 bound_spans.sort();
@@ -1273,6 +1153,187 @@ trait bound{s}",
         None
     }
 
+    fn suggest_field_call(
+        &self,
+        span: Span,
+        rcvr_ty: Ty<'tcx>,
+        expr: &hir::Expr<'_>,
+        item_name: Ident,
+        err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
+    ) -> bool {
+        let tcx = self.tcx;
+        let field_receiver = self.autoderef(span, rcvr_ty).find_map(|(ty, _)| match ty.kind() {
+            ty::Adt(def, substs) if !def.is_enum() => {
+                let variant = &def.non_enum_variant();
+                tcx.find_field_index(item_name, variant).map(|index| {
+                    let field = &variant.fields[index];
+                    let field_ty = field.ty(tcx, substs);
+                    (field, field_ty)
+                })
+            }
+            _ => None,
+        });
+        if let Some((field, field_ty)) = field_receiver {
+            let scope = tcx.parent_module(self.body_id).to_def_id();
+            let is_accessible = field.vis.is_accessible_from(scope, tcx);
+
+            if is_accessible {
+                if self.is_fn_ty(field_ty, span) {
+                    let expr_span = expr.span.to(item_name.span);
+                    err.multipart_suggestion(
+                        &format!(
+                            "to call the function stored in `{}`, \
+                                         surround the field access with parentheses",
+                            item_name,
+                        ),
+                        vec![
+                            (expr_span.shrink_to_lo(), '('.to_string()),
+                            (expr_span.shrink_to_hi(), ')'.to_string()),
+                        ],
+                        Applicability::MachineApplicable,
+                    );
+                } else {
+                    let call_expr = tcx.hir().expect_expr(tcx.hir().get_parent_node(expr.hir_id));
+
+                    if let Some(span) = call_expr.span.trim_start(item_name.span) {
+                        err.span_suggestion(
+                            span,
+                            "remove the arguments",
+                            String::new(),
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                }
+            }
+
+            let field_kind = if is_accessible { "field" } else { "private field" };
+            err.span_label(item_name.span, format!("{}, not a method", field_kind));
+            return true;
+        }
+        false
+    }
+
+    fn suggest_constraining_numerical_ty(
+        &self,
+        tcx: TyCtxt<'tcx>,
+        actual: Ty<'tcx>,
+        source: SelfSource<'_>,
+        span: Span,
+        item_kind: &str,
+        item_name: Ident,
+        ty_str: &str,
+    ) -> bool {
+        let found_candidate = all_traits(self.tcx)
+            .into_iter()
+            .any(|info| self.associated_value(info.def_id, item_name).is_some());
+        let found_assoc = |ty: Ty<'tcx>| {
+            simplify_type(tcx, ty, TreatParams::AsPlaceholders)
+                .and_then(|simp| {
+                    tcx.incoherent_impls(simp)
+                        .iter()
+                        .find_map(|&id| self.associated_value(id, item_name))
+                })
+                .is_some()
+        };
+        let found_candidate = found_candidate
+            || found_assoc(tcx.types.i8)
+            || found_assoc(tcx.types.i16)
+            || found_assoc(tcx.types.i32)
+            || found_assoc(tcx.types.i64)
+            || found_assoc(tcx.types.i128)
+            || found_assoc(tcx.types.u8)
+            || found_assoc(tcx.types.u16)
+            || found_assoc(tcx.types.u32)
+            || found_assoc(tcx.types.u64)
+            || found_assoc(tcx.types.u128)
+            || found_assoc(tcx.types.f32)
+            || found_assoc(tcx.types.f32);
+        if found_candidate
+            && actual.is_numeric()
+            && !actual.has_concrete_skeleton()
+            && let SelfSource::MethodCall(expr) = source
+        {
+            let mut err = struct_span_err!(
+                tcx.sess,
+                span,
+                E0689,
+                "can't call {} `{}` on ambiguous numeric type `{}`",
+                item_kind,
+                item_name,
+                ty_str
+            );
+            let concrete_type = if actual.is_integral() { "i32" } else { "f32" };
+            match expr.kind {
+                ExprKind::Lit(ref lit) => {
+                    // numeric literal
+                    let snippet = tcx
+                        .sess
+                        .source_map()
+                        .span_to_snippet(lit.span)
+                        .unwrap_or_else(|_| "<numeric literal>".to_owned());
+
+                    // If this is a floating point literal that ends with '.',
+                    // get rid of it to stop this from becoming a member access.
+                    let snippet = snippet.strip_suffix('.').unwrap_or(&snippet);
+
+                    err.span_suggestion(
+                        lit.span,
+                        &format!(
+                            "you must specify a concrete type for this numeric value, \
+                                         like `{}`",
+                            concrete_type
+                        ),
+                        format!("{snippet}_{concrete_type}"),
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+                ExprKind::Path(QPath::Resolved(_, path)) => {
+                    // local binding
+                    if let hir::def::Res::Local(hir_id) = path.res {
+                        let span = tcx.hir().span(hir_id);
+                        let snippet = tcx.sess.source_map().span_to_snippet(span);
+                        let filename = tcx.sess.source_map().span_to_filename(span);
+
+                        let parent_node =
+                            self.tcx.hir().get(self.tcx.hir().get_parent_node(hir_id));
+                        let msg = format!(
+                            "you must specify a type for this binding, like `{}`",
+                            concrete_type,
+                        );
+
+                        match (filename, parent_node, snippet) {
+                            (
+                                FileName::Real(_),
+                                Node::Local(hir::Local {
+                                    source: hir::LocalSource::Normal,
+                                    ty,
+                                    ..
+                                }),
+                                Ok(ref snippet),
+                            ) => {
+                                err.span_suggestion(
+                                    // account for `let x: _ = 42;`
+                                    //                  ^^^^
+                                    span.to(ty.as_ref().map(|ty| ty.span).unwrap_or(span)),
+                                    &msg,
+                                    format!("{}: {}", snippet, concrete_type),
+                                    Applicability::MaybeIncorrect,
+                                );
+                            }
+                            _ => {
+                                err.span_label(span, msg);
+                            }
+                        }
+                    }
+                }
+                _ => {}
+            }
+            err.emit();
+            return true;
+        }
+        false
+    }
+
     crate fn note_unmet_impls_on_type(
         &self,
         err: &mut Diagnostic,
@@ -1481,7 +1542,7 @@ fn suggest_use_candidates(&self, err: &mut Diagnostic, msg: String, candidates:
         let (candidates, globs): (Vec<_>, Vec<_>) = candidates.into_iter().partition(|trait_did| {
             if let Some(parent_did) = parent_map.get(trait_did) {
                 // If the item is re-exported as `_`, we should suggest a glob-import instead.
-                if Some(*parent_did) != self.tcx.parent(*trait_did)
+                if *parent_did != self.tcx.parent(*trait_did)
                     && self
                         .tcx
                         .module_children(*parent_did)
@@ -1807,37 +1868,30 @@ fn suggest_traits_to_import(
                     // instead we suggest `T: Foo + Bar` in that case.
                     match hir.get(id) {
                         Node::GenericParam(param) => {
-                            let mut impl_trait = false;
-                            let has_bounds =
-                                if let hir::GenericParamKind::Type { synthetic: true, .. } =
-                                    &param.kind
-                                {
-                                    // We've found `fn foo(x: impl Trait)` instead of
-                                    // `fn foo<T>(x: T)`. We want to suggest the correct
-                                    // `fn foo(x: impl Trait + TraitBound)` instead of
-                                    // `fn foo<T: TraitBound>(x: T)`. (#63706)
-                                    impl_trait = true;
-                                    param.bounds.get(1)
-                                } else {
-                                    param.bounds.get(0)
-                                };
-                            let sp = hir.span(id);
-                            let sp = if let Some(first_bound) = has_bounds {
-                                sp.until(first_bound.span())
-                            } else if let Some(colon_sp) =
-                                // If the generic param is declared with a colon but without bounds:
-                                // fn foo<T:>(t: T) { ... }
-                                param.colon_span_for_suggestions(
-                                    self.inh.tcx.sess.source_map(),
-                                )
+                            enum Introducer {
+                                Plus,
+                                Colon,
+                                Nothing,
+                            }
+                            let ast_generics = hir.get_generics(id.owner).unwrap();
+                            let (sp, mut introducer) = if let Some(span) =
+                                ast_generics.bounds_span_for_suggestions(def_id)
                             {
-                                sp.to(colon_sp)
+                                (span, Introducer::Plus)
+                            } else if let Some(colon_span) = param.colon_span {
+                                (colon_span.shrink_to_hi(), Introducer::Nothing)
                             } else {
-                                sp
+                                (param.span.shrink_to_hi(), Introducer::Colon)
                             };
-                            let trait_def_ids: FxHashSet<DefId> = param
-                                .bounds
-                                .iter()
+                            if matches!(
+                                param.kind,
+                                hir::GenericParamKind::Type { synthetic: true, .. },
+                            ) {
+                                introducer = Introducer::Plus
+                            }
+                            let trait_def_ids: FxHashSet<DefId> = ast_generics
+                                .bounds_for_param(def_id)
+                                .flat_map(|bp| bp.bounds.iter())
                                 .filter_map(|bound| bound.trait_ref()?.trait_def_id())
                                 .collect();
                             if !candidates.iter().any(|t| trait_def_ids.contains(&t.def_id)) {
@@ -1849,11 +1903,13 @@ fn suggest_traits_to_import(
                                     )),
                                     candidates.iter().map(|t| {
                                         format!(
-                                            "{}{} {}{}",
-                                            param.name.ident(),
-                                            if impl_trait { " +" } else { ":" },
+                                            "{} {}",
+                                            match introducer {
+                                                Introducer::Plus => " +",
+                                                Introducer::Colon => ":",
+                                                Introducer::Nothing => "",
+                                            },
                                             self.tcx.def_path_str(t.def_id),
-                                            if has_bounds.is_some() { " + " } else { "" },
                                         )
                                     }),
                                     Applicability::MaybeIncorrect,
index 0d5e7b28a4e65e942c8e2c975f448a3b21a5e0d2..76c955d6f690d672319217ce765caf9cf3ae6206 100644 (file)
 pub use diverges::Diverges;
 pub use expectation::Expectation;
 pub use fn_ctxt::*;
+use hir::def::CtorOf;
 pub use inherited::{Inherited, InheritedBuilder};
 
 use crate::astconv::AstConv;
 use crate::check::gather_locals::GatherLocalsVisitor;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_errors::{pluralize, struct_span_err, Applicability, MultiSpan};
+use rustc_errors::{
+    pluralize, struct_span_err, Applicability, DiagnosticBuilder, EmissionGuarantee, MultiSpan,
+};
 use rustc_hir as hir;
 use rustc_hir::def::Res;
 use rustc_hir::def_id::{DefId, LocalDefId};
@@ -370,16 +373,7 @@ fn typeck_with_fallback<'tcx>(
         let (fcx, wf_tys) = if let Some(hir::FnSig { header, decl, .. }) = fn_sig {
             let fn_sig = if crate::collect::get_infer_ret_ty(&decl.output).is_some() {
                 let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
-                <dyn AstConv<'_>>::ty_of_fn(
-                    &fcx,
-                    id,
-                    header.unsafety,
-                    header.abi,
-                    decl,
-                    &hir::Generics::empty(),
-                    None,
-                    None,
-                )
+                <dyn AstConv<'_>>::ty_of_fn(&fcx, id, header.unsafety, header.abi, decl, None, None)
             } else {
                 tcx.fn_sig(def_id)
             };
@@ -988,3 +982,36 @@ fn has_expected_num_generic_args<'tcx>(
         generics.count() == expected + if generics.has_self { 1 } else { 0 }
     })
 }
+
+/// Suggests calling the constructor of a tuple struct or enum variant
+///
+/// * `snippet` - The snippet of code that references the constructor
+/// * `span` - The span of the snippet
+/// * `params` - The number of parameters the constructor accepts
+/// * `err` - A mutable diagnostic builder to add the suggestion to
+fn suggest_call_constructor<G: EmissionGuarantee>(
+    span: Span,
+    kind: CtorOf,
+    params: usize,
+    err: &mut DiagnosticBuilder<'_, G>,
+) {
+    // Note: tuple-structs don't have named fields, so just use placeholders
+    let args = vec!["_"; params].join(", ");
+    let applicable = if params > 0 {
+        Applicability::HasPlaceholders
+    } else {
+        // When n = 0, it's an empty-tuple struct/enum variant
+        // so we trivially know how to construct it
+        Applicability::MachineApplicable
+    };
+    let kind = match kind {
+        CtorOf::Struct => "a struct",
+        CtorOf::Variant => "an enum variant",
+    };
+    err.span_label(span, &format!("this is the constructor of {kind}"));
+    err.multipart_suggestion(
+        "call the constructor",
+        vec![(span.shrink_to_lo(), "(".to_string()), (span.shrink_to_hi(), format!(")({args})"))],
+        applicable,
+    );
+}
index 811833bca803143c606d07afed124be1d015d00a..1ae53a77adc566589bc4a489c78903e9a54549ef 100644 (file)
 };
 use rustc_middle::ty::fold::TypeFolder;
 use rustc_middle::ty::TyKind::{Adt, Array, Char, FnDef, Never, Ref, Str, Tuple, Uint};
-use rustc_middle::ty::{
-    self, suggest_constraining_type_param, Ty, TyCtxt, TypeFoldable, TypeVisitor,
-};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitor};
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
 use rustc_trait_selection::infer::InferCtxtExt;
+use rustc_trait_selection::traits::error_reporting::suggestions::InferCtxtExt as _;
 use rustc_trait_selection::traits::{FulfillmentError, TraitEngine, TraitEngineExt};
 
 use std::ops::ControlFlow;
@@ -266,7 +265,7 @@ fn check_overloaded_binop(
             Err(_) if lhs_ty.references_error() || rhs_ty.references_error() => self.tcx.ty_error(),
             Err(errors) => {
                 let source_map = self.tcx.sess.source_map();
-                let (mut err, missing_trait, use_output) = match is_assign {
+                let (mut err, missing_trait, _use_output) = match is_assign {
                     IsAssign::Yes => {
                         let mut err = struct_span_err!(
                             self.tcx.sess,
@@ -449,39 +448,39 @@ fn check_overloaded_binop(
                         // concatenation (e.g., "Hello " + "World!"). This means
                         // we don't want the note in the else clause to be emitted
                     } else if let [ty] = &visitor.0[..] {
-                        if let ty::Param(p) = *ty.kind() {
-                            // Check if the method would be found if the type param wasn't
-                            // involved. If so, it means that adding a trait bound to the param is
-                            // enough. Otherwise we do not give the suggestion.
-                            let mut eraser = TypeParamEraser(self, expr.span);
-                            let needs_bound = self
-                                .lookup_op_method(
-                                    eraser.fold_ty(lhs_ty),
-                                    Some(eraser.fold_ty(rhs_ty)),
-                                    Some(rhs_expr),
-                                    Op::Binary(op, is_assign),
-                                )
-                                .is_ok();
-                            if needs_bound {
-                                suggest_constraining_param(
-                                    self.tcx,
-                                    self.body_id,
+                        // Look for a TraitPredicate in the Fulfillment errors,
+                        // and use it to generate a suggestion.
+                        //
+                        // Note that lookup_op_method must be called again but
+                        // with a specific rhs_ty instead of a placeholder so
+                        // the resulting predicate generates a more specific
+                        // suggestion for the user.
+                        let errors = self
+                            .lookup_op_method(
+                                lhs_ty,
+                                Some(rhs_ty),
+                                Some(rhs_expr),
+                                Op::Binary(op, is_assign),
+                            )
+                            .unwrap_err();
+                        let predicates = errors
+                            .into_iter()
+                            .filter_map(|error| error.obligation.predicate.to_opt_poly_trait_pred())
+                            .collect::<Vec<_>>();
+                        if !predicates.is_empty() {
+                            for pred in predicates {
+                                self.infcx.suggest_restricting_param_bound(
                                     &mut err,
-                                    *ty,
-                                    rhs_ty,
-                                    missing_trait,
-                                    p,
-                                    use_output,
+                                    pred,
+                                    self.body_id,
                                 );
-                            } else if *ty != lhs_ty {
-                                // When we know that a missing bound is responsible, we don't show
-                                // this note as it is redundant.
-                                err.note(&format!(
-                                    "the trait `{missing_trait}` is not implemented for `{lhs_ty}`"
-                                ));
                             }
-                        } else {
-                            bug!("type param visitor stored a non type param: {:?}", ty.kind());
+                        } else if *ty != lhs_ty {
+                            // When we know that a missing bound is responsible, we don't show
+                            // this note as it is redundant.
+                            err.note(&format!(
+                                "the trait `{missing_trait}` is not implemented for `{lhs_ty}`"
+                            ));
                         }
                     }
                 }
@@ -671,24 +670,22 @@ pub fn check_user_unop(
                         ex.span,
                         format!("cannot apply unary operator `{}`", op.as_str()),
                     );
-                    let missing_trait = match op {
-                        hir::UnOp::Deref => unreachable!("check unary op `-` or `!` only"),
-                        hir::UnOp::Not => "std::ops::Not",
-                        hir::UnOp::Neg => "std::ops::Neg",
-                    };
+
                     let mut visitor = TypeParamVisitor(vec![]);
                     visitor.visit_ty(operand_ty);
-                    if let [ty] = &visitor.0[..] && let ty::Param(p) = *operand_ty.kind() {
-                        suggest_constraining_param(
-                            self.tcx,
-                            self.body_id,
-                            &mut err,
-                            *ty,
-                            operand_ty,
-                            missing_trait,
-                            p,
-                            true,
-                        );
+                    if let [_] = &visitor.0[..] && let ty::Param(_) = *operand_ty.kind() {
+                        let predicates = errors
+                            .iter()
+                            .filter_map(|error| {
+                                error.obligation.predicate.clone().to_opt_poly_trait_pred()
+                            });
+                        for pred in predicates {
+                            self.infcx.suggest_restricting_param_bound(
+                                &mut err,
+                                pred,
+                                self.body_id,
+                            );
+                        }
                     }
 
                     let sp = self.tcx.sess.source_map().start_point(ex.span);
@@ -973,46 +970,6 @@ fn is_builtin_binop<'tcx>(lhs: Ty<'tcx>, rhs: Ty<'tcx>, op: hir::BinOp) -> bool
     }
 }
 
-fn suggest_constraining_param(
-    tcx: TyCtxt<'_>,
-    body_id: hir::HirId,
-    mut err: &mut Diagnostic,
-    lhs_ty: Ty<'_>,
-    rhs_ty: Ty<'_>,
-    missing_trait: &str,
-    p: ty::ParamTy,
-    set_output: bool,
-) {
-    let hir = tcx.hir();
-    let msg = &format!("`{lhs_ty}` might need a bound for `{missing_trait}`");
-    // Try to find the def-id and details for the parameter p. We have only the index,
-    // so we have to find the enclosing function's def-id, then look through its declared
-    // generic parameters to get the declaration.
-    let def_id = hir.body_owner_def_id(hir::BodyId { hir_id: body_id });
-    let generics = tcx.generics_of(def_id);
-    let param_def_id = generics.type_param(&p, tcx).def_id;
-    if let Some(generics) = param_def_id
-        .as_local()
-        .map(|id| hir.local_def_id_to_hir_id(id))
-        .and_then(|id| hir.find_by_def_id(hir.get_parent_item(id)))
-        .as_ref()
-        .and_then(|node| node.generics())
-    {
-        let output = if set_output { format!("<Output = {rhs_ty}>") } else { String::new() };
-        suggest_constraining_type_param(
-            tcx,
-            generics,
-            &mut err,
-            &lhs_ty.to_string(),
-            &format!("{missing_trait}{output}"),
-            None,
-        );
-    } else {
-        let span = tcx.def_span(param_def_id);
-        err.span_label(span, msg);
-    }
-}
-
 struct TypeParamVisitor<'tcx>(Vec<Ty<'tcx>>);
 
 impl<'tcx> TypeVisitor<'tcx> for TypeParamVisitor<'tcx> {
index cf0c5703cd0ee7c724ff760b13ef9987ac79bab1..356763fab5e3b35e2b612bfa6905940c693cef68 100644 (file)
@@ -643,6 +643,8 @@ fn check_binding_alt_eq_ty(&self, span: Span, var_id: HirId, ty: Ty<'tcx>, ti: T
             });
             let pre = if in_match { "in the same arm, " } else { "" };
             err.note(&format!("{}a binding must have the same type in all alternatives", pre));
+            // FIXME: check if `var_ty` and `ty` can be made the same type by adding or removing
+            // `ref` or `&` to the pattern.
             err.emit();
         }
     }
index 4e3e32670e96e0b29f32190317bc55ce924a6f0b..ec2b7c13ff33c5325ae7ddeed69ab67ae8eaea8e 100644 (file)
@@ -420,15 +420,11 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
 
             let suggestion = format!(
                 "{} {}",
-                if !gat_item_hir.generics.where_clause.predicates.is_empty() {
-                    ","
-                } else {
-                    " where"
-                },
+                if !gat_item_hir.generics.predicates.is_empty() { "," } else { " where" },
                 unsatisfied_bounds.join(", "),
             );
             err.span_suggestion(
-                gat_item_hir.generics.where_clause.tail_span_for_suggestion(),
+                gat_item_hir.generics.tail_span_for_predicate_suggestion(),
                 &format!("add the required where clause{plural}"),
                 suggestion,
                 Applicability::MachineApplicable,
@@ -1733,7 +1729,6 @@ fn check_variances_for_type_defn<'tcx>(
     let explicitly_bounded_params = Lazy::new(|| {
         let icx = crate::collect::ItemCtxt::new(tcx, item.def_id.to_def_id());
         hir_generics
-            .where_clause
             .predicates
             .iter()
             .filter_map(|predicate| match predicate {
@@ -1760,8 +1755,7 @@ fn check_variances_for_type_defn<'tcx>(
         match param.name {
             hir::ParamName::Error => {}
             _ => {
-                let has_explicit_bounds =
-                    !param.bounds.is_empty() || explicitly_bounded_params.contains(&parameter);
+                let has_explicit_bounds = explicitly_bounded_params.contains(&parameter);
                 report_bivariance(tcx, param, has_explicit_bounds);
             }
         }
@@ -1819,13 +1813,12 @@ fn check_false_global_bounds(fcx: &FnCtxt<'_, '_>, mut span: Span, id: hir::HirI
 
             // only use the span of the predicate clause (#90869)
 
-            if let Some(hir::Generics { where_clause, .. }) =
+            if let Some(hir::Generics { predicates, .. }) =
                 hir_node.and_then(|node| node.generics())
             {
                 let obligation_span = obligation.cause.span(fcx.tcx);
 
-                span = where_clause
-                    .predicates
+                span = predicates
                     .iter()
                     // There seems to be no better way to find out which predicate we are in
                     .find(|pred| pred.span().contains(obligation_span))
index 4f792fa25a12b88e7f2600d452e580061e9ff264..d52886a09bd958d5485dd8764ca75b0e9cd17f84 100644 (file)
@@ -18,8 +18,11 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
 
     for id in tcx.hir().items() {
         if matches!(tcx.hir().def_kind(id.def_id), DefKind::Use) {
+            if tcx.visibility(id.def_id).is_public() {
+                continue;
+            }
             let item = tcx.hir().item(id);
-            if item.vis.node.is_pub() || item.span.is_dummy() {
+            if item.span.is_dummy() {
                 continue;
             }
             if let hir::ItemKind::Use(path, _) = item.kind {
@@ -176,7 +179,7 @@ fn unused_crates_lint(tcx: TyCtxt<'_>) {
                 Some(orig_name) => format!("use {} as {};", orig_name, item.ident.name),
                 None => format!("use {};", item.ident.name),
             };
-            let vis = tcx.sess.source_map().span_to_snippet(item.vis.span).unwrap_or_default();
+            let vis = tcx.sess.source_map().span_to_snippet(item.vis_span).unwrap_or_default();
             let add_vis = |to| if vis.is_empty() { to } else { format!("{} {}", vis, to) };
             lint.build("`extern crate` is not idiomatic in the new edition")
                 .span_suggestion_short(
index 77a537448291719a0966c6435cb68f45c95ed087..19e68f0b14f4f23934dba64e53f2a41e36a521d7 100644 (file)
@@ -50,6 +50,7 @@ fn orphan_check_impl(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGua
             tcx,
             sp,
             tr.path.span,
+            trait_ref.self_ty(),
             impl_.self_ty.span,
             &impl_.generics,
             err,
@@ -201,18 +202,23 @@ fn emit_orphan_check_error<'tcx>(
     tcx: TyCtxt<'tcx>,
     sp: Span,
     trait_span: Span,
+    self_ty: Ty<'tcx>,
     self_ty_span: Span,
     generics: &hir::Generics<'tcx>,
     err: traits::OrphanCheckErr<'tcx>,
 ) -> Result<!, ErrorGuaranteed> {
     Err(match err {
         traits::OrphanCheckErr::NonLocalInputType(tys) => {
+            let msg = match self_ty.kind() {
+                ty::Adt(..) => "can be implemented for types defined outside of the crate",
+                _ if self_ty.is_primitive() => "can be implemented for primitive types",
+                _ => "can be implemented for arbitrary types",
+            };
             let mut err = struct_span_err!(
                 tcx.sess,
                 sp,
                 E0117,
-                "only traits defined in the current crate can be implemented for \
-                        arbitrary types"
+                "only traits defined in the current crate {msg}"
             );
             err.span_label(sp, "impl doesn't use only types from inside the current crate");
             for (ty, is_target_ty) in &tys {
index 153ab8d95fd4bdcec34b3046a46b9e596058f9ad..c1c63c460664cc16eed32f5d518b3e5cbd372517 100644 (file)
@@ -1,4 +1,3 @@
-// ignore-tidy-filelength
 //! "Collection" is the process of determining the type and other external
 //! details of each item in Rust. Collection is specifically concerned
 //! with *inter-procedural* things -- for example, for a function
@@ -41,7 +40,7 @@
 use rustc_middle::ty::util::Discr;
 use rustc_middle::ty::util::IntTypeExt;
 use rustc_middle::ty::{self, AdtKind, Const, DefIdTree, Ty, TyCtxt};
-use rustc_middle::ty::{ReprOptions, ToPredicate, TypeFoldable};
+use rustc_middle::ty::{ReprOptions, ToPredicate};
 use rustc_session::lint;
 use rustc_session::parse::feature_err;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -149,8 +148,7 @@ struct CollectItemTypesVisitor<'tcx> {
 /// all already existing generic type parameters to avoid suggesting a name that is already in use.
 crate fn placeholder_type_error<'tcx>(
     tcx: TyCtxt<'tcx>,
-    span: Option<Span>,
-    generics: &[hir::GenericParam<'_>],
+    generics: Option<&hir::Generics<'_>>,
     placeholder_types: Vec<Span>,
     suggest: bool,
     hir_ty: Option<&hir::Ty<'_>>,
@@ -160,29 +158,45 @@ struct CollectItemTypesVisitor<'tcx> {
         return;
     }
 
-    let type_name = generics.next_type_param_name(None);
+    placeholder_type_error_diag(tcx, generics, placeholder_types, vec![], suggest, hir_ty, kind)
+        .emit();
+}
+
+crate fn placeholder_type_error_diag<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    generics: Option<&hir::Generics<'_>>,
+    placeholder_types: Vec<Span>,
+    additional_spans: Vec<Span>,
+    suggest: bool,
+    hir_ty: Option<&hir::Ty<'_>>,
+    kind: &'static str,
+) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
+    if placeholder_types.is_empty() {
+        return bad_placeholder(tcx, additional_spans, kind);
+    }
+
+    let params = generics.map(|g| g.params).unwrap_or_default();
+    let type_name = params.next_type_param_name(None);
     let mut sugg: Vec<_> =
         placeholder_types.iter().map(|sp| (*sp, (*type_name).to_string())).collect();
 
-    if generics.is_empty() {
-        if let Some(span) = span {
-            sugg.push((span, format!("<{}>", type_name)));
+    if let Some(generics) = generics {
+        if let Some(arg) = params.iter().find(|arg| {
+            matches!(arg.name, hir::ParamName::Plain(Ident { name: kw::Underscore, .. }))
+        }) {
+            // Account for `_` already present in cases like `struct S<_>(_);` and suggest
+            // `struct S<T>(T);` instead of `struct S<_, T>(T);`.
+            sugg.push((arg.span, (*type_name).to_string()));
+        } else if let Some(span) = generics.span_for_param_suggestion() {
+            // Account for bounds, we want `fn foo<T: E, K>(_: K)` not `fn foo<T, K: E>(_: K)`.
+            sugg.push((span, format!(", {}", type_name)));
+        } else {
+            sugg.push((generics.span, format!("<{}>", type_name)));
         }
-    } else if let Some(arg) = generics
-        .iter()
-        .find(|arg| matches!(arg.name, hir::ParamName::Plain(Ident { name: kw::Underscore, .. })))
-    {
-        // Account for `_` already present in cases like `struct S<_>(_);` and suggest
-        // `struct S<T>(T);` instead of `struct S<_, T>(T);`.
-        sugg.push((arg.span, (*type_name).to_string()));
-    } else {
-        let last = generics.iter().last().unwrap();
-        // Account for bounds, we want `fn foo<T: E, K>(_: K)` not `fn foo<T, K: E>(_: K)`.
-        let span = last.bounds_span_for_suggestions().unwrap_or(last.span.shrink_to_hi());
-        sugg.push((span, format!(", {}", type_name)));
     }
 
-    let mut err = bad_placeholder(tcx, placeholder_types, kind);
+    let mut err =
+        bad_placeholder(tcx, placeholder_types.into_iter().chain(additional_spans).collect(), kind);
 
     // Suggest, but only if it is not a function in const or static
     if suggest {
@@ -218,7 +232,8 @@ struct CollectItemTypesVisitor<'tcx> {
             );
         }
     }
-    err.emit();
+
+    err
 }
 
 fn reject_placeholder_type_signatures_in_item<'tcx>(
@@ -241,15 +256,7 @@ fn reject_placeholder_type_signatures_in_item<'tcx>(
     let mut visitor = HirPlaceholderCollector::default();
     visitor.visit_item(item);
 
-    placeholder_type_error(
-        tcx,
-        Some(generics.span),
-        generics.params,
-        visitor.0,
-        suggest,
-        None,
-        item.kind.descr(),
-    );
+    placeholder_type_error(tcx, Some(generics), visitor.0, suggest, None, item.kind.descr());
 }
 
 impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
@@ -651,27 +658,8 @@ fn type_parameter_bounds_in_generics(
         only_self_bounds: OnlySelfBounds,
         assoc_name: Option<Ident>,
     ) -> Vec<(ty::Predicate<'tcx>, Span)> {
-        let from_ty_params = ast_generics
-            .params
-            .iter()
-            .filter_map(|param| match param.kind {
-                GenericParamKind::Type { .. } | GenericParamKind::Const { .. }
-                    if param.hir_id == param_id =>
-                {
-                    Some(&param.bounds)
-                }
-                _ => None,
-            })
-            .flat_map(|bounds| bounds.iter())
-            .filter(|b| match assoc_name {
-                Some(assoc_name) => self.bound_defines_assoc_item(b, assoc_name),
-                None => true,
-            })
-            .flat_map(|b| predicates_from_bound(self, ty, b, ty::List::empty()));
-
         let param_def_id = self.tcx.hir().local_def_id(param_id).to_def_id();
-        let from_where_clauses = ast_generics
-            .where_clause
+        ast_generics
             .predicates
             .iter()
             .filter_map(|wp| match *wp {
@@ -696,9 +684,8 @@ fn type_parameter_bounds_in_generics(
                     })
                     .filter_map(move |b| bt.map(|bt| (bt, b, bvars)))
             })
-            .flat_map(|(bt, b, bvars)| predicates_from_bound(self, bt, b, bvars));
-
-        from_ty_params.chain(from_where_clauses).collect()
+            .flat_map(|(bt, b, bvars)| predicates_from_bound(self, bt, b, bvars))
+            .collect()
     }
 
     fn bound_defines_assoc_item(&self, b: &hir::GenericBound<'_>, assoc_name: Ident) -> bool {
@@ -744,7 +731,6 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
                         placeholder_type_error(
                             tcx,
                             None,
-                            &[],
                             visitor.0,
                             false,
                             None,
@@ -824,15 +810,7 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
                     if let hir::TyKind::TraitObject(..) = ty.kind {
                         let mut visitor = HirPlaceholderCollector::default();
                         visitor.visit_item(it);
-                        placeholder_type_error(
-                            tcx,
-                            None,
-                            &[],
-                            visitor.0,
-                            false,
-                            None,
-                            it.kind.descr(),
-                        );
+                        placeholder_type_error(tcx, None, visitor.0, false, None, it.kind.descr());
                     }
                 }
                 _ => (),
@@ -860,7 +838,7 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
             // Account for `const C: _;`.
             let mut visitor = HirPlaceholderCollector::default();
             visitor.visit_trait_item(trait_item);
-            placeholder_type_error(tcx, None, &[], visitor.0, false, None, "constant");
+            placeholder_type_error(tcx, None, visitor.0, false, None, "constant");
         }
 
         hir::TraitItemKind::Type(_, Some(_)) => {
@@ -869,7 +847,7 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
             // Account for `type T = _;`.
             let mut visitor = HirPlaceholderCollector::default();
             visitor.visit_trait_item(trait_item);
-            placeholder_type_error(tcx, None, &[], visitor.0, false, None, "associated type");
+            placeholder_type_error(tcx, None, visitor.0, false, None, "associated type");
         }
 
         hir::TraitItemKind::Type(_, None) => {
@@ -879,7 +857,7 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
             let mut visitor = HirPlaceholderCollector::default();
             visitor.visit_trait_item(trait_item);
 
-            placeholder_type_error(tcx, None, &[], visitor.0, false, None, "associated type");
+            placeholder_type_error(tcx, None, visitor.0, false, None, "associated type");
         }
     };
 
@@ -901,7 +879,7 @@ fn convert_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) {
             let mut visitor = HirPlaceholderCollector::default();
             visitor.visit_impl_item(impl_item);
 
-            placeholder_type_error(tcx, None, &[], visitor.0, false, None, "associated type");
+            placeholder_type_error(tcx, None, visitor.0, false, None, "associated type");
         }
         hir::ImplItemKind::Const(..) => {}
     }
@@ -1864,69 +1842,35 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
     match tcx.hir().get(hir_id) {
         TraitItem(hir::TraitItem {
             kind: TraitItemKind::Fn(sig, TraitFn::Provided(_)),
-            ident,
             generics,
             ..
         })
-        | ImplItem(hir::ImplItem { kind: ImplItemKind::Fn(sig, _), ident, generics, .. })
-        | Item(hir::Item { kind: ItemKind::Fn(sig, generics, _), ident, .. }) => {
-            match get_infer_ret_ty(&sig.decl.output) {
-                Some(ty) => {
-                    let fn_sig = tcx.typeck(def_id).liberated_fn_sigs()[hir_id];
-                    // Typeck doesn't expect erased regions to be returned from `type_of`.
-                    let fn_sig = tcx.fold_regions(fn_sig, &mut false, |r, _| match *r {
-                        ty::ReErased => tcx.lifetimes.re_static,
-                        _ => r,
-                    });
-                    let fn_sig = ty::Binder::dummy(fn_sig);
-
-                    let mut visitor = HirPlaceholderCollector::default();
-                    visitor.visit_ty(ty);
-                    let mut diag = bad_placeholder(tcx, visitor.0, "return type");
-                    let ret_ty = fn_sig.skip_binder().output();
-                    if !ret_ty.references_error() {
-                        if !ret_ty.is_closure() {
-                            let ret_ty_str = match ret_ty.kind() {
-                                // Suggest a function pointer return type instead of a unique function definition
-                                // (e.g. `fn() -> i32` instead of `fn() -> i32 { f }`, the latter of which is invalid
-                                // syntax)
-                                ty::FnDef(..) => ret_ty.fn_sig(tcx).to_string(),
-                                _ => ret_ty.to_string(),
-                            };
-                            diag.span_suggestion(
-                                ty.span,
-                                "replace with the correct return type",
-                                ret_ty_str,
-                                Applicability::MaybeIncorrect,
-                            );
-                        } else {
-                            // We're dealing with a closure, so we should suggest using `impl Fn` or trait bounds
-                            // to prevent the user from getting a papercut while trying to use the unique closure
-                            // syntax (e.g. `[closure@src/lib.rs:2:5: 2:9]`).
-                            diag.help("consider using an `Fn`, `FnMut`, or `FnOnce` trait bound");
-                            diag.note("for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html");
-                        }
-                    }
-                    diag.emit();
+        | Item(hir::Item { kind: ItemKind::Fn(sig, generics, _), .. }) => {
+            infer_return_ty_for_fn_sig(tcx, sig, generics, def_id, &icx)
+        }
 
-                    fn_sig
-                }
-                None => <dyn AstConv<'_>>::ty_of_fn(
+        ImplItem(hir::ImplItem { kind: ImplItemKind::Fn(sig, _), generics, .. }) => {
+            // Do not try to inference the return type for a impl method coming from a trait
+            if let Item(hir::Item { kind: ItemKind::Impl(i), .. }) =
+                tcx.hir().get(tcx.hir().get_parent_node(hir_id))
+                && i.of_trait.is_some()
+            {
+                <dyn AstConv<'_>>::ty_of_fn(
                     &icx,
                     hir_id,
                     sig.header.unsafety,
                     sig.header.abi,
                     sig.decl,
-                    generics,
-                    Some(ident.span),
+                    Some(generics),
                     None,
-                ),
+                )
+            } else {
+                infer_return_ty_for_fn_sig(tcx, sig, generics, def_id, &icx)
             }
         }
 
         TraitItem(hir::TraitItem {
             kind: TraitItemKind::Fn(FnSig { header, decl, span: _ }, _),
-            ident,
             generics,
             ..
         }) => <dyn AstConv<'_>>::ty_of_fn(
@@ -1935,16 +1879,13 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
             header.unsafety,
             header.abi,
             decl,
-            generics,
-            Some(ident.span),
+            Some(generics),
             None,
         ),
 
-        ForeignItem(&hir::ForeignItem {
-            kind: ForeignItemKind::Fn(fn_decl, _, _), ident, ..
-        }) => {
+        ForeignItem(&hir::ForeignItem { kind: ForeignItemKind::Fn(fn_decl, _, _), .. }) => {
             let abi = tcx.hir().get_foreign_abi(hir_id);
-            compute_sig_of_foreign_fn_decl(tcx, def_id.to_def_id(), fn_decl, abi, ident)
+            compute_sig_of_foreign_fn_decl(tcx, def_id.to_def_id(), fn_decl, abi)
         }
 
         Ctor(data) | Variant(hir::Variant { data, .. }) if data.ctor_hir_id().is_some() => {
@@ -1982,6 +1923,69 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
     }
 }
 
+fn infer_return_ty_for_fn_sig<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    sig: &hir::FnSig<'_>,
+    generics: &hir::Generics<'_>,
+    def_id: LocalDefId,
+    icx: &ItemCtxt<'tcx>,
+) -> ty::PolyFnSig<'tcx> {
+    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+
+    match get_infer_ret_ty(&sig.decl.output) {
+        Some(ty) => {
+            let fn_sig = tcx.typeck(def_id).liberated_fn_sigs()[hir_id];
+            // Typeck doesn't expect erased regions to be returned from `type_of`.
+            let fn_sig = tcx.fold_regions(fn_sig, &mut false, |r, _| match *r {
+                ty::ReErased => tcx.lifetimes.re_static,
+                _ => r,
+            });
+            let fn_sig = ty::Binder::dummy(fn_sig);
+
+            let mut visitor = HirPlaceholderCollector::default();
+            visitor.visit_ty(ty);
+            let mut diag = bad_placeholder(tcx, visitor.0, "return type");
+            let ret_ty = fn_sig.skip_binder().output();
+            if ret_ty.is_suggestable(tcx) {
+                diag.span_suggestion(
+                    ty.span,
+                    "replace with the correct return type",
+                    ret_ty.to_string(),
+                    Applicability::MachineApplicable,
+                );
+            } else if matches!(ret_ty.kind(), ty::FnDef(..)) {
+                let fn_sig = ret_ty.fn_sig(tcx);
+                if fn_sig.skip_binder().inputs_and_output.iter().all(|t| t.is_suggestable(tcx)) {
+                    diag.span_suggestion(
+                        ty.span,
+                        "replace with the correct return type",
+                        fn_sig.to_string(),
+                        Applicability::MachineApplicable,
+                    );
+                }
+            } else if ret_ty.is_closure() {
+                // We're dealing with a closure, so we should suggest using `impl Fn` or trait bounds
+                // to prevent the user from getting a papercut while trying to use the unique closure
+                // syntax (e.g. `[closure@src/lib.rs:2:5: 2:9]`).
+                diag.help("consider using an `Fn`, `FnMut`, or `FnOnce` trait bound");
+                diag.note("for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html");
+            }
+            diag.emit();
+
+            fn_sig
+        }
+        None => <dyn AstConv<'_>>::ty_of_fn(
+            icx,
+            hir_id,
+            sig.header.unsafety,
+            sig.header.abi,
+            sig.decl,
+            Some(generics),
+            None,
+        ),
+    }
+}
+
 fn impl_trait_ref(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::TraitRef<'_>> {
     let icx = ItemCtxt::new(tcx, def_id);
     match tcx.hir().expect_item(def_id.expect_local()).kind {
@@ -2137,16 +2141,16 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
 
     let icx = ItemCtxt::new(tcx, def_id);
 
-    const NO_GENERICS: &hir::Generics<'_> = &hir::Generics::empty();
+    const NO_GENERICS: &hir::Generics<'_> = hir::Generics::empty();
 
     // We use an `IndexSet` to preserves order of insertion.
     // Preserving the order of insertion is important here so as not to break UI tests.
     let mut predicates: FxIndexSet<(ty::Predicate<'_>, Span)> = FxIndexSet::default();
 
     let ast_generics = match node {
-        Node::TraitItem(item) => &item.generics,
+        Node::TraitItem(item) => item.generics,
 
-        Node::ImplItem(item) => &item.generics,
+        Node::ImplItem(item) => item.generics,
 
         Node::Item(item) => {
             match item.kind {
@@ -2160,15 +2164,15 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
                 | ItemKind::TyAlias(_, ref generics)
                 | ItemKind::Enum(_, ref generics)
                 | ItemKind::Struct(_, ref generics)
-                | ItemKind::Union(_, ref generics) => generics,
+                | ItemKind::Union(_, ref generics) => *generics,
 
                 ItemKind::Trait(_, _, ref generics, ..) => {
                     is_trait = Some(ty::TraitRef::identity(tcx, def_id));
-                    generics
+                    *generics
                 }
                 ItemKind::TraitAlias(ref generics, _) => {
                     is_trait = Some(ty::TraitRef::identity(tcx, def_id));
-                    generics
+                    *generics
                 }
                 ItemKind::OpaqueTy(OpaqueTy {
                     origin: hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..),
@@ -2205,7 +2209,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
 
         Node::ForeignItem(item) => match item.kind {
             ForeignItemKind::Static(..) => NO_GENERICS,
-            ForeignItemKind::Fn(_, _, ref generics) => generics,
+            ForeignItemKind::Fn(_, _, ref generics) => *generics,
             ForeignItemKind::Type => NO_GENERICS,
         },
 
@@ -2239,29 +2243,9 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
     // Collect the region predicates that were declared inline as
     // well. In the case of parameters declared on a fn or method, we
     // have to be careful to only iterate over early-bound regions.
-    let mut index = parent_count + has_own_self as u32;
-    for param in early_bound_lifetimes_from_generics(tcx, hir_id.owner, ast_generics) {
-        let region = tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion {
-            def_id: tcx.hir().local_def_id(param.hir_id).to_def_id(),
-            index,
-            name: param.name.ident().name,
-        }));
-        index += 1;
-
-        match param.kind {
-            GenericParamKind::Lifetime { .. } => {
-                param.bounds.iter().for_each(|bound| match bound {
-                    hir::GenericBound::Outlives(lt) => {
-                        let bound = <dyn AstConv<'_>>::ast_region_to_region(&icx, lt, None);
-                        let outlives = ty::Binder::dummy(ty::OutlivesPredicate(region, bound));
-                        predicates.insert((outlives.to_predicate(tcx), lt.span));
-                    }
-                    _ => bug!(),
-                });
-            }
-            _ => bug!(),
-        }
-    }
+    let mut index = parent_count
+        + has_own_self as u32
+        + early_bound_lifetimes_from_generics(tcx, hir_id.owner, ast_generics).count() as u32;
 
     // Collect the predicates that were written inline by the user on each
     // type parameter (e.g., `<T: Foo>`).
@@ -2274,28 +2258,26 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
                 let param_ty = ty::ParamTy::new(index, name).to_ty(tcx);
                 index += 1;
 
-                let mut bounds = <dyn AstConv<'_>>::compute_bounds(&icx, param_ty, param.bounds);
+                let mut bounds = Bounds::default();
                 // Params are implicitly sized unless a `?Sized` bound is found
                 <dyn AstConv<'_>>::add_implicitly_sized(
                     &icx,
                     &mut bounds,
-                    param.bounds,
-                    Some((param.hir_id, ast_generics.where_clause.predicates)),
+                    &[],
+                    Some((param.hir_id, ast_generics.predicates)),
                     param.span,
                 );
                 predicates.extend(bounds.predicates(tcx, param_ty));
             }
             GenericParamKind::Const { .. } => {
                 // Bounds on const parameters are currently not possible.
-                debug_assert!(param.bounds.is_empty());
                 index += 1;
             }
         }
     }
 
     // Add in the bounds that appear in the where-clause.
-    let where_clause = &ast_generics.where_clause;
-    for predicate in where_clause.predicates {
+    for predicate in ast_generics.predicates {
         match predicate {
             hir::WherePredicate::BoundPredicate(bound_pred) => {
                 let ty = icx.to_ty(bound_pred.bounded_ty);
@@ -2553,7 +2535,6 @@ fn compute_sig_of_foreign_fn_decl<'tcx>(
     def_id: DefId,
     decl: &'tcx hir::FnDecl<'tcx>,
     abi: abi::Abi,
-    ident: Ident,
 ) -> ty::PolyFnSig<'tcx> {
     let unsafety = if abi == abi::Abi::RustIntrinsic {
         intrinsic_operation_unsafety(tcx.item_name(def_id))
@@ -2567,8 +2548,7 @@ fn compute_sig_of_foreign_fn_decl<'tcx>(
         unsafety,
         abi,
         decl,
-        &hir::Generics::empty(),
-        Some(ident.span),
+        None,
         None,
     );
 
@@ -3182,7 +3162,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
 
     // #73631: closures inherit `#[target_feature]` annotations
     if tcx.features().target_feature_11 && tcx.is_closure(id) {
-        let owner_id = tcx.parent(id).expect("closure should have a parent");
+        let owner_id = tcx.parent(id);
         codegen_fn_attrs
             .target_features
             .extend(tcx.codegen_fn_attrs(owner_id).target_features.iter().copied())
index fa06ec09fce22c6e7ed0960af0240f2752ff2275..75ad584f419907370ce96c8a093cc617c4e21af6 100644 (file)
@@ -337,8 +337,8 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
                         icx.to_ty(ty)
                     }
                 }
-                ItemKind::TyAlias(self_ty, _)
-                | ItemKind::Impl(hir::Impl { self_ty, .. }) => icx.to_ty(self_ty),
+                ItemKind::TyAlias(self_ty, _) => icx.to_ty(self_ty),
+                ItemKind::Impl(hir::Impl { self_ty, .. }) => icx.to_ty(*self_ty),
                 ItemKind::Fn(..) => {
                     let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
                     tcx.mk_fn_def(def_id.to_def_id(), substs)
@@ -683,7 +683,7 @@ fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) {
         Some(hidden) => hidden.ty,
         None => {
             let span = tcx.def_span(def_id);
-            let name = tcx.item_name(tcx.parent(def_id.to_def_id()).unwrap());
+            let name = tcx.item_name(tcx.local_parent(def_id).to_def_id());
             let label = format!(
                 "`{}` must be used in combination with a concrete type within the same module",
                 name
index 1088be5f566571d2ff7039c47a40b04012519dee..3d2f93537e4e8d5d9eccd66aefcb68dec2f76514 100644 (file)
@@ -1,6 +1,6 @@
 //! Errors emitted by typeck.
 use rustc_errors::Applicability;
-use rustc_macros::SessionDiagnostic;
+use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic};
 use rustc_middle::ty::Ty;
 use rustc_span::{symbol::Ident, Span, Symbol};
 
@@ -134,7 +134,7 @@ pub struct TypeofReservedKeywordUsed<'tcx> {
     #[primary_span]
     #[label]
     pub span: Span,
-    #[suggestion_verbose(message = "suggestion", code = "{ty}")]
+    #[suggestion_verbose(code = "{ty}")]
     pub opt_sugg: Option<(Span, Applicability)>,
 }
 
@@ -190,3 +190,41 @@ pub struct AddressOfTemporaryTaken {
     #[label]
     pub span: Span,
 }
+
+#[derive(SessionSubdiagnostic)]
+pub enum AddReturnTypeSuggestion<'tcx> {
+    #[suggestion(
+        slug = "typeck-add-return-type-add",
+        code = "-> {found} ",
+        applicability = "machine-applicable"
+    )]
+    Add {
+        #[primary_span]
+        span: Span,
+        found: Ty<'tcx>,
+    },
+    #[suggestion(
+        slug = "typeck-add-return-type-missing-here",
+        code = "-> _ ",
+        applicability = "has-placeholders"
+    )]
+    MissingHere {
+        #[primary_span]
+        span: Span,
+    },
+}
+
+#[derive(SessionSubdiagnostic)]
+pub enum ExpectedReturnTypeLabel<'tcx> {
+    #[label(slug = "typeck-expected-default-return-type")]
+    Unit {
+        #[primary_span]
+        span: Span,
+    },
+    #[label(slug = "typeck-expected-return-type")]
+    Other {
+        #[primary_span]
+        span: Span,
+        expected: Ty<'tcx>,
+    },
+}
index 9fb9652b849c9142b87d47fb8f8a90ce30e915a0..03b3d68d59f4cb2cf5ab40790d980321ea815faa 100644 (file)
@@ -213,7 +213,7 @@ fn main_fn_where_clauses_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
         let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
         match tcx.hir().find(hir_id) {
             Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, ref generics, _), .. })) => {
-                generics.where_clause.span()
+                generics.where_clause_span()
             }
             _ => {
                 span_bug!(tcx.def_span(def_id), "main has a non-function type");
@@ -408,7 +408,7 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) {
                         .emit();
                         error = true;
                     }
-                    if let Some(sp) = generics.where_clause.span() {
+                    if let Some(sp) = generics.where_clause_span() {
                         struct_span_err!(
                             tcx.sess,
                             sp,
index 404cfa6addb73b271bf42a90889b3535252a6c82..6660380e4beb0d1ab28763728fea87587468e8e1 100644 (file)
@@ -67,3 +67,27 @@ fn bench_from_array_1000(b: &mut Bencher) {
         black_box(deq);
     })
 }
+
+#[bench]
+fn bench_extend_bytes(b: &mut Bencher) {
+    let mut ring: VecDeque<u8> = VecDeque::with_capacity(1000);
+    let input: &[u8] = &[128; 512];
+
+    b.iter(|| {
+        ring.clear();
+        ring.extend(black_box(input));
+    });
+}
+
+#[bench]
+fn bench_extend_vec(b: &mut Bencher) {
+    let mut ring: VecDeque<u8> = VecDeque::with_capacity(1000);
+    let input = vec![128; 512];
+
+    b.iter(|| {
+        ring.clear();
+
+        let input = input.clone();
+        ring.extend(black_box(input));
+    });
+}
index 8b13e36c4b3c7e342a45d403b0ef901f3dd80c0c..cb4e438f8bea22cbd34455f8aed2791f2bc5e856 100644 (file)
@@ -292,8 +292,7 @@ pub fn to_mut(&mut self) -> &mut <B as ToOwned>::Owned {
     ///
     /// # Examples
     ///
-    /// Calling `into_owned` on a `Cow::Borrowed` clones the underlying data
-    /// and becomes a `Cow::Owned`:
+    /// Calling `into_owned` on a `Cow::Borrowed` returns a clone of the borrowed data:
     ///
     /// ```
     /// use std::borrow::Cow;
@@ -307,7 +306,8 @@ pub fn to_mut(&mut self) -> &mut <B as ToOwned>::Owned {
     /// );
     /// ```
     ///
-    /// Calling `into_owned` on a `Cow::Owned` is a no-op:
+    /// Calling `into_owned` on a `Cow::Owned` returns the owned data. The data is moved out of the
+    /// `Cow` without being cloned.
     ///
     /// ```
     /// use std::borrow::Cow;
index ef5bef0253a569b2cbcc60d277a1b3ad8217d55c..c3c1d0c92a86be67d291e2cc05d73f2003620b2f 100644 (file)
 
 use super::SpecExtend;
 
+#[cfg(test)]
+mod tests;
+
 /// A priority queue implemented with a binary heap.
 ///
 /// This will be a max-heap.
diff --git a/library/alloc/src/collections/binary_heap/tests.rs b/library/alloc/src/collections/binary_heap/tests.rs
new file mode 100644 (file)
index 0000000..7c758db
--- /dev/null
@@ -0,0 +1,489 @@
+use super::*;
+use crate::boxed::Box;
+use std::iter::TrustedLen;
+use std::panic::{catch_unwind, AssertUnwindSafe};
+use std::sync::atomic::{AtomicU32, Ordering};
+
+#[test]
+fn test_iterator() {
+    let data = vec![5, 9, 3];
+    let iterout = [9, 5, 3];
+    let heap = BinaryHeap::from(data);
+    let mut i = 0;
+    for el in &heap {
+        assert_eq!(*el, iterout[i]);
+        i += 1;
+    }
+}
+
+#[test]
+fn test_iter_rev_cloned_collect() {
+    let data = vec![5, 9, 3];
+    let iterout = vec![3, 5, 9];
+    let pq = BinaryHeap::from(data);
+
+    let v: Vec<_> = pq.iter().rev().cloned().collect();
+    assert_eq!(v, iterout);
+}
+
+#[test]
+fn test_into_iter_collect() {
+    let data = vec![5, 9, 3];
+    let iterout = vec![9, 5, 3];
+    let pq = BinaryHeap::from(data);
+
+    let v: Vec<_> = pq.into_iter().collect();
+    assert_eq!(v, iterout);
+}
+
+#[test]
+fn test_into_iter_size_hint() {
+    let data = vec![5, 9];
+    let pq = BinaryHeap::from(data);
+
+    let mut it = pq.into_iter();
+
+    assert_eq!(it.size_hint(), (2, Some(2)));
+    assert_eq!(it.next(), Some(9));
+
+    assert_eq!(it.size_hint(), (1, Some(1)));
+    assert_eq!(it.next(), Some(5));
+
+    assert_eq!(it.size_hint(), (0, Some(0)));
+    assert_eq!(it.next(), None);
+}
+
+#[test]
+fn test_into_iter_rev_collect() {
+    let data = vec![5, 9, 3];
+    let iterout = vec![3, 5, 9];
+    let pq = BinaryHeap::from(data);
+
+    let v: Vec<_> = pq.into_iter().rev().collect();
+    assert_eq!(v, iterout);
+}
+
+#[test]
+fn test_into_iter_sorted_collect() {
+    let heap = BinaryHeap::from(vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]);
+    let it = heap.into_iter_sorted();
+    let sorted = it.collect::<Vec<_>>();
+    assert_eq!(sorted, vec![10, 9, 8, 7, 6, 5, 4, 3, 2, 2, 1, 1, 0]);
+}
+
+#[test]
+fn test_drain_sorted_collect() {
+    let mut heap = BinaryHeap::from(vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]);
+    let it = heap.drain_sorted();
+    let sorted = it.collect::<Vec<_>>();
+    assert_eq!(sorted, vec![10, 9, 8, 7, 6, 5, 4, 3, 2, 2, 1, 1, 0]);
+}
+
+fn check_exact_size_iterator<I: ExactSizeIterator>(len: usize, it: I) {
+    let mut it = it;
+
+    for i in 0..it.len() {
+        let (lower, upper) = it.size_hint();
+        assert_eq!(Some(lower), upper);
+        assert_eq!(lower, len - i);
+        assert_eq!(it.len(), len - i);
+        it.next();
+    }
+    assert_eq!(it.len(), 0);
+    assert!(it.is_empty());
+}
+
+#[test]
+fn test_exact_size_iterator() {
+    let heap = BinaryHeap::from(vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]);
+    check_exact_size_iterator(heap.len(), heap.iter());
+    check_exact_size_iterator(heap.len(), heap.clone().into_iter());
+    check_exact_size_iterator(heap.len(), heap.clone().into_iter_sorted());
+    check_exact_size_iterator(heap.len(), heap.clone().drain());
+    check_exact_size_iterator(heap.len(), heap.clone().drain_sorted());
+}
+
+fn check_trusted_len<I: TrustedLen>(len: usize, it: I) {
+    let mut it = it;
+    for i in 0..len {
+        let (lower, upper) = it.size_hint();
+        if upper.is_some() {
+            assert_eq!(Some(lower), upper);
+            assert_eq!(lower, len - i);
+        }
+        it.next();
+    }
+}
+
+#[test]
+fn test_trusted_len() {
+    let heap = BinaryHeap::from(vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]);
+    check_trusted_len(heap.len(), heap.clone().into_iter_sorted());
+    check_trusted_len(heap.len(), heap.clone().drain_sorted());
+}
+
+#[test]
+fn test_peek_and_pop() {
+    let data = vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1];
+    let mut sorted = data.clone();
+    sorted.sort();
+    let mut heap = BinaryHeap::from(data);
+    while !heap.is_empty() {
+        assert_eq!(heap.peek().unwrap(), sorted.last().unwrap());
+        assert_eq!(heap.pop().unwrap(), sorted.pop().unwrap());
+    }
+}
+
+#[test]
+fn test_peek_mut() {
+    let data = vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1];
+    let mut heap = BinaryHeap::from(data);
+    assert_eq!(heap.peek(), Some(&10));
+    {
+        let mut top = heap.peek_mut().unwrap();
+        *top -= 2;
+    }
+    assert_eq!(heap.peek(), Some(&9));
+}
+
+#[test]
+fn test_peek_mut_pop() {
+    let data = vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1];
+    let mut heap = BinaryHeap::from(data);
+    assert_eq!(heap.peek(), Some(&10));
+    {
+        let mut top = heap.peek_mut().unwrap();
+        *top -= 2;
+        assert_eq!(PeekMut::pop(top), 8);
+    }
+    assert_eq!(heap.peek(), Some(&9));
+}
+
+#[test]
+fn test_push() {
+    let mut heap = BinaryHeap::from(vec![2, 4, 9]);
+    assert_eq!(heap.len(), 3);
+    assert!(*heap.peek().unwrap() == 9);
+    heap.push(11);
+    assert_eq!(heap.len(), 4);
+    assert!(*heap.peek().unwrap() == 11);
+    heap.push(5);
+    assert_eq!(heap.len(), 5);
+    assert!(*heap.peek().unwrap() == 11);
+    heap.push(27);
+    assert_eq!(heap.len(), 6);
+    assert!(*heap.peek().unwrap() == 27);
+    heap.push(3);
+    assert_eq!(heap.len(), 7);
+    assert!(*heap.peek().unwrap() == 27);
+    heap.push(103);
+    assert_eq!(heap.len(), 8);
+    assert!(*heap.peek().unwrap() == 103);
+}
+
+#[test]
+fn test_push_unique() {
+    let mut heap = BinaryHeap::<Box<_>>::from(vec![box 2, box 4, box 9]);
+    assert_eq!(heap.len(), 3);
+    assert!(**heap.peek().unwrap() == 9);
+    heap.push(box 11);
+    assert_eq!(heap.len(), 4);
+    assert!(**heap.peek().unwrap() == 11);
+    heap.push(box 5);
+    assert_eq!(heap.len(), 5);
+    assert!(**heap.peek().unwrap() == 11);
+    heap.push(box 27);
+    assert_eq!(heap.len(), 6);
+    assert!(**heap.peek().unwrap() == 27);
+    heap.push(box 3);
+    assert_eq!(heap.len(), 7);
+    assert!(**heap.peek().unwrap() == 27);
+    heap.push(box 103);
+    assert_eq!(heap.len(), 8);
+    assert!(**heap.peek().unwrap() == 103);
+}
+
+fn check_to_vec(mut data: Vec<i32>) {
+    let heap = BinaryHeap::from(data.clone());
+    let mut v = heap.clone().into_vec();
+    v.sort();
+    data.sort();
+
+    assert_eq!(v, data);
+    assert_eq!(heap.into_sorted_vec(), data);
+}
+
+#[test]
+fn test_to_vec() {
+    check_to_vec(vec![]);
+    check_to_vec(vec![5]);
+    check_to_vec(vec![3, 2]);
+    check_to_vec(vec![2, 3]);
+    check_to_vec(vec![5, 1, 2]);
+    check_to_vec(vec![1, 100, 2, 3]);
+    check_to_vec(vec![1, 3, 5, 7, 9, 2, 4, 6, 8, 0]);
+    check_to_vec(vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]);
+    check_to_vec(vec![9, 11, 9, 9, 9, 9, 11, 2, 3, 4, 11, 9, 0, 0, 0, 0]);
+    check_to_vec(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
+    check_to_vec(vec![10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]);
+    check_to_vec(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 1, 2]);
+    check_to_vec(vec![5, 4, 3, 2, 1, 5, 4, 3, 2, 1, 5, 4, 3, 2, 1]);
+}
+
+#[test]
+fn test_in_place_iterator_specialization() {
+    let src: Vec<usize> = vec![1, 2, 3];
+    let src_ptr = src.as_ptr();
+    let heap: BinaryHeap<_> = src.into_iter().map(std::convert::identity).collect();
+    let heap_ptr = heap.iter().next().unwrap() as *const usize;
+    assert_eq!(src_ptr, heap_ptr);
+    let sink: Vec<_> = heap.into_iter().map(std::convert::identity).collect();
+    let sink_ptr = sink.as_ptr();
+    assert_eq!(heap_ptr, sink_ptr);
+}
+
+#[test]
+fn test_empty_pop() {
+    let mut heap = BinaryHeap::<i32>::new();
+    assert!(heap.pop().is_none());
+}
+
+#[test]
+fn test_empty_peek() {
+    let empty = BinaryHeap::<i32>::new();
+    assert!(empty.peek().is_none());
+}
+
+#[test]
+fn test_empty_peek_mut() {
+    let mut empty = BinaryHeap::<i32>::new();
+    assert!(empty.peek_mut().is_none());
+}
+
+#[test]
+fn test_from_iter() {
+    let xs = vec![9, 8, 7, 6, 5, 4, 3, 2, 1];
+
+    let mut q: BinaryHeap<_> = xs.iter().rev().cloned().collect();
+
+    for &x in &xs {
+        assert_eq!(q.pop().unwrap(), x);
+    }
+}
+
+#[test]
+fn test_drain() {
+    let mut q: BinaryHeap<_> = [9, 8, 7, 6, 5, 4, 3, 2, 1].iter().cloned().collect();
+
+    assert_eq!(q.drain().take(5).count(), 5);
+
+    assert!(q.is_empty());
+}
+
+#[test]
+fn test_drain_sorted() {
+    let mut q: BinaryHeap<_> = [9, 8, 7, 6, 5, 4, 3, 2, 1].iter().cloned().collect();
+
+    assert_eq!(q.drain_sorted().take(5).collect::<Vec<_>>(), vec![9, 8, 7, 6, 5]);
+
+    assert!(q.is_empty());
+}
+
+#[test]
+fn test_drain_sorted_leak() {
+    static DROPS: AtomicU32 = AtomicU32::new(0);
+
+    #[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
+    struct D(u32, bool);
+
+    impl Drop for D {
+        fn drop(&mut self) {
+            DROPS.fetch_add(1, Ordering::SeqCst);
+
+            if self.1 {
+                panic!("panic in `drop`");
+            }
+        }
+    }
+
+    let mut q = BinaryHeap::from(vec![
+        D(0, false),
+        D(1, false),
+        D(2, false),
+        D(3, true),
+        D(4, false),
+        D(5, false),
+    ]);
+
+    catch_unwind(AssertUnwindSafe(|| drop(q.drain_sorted()))).ok();
+
+    assert_eq!(DROPS.load(Ordering::SeqCst), 6);
+}
+
+#[test]
+fn test_extend_ref() {
+    let mut a = BinaryHeap::new();
+    a.push(1);
+    a.push(2);
+
+    a.extend(&[3, 4, 5]);
+
+    assert_eq!(a.len(), 5);
+    assert_eq!(a.into_sorted_vec(), [1, 2, 3, 4, 5]);
+
+    let mut a = BinaryHeap::new();
+    a.push(1);
+    a.push(2);
+    let mut b = BinaryHeap::new();
+    b.push(3);
+    b.push(4);
+    b.push(5);
+
+    a.extend(&b);
+
+    assert_eq!(a.len(), 5);
+    assert_eq!(a.into_sorted_vec(), [1, 2, 3, 4, 5]);
+}
+
+#[test]
+fn test_append() {
+    let mut a = BinaryHeap::from(vec![-10, 1, 2, 3, 3]);
+    let mut b = BinaryHeap::from(vec![-20, 5, 43]);
+
+    a.append(&mut b);
+
+    assert_eq!(a.into_sorted_vec(), [-20, -10, 1, 2, 3, 3, 5, 43]);
+    assert!(b.is_empty());
+}
+
+#[test]
+fn test_append_to_empty() {
+    let mut a = BinaryHeap::new();
+    let mut b = BinaryHeap::from(vec![-20, 5, 43]);
+
+    a.append(&mut b);
+
+    assert_eq!(a.into_sorted_vec(), [-20, 5, 43]);
+    assert!(b.is_empty());
+}
+
+#[test]
+fn test_extend_specialization() {
+    let mut a = BinaryHeap::from(vec![-10, 1, 2, 3, 3]);
+    let b = BinaryHeap::from(vec![-20, 5, 43]);
+
+    a.extend(b);
+
+    assert_eq!(a.into_sorted_vec(), [-20, -10, 1, 2, 3, 3, 5, 43]);
+}
+
+#[allow(dead_code)]
+fn assert_covariance() {
+    fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> {
+        d
+    }
+}
+
+#[test]
+fn test_retain() {
+    let mut a = BinaryHeap::from(vec![100, 10, 50, 1, 2, 20, 30]);
+    a.retain(|&x| x != 2);
+
+    // Check that 20 moved into 10's place.
+    assert_eq!(a.clone().into_vec(), [100, 20, 50, 1, 10, 30]);
+
+    a.retain(|_| true);
+
+    assert_eq!(a.clone().into_vec(), [100, 20, 50, 1, 10, 30]);
+
+    a.retain(|&x| x < 50);
+
+    assert_eq!(a.clone().into_vec(), [30, 20, 10, 1]);
+
+    a.retain(|_| false);
+
+    assert!(a.is_empty());
+}
+
+// old binaryheap failed this test
+//
+// Integrity means that all elements are present after a comparison panics,
+// even if the order might not be correct.
+//
+// Destructors must be called exactly once per element.
+// FIXME: re-enable emscripten once it can unwind again
+#[test]
+#[cfg(not(target_os = "emscripten"))]
+fn panic_safe() {
+    use rand::{seq::SliceRandom, thread_rng};
+    use std::cmp;
+    use std::panic::{self, AssertUnwindSafe};
+    use std::sync::atomic::{AtomicUsize, Ordering};
+
+    static DROP_COUNTER: AtomicUsize = AtomicUsize::new(0);
+
+    #[derive(Eq, PartialEq, Ord, Clone, Debug)]
+    struct PanicOrd<T>(T, bool);
+
+    impl<T> Drop for PanicOrd<T> {
+        fn drop(&mut self) {
+            // update global drop count
+            DROP_COUNTER.fetch_add(1, Ordering::SeqCst);
+        }
+    }
+
+    impl<T: PartialOrd> PartialOrd for PanicOrd<T> {
+        fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
+            if self.1 || other.1 {
+                panic!("Panicking comparison");
+            }
+            self.0.partial_cmp(&other.0)
+        }
+    }
+    let mut rng = thread_rng();
+    const DATASZ: usize = 32;
+    // Miri is too slow
+    let ntest = if cfg!(miri) { 1 } else { 10 };
+
+    // don't use 0 in the data -- we want to catch the zeroed-out case.
+    let data = (1..=DATASZ).collect::<Vec<_>>();
+
+    // since it's a fuzzy test, run several tries.
+    for _ in 0..ntest {
+        for i in 1..=DATASZ {
+            DROP_COUNTER.store(0, Ordering::SeqCst);
+
+            let mut panic_ords: Vec<_> =
+                data.iter().filter(|&&x| x != i).map(|&x| PanicOrd(x, false)).collect();
+            let panic_item = PanicOrd(i, true);
+
+            // heapify the sane items
+            panic_ords.shuffle(&mut rng);
+            let mut heap = BinaryHeap::from(panic_ords);
+            let inner_data;
+
+            {
+                // push the panicking item to the heap and catch the panic
+                let thread_result = {
+                    let mut heap_ref = AssertUnwindSafe(&mut heap);
+                    panic::catch_unwind(move || {
+                        heap_ref.push(panic_item);
+                    })
+                };
+                assert!(thread_result.is_err());
+
+                // Assert no elements were dropped
+                let drops = DROP_COUNTER.load(Ordering::SeqCst);
+                assert!(drops == 0, "Must not drop items. drops={}", drops);
+                inner_data = heap.clone().into_vec();
+                drop(heap);
+            }
+            let drops = DROP_COUNTER.load(Ordering::SeqCst);
+            assert_eq!(drops, DATASZ);
+
+            let mut data_sorted = inner_data.into_iter().map(|p| p.0).collect::<Vec<_>>();
+            data_sorted.sort();
+            assert_eq!(data_sorted, data);
+        }
+    }
+}
index d81f24e72024d5ea7688ca30fd44e5cbffb8386b..736b38370ab87929a5b9b60efec2bf5cd2de4142 100644 (file)
@@ -645,7 +645,7 @@ pub fn clear(&mut self) {
     /// Returns `true` if the `LinkedList` contains an element equal to the
     /// given value.
     ///
-    /// This operation should compute in *O*(*n*) time.
+    /// This operation should compute linearly in *O*(*n*) time.
     ///
     /// # Examples
     ///
@@ -1569,7 +1569,7 @@ pub fn split_before(&mut self) -> LinkedList<T> {
     /// Appends an element to the front of the cursor's parent list. The node
     /// that the cursor points to is unchanged, even if it is the "ghost" node.
     ///
-    /// This operation should compute in O(1) time.
+    /// This operation should compute in *O*(1) time.
     // `push_front` continues to point to "ghost" when it addes a node to mimic
     // the behavior of `insert_before` on an empty list.
     #[unstable(feature = "linked_list_cursors", issue = "58533")]
@@ -1584,7 +1584,7 @@ pub fn push_front(&mut self, elt: T) {
     /// Appends an element to the back of the cursor's parent list. The node
     /// that the cursor points to is unchanged, even if it is the "ghost" node.
     ///
-    /// This operation should compute in O(1) time.
+    /// This operation should compute in *O*(1) time.
     #[unstable(feature = "linked_list_cursors", issue = "58533")]
     pub fn push_back(&mut self, elt: T) {
         // Safety: We know that `push_back` does not change the position in
@@ -1603,7 +1603,7 @@ pub fn push_back(&mut self, elt: T) {
     /// unchanged, unless it was pointing to the front element. In that case, it
     /// points to the new front element.
     ///
-    /// This operation should compute in O(1) time.
+    /// This operation should compute in *O*(1) time.
     #[unstable(feature = "linked_list_cursors", issue = "58533")]
     pub fn pop_front(&mut self) -> Option<T> {
         // We can't check if current is empty, we must check the list directly.
@@ -1630,7 +1630,7 @@ pub fn pop_front(&mut self) -> Option<T> {
     /// unchanged, unless it was pointing to the back element. In that case, it
     /// points to the "ghost" element.
     ///
-    /// This operation should compute in O(1) time.
+    /// This operation should compute in *O*(1) time.
     #[unstable(feature = "linked_list_cursors", issue = "58533")]
     pub fn pop_back(&mut self) -> Option<T> {
         if self.list.is_empty() {
index 5a65ed7a962e9eabdca357380e8d7da19bfbc872..38c702aa387bd1a46c74b719482b4e6358145416 100644 (file)
@@ -1,10 +1,55 @@
 use super::*;
+use crate::vec::Vec;
 
+use std::panic::{catch_unwind, AssertUnwindSafe};
 use std::thread;
-use std::vec::Vec;
 
 use rand::{thread_rng, RngCore};
 
+#[test]
+fn test_basic() {
+    let mut m = LinkedList::<Box<_>>::new();
+    assert_eq!(m.pop_front(), None);
+    assert_eq!(m.pop_back(), None);
+    assert_eq!(m.pop_front(), None);
+    m.push_front(box 1);
+    assert_eq!(m.pop_front(), Some(box 1));
+    m.push_back(box 2);
+    m.push_back(box 3);
+    assert_eq!(m.len(), 2);
+    assert_eq!(m.pop_front(), Some(box 2));
+    assert_eq!(m.pop_front(), Some(box 3));
+    assert_eq!(m.len(), 0);
+    assert_eq!(m.pop_front(), None);
+    m.push_back(box 1);
+    m.push_back(box 3);
+    m.push_back(box 5);
+    m.push_back(box 7);
+    assert_eq!(m.pop_front(), Some(box 1));
+
+    let mut n = LinkedList::new();
+    n.push_front(2);
+    n.push_front(3);
+    {
+        assert_eq!(n.front().unwrap(), &3);
+        let x = n.front_mut().unwrap();
+        assert_eq!(*x, 3);
+        *x = 0;
+    }
+    {
+        assert_eq!(n.back().unwrap(), &2);
+        let y = n.back_mut().unwrap();
+        assert_eq!(*y, 2);
+        *y = 1;
+    }
+    assert_eq!(n.pop_front(), Some(0));
+    assert_eq!(n.pop_front(), Some(1));
+}
+
+fn generate_test() -> LinkedList<i32> {
+    list_from(&[0, 1, 2, 3, 4, 5, 6])
+}
+
 fn list_from<T: Clone>(v: &[T]) -> LinkedList<T> {
     v.iter().cloned().collect()
 }
@@ -110,6 +155,123 @@ fn test_append() {
     check_links(&n);
 }
 
+#[test]
+fn test_iterator() {
+    let m = generate_test();
+    for (i, elt) in m.iter().enumerate() {
+        assert_eq!(i as i32, *elt);
+    }
+    let mut n = LinkedList::new();
+    assert_eq!(n.iter().next(), None);
+    n.push_front(4);
+    let mut it = n.iter();
+    assert_eq!(it.size_hint(), (1, Some(1)));
+    assert_eq!(it.next().unwrap(), &4);
+    assert_eq!(it.size_hint(), (0, Some(0)));
+    assert_eq!(it.next(), None);
+}
+
+#[test]
+fn test_iterator_clone() {
+    let mut n = LinkedList::new();
+    n.push_back(2);
+    n.push_back(3);
+    n.push_back(4);
+    let mut it = n.iter();
+    it.next();
+    let mut jt = it.clone();
+    assert_eq!(it.next(), jt.next());
+    assert_eq!(it.next_back(), jt.next_back());
+    assert_eq!(it.next(), jt.next());
+}
+
+#[test]
+fn test_iterator_double_end() {
+    let mut n = LinkedList::new();
+    assert_eq!(n.iter().next(), None);
+    n.push_front(4);
+    n.push_front(5);
+    n.push_front(6);
+    let mut it = n.iter();
+    assert_eq!(it.size_hint(), (3, Some(3)));
+    assert_eq!(it.next().unwrap(), &6);
+    assert_eq!(it.size_hint(), (2, Some(2)));
+    assert_eq!(it.next_back().unwrap(), &4);
+    assert_eq!(it.size_hint(), (1, Some(1)));
+    assert_eq!(it.next_back().unwrap(), &5);
+    assert_eq!(it.next_back(), None);
+    assert_eq!(it.next(), None);
+}
+
+#[test]
+fn test_rev_iter() {
+    let m = generate_test();
+    for (i, elt) in m.iter().rev().enumerate() {
+        assert_eq!((6 - i) as i32, *elt);
+    }
+    let mut n = LinkedList::new();
+    assert_eq!(n.iter().rev().next(), None);
+    n.push_front(4);
+    let mut it = n.iter().rev();
+    assert_eq!(it.size_hint(), (1, Some(1)));
+    assert_eq!(it.next().unwrap(), &4);
+    assert_eq!(it.size_hint(), (0, Some(0)));
+    assert_eq!(it.next(), None);
+}
+
+#[test]
+fn test_mut_iter() {
+    let mut m = generate_test();
+    let mut len = m.len();
+    for (i, elt) in m.iter_mut().enumerate() {
+        assert_eq!(i as i32, *elt);
+        len -= 1;
+    }
+    assert_eq!(len, 0);
+    let mut n = LinkedList::new();
+    assert!(n.iter_mut().next().is_none());
+    n.push_front(4);
+    n.push_back(5);
+    let mut it = n.iter_mut();
+    assert_eq!(it.size_hint(), (2, Some(2)));
+    assert!(it.next().is_some());
+    assert!(it.next().is_some());
+    assert_eq!(it.size_hint(), (0, Some(0)));
+    assert!(it.next().is_none());
+}
+
+#[test]
+fn test_iterator_mut_double_end() {
+    let mut n = LinkedList::new();
+    assert!(n.iter_mut().next_back().is_none());
+    n.push_front(4);
+    n.push_front(5);
+    n.push_front(6);
+    let mut it = n.iter_mut();
+    assert_eq!(it.size_hint(), (3, Some(3)));
+    assert_eq!(*it.next().unwrap(), 6);
+    assert_eq!(it.size_hint(), (2, Some(2)));
+    assert_eq!(*it.next_back().unwrap(), 4);
+    assert_eq!(it.size_hint(), (1, Some(1)));
+    assert_eq!(*it.next_back().unwrap(), 5);
+    assert!(it.next_back().is_none());
+    assert!(it.next().is_none());
+}
+
+#[test]
+fn test_mut_rev_iter() {
+    let mut m = generate_test();
+    for (i, elt) in m.iter_mut().rev().enumerate() {
+        assert_eq!((6 - i) as i32, *elt);
+    }
+    let mut n = LinkedList::new();
+    assert!(n.iter_mut().rev().next().is_none());
+    n.push_front(4);
+    let mut it = n.iter_mut().rev();
+    assert!(it.next().is_some());
+    assert!(it.next().is_none());
+}
+
 #[test]
 fn test_clone_from() {
     // Short cloned from long
@@ -168,13 +330,60 @@ fn test_send() {
 }
 
 #[test]
-fn test_fuzz() {
-    for _ in 0..25 {
-        fuzz_test(3);
-        fuzz_test(16);
-        #[cfg(not(miri))] // Miri is too slow
-        fuzz_test(189);
-    }
+fn test_eq() {
+    let mut n = list_from(&[]);
+    let mut m = list_from(&[]);
+    assert!(n == m);
+    n.push_front(1);
+    assert!(n != m);
+    m.push_back(1);
+    assert!(n == m);
+
+    let n = list_from(&[2, 3, 4]);
+    let m = list_from(&[1, 2, 3]);
+    assert!(n != m);
+}
+
+#[test]
+fn test_ord() {
+    let n = list_from(&[]);
+    let m = list_from(&[1, 2, 3]);
+    assert!(n < m);
+    assert!(m > n);
+    assert!(n <= n);
+    assert!(n >= n);
+}
+
+#[test]
+fn test_ord_nan() {
+    let nan = 0.0f64 / 0.0;
+    let n = list_from(&[nan]);
+    let m = list_from(&[nan]);
+    assert!(!(n < m));
+    assert!(!(n > m));
+    assert!(!(n <= m));
+    assert!(!(n >= m));
+
+    let n = list_from(&[nan]);
+    let one = list_from(&[1.0f64]);
+    assert!(!(n < one));
+    assert!(!(n > one));
+    assert!(!(n <= one));
+    assert!(!(n >= one));
+
+    let u = list_from(&[1.0f64, 2.0, nan]);
+    let v = list_from(&[1.0f64, 2.0, 3.0]);
+    assert!(!(u < v));
+    assert!(!(u > v));
+    assert!(!(u <= v));
+    assert!(!(u >= v));
+
+    let s = list_from(&[1.0f64, 2.0, 4.0, 2.0]);
+    let t = list_from(&[1.0f64, 2.0, 3.0, 2.0]);
+    assert!(!(s < t));
+    assert!(s > one);
+    assert!(!(s <= one));
+    assert!(s >= one);
 }
 
 #[test]
@@ -215,6 +424,62 @@ fn test_split_off() {
     }
 }
 
+#[test]
+fn test_split_off_2() {
+    // singleton
+    {
+        let mut m = LinkedList::new();
+        m.push_back(1);
+
+        let p = m.split_off(0);
+        assert_eq!(m.len(), 0);
+        assert_eq!(p.len(), 1);
+        assert_eq!(p.back(), Some(&1));
+        assert_eq!(p.front(), Some(&1));
+    }
+
+    // not singleton, forwards
+    {
+        let u = vec![1, 2, 3, 4, 5];
+        let mut m = list_from(&u);
+        let mut n = m.split_off(2);
+        assert_eq!(m.len(), 2);
+        assert_eq!(n.len(), 3);
+        for elt in 1..3 {
+            assert_eq!(m.pop_front(), Some(elt));
+        }
+        for elt in 3..6 {
+            assert_eq!(n.pop_front(), Some(elt));
+        }
+    }
+    // not singleton, backwards
+    {
+        let u = vec![1, 2, 3, 4, 5];
+        let mut m = list_from(&u);
+        let mut n = m.split_off(4);
+        assert_eq!(m.len(), 4);
+        assert_eq!(n.len(), 1);
+        for elt in 1..5 {
+            assert_eq!(m.pop_front(), Some(elt));
+        }
+        for elt in 5..6 {
+            assert_eq!(n.pop_front(), Some(elt));
+        }
+    }
+
+    // no-op on the last index
+    {
+        let mut m = LinkedList::new();
+        m.push_back(1);
+
+        let p = m.split_off(1);
+        assert_eq!(m.len(), 1);
+        assert_eq!(p.len(), 0);
+        assert_eq!(m.back(), Some(&1));
+        assert_eq!(m.front(), Some(&1));
+    }
+}
+
 fn fuzz_test(sz: i32) {
     let mut m: LinkedList<_> = LinkedList::new();
     let mut v = vec![];
@@ -253,6 +518,25 @@ fn fuzz_test(sz: i32) {
     assert_eq!(i, v.len());
 }
 
+#[test]
+fn test_fuzz() {
+    for _ in 0..25 {
+        fuzz_test(3);
+        fuzz_test(16);
+        #[cfg(not(miri))] // Miri is too slow
+        fuzz_test(189);
+    }
+}
+
+#[test]
+fn test_show() {
+    let list: LinkedList<_> = (0..10).collect();
+    assert_eq!(format!("{list:?}"), "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]");
+
+    let list: LinkedList<_> = ["just", "one", "test", "more"].into_iter().collect();
+    assert_eq!(format!("{list:?}"), "[\"just\", \"one\", \"test\", \"more\"]");
+}
+
 #[test]
 fn drain_filter_test() {
     let mut m: LinkedList<u32> = LinkedList::new();
@@ -475,3 +759,398 @@ fn test_cursor_pop_front_back() {
     assert_eq!(c.current(), None);
     assert_eq!(c.index, 2);
 }
+
+#[test]
+fn test_extend_ref() {
+    let mut a = LinkedList::new();
+    a.push_back(1);
+
+    a.extend(&[2, 3, 4]);
+
+    assert_eq!(a.len(), 4);
+    assert_eq!(a, list_from(&[1, 2, 3, 4]));
+
+    let mut b = LinkedList::new();
+    b.push_back(5);
+    b.push_back(6);
+    a.extend(&b);
+
+    assert_eq!(a.len(), 6);
+    assert_eq!(a, list_from(&[1, 2, 3, 4, 5, 6]));
+}
+
+#[test]
+fn test_extend() {
+    let mut a = LinkedList::new();
+    a.push_back(1);
+    a.extend(vec![2, 3, 4]); // uses iterator
+
+    assert_eq!(a.len(), 4);
+    assert!(a.iter().eq(&[1, 2, 3, 4]));
+
+    let b: LinkedList<_> = [5, 6, 7].into_iter().collect();
+    a.extend(b); // specializes to `append`
+
+    assert_eq!(a.len(), 7);
+    assert!(a.iter().eq(&[1, 2, 3, 4, 5, 6, 7]));
+}
+
+#[test]
+fn test_contains() {
+    let mut l = LinkedList::new();
+    l.extend(&[2, 3, 4]);
+
+    assert!(l.contains(&3));
+    assert!(!l.contains(&1));
+
+    l.clear();
+
+    assert!(!l.contains(&3));
+}
+
+#[test]
+fn drain_filter_empty() {
+    let mut list: LinkedList<i32> = LinkedList::new();
+
+    {
+        let mut iter = list.drain_filter(|_| true);
+        assert_eq!(iter.size_hint(), (0, Some(0)));
+        assert_eq!(iter.next(), None);
+        assert_eq!(iter.size_hint(), (0, Some(0)));
+        assert_eq!(iter.next(), None);
+        assert_eq!(iter.size_hint(), (0, Some(0)));
+    }
+
+    assert_eq!(list.len(), 0);
+    assert_eq!(list.into_iter().collect::<Vec<_>>(), vec![]);
+}
+
+#[test]
+fn drain_filter_zst() {
+    let mut list: LinkedList<_> = [(), (), (), (), ()].into_iter().collect();
+    let initial_len = list.len();
+    let mut count = 0;
+
+    {
+        let mut iter = list.drain_filter(|_| true);
+        assert_eq!(iter.size_hint(), (0, Some(initial_len)));
+        while let Some(_) = iter.next() {
+            count += 1;
+            assert_eq!(iter.size_hint(), (0, Some(initial_len - count)));
+        }
+        assert_eq!(iter.size_hint(), (0, Some(0)));
+        assert_eq!(iter.next(), None);
+        assert_eq!(iter.size_hint(), (0, Some(0)));
+    }
+
+    assert_eq!(count, initial_len);
+    assert_eq!(list.len(), 0);
+    assert_eq!(list.into_iter().collect::<Vec<_>>(), vec![]);
+}
+
+#[test]
+fn drain_filter_false() {
+    let mut list: LinkedList<_> = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
+
+    let initial_len = list.len();
+    let mut count = 0;
+
+    {
+        let mut iter = list.drain_filter(|_| false);
+        assert_eq!(iter.size_hint(), (0, Some(initial_len)));
+        for _ in iter.by_ref() {
+            count += 1;
+        }
+        assert_eq!(iter.size_hint(), (0, Some(0)));
+        assert_eq!(iter.next(), None);
+        assert_eq!(iter.size_hint(), (0, Some(0)));
+    }
+
+    assert_eq!(count, 0);
+    assert_eq!(list.len(), initial_len);
+    assert_eq!(list.into_iter().collect::<Vec<_>>(), vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
+}
+
+#[test]
+fn drain_filter_true() {
+    let mut list: LinkedList<_> = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
+
+    let initial_len = list.len();
+    let mut count = 0;
+
+    {
+        let mut iter = list.drain_filter(|_| true);
+        assert_eq!(iter.size_hint(), (0, Some(initial_len)));
+        while let Some(_) = iter.next() {
+            count += 1;
+            assert_eq!(iter.size_hint(), (0, Some(initial_len - count)));
+        }
+        assert_eq!(iter.size_hint(), (0, Some(0)));
+        assert_eq!(iter.next(), None);
+        assert_eq!(iter.size_hint(), (0, Some(0)));
+    }
+
+    assert_eq!(count, initial_len);
+    assert_eq!(list.len(), 0);
+    assert_eq!(list.into_iter().collect::<Vec<_>>(), vec![]);
+}
+
+#[test]
+fn drain_filter_complex() {
+    {
+        //                [+xxx++++++xxxxx++++x+x++]
+        let mut list = [
+            1, 2, 4, 6, 7, 9, 11, 13, 15, 17, 18, 20, 22, 24, 26, 27, 29, 31, 33, 34, 35, 36, 37,
+            39,
+        ]
+        .into_iter()
+        .collect::<LinkedList<_>>();
+
+        let removed = list.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
+        assert_eq!(removed.len(), 10);
+        assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]);
+
+        assert_eq!(list.len(), 14);
+        assert_eq!(
+            list.into_iter().collect::<Vec<_>>(),
+            vec![1, 7, 9, 11, 13, 15, 17, 27, 29, 31, 33, 35, 37, 39]
+        );
+    }
+
+    {
+        // [xxx++++++xxxxx++++x+x++]
+        let mut list =
+            [2, 4, 6, 7, 9, 11, 13, 15, 17, 18, 20, 22, 24, 26, 27, 29, 31, 33, 34, 35, 36, 37, 39]
+                .into_iter()
+                .collect::<LinkedList<_>>();
+
+        let removed = list.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
+        assert_eq!(removed.len(), 10);
+        assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]);
+
+        assert_eq!(list.len(), 13);
+        assert_eq!(
+            list.into_iter().collect::<Vec<_>>(),
+            vec![7, 9, 11, 13, 15, 17, 27, 29, 31, 33, 35, 37, 39]
+        );
+    }
+
+    {
+        // [xxx++++++xxxxx++++x+x]
+        let mut list =
+            [2, 4, 6, 7, 9, 11, 13, 15, 17, 18, 20, 22, 24, 26, 27, 29, 31, 33, 34, 35, 36]
+                .into_iter()
+                .collect::<LinkedList<_>>();
+
+        let removed = list.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
+        assert_eq!(removed.len(), 10);
+        assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]);
+
+        assert_eq!(list.len(), 11);
+        assert_eq!(
+            list.into_iter().collect::<Vec<_>>(),
+            vec![7, 9, 11, 13, 15, 17, 27, 29, 31, 33, 35]
+        );
+    }
+
+    {
+        // [xxxxxxxxxx+++++++++++]
+        let mut list = [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
+            .into_iter()
+            .collect::<LinkedList<_>>();
+
+        let removed = list.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
+        assert_eq!(removed.len(), 10);
+        assert_eq!(removed, vec![2, 4, 6, 8, 10, 12, 14, 16, 18, 20]);
+
+        assert_eq!(list.len(), 10);
+        assert_eq!(list.into_iter().collect::<Vec<_>>(), vec![1, 3, 5, 7, 9, 11, 13, 15, 17, 19]);
+    }
+
+    {
+        // [+++++++++++xxxxxxxxxx]
+        let mut list = [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
+            .into_iter()
+            .collect::<LinkedList<_>>();
+
+        let removed = list.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
+        assert_eq!(removed.len(), 10);
+        assert_eq!(removed, vec![2, 4, 6, 8, 10, 12, 14, 16, 18, 20]);
+
+        assert_eq!(list.len(), 10);
+        assert_eq!(list.into_iter().collect::<Vec<_>>(), vec![1, 3, 5, 7, 9, 11, 13, 15, 17, 19]);
+    }
+}
+
+#[test]
+fn drain_filter_drop_panic_leak() {
+    static mut DROPS: i32 = 0;
+
+    struct D(bool);
+
+    impl Drop for D {
+        fn drop(&mut self) {
+            unsafe {
+                DROPS += 1;
+            }
+
+            if self.0 {
+                panic!("panic in `drop`");
+            }
+        }
+    }
+
+    let mut q = LinkedList::new();
+    q.push_back(D(false));
+    q.push_back(D(false));
+    q.push_back(D(false));
+    q.push_back(D(false));
+    q.push_back(D(false));
+    q.push_front(D(false));
+    q.push_front(D(true));
+    q.push_front(D(false));
+
+    catch_unwind(AssertUnwindSafe(|| drop(q.drain_filter(|_| true)))).ok();
+
+    assert_eq!(unsafe { DROPS }, 8);
+    assert!(q.is_empty());
+}
+
+#[test]
+fn drain_filter_pred_panic_leak() {
+    static mut DROPS: i32 = 0;
+
+    #[derive(Debug)]
+    struct D(u32);
+
+    impl Drop for D {
+        fn drop(&mut self) {
+            unsafe {
+                DROPS += 1;
+            }
+        }
+    }
+
+    let mut q = LinkedList::new();
+    q.push_back(D(3));
+    q.push_back(D(4));
+    q.push_back(D(5));
+    q.push_back(D(6));
+    q.push_back(D(7));
+    q.push_front(D(2));
+    q.push_front(D(1));
+    q.push_front(D(0));
+
+    catch_unwind(AssertUnwindSafe(|| {
+        drop(q.drain_filter(|item| if item.0 >= 2 { panic!() } else { true }))
+    }))
+    .ok();
+
+    assert_eq!(unsafe { DROPS }, 2); // 0 and 1
+    assert_eq!(q.len(), 6);
+}
+
+#[test]
+fn test_drop() {
+    static mut DROPS: i32 = 0;
+    struct Elem;
+    impl Drop for Elem {
+        fn drop(&mut self) {
+            unsafe {
+                DROPS += 1;
+            }
+        }
+    }
+
+    let mut ring = LinkedList::new();
+    ring.push_back(Elem);
+    ring.push_front(Elem);
+    ring.push_back(Elem);
+    ring.push_front(Elem);
+    drop(ring);
+
+    assert_eq!(unsafe { DROPS }, 4);
+}
+
+#[test]
+fn test_drop_with_pop() {
+    static mut DROPS: i32 = 0;
+    struct Elem;
+    impl Drop for Elem {
+        fn drop(&mut self) {
+            unsafe {
+                DROPS += 1;
+            }
+        }
+    }
+
+    let mut ring = LinkedList::new();
+    ring.push_back(Elem);
+    ring.push_front(Elem);
+    ring.push_back(Elem);
+    ring.push_front(Elem);
+
+    drop(ring.pop_back());
+    drop(ring.pop_front());
+    assert_eq!(unsafe { DROPS }, 2);
+
+    drop(ring);
+    assert_eq!(unsafe { DROPS }, 4);
+}
+
+#[test]
+fn test_drop_clear() {
+    static mut DROPS: i32 = 0;
+    struct Elem;
+    impl Drop for Elem {
+        fn drop(&mut self) {
+            unsafe {
+                DROPS += 1;
+            }
+        }
+    }
+
+    let mut ring = LinkedList::new();
+    ring.push_back(Elem);
+    ring.push_front(Elem);
+    ring.push_back(Elem);
+    ring.push_front(Elem);
+    ring.clear();
+    assert_eq!(unsafe { DROPS }, 4);
+
+    drop(ring);
+    assert_eq!(unsafe { DROPS }, 4);
+}
+
+#[test]
+fn test_drop_panic() {
+    static mut DROPS: i32 = 0;
+
+    struct D(bool);
+
+    impl Drop for D {
+        fn drop(&mut self) {
+            unsafe {
+                DROPS += 1;
+            }
+
+            if self.0 {
+                panic!("panic in `drop`");
+            }
+        }
+    }
+
+    let mut q = LinkedList::new();
+    q.push_back(D(false));
+    q.push_back(D(false));
+    q.push_back(D(false));
+    q.push_back(D(false));
+    q.push_back(D(false));
+    q.push_front(D(false));
+    q.push_front(D(false));
+    q.push_front(D(true));
+
+    catch_unwind(move || drop(q)).ok();
+
+    assert_eq!(unsafe { DROPS }, 8);
+}
index 488671d8d8d19b7fbf1ab6129ec934969e37dc41..5f1a6848ae62a324c2f410e58b15797ecb808653 100644 (file)
 
 mod ring_slices;
 
+use self::spec_extend::SpecExtend;
+
+mod spec_extend;
+
 #[cfg(test)]
 mod tests;
 
@@ -1342,6 +1346,12 @@ pub fn clear(&mut self) {
     /// Returns `true` if the deque contains an element equal to the
     /// given value.
     ///
+    /// This operation is *O*(*n*).
+    ///
+    /// Note that if you have a sorted `VecDeque`, [`binary_search`] may be faster.
+    ///
+    /// [`binary_search`]: VecDeque::binary_search
+    ///
     /// # Examples
     ///
     /// ```
@@ -2560,7 +2570,8 @@ unsafe fn rotate_right_inner(&mut self, k: usize) {
         }
     }
 
-    /// Binary searches the sorted deque for a given element.
+    /// Binary searches this `VecDeque` for a given element.
+    /// This behaves similarly to [`contains`] if this `VecDeque` is sorted.
     ///
     /// If the value is found then [`Result::Ok`] is returned, containing the
     /// index of the matching element. If there are multiple matches, then any
@@ -2570,6 +2581,7 @@ unsafe fn rotate_right_inner(&mut self, k: usize) {
     ///
     /// See also [`binary_search_by`], [`binary_search_by_key`], and [`partition_point`].
     ///
+    /// [`contains`]: VecDeque::contains
     /// [`binary_search_by`]: VecDeque::binary_search_by
     /// [`binary_search_by_key`]: VecDeque::binary_search_by_key
     /// [`partition_point`]: VecDeque::partition_point
@@ -2614,7 +2626,8 @@ pub fn binary_search(&self, x: &T) -> Result<usize, usize>
         self.binary_search_by(|e| e.cmp(x))
     }
 
-    /// Binary searches the sorted deque with a comparator function.
+    /// Binary searches this `VecDeque` with a comparator function.
+    /// This behaves similarly to [`contains`] if this `VecDeque` is sorted.
     ///
     /// The comparator function should implement an order consistent
     /// with the sort order of the deque, returning an order code that
@@ -2629,6 +2642,7 @@ pub fn binary_search(&self, x: &T) -> Result<usize, usize>
     ///
     /// See also [`binary_search`], [`binary_search_by_key`], and [`partition_point`].
     ///
+    /// [`contains`]: VecDeque::contains
     /// [`binary_search`]: VecDeque::binary_search
     /// [`binary_search_by_key`]: VecDeque::binary_search_by_key
     /// [`partition_point`]: VecDeque::partition_point
@@ -2667,7 +2681,8 @@ pub fn binary_search_by<'a, F>(&'a self, mut f: F) -> Result<usize, usize>
         }
     }
 
-    /// Binary searches the sorted deque with a key extraction function.
+    /// Binary searches this `VecDeque` with a key extraction function.
+    /// This behaves similarly to [`contains`] if this `VecDeque` is sorted.
     ///
     /// Assumes that the deque is sorted by the key, for instance with
     /// [`make_contiguous().sort_by_key()`] using the same key extraction function.
@@ -2680,6 +2695,7 @@ pub fn binary_search_by<'a, F>(&'a self, mut f: F) -> Result<usize, usize>
     ///
     /// See also [`binary_search`], [`binary_search_by`], and [`partition_point`].
     ///
+    /// [`contains`]: VecDeque::contains
     /// [`make_contiguous().sort_by_key()`]: VecDeque::make_contiguous
     /// [`binary_search`]: VecDeque::binary_search
     /// [`binary_search_by`]: VecDeque::binary_search_by
@@ -2958,24 +2974,7 @@ fn into_iter(self) -> IterMut<'a, T> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T, A: Allocator> Extend<T> for VecDeque<T, A> {
     fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
-        // This function should be the moral equivalent of:
-        //
-        //      for item in iter.into_iter() {
-        //          self.push_back(item);
-        //      }
-        let mut iter = iter.into_iter();
-        while let Some(element) = iter.next() {
-            if self.len() == self.capacity() {
-                let (lower, _) = iter.size_hint();
-                self.reserve(lower.saturating_add(1));
-            }
-
-            let head = self.head;
-            self.head = self.wrap_add(self.head, 1);
-            unsafe {
-                self.buffer_write(head, element);
-            }
-        }
+        <Self as SpecExtend<T, I::IntoIter>>::spec_extend(self, iter.into_iter());
     }
 
     #[inline]
@@ -2992,7 +2991,7 @@ fn extend_reserve(&mut self, additional: usize) {
 #[stable(feature = "extend_ref", since = "1.2.0")]
 impl<'a, T: 'a + Copy, A: Allocator> Extend<&'a T> for VecDeque<T, A> {
     fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
-        self.extend(iter.into_iter().cloned());
+        self.spec_extend(iter.into_iter());
     }
 
     #[inline]
diff --git a/library/alloc/src/collections/vec_deque/spec_extend.rs b/library/alloc/src/collections/vec_deque/spec_extend.rs
new file mode 100644 (file)
index 0000000..172f2e9
--- /dev/null
@@ -0,0 +1,73 @@
+use crate::alloc::Allocator;
+use crate::vec;
+use core::slice;
+
+use super::VecDeque;
+
+// Specialization trait used for VecDeque::extend
+pub(super) trait SpecExtend<T, I> {
+    fn spec_extend(&mut self, iter: I);
+}
+
+impl<T, I, A: Allocator> SpecExtend<T, I> for VecDeque<T, A>
+where
+    I: Iterator<Item = T>,
+{
+    default fn spec_extend(&mut self, mut iter: I) {
+        // This function should be the moral equivalent of:
+        //
+        //      for item in iter {
+        //          self.push_back(item);
+        //      }
+        while let Some(element) = iter.next() {
+            if self.len() == self.capacity() {
+                let (lower, _) = iter.size_hint();
+                self.reserve(lower.saturating_add(1));
+            }
+
+            let head = self.head;
+            self.head = self.wrap_add(self.head, 1);
+            unsafe {
+                self.buffer_write(head, element);
+            }
+        }
+    }
+}
+
+impl<T, A: Allocator> SpecExtend<T, vec::IntoIter<T>> for VecDeque<T, A> {
+    fn spec_extend(&mut self, mut iterator: vec::IntoIter<T>) {
+        let slice = iterator.as_slice();
+        self.reserve(slice.len());
+
+        unsafe {
+            self.copy_slice(self.head, slice);
+            self.head = self.wrap_add(self.head, slice.len());
+        }
+        iterator.forget_remaining_elements();
+    }
+}
+
+impl<'a, T: 'a, I, A: Allocator> SpecExtend<&'a T, I> for VecDeque<T, A>
+where
+    I: Iterator<Item = &'a T>,
+    T: Copy,
+{
+    default fn spec_extend(&mut self, iterator: I) {
+        self.spec_extend(iterator.copied())
+    }
+}
+
+impl<'a, T: 'a, A: Allocator> SpecExtend<&'a T, slice::Iter<'a, T>> for VecDeque<T, A>
+where
+    T: Copy,
+{
+    fn spec_extend(&mut self, iterator: slice::Iter<'a, T>) {
+        let slice = iterator.as_slice();
+        self.reserve(slice.len());
+
+        unsafe {
+            self.copy_slice(self.head, slice);
+            self.head = self.wrap_add(self.head, slice.len());
+        }
+    }
+}
index 2be83f68f017f280b50a910b05987c924e161d58..f2869a54713d29d70eb9c6f90189ad9cab8c23c9 100644 (file)
@@ -162,6 +162,300 @@ fn test_insert() {
     }
 }
 
+#[test]
+fn test_get() {
+    let mut tester = VecDeque::new();
+    tester.push_back(1);
+    tester.push_back(2);
+    tester.push_back(3);
+
+    assert_eq!(tester.len(), 3);
+
+    assert_eq!(tester.get(1), Some(&2));
+    assert_eq!(tester.get(2), Some(&3));
+    assert_eq!(tester.get(0), Some(&1));
+    assert_eq!(tester.get(3), None);
+
+    tester.remove(0);
+
+    assert_eq!(tester.len(), 2);
+    assert_eq!(tester.get(0), Some(&2));
+    assert_eq!(tester.get(1), Some(&3));
+    assert_eq!(tester.get(2), None);
+}
+
+#[test]
+fn test_get_mut() {
+    let mut tester = VecDeque::new();
+    tester.push_back(1);
+    tester.push_back(2);
+    tester.push_back(3);
+
+    assert_eq!(tester.len(), 3);
+
+    if let Some(elem) = tester.get_mut(0) {
+        assert_eq!(*elem, 1);
+        *elem = 10;
+    }
+
+    if let Some(elem) = tester.get_mut(2) {
+        assert_eq!(*elem, 3);
+        *elem = 30;
+    }
+
+    assert_eq!(tester.get(0), Some(&10));
+    assert_eq!(tester.get(2), Some(&30));
+    assert_eq!(tester.get_mut(3), None);
+
+    tester.remove(2);
+
+    assert_eq!(tester.len(), 2);
+    assert_eq!(tester.get(0), Some(&10));
+    assert_eq!(tester.get(1), Some(&2));
+    assert_eq!(tester.get(2), None);
+}
+
+#[test]
+fn test_swap() {
+    let mut tester = VecDeque::new();
+    tester.push_back(1);
+    tester.push_back(2);
+    tester.push_back(3);
+
+    assert_eq!(tester, [1, 2, 3]);
+
+    tester.swap(0, 0);
+    assert_eq!(tester, [1, 2, 3]);
+    tester.swap(0, 1);
+    assert_eq!(tester, [2, 1, 3]);
+    tester.swap(2, 1);
+    assert_eq!(tester, [2, 3, 1]);
+    tester.swap(1, 2);
+    assert_eq!(tester, [2, 1, 3]);
+    tester.swap(0, 2);
+    assert_eq!(tester, [3, 1, 2]);
+    tester.swap(2, 2);
+    assert_eq!(tester, [3, 1, 2]);
+}
+
+#[test]
+#[should_panic = "assertion failed: j < self.len()"]
+fn test_swap_panic() {
+    let mut tester = VecDeque::new();
+    tester.push_back(1);
+    tester.push_back(2);
+    tester.push_back(3);
+    tester.swap(2, 3);
+}
+
+#[test]
+fn test_reserve_exact() {
+    let mut tester: VecDeque<i32> = VecDeque::with_capacity(1);
+    assert!(tester.capacity() == 1);
+    tester.reserve_exact(50);
+    assert!(tester.capacity() >= 51);
+    tester.reserve_exact(40);
+    assert!(tester.capacity() >= 51);
+    tester.reserve_exact(200);
+    assert!(tester.capacity() >= 200);
+}
+
+#[test]
+#[should_panic = "capacity overflow"]
+fn test_reserve_exact_panic() {
+    let mut tester: VecDeque<i32> = VecDeque::new();
+    tester.reserve_exact(usize::MAX);
+}
+
+#[test]
+fn test_try_reserve_exact() {
+    let mut tester: VecDeque<i32> = VecDeque::with_capacity(1);
+    assert!(tester.capacity() == 1);
+    assert_eq!(tester.try_reserve_exact(100), Ok(()));
+    assert!(tester.capacity() >= 100);
+    assert_eq!(tester.try_reserve_exact(50), Ok(()));
+    assert!(tester.capacity() >= 100);
+    assert_eq!(tester.try_reserve_exact(200), Ok(()));
+    assert!(tester.capacity() >= 200);
+    assert_eq!(tester.try_reserve_exact(0), Ok(()));
+    assert!(tester.capacity() >= 200);
+    assert!(tester.try_reserve_exact(usize::MAX).is_err());
+}
+
+#[test]
+fn test_try_reserve() {
+    let mut tester: VecDeque<i32> = VecDeque::with_capacity(1);
+    assert!(tester.capacity() == 1);
+    assert_eq!(tester.try_reserve(100), Ok(()));
+    assert!(tester.capacity() >= 100);
+    assert_eq!(tester.try_reserve(50), Ok(()));
+    assert!(tester.capacity() >= 100);
+    assert_eq!(tester.try_reserve(200), Ok(()));
+    assert!(tester.capacity() >= 200);
+    assert_eq!(tester.try_reserve(0), Ok(()));
+    assert!(tester.capacity() >= 200);
+    assert!(tester.try_reserve(usize::MAX).is_err());
+}
+
+#[test]
+fn test_contains() {
+    let mut tester = VecDeque::new();
+    tester.push_back(1);
+    tester.push_back(2);
+    tester.push_back(3);
+
+    assert!(tester.contains(&1));
+    assert!(tester.contains(&3));
+    assert!(!tester.contains(&0));
+    assert!(!tester.contains(&4));
+    tester.remove(0);
+    assert!(!tester.contains(&1));
+    assert!(tester.contains(&2));
+    assert!(tester.contains(&3));
+}
+
+#[test]
+fn test_rotate_left_right() {
+    let mut tester: VecDeque<_> = (1..=10).collect();
+
+    assert_eq!(tester.len(), 10);
+
+    tester.rotate_left(0);
+    assert_eq!(tester, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
+
+    tester.rotate_right(0);
+    assert_eq!(tester, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
+
+    tester.rotate_left(3);
+    assert_eq!(tester, [4, 5, 6, 7, 8, 9, 10, 1, 2, 3]);
+
+    tester.rotate_right(5);
+    assert_eq!(tester, [9, 10, 1, 2, 3, 4, 5, 6, 7, 8]);
+
+    tester.rotate_left(tester.len());
+    assert_eq!(tester, [9, 10, 1, 2, 3, 4, 5, 6, 7, 8]);
+
+    tester.rotate_right(tester.len());
+    assert_eq!(tester, [9, 10, 1, 2, 3, 4, 5, 6, 7, 8]);
+
+    tester.rotate_left(1);
+    assert_eq!(tester, [10, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
+}
+
+#[test]
+#[should_panic = "assertion failed: mid <= self.len()"]
+fn test_rotate_left_panic() {
+    let mut tester: VecDeque<_> = (1..=10).collect();
+    tester.rotate_left(tester.len() + 1);
+}
+
+#[test]
+#[should_panic = "assertion failed: k <= self.len()"]
+fn test_rotate_right_panic() {
+    let mut tester: VecDeque<_> = (1..=10).collect();
+    tester.rotate_right(tester.len() + 1);
+}
+
+#[test]
+fn test_binary_search() {
+    // If the givin VecDeque is not sorted, the returned result is unspecified and meaningless,
+    // as this method performs a binary search.
+
+    let tester: VecDeque<_> = [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into();
+
+    assert_eq!(tester.binary_search(&0), Ok(0));
+    assert_eq!(tester.binary_search(&5), Ok(5));
+    assert_eq!(tester.binary_search(&55), Ok(10));
+    assert_eq!(tester.binary_search(&4), Err(5));
+    assert_eq!(tester.binary_search(&-1), Err(0));
+    assert!(matches!(tester.binary_search(&1), Ok(1..=2)));
+
+    let tester: VecDeque<_> = [1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3].into();
+    assert_eq!(tester.binary_search(&1), Ok(0));
+    assert!(matches!(tester.binary_search(&2), Ok(1..=4)));
+    assert!(matches!(tester.binary_search(&3), Ok(5..=13)));
+    assert_eq!(tester.binary_search(&-2), Err(0));
+    assert_eq!(tester.binary_search(&0), Err(0));
+    assert_eq!(tester.binary_search(&4), Err(14));
+    assert_eq!(tester.binary_search(&5), Err(14));
+}
+
+#[test]
+fn test_binary_search_by() {
+    // If the givin VecDeque is not sorted, the returned result is unspecified and meaningless,
+    // as this method performs a binary search.
+
+    let tester: VecDeque<_> = [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into();
+
+    assert_eq!(tester.binary_search_by(|x| x.cmp(&0)), Ok(0));
+    assert_eq!(tester.binary_search_by(|x| x.cmp(&5)), Ok(5));
+    assert_eq!(tester.binary_search_by(|x| x.cmp(&55)), Ok(10));
+    assert_eq!(tester.binary_search_by(|x| x.cmp(&4)), Err(5));
+    assert_eq!(tester.binary_search_by(|x| x.cmp(&-1)), Err(0));
+    assert!(matches!(tester.binary_search_by(|x| x.cmp(&1)), Ok(1..=2)));
+}
+
+#[test]
+fn test_binary_search_key() {
+    // If the givin VecDeque is not sorted, the returned result is unspecified and meaningless,
+    // as this method performs a binary search.
+
+    let tester: VecDeque<_> = [
+        (-1, 0),
+        (2, 10),
+        (6, 5),
+        (7, 1),
+        (8, 10),
+        (10, 2),
+        (20, 3),
+        (24, 5),
+        (25, 18),
+        (28, 13),
+        (31, 21),
+        (32, 4),
+        (54, 25),
+    ]
+    .into();
+
+    assert_eq!(tester.binary_search_by_key(&-1, |&(a, _b)| a), Ok(0));
+    assert_eq!(tester.binary_search_by_key(&8, |&(a, _b)| a), Ok(4));
+    assert_eq!(tester.binary_search_by_key(&25, |&(a, _b)| a), Ok(8));
+    assert_eq!(tester.binary_search_by_key(&54, |&(a, _b)| a), Ok(12));
+    assert_eq!(tester.binary_search_by_key(&-2, |&(a, _b)| a), Err(0));
+    assert_eq!(tester.binary_search_by_key(&1, |&(a, _b)| a), Err(1));
+    assert_eq!(tester.binary_search_by_key(&4, |&(a, _b)| a), Err(2));
+    assert_eq!(tester.binary_search_by_key(&13, |&(a, _b)| a), Err(6));
+    assert_eq!(tester.binary_search_by_key(&55, |&(a, _b)| a), Err(13));
+    assert_eq!(tester.binary_search_by_key(&100, |&(a, _b)| a), Err(13));
+
+    let tester: VecDeque<_> = [
+        (0, 0),
+        (2, 1),
+        (6, 1),
+        (5, 1),
+        (3, 1),
+        (1, 2),
+        (2, 3),
+        (4, 5),
+        (5, 8),
+        (8, 13),
+        (1, 21),
+        (2, 34),
+        (4, 55),
+    ]
+    .into();
+
+    assert_eq!(tester.binary_search_by_key(&0, |&(_a, b)| b), Ok(0));
+    assert!(matches!(tester.binary_search_by_key(&1, |&(_a, b)| b), Ok(1..=4)));
+    assert_eq!(tester.binary_search_by_key(&8, |&(_a, b)| b), Ok(8));
+    assert_eq!(tester.binary_search_by_key(&13, |&(_a, b)| b), Ok(9));
+    assert_eq!(tester.binary_search_by_key(&55, |&(_a, b)| b), Ok(12));
+    assert_eq!(tester.binary_search_by_key(&-1, |&(_a, b)| b), Err(0));
+    assert_eq!(tester.binary_search_by_key(&4, |&(_a, b)| b), Err(7));
+    assert_eq!(tester.binary_search_by_key(&56, |&(_a, b)| b), Err(13));
+    assert_eq!(tester.binary_search_by_key(&100, |&(_a, b)| b), Err(13));
+}
+
 #[test]
 fn make_contiguous_big_tail() {
     let mut tester = VecDeque::with_capacity(15);
index 501a6353b2c97ae9797ce572e5997ffd0ba0b5d0..73b75ea4d83d5baff277aa164d5b8e2096d1d96a 100644 (file)
 //!
 //! 3. An asterisk `.*`:
 //!
-//!    `.*` means that this `{...}` is associated with *two* format inputs rather than one: the
-//!    first input holds the `usize` precision, and the second holds the value to print. Note that
-//!    in this case, if one uses the format string `{<arg>:<spec>.*}`, then the `<arg>` part refers
-//!    to the *value* to print, and the `precision` must come in the input preceding `<arg>`.
+//!    `.*` means that this `{...}` is associated with *two* format inputs rather than one:
+//!    - If a format string in the fashion of `{:<spec>.*}` is used, then the first input holds
+//!      the `usize` precision, and the second holds the value to print.
+//!    - If a format string in the fashion of `{<arg>:<spec>.*}` is used, then the `<arg>` part
+//!      refers to the value to print, and the `precision` is taken like it was specified with an
+//!      omitted positional parameter (`{}` instead of `{<arg>:}`).
 //!
 //! For example, the following calls all print the same thing `Hello x is 0.01000`:
 //!
 //! // Hello {arg 0 ("x")} is {arg 2 (0.01) with precision specified in arg 1 (5)}
 //! println!("Hello {0} is {2:.1$}", "x", 5, 0.01);
 //!
-//! // Hello {next arg ("x")} is {second of next two args (0.01) with precision
-//! //                          specified in first of next two args (5)}
+//! // Hello {next arg -> arg 0 ("x")} is {second of next two args -> arg 2 (0.01) with precision
+//! //                          specified in first of next two args -> arg 1 (5)}
 //! println!("Hello {} is {:.*}",    "x", 5, 0.01);
 //!
-//! // Hello {next arg ("x")} is {arg 2 (0.01) with precision
-//! //                          specified in its predecessor (5)}
+//! // Hello {arg 1 ("x")} is {arg 2 (0.01) with precision
+//! //                          specified in next arg -> arg 0 (5)}
+//! println!("Hello {1} is {2:.*}",  5, "x", 0.01);
+//!
+//! // Hello {next arg -> arg 0 ("x")} is {arg 2 (0.01) with precision
+//! //                          specified in next arg -> arg 1 (5)}
 //! println!("Hello {} is {2:.*}",   "x", 5, 0.01);
 //!
-//! // Hello {next arg ("x")} is {arg "number" (0.01) with precision specified
+//! // Hello {next arg -> arg 0 ("x")} is {arg "number" (0.01) with precision specified
 //! //                          in arg "prec" (5)}
 //! println!("Hello {} is {number:.prec$}", "x", prec = 5, number = 0.01);
 //! ```
 //! ```text
 //! format_string := text [ maybe_format text ] *
 //! maybe_format := '{' '{' | '}' '}' | format
-//! format := '{' [ argument ] [ ':' format_spec ] '}'
+//! format := '{' [ argument ] [ ':' format_spec ] [ ws ] * '}'
 //! argument := integer | identifier
 //!
 //! format_spec := [[fill]align][sign]['#']['0'][width]['.' precision]type
 //! count := parameter | integer
 //! parameter := argument '$'
 //! ```
-//! In the above grammar, `text` must not contain any `'{'` or `'}'` characters.
+//! In the above grammar,
+//! - `text` must not contain any `'{'` or `'}'` characters,
+//! - `ws` is any character for which [`char::is_whitespace`] returns `true`, has no semantic
+//!   meaning and is completely optional,
+//! - `integer` is a decimal integer that may contain leading zeroes and
+//! - `identifier` is an `IDENTIFIER_OR_KEYWORD` (not an `IDENTIFIER`) as defined by the [Rust language reference](https://doc.rust-lang.org/reference/identifiers.html).
 //!
 //! # Formatting traits
 //!
 //! ```
 //!
 //! Your type will be passed as `self` by-reference, and then the function
-//! should emit output into the `f.buf` stream. It is up to each format trait
-//! implementation to correctly adhere to the requested formatting parameters.
-//! The values of these parameters will be listed in the fields of the
+//! should emit output into the Formatter `f` which implements `fmt::Write`. It is up to each
+//! format trait implementation to correctly adhere to the requested formatting parameters.
+//! The values of these parameters can be accessed with methods of the
 //! [`Formatter`] struct. In order to help with this, the [`Formatter`] struct also
 //! provides some helper methods.
 //!
 //!
 //! ```ignore (only-for-syntax-highlight)
 //! format!      // described above
-//! write!       // first argument is a &mut io::Write, the destination
+//! write!       // first argument is either a &mut io::Write or a &mut fmt::Write, the destination
 //! writeln!     // same as write but appends a newline
 //! print!       // the format string is printed to the standard output
 //! println!     // same as print but appends a newline
 //!
 //! ### `write!`
 //!
-//! This and [`writeln!`] are two macros which are used to emit the format string
+//! [`write!`] and [`writeln!`] are two macros which are used to emit the format string
 //! to a specified stream. This is used to prevent intermediate allocations of
 //! format strings and instead directly write the output. Under the hood, this
 //! function is actually invoking the [`write_fmt`] function defined on the
-//! [`std::io::Write`] trait. Example usage is:
+//! [`std::io::Write`] and the [`std::fmt::Write`] trait. Example usage is:
 //!
 //! ```
 //! # #![allow(unused_must_use)]
 //!
 //! ### `format_args!`
 //!
-//! This is a curious macro used to safely pass around
+//! [`format_args!`] is a curious macro used to safely pass around
 //! an opaque object describing the format string. This object
 //! does not require any heap allocations to create, and it only
 //! references information on the stack. Under the hood, all of
 //! [`to_string`]: crate::string::ToString::to_string "ToString::to_string"
 //! [`write_fmt`]: ../../std/io/trait.Write.html#method.write_fmt
 //! [`std::io::Write`]: ../../std/io/trait.Write.html
+//! [`std::fmt::Write`]: ../../std/fmt/trait.Write.html
 //! [`print!`]: ../../std/macro.print.html "print!"
 //! [`println!`]: ../../std/macro.println.html "println!"
 //! [`eprint!`]: ../../std/macro.eprint.html "eprint!"
 //! [`eprintln!`]: ../../std/macro.eprintln.html "eprintln!"
+//! [`format_args!`]: ../../std/macro.format_args.html "format_args!"
 //! [`fmt::Arguments`]: Arguments "fmt::Arguments"
 //! [`format`]: format() "fmt::format"
 
index a42f1c3b4bbae1cc154726eccf840b2d3d4af71f..4bcc78ae0f4b2df78e9c2ce586631666be80b88a 100644 (file)
@@ -1956,6 +1956,25 @@ fn from(cow: Cow<'a, B>) -> Rc<B> {
     }
 }
 
+#[stable(feature = "shared_from_str", since = "1.62.0")]
+impl From<Rc<str>> for Rc<[u8]> {
+    /// Converts a reference-counted string slice into a byte slice.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # use std::rc::Rc;
+    /// let string: Rc<str> = Rc::from("eggplant");
+    /// let bytes: Rc<[u8]> = Rc::from(string);
+    /// assert_eq!("eggplant".as_bytes(), bytes.as_ref());
+    /// ```
+    #[inline]
+    fn from(rc: Rc<str>) -> Self {
+        // SAFETY: `str` has the same layout as `[u8]`.
+        unsafe { Rc::from_raw(Rc::into_raw(rc) as *const [u8]) }
+    }
+}
+
 #[stable(feature = "boxed_slice_try_from", since = "1.43.0")]
 impl<T, const N: usize> TryFrom<Rc<[T]>> for Rc<[T; N]> {
     type Error = Rc<[T]>;
index e97c1637fd5a26fea0b4674e7e7de6419d363ac5..2272c5b7330dc872b0386646fecb655288061c1b 100644 (file)
@@ -770,7 +770,10 @@ pub fn into_raw_parts(self) -> (*mut u8, usize, usize) {
     /// * The first `length` bytes at `buf` need to be valid UTF-8.
     ///
     /// Violating these may cause problems like corrupting the allocator's
-    /// internal data structures.
+    /// internal data structures. For example, it is normally **not** safe to
+    /// build a `String` from a pointer to a C `char` array containing UTF-8
+    /// _unless_ you are certain that array was originally allocated by the
+    /// Rust standard library's allocator.
     ///
     /// The ownership of `buf` is effectively transferred to the
     /// `String` which may then deallocate, reallocate or change the
index a19999cd725807c9860b330aea502ec6d0dc3eb0..1e2caddcacb19ed5c0719e6932eda6d67ce657ad 100644 (file)
@@ -2556,6 +2556,25 @@ fn from(cow: Cow<'a, B>) -> Arc<B> {
     }
 }
 
+#[stable(feature = "shared_from_str", since = "1.62.0")]
+impl From<Arc<str>> for Arc<[u8]> {
+    /// Converts an atomically reference-counted string slice into a byte slice.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # use std::sync::Arc;
+    /// let string: Arc<str> = Arc::from("eggplant");
+    /// let bytes: Arc<[u8]> = Arc::from(string);
+    /// assert_eq!("eggplant".as_bytes(), bytes.as_ref());
+    /// ```
+    #[inline]
+    fn from(rc: Arc<str>) -> Self {
+        // SAFETY: `str` has the same layout as `[u8]`.
+        unsafe { Arc::from_raw(Arc::into_raw(rc) as *const [u8]) }
+    }
+}
+
 #[stable(feature = "boxed_slice_try_from", since = "1.43.0")]
 impl<T, const N: usize> TryFrom<Arc<[T]>> for Arc<[T; N]> {
     type Error = Arc<[T]>;
index 03c532bb69769d13e5fddf5dc3389d4ec6b7bc53..8134eea570ad722e347379b41973f4880e1b7abf 100644 (file)
@@ -121,6 +121,11 @@ pub(super) fn forget_allocation_drop_remaining(&mut self) {
             ptr::drop_in_place(remaining);
         }
     }
+
+    /// Forgets to Drop the remaining elements while still allowing the backing allocation to be freed.
+    pub(crate) fn forget_remaining_elements(&mut self) {
+        self.ptr = self.end;
+    }
 }
 
 #[stable(feature = "vec_intoiter_as_ref", since = "1.46.0")]
index 0efc4893c3c42847a696197a1a223687cd9f0741..edf270db81d4d8fb52339f8ac23162e15cb855b7 100644 (file)
@@ -2,7 +2,7 @@
 
 #[rustc_specialization_trait]
 pub(super) unsafe trait IsZero {
-    /// Whether this value is zero
+    /// Whether this value's representation is all zeros
     fn is_zero(&self) -> bool;
 }
 
@@ -49,6 +49,20 @@ fn is_zero(&self) -> bool {
     }
 }
 
+unsafe impl<T: IsZero, const N: usize> IsZero for [T; N] {
+    #[inline]
+    fn is_zero(&self) -> bool {
+        // Because this is generated as a runtime check, it's not obvious that
+        // it's worth doing if the array is really long.  The threshold here
+        // is largely arbitrary, but was picked because as of 2022-05-01 LLVM
+        // can const-fold the check in `vec![[0; 32]; n]` but not in
+        // `vec![[0; 64]; n]`: https://godbolt.org/z/WTzjzfs5b
+        // Feel free to tweak if you have better evidence.
+
+        N <= 32 && self.iter().all(IsZero::is_zero)
+    }
+}
+
 // `Option<&T>` and `Option<Box<T>>` are guaranteed to represent `None` as null.
 // For fat pointers, the bytes that would be the pointer metadata in the `Some`
 // variant are padding in the `None` variant, so ignoring them and
index 8c2f52172ee70d44286fdadb06d0b982694eae33..3dc8a4fbba86ba064926de4668fb25a3dfefba01 100644 (file)
@@ -489,8 +489,10 @@ pub fn with_capacity(capacity: usize) -> Self {
     /// * `length` needs to be less than or equal to `capacity`.
     ///
     /// Violating these may cause problems like corrupting the allocator's
-    /// internal data structures. For example it is **not** safe
-    /// to build a `Vec<u8>` from a pointer to a C `char` array with length `size_t`.
+    /// internal data structures. For example it is normally **not** safe
+    /// to build a `Vec<u8>` from a pointer to a C `char` array with length
+    /// `size_t`, doing so is only safe if the array was initially allocated by
+    /// a `Vec` or `String`.
     /// It's also not safe to build one from a `Vec<u16>` and its length, because
     /// the allocator cares about the alignment, and these two types have different
     /// alignments. The buffer was allocated with alignment 2 (for `u16`), but after
@@ -2987,48 +2989,6 @@ fn from(s: &mut [T]) -> Vec<T> {
     }
 }
 
-#[cfg(not(no_global_oom_handling))]
-#[stable(feature = "vec_from_array_ref", since = "1.61.0")]
-impl<T: Clone, const N: usize> From<&[T; N]> for Vec<T> {
-    /// Allocate a `Vec<T>` and fill it by cloning `s`'s items.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// assert_eq!(Vec::from(b"raw"), vec![b'r', b'a', b'w']);
-    /// ```
-    #[cfg(not(test))]
-    fn from(s: &[T; N]) -> Vec<T> {
-        s.to_vec()
-    }
-
-    #[cfg(test)]
-    fn from(s: &[T; N]) -> Vec<T> {
-        crate::slice::to_vec(s, Global)
-    }
-}
-
-#[cfg(not(no_global_oom_handling))]
-#[stable(feature = "vec_from_array_ref", since = "1.61.0")]
-impl<T: Clone, const N: usize> From<&mut [T; N]> for Vec<T> {
-    /// Allocate a `Vec<T>` and fill it by cloning `s`'s items.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// assert_eq!(Vec::from(&mut [1, 2, 3]), vec![1, 2, 3]);
-    /// ```
-    #[cfg(not(test))]
-    fn from(s: &mut [T; N]) -> Vec<T> {
-        s.to_vec()
-    }
-
-    #[cfg(test)]
-    fn from(s: &mut [T; N]) -> Vec<T> {
-        crate::slice::to_vec(s, Global)
-    }
-}
-
 #[stable(feature = "vec_from_cow_slice", since = "1.14.0")]
 impl<'a, T> From<Cow<'a, [T]>> for Vec<T>
 where
index c3b4534096de5f1c5a7171db69fd46f5f4bd7922..506ee0ecfa279c7693cc9a19e58d98a668425b7d 100644 (file)
@@ -62,7 +62,7 @@ fn spec_extend(&mut self, mut iterator: IntoIter<T>) {
         unsafe {
             self.append_elements(iterator.as_slice() as _);
         }
-        iterator.ptr = iterator.end;
+        iterator.forget_remaining_elements();
     }
 }
 
diff --git a/library/alloc/tests/binary_heap.rs b/library/alloc/tests/binary_heap.rs
deleted file mode 100644 (file)
index f32118b..0000000
+++ /dev/null
@@ -1,489 +0,0 @@
-use std::collections::binary_heap::{Drain, PeekMut};
-use std::collections::BinaryHeap;
-use std::iter::TrustedLen;
-use std::panic::{catch_unwind, AssertUnwindSafe};
-use std::sync::atomic::{AtomicU32, Ordering};
-
-#[test]
-fn test_iterator() {
-    let data = vec![5, 9, 3];
-    let iterout = [9, 5, 3];
-    let heap = BinaryHeap::from(data);
-    let mut i = 0;
-    for el in &heap {
-        assert_eq!(*el, iterout[i]);
-        i += 1;
-    }
-}
-
-#[test]
-fn test_iter_rev_cloned_collect() {
-    let data = vec![5, 9, 3];
-    let iterout = vec![3, 5, 9];
-    let pq = BinaryHeap::from(data);
-
-    let v: Vec<_> = pq.iter().rev().cloned().collect();
-    assert_eq!(v, iterout);
-}
-
-#[test]
-fn test_into_iter_collect() {
-    let data = vec![5, 9, 3];
-    let iterout = vec![9, 5, 3];
-    let pq = BinaryHeap::from(data);
-
-    let v: Vec<_> = pq.into_iter().collect();
-    assert_eq!(v, iterout);
-}
-
-#[test]
-fn test_into_iter_size_hint() {
-    let data = vec![5, 9];
-    let pq = BinaryHeap::from(data);
-
-    let mut it = pq.into_iter();
-
-    assert_eq!(it.size_hint(), (2, Some(2)));
-    assert_eq!(it.next(), Some(9));
-
-    assert_eq!(it.size_hint(), (1, Some(1)));
-    assert_eq!(it.next(), Some(5));
-
-    assert_eq!(it.size_hint(), (0, Some(0)));
-    assert_eq!(it.next(), None);
-}
-
-#[test]
-fn test_into_iter_rev_collect() {
-    let data = vec![5, 9, 3];
-    let iterout = vec![3, 5, 9];
-    let pq = BinaryHeap::from(data);
-
-    let v: Vec<_> = pq.into_iter().rev().collect();
-    assert_eq!(v, iterout);
-}
-
-#[test]
-fn test_into_iter_sorted_collect() {
-    let heap = BinaryHeap::from(vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]);
-    let it = heap.into_iter_sorted();
-    let sorted = it.collect::<Vec<_>>();
-    assert_eq!(sorted, vec![10, 9, 8, 7, 6, 5, 4, 3, 2, 2, 1, 1, 0]);
-}
-
-#[test]
-fn test_drain_sorted_collect() {
-    let mut heap = BinaryHeap::from(vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]);
-    let it = heap.drain_sorted();
-    let sorted = it.collect::<Vec<_>>();
-    assert_eq!(sorted, vec![10, 9, 8, 7, 6, 5, 4, 3, 2, 2, 1, 1, 0]);
-}
-
-fn check_exact_size_iterator<I: ExactSizeIterator>(len: usize, it: I) {
-    let mut it = it;
-
-    for i in 0..it.len() {
-        let (lower, upper) = it.size_hint();
-        assert_eq!(Some(lower), upper);
-        assert_eq!(lower, len - i);
-        assert_eq!(it.len(), len - i);
-        it.next();
-    }
-    assert_eq!(it.len(), 0);
-    assert!(it.is_empty());
-}
-
-#[test]
-fn test_exact_size_iterator() {
-    let heap = BinaryHeap::from(vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]);
-    check_exact_size_iterator(heap.len(), heap.iter());
-    check_exact_size_iterator(heap.len(), heap.clone().into_iter());
-    check_exact_size_iterator(heap.len(), heap.clone().into_iter_sorted());
-    check_exact_size_iterator(heap.len(), heap.clone().drain());
-    check_exact_size_iterator(heap.len(), heap.clone().drain_sorted());
-}
-
-fn check_trusted_len<I: TrustedLen>(len: usize, it: I) {
-    let mut it = it;
-    for i in 0..len {
-        let (lower, upper) = it.size_hint();
-        if upper.is_some() {
-            assert_eq!(Some(lower), upper);
-            assert_eq!(lower, len - i);
-        }
-        it.next();
-    }
-}
-
-#[test]
-fn test_trusted_len() {
-    let heap = BinaryHeap::from(vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]);
-    check_trusted_len(heap.len(), heap.clone().into_iter_sorted());
-    check_trusted_len(heap.len(), heap.clone().drain_sorted());
-}
-
-#[test]
-fn test_peek_and_pop() {
-    let data = vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1];
-    let mut sorted = data.clone();
-    sorted.sort();
-    let mut heap = BinaryHeap::from(data);
-    while !heap.is_empty() {
-        assert_eq!(heap.peek().unwrap(), sorted.last().unwrap());
-        assert_eq!(heap.pop().unwrap(), sorted.pop().unwrap());
-    }
-}
-
-#[test]
-fn test_peek_mut() {
-    let data = vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1];
-    let mut heap = BinaryHeap::from(data);
-    assert_eq!(heap.peek(), Some(&10));
-    {
-        let mut top = heap.peek_mut().unwrap();
-        *top -= 2;
-    }
-    assert_eq!(heap.peek(), Some(&9));
-}
-
-#[test]
-fn test_peek_mut_pop() {
-    let data = vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1];
-    let mut heap = BinaryHeap::from(data);
-    assert_eq!(heap.peek(), Some(&10));
-    {
-        let mut top = heap.peek_mut().unwrap();
-        *top -= 2;
-        assert_eq!(PeekMut::pop(top), 8);
-    }
-    assert_eq!(heap.peek(), Some(&9));
-}
-
-#[test]
-fn test_push() {
-    let mut heap = BinaryHeap::from(vec![2, 4, 9]);
-    assert_eq!(heap.len(), 3);
-    assert!(*heap.peek().unwrap() == 9);
-    heap.push(11);
-    assert_eq!(heap.len(), 4);
-    assert!(*heap.peek().unwrap() == 11);
-    heap.push(5);
-    assert_eq!(heap.len(), 5);
-    assert!(*heap.peek().unwrap() == 11);
-    heap.push(27);
-    assert_eq!(heap.len(), 6);
-    assert!(*heap.peek().unwrap() == 27);
-    heap.push(3);
-    assert_eq!(heap.len(), 7);
-    assert!(*heap.peek().unwrap() == 27);
-    heap.push(103);
-    assert_eq!(heap.len(), 8);
-    assert!(*heap.peek().unwrap() == 103);
-}
-
-#[test]
-fn test_push_unique() {
-    let mut heap = BinaryHeap::<Box<_>>::from(vec![box 2, box 4, box 9]);
-    assert_eq!(heap.len(), 3);
-    assert!(**heap.peek().unwrap() == 9);
-    heap.push(box 11);
-    assert_eq!(heap.len(), 4);
-    assert!(**heap.peek().unwrap() == 11);
-    heap.push(box 5);
-    assert_eq!(heap.len(), 5);
-    assert!(**heap.peek().unwrap() == 11);
-    heap.push(box 27);
-    assert_eq!(heap.len(), 6);
-    assert!(**heap.peek().unwrap() == 27);
-    heap.push(box 3);
-    assert_eq!(heap.len(), 7);
-    assert!(**heap.peek().unwrap() == 27);
-    heap.push(box 103);
-    assert_eq!(heap.len(), 8);
-    assert!(**heap.peek().unwrap() == 103);
-}
-
-fn check_to_vec(mut data: Vec<i32>) {
-    let heap = BinaryHeap::from(data.clone());
-    let mut v = heap.clone().into_vec();
-    v.sort();
-    data.sort();
-
-    assert_eq!(v, data);
-    assert_eq!(heap.into_sorted_vec(), data);
-}
-
-#[test]
-fn test_to_vec() {
-    check_to_vec(vec![]);
-    check_to_vec(vec![5]);
-    check_to_vec(vec![3, 2]);
-    check_to_vec(vec![2, 3]);
-    check_to_vec(vec![5, 1, 2]);
-    check_to_vec(vec![1, 100, 2, 3]);
-    check_to_vec(vec![1, 3, 5, 7, 9, 2, 4, 6, 8, 0]);
-    check_to_vec(vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]);
-    check_to_vec(vec![9, 11, 9, 9, 9, 9, 11, 2, 3, 4, 11, 9, 0, 0, 0, 0]);
-    check_to_vec(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
-    check_to_vec(vec![10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]);
-    check_to_vec(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 1, 2]);
-    check_to_vec(vec![5, 4, 3, 2, 1, 5, 4, 3, 2, 1, 5, 4, 3, 2, 1]);
-}
-
-#[test]
-fn test_in_place_iterator_specialization() {
-    let src: Vec<usize> = vec![1, 2, 3];
-    let src_ptr = src.as_ptr();
-    let heap: BinaryHeap<_> = src.into_iter().map(std::convert::identity).collect();
-    let heap_ptr = heap.iter().next().unwrap() as *const usize;
-    assert_eq!(src_ptr, heap_ptr);
-    let sink: Vec<_> = heap.into_iter().map(std::convert::identity).collect();
-    let sink_ptr = sink.as_ptr();
-    assert_eq!(heap_ptr, sink_ptr);
-}
-
-#[test]
-fn test_empty_pop() {
-    let mut heap = BinaryHeap::<i32>::new();
-    assert!(heap.pop().is_none());
-}
-
-#[test]
-fn test_empty_peek() {
-    let empty = BinaryHeap::<i32>::new();
-    assert!(empty.peek().is_none());
-}
-
-#[test]
-fn test_empty_peek_mut() {
-    let mut empty = BinaryHeap::<i32>::new();
-    assert!(empty.peek_mut().is_none());
-}
-
-#[test]
-fn test_from_iter() {
-    let xs = vec![9, 8, 7, 6, 5, 4, 3, 2, 1];
-
-    let mut q: BinaryHeap<_> = xs.iter().rev().cloned().collect();
-
-    for &x in &xs {
-        assert_eq!(q.pop().unwrap(), x);
-    }
-}
-
-#[test]
-fn test_drain() {
-    let mut q: BinaryHeap<_> = [9, 8, 7, 6, 5, 4, 3, 2, 1].iter().cloned().collect();
-
-    assert_eq!(q.drain().take(5).count(), 5);
-
-    assert!(q.is_empty());
-}
-
-#[test]
-fn test_drain_sorted() {
-    let mut q: BinaryHeap<_> = [9, 8, 7, 6, 5, 4, 3, 2, 1].iter().cloned().collect();
-
-    assert_eq!(q.drain_sorted().take(5).collect::<Vec<_>>(), vec![9, 8, 7, 6, 5]);
-
-    assert!(q.is_empty());
-}
-
-#[test]
-fn test_drain_sorted_leak() {
-    static DROPS: AtomicU32 = AtomicU32::new(0);
-
-    #[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
-    struct D(u32, bool);
-
-    impl Drop for D {
-        fn drop(&mut self) {
-            DROPS.fetch_add(1, Ordering::SeqCst);
-
-            if self.1 {
-                panic!("panic in `drop`");
-            }
-        }
-    }
-
-    let mut q = BinaryHeap::from(vec![
-        D(0, false),
-        D(1, false),
-        D(2, false),
-        D(3, true),
-        D(4, false),
-        D(5, false),
-    ]);
-
-    catch_unwind(AssertUnwindSafe(|| drop(q.drain_sorted()))).ok();
-
-    assert_eq!(DROPS.load(Ordering::SeqCst), 6);
-}
-
-#[test]
-fn test_extend_ref() {
-    let mut a = BinaryHeap::new();
-    a.push(1);
-    a.push(2);
-
-    a.extend(&[3, 4, 5]);
-
-    assert_eq!(a.len(), 5);
-    assert_eq!(a.into_sorted_vec(), [1, 2, 3, 4, 5]);
-
-    let mut a = BinaryHeap::new();
-    a.push(1);
-    a.push(2);
-    let mut b = BinaryHeap::new();
-    b.push(3);
-    b.push(4);
-    b.push(5);
-
-    a.extend(&b);
-
-    assert_eq!(a.len(), 5);
-    assert_eq!(a.into_sorted_vec(), [1, 2, 3, 4, 5]);
-}
-
-#[test]
-fn test_append() {
-    let mut a = BinaryHeap::from(vec![-10, 1, 2, 3, 3]);
-    let mut b = BinaryHeap::from(vec![-20, 5, 43]);
-
-    a.append(&mut b);
-
-    assert_eq!(a.into_sorted_vec(), [-20, -10, 1, 2, 3, 3, 5, 43]);
-    assert!(b.is_empty());
-}
-
-#[test]
-fn test_append_to_empty() {
-    let mut a = BinaryHeap::new();
-    let mut b = BinaryHeap::from(vec![-20, 5, 43]);
-
-    a.append(&mut b);
-
-    assert_eq!(a.into_sorted_vec(), [-20, 5, 43]);
-    assert!(b.is_empty());
-}
-
-#[test]
-fn test_extend_specialization() {
-    let mut a = BinaryHeap::from(vec![-10, 1, 2, 3, 3]);
-    let b = BinaryHeap::from(vec![-20, 5, 43]);
-
-    a.extend(b);
-
-    assert_eq!(a.into_sorted_vec(), [-20, -10, 1, 2, 3, 3, 5, 43]);
-}
-
-#[allow(dead_code)]
-fn assert_covariance() {
-    fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> {
-        d
-    }
-}
-
-#[test]
-fn test_retain() {
-    let mut a = BinaryHeap::from(vec![100, 10, 50, 1, 2, 20, 30]);
-    a.retain(|&x| x != 2);
-
-    // Check that 20 moved into 10's place.
-    assert_eq!(a.clone().into_vec(), [100, 20, 50, 1, 10, 30]);
-
-    a.retain(|_| true);
-
-    assert_eq!(a.clone().into_vec(), [100, 20, 50, 1, 10, 30]);
-
-    a.retain(|&x| x < 50);
-
-    assert_eq!(a.clone().into_vec(), [30, 20, 10, 1]);
-
-    a.retain(|_| false);
-
-    assert!(a.is_empty());
-}
-
-// old binaryheap failed this test
-//
-// Integrity means that all elements are present after a comparison panics,
-// even if the order might not be correct.
-//
-// Destructors must be called exactly once per element.
-// FIXME: re-enable emscripten once it can unwind again
-#[test]
-#[cfg(not(target_os = "emscripten"))]
-fn panic_safe() {
-    use rand::{seq::SliceRandom, thread_rng};
-    use std::cmp;
-    use std::panic::{self, AssertUnwindSafe};
-    use std::sync::atomic::{AtomicUsize, Ordering};
-
-    static DROP_COUNTER: AtomicUsize = AtomicUsize::new(0);
-
-    #[derive(Eq, PartialEq, Ord, Clone, Debug)]
-    struct PanicOrd<T>(T, bool);
-
-    impl<T> Drop for PanicOrd<T> {
-        fn drop(&mut self) {
-            // update global drop count
-            DROP_COUNTER.fetch_add(1, Ordering::SeqCst);
-        }
-    }
-
-    impl<T: PartialOrd> PartialOrd for PanicOrd<T> {
-        fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
-            if self.1 || other.1 {
-                panic!("Panicking comparison");
-            }
-            self.0.partial_cmp(&other.0)
-        }
-    }
-    let mut rng = thread_rng();
-    const DATASZ: usize = 32;
-    // Miri is too slow
-    let ntest = if cfg!(miri) { 1 } else { 10 };
-
-    // don't use 0 in the data -- we want to catch the zeroed-out case.
-    let data = (1..=DATASZ).collect::<Vec<_>>();
-
-    // since it's a fuzzy test, run several tries.
-    for _ in 0..ntest {
-        for i in 1..=DATASZ {
-            DROP_COUNTER.store(0, Ordering::SeqCst);
-
-            let mut panic_ords: Vec<_> =
-                data.iter().filter(|&&x| x != i).map(|&x| PanicOrd(x, false)).collect();
-            let panic_item = PanicOrd(i, true);
-
-            // heapify the sane items
-            panic_ords.shuffle(&mut rng);
-            let mut heap = BinaryHeap::from(panic_ords);
-            let inner_data;
-
-            {
-                // push the panicking item to the heap and catch the panic
-                let thread_result = {
-                    let mut heap_ref = AssertUnwindSafe(&mut heap);
-                    panic::catch_unwind(move || {
-                        heap_ref.push(panic_item);
-                    })
-                };
-                assert!(thread_result.is_err());
-
-                // Assert no elements were dropped
-                let drops = DROP_COUNTER.load(Ordering::SeqCst);
-                assert!(drops == 0, "Must not drop items. drops={}", drops);
-                inner_data = heap.clone().into_vec();
-                drop(heap);
-            }
-            let drops = DROP_COUNTER.load(Ordering::SeqCst);
-            assert_eq!(drops, DATASZ);
-
-            let mut data_sorted = inner_data.into_iter().map(|p| p.0).collect::<Vec<_>>();
-            data_sorted.sort();
-            assert_eq!(data_sorted, data);
-        }
-    }
-}
index 8fbb10e1d5cb6745e0d4f986782e3d653104e155..4a5817939567b8690b3841c9d611999bda8571d3 100644 (file)
@@ -1,5 +1,6 @@
 use std::borrow::Cow::{Borrowed, Owned};
-use std::ffi::{c_char, CStr};
+use std::ffi::CStr;
+use std::os::raw::c_char;
 
 #[test]
 fn to_str() {
index 8de159246c6e0693f6e60f19725e1ba6985f5252..601a87aa4ac899af12c2419fef3d1c2a67b0d106 100644 (file)
@@ -47,7 +47,6 @@
 use std::hash::{Hash, Hasher};
 
 mod arc;
-mod binary_heap;
 mod borrow;
 mod boxed;
 mod btree_set_hash;
index 66a9cca6644c41481c65fb0521f5692e9baa0ca9..65b09cb00c45ddeb06a951f9c7e2037178ed35d3 100644 (file)
@@ -1,241 +1,4 @@
 use std::collections::LinkedList;
-use std::panic::{catch_unwind, AssertUnwindSafe};
-
-#[test]
-fn test_basic() {
-    let mut m = LinkedList::<Box<_>>::new();
-    assert_eq!(m.pop_front(), None);
-    assert_eq!(m.pop_back(), None);
-    assert_eq!(m.pop_front(), None);
-    m.push_front(box 1);
-    assert_eq!(m.pop_front(), Some(box 1));
-    m.push_back(box 2);
-    m.push_back(box 3);
-    assert_eq!(m.len(), 2);
-    assert_eq!(m.pop_front(), Some(box 2));
-    assert_eq!(m.pop_front(), Some(box 3));
-    assert_eq!(m.len(), 0);
-    assert_eq!(m.pop_front(), None);
-    m.push_back(box 1);
-    m.push_back(box 3);
-    m.push_back(box 5);
-    m.push_back(box 7);
-    assert_eq!(m.pop_front(), Some(box 1));
-
-    let mut n = LinkedList::new();
-    n.push_front(2);
-    n.push_front(3);
-    {
-        assert_eq!(n.front().unwrap(), &3);
-        let x = n.front_mut().unwrap();
-        assert_eq!(*x, 3);
-        *x = 0;
-    }
-    {
-        assert_eq!(n.back().unwrap(), &2);
-        let y = n.back_mut().unwrap();
-        assert_eq!(*y, 2);
-        *y = 1;
-    }
-    assert_eq!(n.pop_front(), Some(0));
-    assert_eq!(n.pop_front(), Some(1));
-}
-
-fn generate_test() -> LinkedList<i32> {
-    list_from(&[0, 1, 2, 3, 4, 5, 6])
-}
-
-fn list_from<T: Clone>(v: &[T]) -> LinkedList<T> {
-    v.iter().cloned().collect()
-}
-
-#[test]
-fn test_split_off() {
-    // singleton
-    {
-        let mut m = LinkedList::new();
-        m.push_back(1);
-
-        let p = m.split_off(0);
-        assert_eq!(m.len(), 0);
-        assert_eq!(p.len(), 1);
-        assert_eq!(p.back(), Some(&1));
-        assert_eq!(p.front(), Some(&1));
-    }
-
-    // not singleton, forwards
-    {
-        let u = vec![1, 2, 3, 4, 5];
-        let mut m = list_from(&u);
-        let mut n = m.split_off(2);
-        assert_eq!(m.len(), 2);
-        assert_eq!(n.len(), 3);
-        for elt in 1..3 {
-            assert_eq!(m.pop_front(), Some(elt));
-        }
-        for elt in 3..6 {
-            assert_eq!(n.pop_front(), Some(elt));
-        }
-    }
-    // not singleton, backwards
-    {
-        let u = vec![1, 2, 3, 4, 5];
-        let mut m = list_from(&u);
-        let mut n = m.split_off(4);
-        assert_eq!(m.len(), 4);
-        assert_eq!(n.len(), 1);
-        for elt in 1..5 {
-            assert_eq!(m.pop_front(), Some(elt));
-        }
-        for elt in 5..6 {
-            assert_eq!(n.pop_front(), Some(elt));
-        }
-    }
-
-    // no-op on the last index
-    {
-        let mut m = LinkedList::new();
-        m.push_back(1);
-
-        let p = m.split_off(1);
-        assert_eq!(m.len(), 1);
-        assert_eq!(p.len(), 0);
-        assert_eq!(m.back(), Some(&1));
-        assert_eq!(m.front(), Some(&1));
-    }
-}
-
-#[test]
-fn test_iterator() {
-    let m = generate_test();
-    for (i, elt) in m.iter().enumerate() {
-        assert_eq!(i as i32, *elt);
-    }
-    let mut n = LinkedList::new();
-    assert_eq!(n.iter().next(), None);
-    n.push_front(4);
-    let mut it = n.iter();
-    assert_eq!(it.size_hint(), (1, Some(1)));
-    assert_eq!(it.next().unwrap(), &4);
-    assert_eq!(it.size_hint(), (0, Some(0)));
-    assert_eq!(it.next(), None);
-}
-
-#[test]
-fn test_iterator_clone() {
-    let mut n = LinkedList::new();
-    n.push_back(2);
-    n.push_back(3);
-    n.push_back(4);
-    let mut it = n.iter();
-    it.next();
-    let mut jt = it.clone();
-    assert_eq!(it.next(), jt.next());
-    assert_eq!(it.next_back(), jt.next_back());
-    assert_eq!(it.next(), jt.next());
-}
-
-#[test]
-fn test_iterator_double_end() {
-    let mut n = LinkedList::new();
-    assert_eq!(n.iter().next(), None);
-    n.push_front(4);
-    n.push_front(5);
-    n.push_front(6);
-    let mut it = n.iter();
-    assert_eq!(it.size_hint(), (3, Some(3)));
-    assert_eq!(it.next().unwrap(), &6);
-    assert_eq!(it.size_hint(), (2, Some(2)));
-    assert_eq!(it.next_back().unwrap(), &4);
-    assert_eq!(it.size_hint(), (1, Some(1)));
-    assert_eq!(it.next_back().unwrap(), &5);
-    assert_eq!(it.next_back(), None);
-    assert_eq!(it.next(), None);
-}
-
-#[test]
-fn test_rev_iter() {
-    let m = generate_test();
-    for (i, elt) in m.iter().rev().enumerate() {
-        assert_eq!((6 - i) as i32, *elt);
-    }
-    let mut n = LinkedList::new();
-    assert_eq!(n.iter().rev().next(), None);
-    n.push_front(4);
-    let mut it = n.iter().rev();
-    assert_eq!(it.size_hint(), (1, Some(1)));
-    assert_eq!(it.next().unwrap(), &4);
-    assert_eq!(it.size_hint(), (0, Some(0)));
-    assert_eq!(it.next(), None);
-}
-
-#[test]
-fn test_mut_iter() {
-    let mut m = generate_test();
-    let mut len = m.len();
-    for (i, elt) in m.iter_mut().enumerate() {
-        assert_eq!(i as i32, *elt);
-        len -= 1;
-    }
-    assert_eq!(len, 0);
-    let mut n = LinkedList::new();
-    assert!(n.iter_mut().next().is_none());
-    n.push_front(4);
-    n.push_back(5);
-    let mut it = n.iter_mut();
-    assert_eq!(it.size_hint(), (2, Some(2)));
-    assert!(it.next().is_some());
-    assert!(it.next().is_some());
-    assert_eq!(it.size_hint(), (0, Some(0)));
-    assert!(it.next().is_none());
-}
-
-#[test]
-fn test_iterator_mut_double_end() {
-    let mut n = LinkedList::new();
-    assert!(n.iter_mut().next_back().is_none());
-    n.push_front(4);
-    n.push_front(5);
-    n.push_front(6);
-    let mut it = n.iter_mut();
-    assert_eq!(it.size_hint(), (3, Some(3)));
-    assert_eq!(*it.next().unwrap(), 6);
-    assert_eq!(it.size_hint(), (2, Some(2)));
-    assert_eq!(*it.next_back().unwrap(), 4);
-    assert_eq!(it.size_hint(), (1, Some(1)));
-    assert_eq!(*it.next_back().unwrap(), 5);
-    assert!(it.next_back().is_none());
-    assert!(it.next().is_none());
-}
-
-#[test]
-fn test_mut_rev_iter() {
-    let mut m = generate_test();
-    for (i, elt) in m.iter_mut().rev().enumerate() {
-        assert_eq!((6 - i) as i32, *elt);
-    }
-    let mut n = LinkedList::new();
-    assert!(n.iter_mut().rev().next().is_none());
-    n.push_front(4);
-    let mut it = n.iter_mut().rev();
-    assert!(it.next().is_some());
-    assert!(it.next().is_none());
-}
-
-#[test]
-fn test_eq() {
-    let mut n = list_from(&[]);
-    let mut m = list_from(&[]);
-    assert!(n == m);
-    n.push_front(1);
-    assert!(n != m);
-    m.push_back(1);
-    assert!(n == m);
-
-    let n = list_from(&[2, 3, 4]);
-    let m = list_from(&[1, 2, 3]);
-    assert!(n != m);
-}
 
 #[test]
 fn test_hash() {
@@ -256,449 +19,3 @@ fn test_hash() {
 
     assert!(hash(&x) == hash(&y));
 }
-
-#[test]
-fn test_ord() {
-    let n = list_from(&[]);
-    let m = list_from(&[1, 2, 3]);
-    assert!(n < m);
-    assert!(m > n);
-    assert!(n <= n);
-    assert!(n >= n);
-}
-
-#[test]
-fn test_ord_nan() {
-    let nan = 0.0f64 / 0.0;
-    let n = list_from(&[nan]);
-    let m = list_from(&[nan]);
-    assert!(!(n < m));
-    assert!(!(n > m));
-    assert!(!(n <= m));
-    assert!(!(n >= m));
-
-    let n = list_from(&[nan]);
-    let one = list_from(&[1.0f64]);
-    assert!(!(n < one));
-    assert!(!(n > one));
-    assert!(!(n <= one));
-    assert!(!(n >= one));
-
-    let u = list_from(&[1.0f64, 2.0, nan]);
-    let v = list_from(&[1.0f64, 2.0, 3.0]);
-    assert!(!(u < v));
-    assert!(!(u > v));
-    assert!(!(u <= v));
-    assert!(!(u >= v));
-
-    let s = list_from(&[1.0f64, 2.0, 4.0, 2.0]);
-    let t = list_from(&[1.0f64, 2.0, 3.0, 2.0]);
-    assert!(!(s < t));
-    assert!(s > one);
-    assert!(!(s <= one));
-    assert!(s >= one);
-}
-
-#[test]
-fn test_show() {
-    let list: LinkedList<_> = (0..10).collect();
-    assert_eq!(format!("{list:?}"), "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]");
-
-    let list: LinkedList<_> = ["just", "one", "test", "more"].into_iter().collect();
-    assert_eq!(format!("{list:?}"), "[\"just\", \"one\", \"test\", \"more\"]");
-}
-
-#[test]
-fn test_extend_ref() {
-    let mut a = LinkedList::new();
-    a.push_back(1);
-
-    a.extend(&[2, 3, 4]);
-
-    assert_eq!(a.len(), 4);
-    assert_eq!(a, list_from(&[1, 2, 3, 4]));
-
-    let mut b = LinkedList::new();
-    b.push_back(5);
-    b.push_back(6);
-    a.extend(&b);
-
-    assert_eq!(a.len(), 6);
-    assert_eq!(a, list_from(&[1, 2, 3, 4, 5, 6]));
-}
-
-#[test]
-fn test_extend() {
-    let mut a = LinkedList::new();
-    a.push_back(1);
-    a.extend(vec![2, 3, 4]); // uses iterator
-
-    assert_eq!(a.len(), 4);
-    assert!(a.iter().eq(&[1, 2, 3, 4]));
-
-    let b: LinkedList<_> = [5, 6, 7].into_iter().collect();
-    a.extend(b); // specializes to `append`
-
-    assert_eq!(a.len(), 7);
-    assert!(a.iter().eq(&[1, 2, 3, 4, 5, 6, 7]));
-}
-
-#[test]
-fn test_contains() {
-    let mut l = LinkedList::new();
-    l.extend(&[2, 3, 4]);
-
-    assert!(l.contains(&3));
-    assert!(!l.contains(&1));
-
-    l.clear();
-
-    assert!(!l.contains(&3));
-}
-
-#[test]
-fn drain_filter_empty() {
-    let mut list: LinkedList<i32> = LinkedList::new();
-
-    {
-        let mut iter = list.drain_filter(|_| true);
-        assert_eq!(iter.size_hint(), (0, Some(0)));
-        assert_eq!(iter.next(), None);
-        assert_eq!(iter.size_hint(), (0, Some(0)));
-        assert_eq!(iter.next(), None);
-        assert_eq!(iter.size_hint(), (0, Some(0)));
-    }
-
-    assert_eq!(list.len(), 0);
-    assert_eq!(list.into_iter().collect::<Vec<_>>(), vec![]);
-}
-
-#[test]
-fn drain_filter_zst() {
-    let mut list: LinkedList<_> = [(), (), (), (), ()].into_iter().collect();
-    let initial_len = list.len();
-    let mut count = 0;
-
-    {
-        let mut iter = list.drain_filter(|_| true);
-        assert_eq!(iter.size_hint(), (0, Some(initial_len)));
-        while let Some(_) = iter.next() {
-            count += 1;
-            assert_eq!(iter.size_hint(), (0, Some(initial_len - count)));
-        }
-        assert_eq!(iter.size_hint(), (0, Some(0)));
-        assert_eq!(iter.next(), None);
-        assert_eq!(iter.size_hint(), (0, Some(0)));
-    }
-
-    assert_eq!(count, initial_len);
-    assert_eq!(list.len(), 0);
-    assert_eq!(list.into_iter().collect::<Vec<_>>(), vec![]);
-}
-
-#[test]
-fn drain_filter_false() {
-    let mut list: LinkedList<_> = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
-
-    let initial_len = list.len();
-    let mut count = 0;
-
-    {
-        let mut iter = list.drain_filter(|_| false);
-        assert_eq!(iter.size_hint(), (0, Some(initial_len)));
-        for _ in iter.by_ref() {
-            count += 1;
-        }
-        assert_eq!(iter.size_hint(), (0, Some(0)));
-        assert_eq!(iter.next(), None);
-        assert_eq!(iter.size_hint(), (0, Some(0)));
-    }
-
-    assert_eq!(count, 0);
-    assert_eq!(list.len(), initial_len);
-    assert_eq!(list.into_iter().collect::<Vec<_>>(), vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
-}
-
-#[test]
-fn drain_filter_true() {
-    let mut list: LinkedList<_> = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
-
-    let initial_len = list.len();
-    let mut count = 0;
-
-    {
-        let mut iter = list.drain_filter(|_| true);
-        assert_eq!(iter.size_hint(), (0, Some(initial_len)));
-        while let Some(_) = iter.next() {
-            count += 1;
-            assert_eq!(iter.size_hint(), (0, Some(initial_len - count)));
-        }
-        assert_eq!(iter.size_hint(), (0, Some(0)));
-        assert_eq!(iter.next(), None);
-        assert_eq!(iter.size_hint(), (0, Some(0)));
-    }
-
-    assert_eq!(count, initial_len);
-    assert_eq!(list.len(), 0);
-    assert_eq!(list.into_iter().collect::<Vec<_>>(), vec![]);
-}
-
-#[test]
-fn drain_filter_complex() {
-    {
-        //                [+xxx++++++xxxxx++++x+x++]
-        let mut list = [
-            1, 2, 4, 6, 7, 9, 11, 13, 15, 17, 18, 20, 22, 24, 26, 27, 29, 31, 33, 34, 35, 36, 37,
-            39,
-        ]
-        .into_iter()
-        .collect::<LinkedList<_>>();
-
-        let removed = list.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
-        assert_eq!(removed.len(), 10);
-        assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]);
-
-        assert_eq!(list.len(), 14);
-        assert_eq!(
-            list.into_iter().collect::<Vec<_>>(),
-            vec![1, 7, 9, 11, 13, 15, 17, 27, 29, 31, 33, 35, 37, 39]
-        );
-    }
-
-    {
-        // [xxx++++++xxxxx++++x+x++]
-        let mut list =
-            [2, 4, 6, 7, 9, 11, 13, 15, 17, 18, 20, 22, 24, 26, 27, 29, 31, 33, 34, 35, 36, 37, 39]
-                .into_iter()
-                .collect::<LinkedList<_>>();
-
-        let removed = list.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
-        assert_eq!(removed.len(), 10);
-        assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]);
-
-        assert_eq!(list.len(), 13);
-        assert_eq!(
-            list.into_iter().collect::<Vec<_>>(),
-            vec![7, 9, 11, 13, 15, 17, 27, 29, 31, 33, 35, 37, 39]
-        );
-    }
-
-    {
-        // [xxx++++++xxxxx++++x+x]
-        let mut list =
-            [2, 4, 6, 7, 9, 11, 13, 15, 17, 18, 20, 22, 24, 26, 27, 29, 31, 33, 34, 35, 36]
-                .into_iter()
-                .collect::<LinkedList<_>>();
-
-        let removed = list.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
-        assert_eq!(removed.len(), 10);
-        assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]);
-
-        assert_eq!(list.len(), 11);
-        assert_eq!(
-            list.into_iter().collect::<Vec<_>>(),
-            vec![7, 9, 11, 13, 15, 17, 27, 29, 31, 33, 35]
-        );
-    }
-
-    {
-        // [xxxxxxxxxx+++++++++++]
-        let mut list = [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
-            .into_iter()
-            .collect::<LinkedList<_>>();
-
-        let removed = list.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
-        assert_eq!(removed.len(), 10);
-        assert_eq!(removed, vec![2, 4, 6, 8, 10, 12, 14, 16, 18, 20]);
-
-        assert_eq!(list.len(), 10);
-        assert_eq!(list.into_iter().collect::<Vec<_>>(), vec![1, 3, 5, 7, 9, 11, 13, 15, 17, 19]);
-    }
-
-    {
-        // [+++++++++++xxxxxxxxxx]
-        let mut list = [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
-            .into_iter()
-            .collect::<LinkedList<_>>();
-
-        let removed = list.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
-        assert_eq!(removed.len(), 10);
-        assert_eq!(removed, vec![2, 4, 6, 8, 10, 12, 14, 16, 18, 20]);
-
-        assert_eq!(list.len(), 10);
-        assert_eq!(list.into_iter().collect::<Vec<_>>(), vec![1, 3, 5, 7, 9, 11, 13, 15, 17, 19]);
-    }
-}
-
-#[test]
-fn drain_filter_drop_panic_leak() {
-    static mut DROPS: i32 = 0;
-
-    struct D(bool);
-
-    impl Drop for D {
-        fn drop(&mut self) {
-            unsafe {
-                DROPS += 1;
-            }
-
-            if self.0 {
-                panic!("panic in `drop`");
-            }
-        }
-    }
-
-    let mut q = LinkedList::new();
-    q.push_back(D(false));
-    q.push_back(D(false));
-    q.push_back(D(false));
-    q.push_back(D(false));
-    q.push_back(D(false));
-    q.push_front(D(false));
-    q.push_front(D(true));
-    q.push_front(D(false));
-
-    catch_unwind(AssertUnwindSafe(|| drop(q.drain_filter(|_| true)))).ok();
-
-    assert_eq!(unsafe { DROPS }, 8);
-    assert!(q.is_empty());
-}
-
-#[test]
-fn drain_filter_pred_panic_leak() {
-    static mut DROPS: i32 = 0;
-
-    #[derive(Debug)]
-    struct D(u32);
-
-    impl Drop for D {
-        fn drop(&mut self) {
-            unsafe {
-                DROPS += 1;
-            }
-        }
-    }
-
-    let mut q = LinkedList::new();
-    q.push_back(D(3));
-    q.push_back(D(4));
-    q.push_back(D(5));
-    q.push_back(D(6));
-    q.push_back(D(7));
-    q.push_front(D(2));
-    q.push_front(D(1));
-    q.push_front(D(0));
-
-    catch_unwind(AssertUnwindSafe(|| {
-        drop(q.drain_filter(|item| if item.0 >= 2 { panic!() } else { true }))
-    }))
-    .ok();
-
-    assert_eq!(unsafe { DROPS }, 2); // 0 and 1
-    assert_eq!(q.len(), 6);
-}
-
-#[test]
-fn test_drop() {
-    static mut DROPS: i32 = 0;
-    struct Elem;
-    impl Drop for Elem {
-        fn drop(&mut self) {
-            unsafe {
-                DROPS += 1;
-            }
-        }
-    }
-
-    let mut ring = LinkedList::new();
-    ring.push_back(Elem);
-    ring.push_front(Elem);
-    ring.push_back(Elem);
-    ring.push_front(Elem);
-    drop(ring);
-
-    assert_eq!(unsafe { DROPS }, 4);
-}
-
-#[test]
-fn test_drop_with_pop() {
-    static mut DROPS: i32 = 0;
-    struct Elem;
-    impl Drop for Elem {
-        fn drop(&mut self) {
-            unsafe {
-                DROPS += 1;
-            }
-        }
-    }
-
-    let mut ring = LinkedList::new();
-    ring.push_back(Elem);
-    ring.push_front(Elem);
-    ring.push_back(Elem);
-    ring.push_front(Elem);
-
-    drop(ring.pop_back());
-    drop(ring.pop_front());
-    assert_eq!(unsafe { DROPS }, 2);
-
-    drop(ring);
-    assert_eq!(unsafe { DROPS }, 4);
-}
-
-#[test]
-fn test_drop_clear() {
-    static mut DROPS: i32 = 0;
-    struct Elem;
-    impl Drop for Elem {
-        fn drop(&mut self) {
-            unsafe {
-                DROPS += 1;
-            }
-        }
-    }
-
-    let mut ring = LinkedList::new();
-    ring.push_back(Elem);
-    ring.push_front(Elem);
-    ring.push_back(Elem);
-    ring.push_front(Elem);
-    ring.clear();
-    assert_eq!(unsafe { DROPS }, 4);
-
-    drop(ring);
-    assert_eq!(unsafe { DROPS }, 4);
-}
-
-#[test]
-fn test_drop_panic() {
-    static mut DROPS: i32 = 0;
-
-    struct D(bool);
-
-    impl Drop for D {
-        fn drop(&mut self) {
-            unsafe {
-                DROPS += 1;
-            }
-
-            if self.0 {
-                panic!("panic in `drop`");
-            }
-        }
-    }
-
-    let mut q = LinkedList::new();
-    q.push_back(D(false));
-    q.push_back(D(false));
-    q.push_back(D(false));
-    q.push_back(D(false));
-    q.push_back(D(false));
-    q.push_front(D(false));
-    q.push_front(D(false));
-    q.push_front(D(true));
-
-    catch_unwind(move || drop(q)).ok();
-
-    assert_eq!(unsafe { DROPS }, 8);
-}
index 24257ba98785d52421d6e83e8e6a5c34133740cd..0abe20e4ca3b2aea95aa0fbd59f1906a7ad8e8d4 100644 (file)
@@ -367,3 +367,27 @@ fn bench_partial_cmp(b: &mut Bencher) {
 fn bench_lt(b: &mut Bencher) {
     b.iter(|| (0..100000).map(black_box).lt((0..100000).map(black_box)))
 }
+
+#[bench]
+fn bench_trusted_random_access_adapters(b: &mut Bencher) {
+    let vec1: Vec<_> = (0usize..100000).collect();
+    let vec2 = black_box(vec1.clone());
+    b.iter(|| {
+        let mut iter = vec1
+            .iter()
+            .copied()
+            .enumerate()
+            .map(|(idx, e)| idx.wrapping_add(e))
+            .zip(vec2.iter().copied())
+            .map(|(a, b)| a.wrapping_add(b))
+            .fuse();
+        let mut acc: usize = 0;
+        let size = iter.size();
+        for i in 0..size {
+            // SAFETY: TRA requirements are satisfied by 0..size iteration and then dropping the
+            // iterator.
+            acc = acc.wrapping_add(unsafe { iter.__iterator_get_unchecked(i) });
+        }
+        acc
+    })
+}
index d5e1ec083f95d24488381be269ddb2191980063f..f1f1ae6e4635dee4b50a3cdc2458322c0b72e659 100644 (file)
@@ -3,6 +3,7 @@
 #![feature(flt2dec)]
 #![feature(int_log)]
 #![feature(test)]
+#![feature(trusted_random_access)]
 
 extern crate test;
 
index 417ed51c6b6a23063b3a84355397aea07d1cca20..7ef78e0b48af161015ef27375dee5755afcdc9df 100644 (file)
@@ -1,10 +1,6 @@
 // implements the unary operator "op &T"
 // based on "op T" where T is expected to be `Copy`able
 macro_rules! forward_ref_unop {
-    (impl $imp:ident, $method:ident for $t:ty) => {
-        forward_ref_unop!(impl $imp, $method for $t,
-                #[stable(feature = "rust1", since = "1.0.0")]);
-    };
     (impl const $imp:ident, $method:ident for $t:ty) => {
         forward_ref_unop!(impl const $imp, $method for $t,
                 #[stable(feature = "rust1", since = "1.0.0")]);
@@ -38,10 +34,6 @@ fn $method(self) -> <$t as $imp>::Output {
 // implements binary operators "&T op U", "T op &U", "&T op &U"
 // based on "T op U" where T and U are expected to be `Copy`able
 macro_rules! forward_ref_binop {
-    (impl $imp:ident, $method:ident for $t:ty, $u:ty) => {
-        forward_ref_binop!(impl $imp, $method for $t, $u,
-                #[stable(feature = "rust1", since = "1.0.0")]);
-    };
     (impl const $imp:ident, $method:ident for $t:ty, $u:ty) => {
         forward_ref_binop!(impl const $imp, $method for $t, $u,
                 #[stable(feature = "rust1", since = "1.0.0")]);
@@ -230,22 +222,6 @@ macro_rules! cfg_if {
         }
     };
 
-    // match if/else chains lacking a final `else`
-    (
-        if #[cfg( $i_meta:meta )] { $( $i_tokens:tt )* }
-        $(
-            else if #[cfg( $e_meta:meta )] { $( $e_tokens:tt )* }
-        )*
-    ) => {
-        cfg_if! {
-            @__items () ;
-            (( $i_meta ) ( $( $i_tokens )* )) ,
-            $(
-                (( $e_meta ) ( $( $e_tokens )* )) ,
-            )*
-        }
-    };
-
     // Internal and recursive macro to emit all the items
     //
     // Collects all the previous cfgs in a list at the beginning, so they can be
index 84e4618844a610ffd503691829a6db12c0c7cabf..10b4db84b3904e1a115e50dcb261d86259e17504 100644 (file)
@@ -129,6 +129,7 @@ fn advance_by(&mut self, n: usize) -> Result<(), usize> {
 
     #[rustc_inherit_overflow_checks]
     #[doc(hidden)]
+    #[inline]
     unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> <Self as Iterator>::Item
     where
         Self: TrustedRandomAccessNoCoerce,
index 4b03449972c9a7273f078f6c01fed1da1882a742..6cbb35dc7c6292ff586bbd36d3b73f64a13c202d 100644 (file)
@@ -125,6 +125,7 @@ fn fold<Acc, G>(self, init: Acc, g: G) -> Acc
     }
 
     #[doc(hidden)]
+    #[inline]
     unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> B
     where
         Self: TrustedRandomAccessNoCoerce,
index f50e71da20f160d83806b9e82e67c3107e0ad1bf..de44bd66501e20bb3445fdffdb700062d65c00f4 100644 (file)
@@ -554,6 +554,7 @@ fn size(&self) -> usize
 ///
 /// Same requirements calling `get_unchecked` directly.
 #[doc(hidden)]
+#[inline]
 pub(in crate::iter::adapters) unsafe fn try_get_unchecked<I>(it: &mut I, idx: usize) -> I::Item
 where
     I: Iterator,
@@ -576,6 +577,7 @@ unsafe impl<I: Iterator> SpecTrustedRandomAccess for I {
 }
 
 unsafe impl<I: Iterator + TrustedRandomAccessNoCoerce> SpecTrustedRandomAccess for I {
+    #[inline]
     unsafe fn try_get_unchecked(&mut self, index: usize) -> Self::Item {
         // SAFETY: the caller must uphold the contract for
         // `Iterator::__iterator_get_unchecked`.
index 44bc6890c55b5e8ae3505759a2fe6c357fe07d06..6f62662d88066db18271712880d2b40917eaa572 100644 (file)
@@ -27,7 +27,7 @@
 /// use std::iter;
 ///
 /// // let's assume we have some value of a type that is not `Clone`
-/// // or which don't want to have in memory just yet because it is expensive:
+/// // or which we don't want to have in memory just yet because it is expensive:
 /// #[derive(PartialEq, Debug)]
 /// struct Expensive;
 ///
index 7b75ab96ee7deea69f7f194b115490bc51702a64..12ca508bed2b93e5e49d494c9f7429e676c68d3b 100644 (file)
 #[rustc_on_unimplemented(
     on(
         _Self = "[{A}]",
-        message = "a value of type `{Self}` cannot be built since `{Self}` has no definite size",
+        message = "a slice of type `{Self}` cannot be built since `{Self}` has no definite size",
         label = "try explicitly collecting into a `Vec<{A}>`",
     ),
     on(
-        all(
-            A = "{integer}",
-            any(
-                _Self = "[i8]",
-                _Self = "[i16]",
-                _Self = "[i32]",
-                _Self = "[i64]",
-                _Self = "[i128]",
-                _Self = "[isize]",
-                _Self = "[u8]",
-                _Self = "[u16]",
-                _Self = "[u32]",
-                _Self = "[u64]",
-                _Self = "[u128]",
-                _Self = "[usize]"
-            )
-        ),
-        message = "a value of type `{Self}` cannot be built since `{Self}` has no definite size",
+        all(A = "{integer}", any(_Self = "[{integral}]",)),
+        message = "a slice of type `{Self}` cannot be built since `{Self}` has no definite size",
         label = "try explicitly collecting into a `Vec<{A}>`",
     ),
+    on(
+        _Self = "[{A}; _]",
+        message = "an array of type `{Self}` cannot be built directly from an iterator",
+        label = "try collecting into a `Vec<{A}>`, then using `.try_into()`",
+    ),
+    on(
+        all(A = "{integer}", any(_Self = "[{integral}; _]",)),
+        message = "an array of type `{Self}` cannot be built directly from an iterator",
+        label = "try collecting into a `Vec<{A}>`, then using `.try_into()`",
+    ),
     message = "a value of type `{Self}` cannot be built from an iterator \
                over elements of type `{A}`",
     label = "value of type `{Self}` cannot be built from `std::iter::Iterator<Item={A}>`"
@@ -267,8 +261,9 @@ pub trait IntoIterator {
     fn into_iter(self) -> Self::IntoIter;
 }
 
+#[rustc_const_unstable(feature = "const_intoiterator_identity", issue = "90603")]
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<I: Iterator> IntoIterator for I {
+impl<I: ~const Iterator> const IntoIterator for I {
     type Item = I::Item;
     type IntoIter = I;
 
index 83f33ca007af1eb74a57e6bb5a58a78a86c3df0a..d00056f0c32e827945f36f127e6e588821013168 100644 (file)
@@ -640,6 +640,8 @@ macro_rules! unreachable {
 ///
 /// Like `panic!`, this macro has a second form for displaying custom values.
 ///
+/// [`todo!`]: crate::todo
+///
 /// # Examples
 ///
 /// Say we have a trait `Foo`:
index a983d0872bcf00828f16cc63385dadc44899e1b8..e1a46086af060407134011f5bacce82997acd4d4 100644 (file)
@@ -449,7 +449,8 @@ pub const fn is_nan(self) -> bool {
     #[inline]
     #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
     pub(crate) const fn abs_private(self) -> f32 {
-        f32::from_bits(self.to_bits() & 0x7fff_ffff)
+        // SAFETY: This transmutation is fine. Probably. For the reasons std is using it.
+        unsafe { mem::transmute::<u32, f32>(mem::transmute::<f32, u32>(self) & 0x7fff_ffff) }
     }
 
     /// Returns `true` if this value is positive infinity or negative infinity, and
@@ -472,7 +473,10 @@ pub(crate) const fn abs_private(self) -> f32 {
     #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
     #[inline]
     pub const fn is_infinite(self) -> bool {
-        self.abs_private() == Self::INFINITY
+        // Getting clever with transmutation can result in incorrect answers on some FPUs
+        // FIXME: alter the Rust <-> Rust calling convention to prevent this problem.
+        // See https://github.com/rust-lang/rust/issues/72327
+        (self == f32::INFINITY) | (self == f32::NEG_INFINITY)
     }
 
     /// Returns `true` if this number is neither infinite nor `NaN`.
@@ -568,15 +572,76 @@ pub const fn is_normal(self) -> bool {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
     pub const fn classify(self) -> FpCategory {
+        // A previous implementation tried to only use bitmask-based checks,
+        // using f32::to_bits to transmute the float to its bit repr and match on that.
+        // Unfortunately, floating point numbers can be much worse than that.
+        // This also needs to not result in recursive evaluations of f64::to_bits.
+        //
+        // On some processors, in some cases, LLVM will "helpfully" lower floating point ops,
+        // in spite of a request for them using f32 and f64, to things like x87 operations.
+        // These have an f64's mantissa, but can have a larger than normal exponent.
+        // FIXME(jubilee): Using x87 operations is never necessary in order to function
+        // on x86 processors for Rust-to-Rust calls, so this issue should not happen.
+        // Code generation should be adjusted to use non-C calling conventions, avoiding this.
+        //
+        if self.is_infinite() {
+            // Thus, a value may compare unequal to infinity, despite having a "full" exponent mask.
+            FpCategory::Infinite
+        } else if self.is_nan() {
+            // And it may not be NaN, as it can simply be an "overextended" finite value.
+            FpCategory::Nan
+        } else {
+            // However, std can't simply compare to zero to check for zero, either,
+            // as correctness requires avoiding equality tests that may be Subnormal == -0.0
+            // because it may be wrong under "denormals are zero" and "flush to zero" modes.
+            // Most of std's targets don't use those, but they are used for thumbv7neon.
+            // So, this does use bitpattern matching for the rest.
+
+            // SAFETY: f32 to u32 is fine. Usually.
+            // If classify has gotten this far, the value is definitely in one of these categories.
+            unsafe { f32::partial_classify(self) }
+        }
+    }
+
+    // This doesn't actually return a right answer for NaN on purpose,
+    // seeing as how it cannot correctly discern between a floating point NaN,
+    // and some normal floating point numbers truncated from an x87 FPU.
+    // FIXME(jubilee): This probably could at least answer things correctly for Infinity,
+    // like the f64 version does, but I need to run more checks on how things go on x86.
+    // I fear losing mantissa data that would have answered that differently.
+    //
+    // # Safety
+    // This requires making sure you call this function for values it answers correctly on,
+    // otherwise it returns a wrong answer. This is not important for memory safety per se,
+    // but getting floats correct is important for not accidentally leaking const eval
+    // runtime-deviating logic which may or may not be acceptable.
+    #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
+    const unsafe fn partial_classify(self) -> FpCategory {
         const EXP_MASK: u32 = 0x7f800000;
         const MAN_MASK: u32 = 0x007fffff;
 
-        let bits = self.to_bits();
-        match (bits & MAN_MASK, bits & EXP_MASK) {
+        // SAFETY: The caller is not asking questions for which this will tell lies.
+        let b = unsafe { mem::transmute::<f32, u32>(self) };
+        match (b & MAN_MASK, b & EXP_MASK) {
             (0, 0) => FpCategory::Zero,
             (_, 0) => FpCategory::Subnormal,
+            _ => FpCategory::Normal,
+        }
+    }
+
+    // This operates on bits, and only bits, so it can ignore concerns about weird FPUs.
+    // FIXME(jubilee): In a just world, this would be the entire impl for classify,
+    // plus a transmute. We do not live in a just world, but we can make it more so.
+    #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
+    const fn classify_bits(b: u32) -> FpCategory {
+        const EXP_MASK: u32 = 0x7f800000;
+        const MAN_MASK: u32 = 0x007fffff;
+
+        match (b & MAN_MASK, b & EXP_MASK) {
             (0, EXP_MASK) => FpCategory::Infinite,
             (_, EXP_MASK) => FpCategory::Nan,
+            (0, 0) => FpCategory::Zero,
+            (_, 0) => FpCategory::Subnormal,
             _ => FpCategory::Normal,
         }
     }
@@ -616,7 +681,8 @@ pub const fn is_sign_positive(self) -> bool {
     pub const fn is_sign_negative(self) -> bool {
         // IEEE754 says: isSignMinus(x) is true if and only if x has negative sign. isSignMinus
         // applies to zeros and NaNs as well.
-        self.to_bits() & 0x8000_0000 != 0
+        // SAFETY: This is just transmuting to get the sign bit, it's fine.
+        unsafe { mem::transmute::<f32, u32>(self) & 0x8000_0000 != 0 }
     }
 
     /// Takes the reciprocal (inverse) of a number, `1/x`.
@@ -831,8 +897,49 @@ pub unsafe fn to_int_unchecked<Int>(self) -> Int
     #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
     #[inline]
     pub const fn to_bits(self) -> u32 {
-        // SAFETY: `u32` is a plain old datatype so we can always transmute to it
-        unsafe { mem::transmute(self) }
+        // SAFETY: `u32` is a plain old datatype so we can always transmute to it.
+        // ...sorta.
+        //
+        // It turns out that at runtime, it is possible for a floating point number
+        // to be subject to a floating point mode that alters nonzero subnormal numbers
+        // to zero on reads and writes, aka "denormals are zero" and "flush to zero".
+        // This is not a problem per se, but at least one tier2 platform for Rust
+        // actually exhibits this behavior by default.
+        //
+        // In addition, on x86 targets with SSE or SSE2 disabled and the x87 FPU enabled,
+        // i.e. not soft-float, the way Rust does parameter passing can actually alter
+        // a number that is "not infinity" to have the same exponent as infinity,
+        // in a slightly unpredictable manner.
+        //
+        // And, of course evaluating to a NaN value is fairly nondeterministic.
+        // More precisely: when NaN should be returned is knowable, but which NaN?
+        // So far that's defined by a combination of LLVM and the CPU, not Rust.
+        // This function, however, allows observing the bitstring of a NaN,
+        // thus introspection on CTFE.
+        //
+        // In order to preserve, at least for the moment, const-to-runtime equivalence,
+        // we reject any of these possible situations from happening.
+        #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
+        const fn ct_f32_to_u32(ct: f32) -> u32 {
+            match ct.classify() {
+                FpCategory::Nan => {
+                    panic!("const-eval error: cannot use f32::to_bits on a NaN")
+                }
+                FpCategory::Subnormal => {
+                    panic!("const-eval error: cannot use f32::to_bits on a subnormal number")
+                }
+                FpCategory::Infinite | FpCategory::Normal | FpCategory::Zero => {
+                    // SAFETY: We have a normal floating point number. Now we transmute, i.e. do a bitcopy.
+                    unsafe { mem::transmute::<f32, u32>(ct) }
+                }
+            }
+        }
+        // SAFETY: `u32` is a plain old datatype so we can always... uh...
+        // ...look, just pretend you forgot what you just read.
+        // Stability concerns.
+        let rt_f32_to_u32 = |rt| unsafe { mem::transmute::<f32, u32>(rt) };
+        // SAFETY: We use internal implementations that either always work or fail at compile time.
+        unsafe { intrinsics::const_eval_select((self,), ct_f32_to_u32, rt_f32_to_u32) }
     }
 
     /// Raw transmutation from `u32`.
@@ -876,9 +983,51 @@ pub const fn to_bits(self) -> u32 {
     #[must_use]
     #[inline]
     pub const fn from_bits(v: u32) -> Self {
-        // SAFETY: `u32` is a plain old datatype so we can always transmute from it
         // It turns out the safety issues with sNaN were overblown! Hooray!
-        unsafe { mem::transmute(v) }
+        // SAFETY: `u32` is a plain old datatype so we can always transmute from it
+        // ...sorta.
+        //
+        // It turns out that at runtime, it is possible for a floating point number
+        // to be subject to floating point modes that alter nonzero subnormal numbers
+        // to zero on reads and writes, aka "denormals are zero" and "flush to zero".
+        // This is not a problem usually, but at least one tier2 platform for Rust
+        // actually exhibits this behavior by default: thumbv7neon
+        // aka "the Neon FPU in AArch32 state"
+        //
+        // In addition, on x86 targets with SSE or SSE2 disabled and the x87 FPU enabled,
+        // i.e. not soft-float, the way Rust does parameter passing can actually alter
+        // a number that is "not infinity" to have the same exponent as infinity,
+        // in a slightly unpredictable manner.
+        //
+        // And, of course evaluating to a NaN value is fairly nondeterministic.
+        // More precisely: when NaN should be returned is knowable, but which NaN?
+        // So far that's defined by a combination of LLVM and the CPU, not Rust.
+        // This function, however, allows observing the bitstring of a NaN,
+        // thus introspection on CTFE.
+        //
+        // In order to preserve, at least for the moment, const-to-runtime equivalence,
+        // reject any of these possible situations from happening.
+        #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
+        const fn ct_u32_to_f32(ct: u32) -> f32 {
+            match f32::classify_bits(ct) {
+                FpCategory::Subnormal => {
+                    panic!("const-eval error: cannot use f32::from_bits on a subnormal number")
+                }
+                FpCategory::Nan => {
+                    panic!("const-eval error: cannot use f32::from_bits on NaN")
+                }
+                FpCategory::Infinite | FpCategory::Normal | FpCategory::Zero => {
+                    // SAFETY: It's not a frumious number
+                    unsafe { mem::transmute::<u32, f32>(ct) }
+                }
+            }
+        }
+        // SAFETY: `u32` is a plain old datatype so we can always... uh...
+        // ...look, just pretend you forgot what you just read.
+        // Stability concerns.
+        let rt_u32_to_f32 = |rt| unsafe { mem::transmute::<u32, f32>(rt) };
+        // SAFETY: We use internal implementations that either always work or fail at compile time.
+        unsafe { intrinsics::const_eval_select((v,), ct_u32_to_f32, rt_u32_to_f32) }
     }
 
     /// Return the memory representation of this floating point number as a byte array in
index 05598e5fe7b07f81d94d5c41c51422a7c6641918..b07f201ca4ad282aa08069d21ed06e25586fc761 100644 (file)
@@ -448,7 +448,10 @@ pub const fn is_nan(self) -> bool {
     #[inline]
     #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
     pub(crate) const fn abs_private(self) -> f64 {
-        f64::from_bits(self.to_bits() & 0x7fff_ffff_ffff_ffff)
+        // SAFETY: This transmutation is fine. Probably. For the reasons std is using it.
+        unsafe {
+            mem::transmute::<u64, f64>(mem::transmute::<f64, u64>(self) & 0x7fff_ffff_ffff_ffff)
+        }
     }
 
     /// Returns `true` if this value is positive infinity or negative infinity, and
@@ -471,7 +474,10 @@ pub(crate) const fn abs_private(self) -> f64 {
     #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
     #[inline]
     pub const fn is_infinite(self) -> bool {
-        self.abs_private() == Self::INFINITY
+        // Getting clever with transmutation can result in incorrect answers on some FPUs
+        // FIXME: alter the Rust <-> Rust calling convention to prevent this problem.
+        // See https://github.com/rust-lang/rust/issues/72327
+        (self == f64::INFINITY) | (self == f64::NEG_INFINITY)
     }
 
     /// Returns `true` if this number is neither infinite nor `NaN`.
@@ -567,15 +573,67 @@ pub const fn is_normal(self) -> bool {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
     pub const fn classify(self) -> FpCategory {
+        // A previous implementation tried to only use bitmask-based checks,
+        // using f64::to_bits to transmute the float to its bit repr and match on that.
+        // Unfortunately, floating point numbers can be much worse than that.
+        // This also needs to not result in recursive evaluations of f64::to_bits.
+        //
+        // On some processors, in some cases, LLVM will "helpfully" lower floating point ops,
+        // in spite of a request for them using f32 and f64, to things like x87 operations.
+        // These have an f64's mantissa, but can have a larger than normal exponent.
+        // FIXME(jubilee): Using x87 operations is never necessary in order to function
+        // on x86 processors for Rust-to-Rust calls, so this issue should not happen.
+        // Code generation should be adjusted to use non-C calling conventions, avoiding this.
+        //
+        // Thus, a value may compare unequal to infinity, despite having a "full" exponent mask.
+        // And it may not be NaN, as it can simply be an "overextended" finite value.
+        if self.is_nan() {
+            FpCategory::Nan
+        } else {
+            // However, std can't simply compare to zero to check for zero, either,
+            // as correctness requires avoiding equality tests that may be Subnormal == -0.0
+            // because it may be wrong under "denormals are zero" and "flush to zero" modes.
+            // Most of std's targets don't use those, but they are used for thumbv7neon.
+            // So, this does use bitpattern matching for the rest.
+
+            // SAFETY: f64 to u64 is fine. Usually.
+            // If control flow has gotten this far, the value is definitely in one of the categories
+            // that f64::partial_classify can correctly analyze.
+            unsafe { f64::partial_classify(self) }
+        }
+    }
+
+    // This doesn't actually return a right answer for NaN on purpose,
+    // seeing as how it cannot correctly discern between a floating point NaN,
+    // and some normal floating point numbers truncated from an x87 FPU.
+    #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
+    const unsafe fn partial_classify(self) -> FpCategory {
         const EXP_MASK: u64 = 0x7ff0000000000000;
         const MAN_MASK: u64 = 0x000fffffffffffff;
 
-        let bits = self.to_bits();
-        match (bits & MAN_MASK, bits & EXP_MASK) {
+        // SAFETY: The caller is not asking questions for which this will tell lies.
+        let b = unsafe { mem::transmute::<f64, u64>(self) };
+        match (b & MAN_MASK, b & EXP_MASK) {
+            (0, EXP_MASK) => FpCategory::Infinite,
             (0, 0) => FpCategory::Zero,
             (_, 0) => FpCategory::Subnormal,
+            _ => FpCategory::Normal,
+        }
+    }
+
+    // This operates on bits, and only bits, so it can ignore concerns about weird FPUs.
+    // FIXME(jubilee): In a just world, this would be the entire impl for classify,
+    // plus a transmute. We do not live in a just world, but we can make it more so.
+    #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
+    const fn classify_bits(b: u64) -> FpCategory {
+        const EXP_MASK: u64 = 0x7ff0000000000000;
+        const MAN_MASK: u64 = 0x000fffffffffffff;
+
+        match (b & MAN_MASK, b & EXP_MASK) {
             (0, EXP_MASK) => FpCategory::Infinite,
             (_, EXP_MASK) => FpCategory::Nan,
+            (0, 0) => FpCategory::Zero,
+            (_, 0) => FpCategory::Subnormal,
             _ => FpCategory::Normal,
         }
     }
@@ -622,7 +680,10 @@ pub fn is_positive(self) -> bool {
     #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
     #[inline]
     pub const fn is_sign_negative(self) -> bool {
-        self.to_bits() & 0x8000_0000_0000_0000 != 0
+        // IEEE754 says: isSignMinus(x) is true if and only if x has negative sign. isSignMinus
+        // applies to zeros and NaNs as well.
+        // SAFETY: This is just transmuting to get the sign bit, it's fine.
+        unsafe { mem::transmute::<f64, u64>(self) & 0x8000_0000_0000_0000 != 0 }
     }
 
     #[must_use]
@@ -847,8 +908,31 @@ pub unsafe fn to_int_unchecked<Int>(self) -> Int
     #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
     #[inline]
     pub const fn to_bits(self) -> u64 {
-        // SAFETY: `u64` is a plain old datatype so we can always transmute to it
-        unsafe { mem::transmute(self) }
+        // SAFETY: `u64` is a plain old datatype so we can always transmute to it.
+        // ...sorta.
+        //
+        // See the SAFETY comment in f64::from_bits for more.
+        #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
+        const fn ct_f64_to_u64(ct: f64) -> u64 {
+            match ct.classify() {
+                FpCategory::Nan => {
+                    panic!("const-eval error: cannot use f64::to_bits on a NaN")
+                }
+                FpCategory::Subnormal => {
+                    panic!("const-eval error: cannot use f64::to_bits on a subnormal number")
+                }
+                FpCategory::Infinite | FpCategory::Normal | FpCategory::Zero => {
+                    // SAFETY: We have a normal floating point number. Now we transmute, i.e. do a bitcopy.
+                    unsafe { mem::transmute::<f64, u64>(ct) }
+                }
+            }
+        }
+        // SAFETY: `u64` is a plain old datatype so we can always... uh...
+        // ...look, just pretend you forgot what you just read.
+        // Stability concerns.
+        let rt_f64_to_u64 = |rt| unsafe { mem::transmute::<f64, u64>(rt) };
+        // SAFETY: We use internal implementations that either always work or fail at compile time.
+        unsafe { intrinsics::const_eval_select((self,), ct_f64_to_u64, rt_f64_to_u64) }
     }
 
     /// Raw transmutation from `u64`.
@@ -892,9 +976,56 @@ pub const fn to_bits(self) -> u64 {
     #[must_use]
     #[inline]
     pub const fn from_bits(v: u64) -> Self {
-        // SAFETY: `u64` is a plain old datatype so we can always transmute from it
         // It turns out the safety issues with sNaN were overblown! Hooray!
-        unsafe { mem::transmute(v) }
+        // SAFETY: `u64` is a plain old datatype so we can always transmute from it
+        // ...sorta.
+        //
+        // It turns out that at runtime, it is possible for a floating point number
+        // to be subject to floating point modes that alter nonzero subnormal numbers
+        // to zero on reads and writes, aka "denormals are zero" and "flush to zero".
+        // This is not a problem usually, but at least one tier2 platform for Rust
+        // actually exhibits an FTZ behavior by default: thumbv7neon
+        // aka "the Neon FPU in AArch32 state"
+        //
+        // Even with this, not all instructions exhibit the FTZ behaviors on thumbv7neon,
+        // so this should load the same bits if LLVM emits the "correct" instructions,
+        // but LLVM sometimes makes interesting choices about float optimization,
+        // and other FPUs may do similar. Thus, it is wise to indulge luxuriously in caution.
+        //
+        // In addition, on x86 targets with SSE or SSE2 disabled and the x87 FPU enabled,
+        // i.e. not soft-float, the way Rust does parameter passing can actually alter
+        // a number that is "not infinity" to have the same exponent as infinity,
+        // in a slightly unpredictable manner.
+        //
+        // And, of course evaluating to a NaN value is fairly nondeterministic.
+        // More precisely: when NaN should be returned is knowable, but which NaN?
+        // So far that's defined by a combination of LLVM and the CPU, not Rust.
+        // This function, however, allows observing the bitstring of a NaN,
+        // thus introspection on CTFE.
+        //
+        // In order to preserve, at least for the moment, const-to-runtime equivalence,
+        // reject any of these possible situations from happening.
+        #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
+        const fn ct_u64_to_f64(ct: u64) -> f64 {
+            match f64::classify_bits(ct) {
+                FpCategory::Subnormal => {
+                    panic!("const-eval error: cannot use f64::from_bits on a subnormal number")
+                }
+                FpCategory::Nan => {
+                    panic!("const-eval error: cannot use f64::from_bits on NaN")
+                }
+                FpCategory::Infinite | FpCategory::Normal | FpCategory::Zero => {
+                    // SAFETY: It's not a frumious number
+                    unsafe { mem::transmute::<u64, f64>(ct) }
+                }
+            }
+        }
+        // SAFETY: `u64` is a plain old datatype so we can always... uh...
+        // ...look, just pretend you forgot what you just read.
+        // Stability concerns.
+        let rt_u64_to_f64 = |rt| unsafe { mem::transmute::<u64, f64>(rt) };
+        // SAFETY: We use internal implementations that either always work or fail at compile time.
+        unsafe { intrinsics::const_eval_select((v,), ct_u64_to_f64, rt_u64_to_f64) }
     }
 
     /// Return the memory representation of this floating point number as a byte array in
index ec460286d0378f9d471991647d53b41777337488..1bf447347408d0ee6e7eea68e5626b868e274ad9 100644 (file)
@@ -2189,7 +2189,7 @@ pub const fn checked_next_multiple_of(self, rhs: Self) -> Option<Self> {
         ///
         /// # Panics
         ///
-        /// When the number is zero, or if the base is not at least 2; it
+        /// When the number is negative, zero, or if the base is not at least 2; it
         /// panics in debug mode and the return value is 0 in release
         /// mode.
         ///
@@ -2223,7 +2223,7 @@ pub const fn log(self, base: Self) -> u32 {
         ///
         /// # Panics
         ///
-        /// When the number is zero it panics in debug mode and the return value
+        /// When the number is negative or zero it panics in debug mode and the return value
         /// is 0 in release mode.
         ///
         /// # Examples
@@ -2256,7 +2256,7 @@ pub const fn log2(self) -> u32 {
         ///
         /// # Panics
         ///
-        /// When the number is zero it panics in debug mode and the return value
+        /// When the number is negative or zero it panics in debug mode and the return value
         /// is 0 in release mode.
         ///
         /// # Example
index 514ac69f7e049f8e69f669dbeacab77e89456d8b..ce52e4773ce1f4388ab289786f02c0c194727348 100644 (file)
@@ -689,7 +689,7 @@ pub const fn checked_rem_euclid(self, rhs: Self) -> Option<Self> {
         ///
         /// # Panics
         ///
-        /// When the number is negative, zero, or if the base is not at least 2;
+        /// When the number is zero, or if the base is not at least 2;
         /// it panics in debug mode and the return value is 0 in release mode.
         ///
         /// # Examples
@@ -722,7 +722,7 @@ pub const fn log(self, base: Self) -> u32 {
         ///
         /// # Panics
         ///
-        /// When the number is negative or zero it panics in debug mode and
+        /// When the number is zero it panics in debug mode and
         /// the return value is 0 in release mode.
         ///
         /// # Examples
@@ -755,7 +755,7 @@ pub const fn log2(self) -> u32 {
         ///
         /// # Panics
         ///
-        /// When the number is negative or zero it panics in debug mode and the
+        /// When the number is zero it panics in debug mode and the
         /// return value is 0 in release mode.
         ///
         /// # Example
index 9d1e7e81b0e7e853eee1b44642e4b49af9957b57..31c1a1d099dc6e9852b265200486060ce1be6966 100644 (file)
 #[unstable(feature = "try_trait_v2", issue = "84277")]
 pub use self::try_trait::{FromResidual, Try};
 
+#[unstable(feature = "try_trait_v2_yeet", issue = "96374")]
+pub use self::try_trait::Yeet;
+
 #[unstable(feature = "try_trait_v2_residual", issue = "91285")]
 pub use self::try_trait::Residual;
 
index ba369e7f3aaa0a2af92477588d6e36e4500405d7..3eaee958b69bd730a16f731b63b1665496596b22 100644 (file)
@@ -330,6 +330,22 @@ pub trait FromResidual<R = <Self as Try>::Residual> {
     fn from_residual(residual: R) -> Self;
 }
 
+#[cfg(not(bootstrap))]
+#[unstable(
+    feature = "yeet_desugar_details",
+    issue = "none",
+    reason = "just here to simplify the desugaring; will never be stabilized"
+)]
+#[inline]
+#[track_caller] // because `Result::from_residual` has it
+#[lang = "from_yeet"]
+pub fn from_yeet<T, Y>(yeeted: Y) -> T
+where
+    T: FromResidual<Yeet<Y>>,
+{
+    FromResidual::from_residual(Yeet(yeeted))
+}
+
 /// Allows retrieving the canonical type implementing [`Try`] that has this type
 /// as its residual and allows it to hold an `O` as its output.
 ///
@@ -395,3 +411,9 @@ fn from_residual(never: NeverShortCircuitResidual) -> Self {
 impl<T> Residual<T> for NeverShortCircuitResidual {
     type TryType = NeverShortCircuit<T>;
 }
+
+/// Implement `FromResidual<Yeet<T>>` on your type to enable
+/// `do yeet expr` syntax in functions returning your type.
+#[unstable(feature = "try_trait_v2_yeet", issue = "96374")]
+#[derive(Debug)]
+pub struct Yeet<T>(pub T);
index 91e4708f6a6090381e0fc5e67e6865f3861a5b1d..f339b076dd7d083a961a64dae88b806774ff7cc4 100644 (file)
@@ -2287,6 +2287,14 @@ fn from_residual(residual: Option<convert::Infallible>) -> Self {
     }
 }
 
+#[unstable(feature = "try_trait_v2_yeet", issue = "96374")]
+impl<T> ops::FromResidual<ops::Yeet<()>> for Option<T> {
+    #[inline]
+    fn from_residual(ops::Yeet(()): ops::Yeet<()>) -> Self {
+        None
+    }
+}
+
 #[unstable(feature = "try_trait_v2_residual", issue = "91285")]
 impl<T> ops::Residual<T> for Option<convert::Infallible> {
     type TryType = Option<T>;
index 714e9b73c78a61f71e4c32e8c2a46dc51eeaa7d2..8eefd9ff20db210a1cfd96b8a77e621fdaaf72ce 100644 (file)
@@ -83,6 +83,7 @@ impl<'a> Location<'a> {
     #[stable(feature = "track_caller", since = "1.46.0")]
     #[rustc_const_unstable(feature = "const_caller_location", issue = "76156")]
     #[track_caller]
+    #[inline]
     pub const fn caller() -> &'static Location<'static> {
         crate::intrinsics::caller_location()
     }
@@ -122,6 +123,7 @@ pub const fn caller() -> &'static Location<'static> {
     /// ```
     #[must_use]
     #[stable(feature = "panic_hooks", since = "1.10.0")]
+    #[inline]
     pub fn file(&self) -> &str {
         self.file
     }
@@ -145,6 +147,7 @@ pub fn file(&self) -> &str {
     /// ```
     #[must_use]
     #[stable(feature = "panic_hooks", since = "1.10.0")]
+    #[inline]
     pub fn line(&self) -> u32 {
         self.line
     }
@@ -168,6 +171,7 @@ pub fn line(&self) -> u32 {
     /// ```
     #[must_use]
     #[stable(feature = "panic_col", since = "1.25.0")]
+    #[inline]
     pub fn column(&self) -> u32 {
         self.col
     }
index 95be879e319aac0b7b51bf7ca0262e76de7a3715..f2948aac3c235c5914cc878bf24dcdf774dc5a9f 100644 (file)
@@ -279,6 +279,13 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     }
 }
 
+#[stable(feature = "assertunwindsafe_default", since = "1.62.0")]
+impl<T: Default> Default for AssertUnwindSafe<T> {
+    fn default() -> Self {
+        Self(Default::default())
+    }
+}
+
 #[stable(feature = "futures_api", since = "1.36.0")]
 impl<F: Future> Future for AssertUnwindSafe<F> {
     type Output = F::Output;
index b2b132300a299869fcfab14e8bc4ece0b0bf4a28..5e5f8a5ab954388880004cf63f4bb4bd763e9e19 100644 (file)
@@ -2107,6 +2107,14 @@ fn from_residual(residual: Result<convert::Infallible, E>) -> Self {
     }
 }
 
+#[unstable(feature = "try_trait_v2_yeet", issue = "96374")]
+impl<T, E, F: From<E>> ops::FromResidual<ops::Yeet<E>> for Result<T, F> {
+    #[inline]
+    fn from_residual(ops::Yeet(e): ops::Yeet<E>) -> Self {
+        Err(From::from(e))
+    }
+}
+
 #[unstable(feature = "try_trait_v2_residual", issue = "91285")]
 impl<T, E> ops::Residual<T> for Result<convert::Infallible, E> {
     type TryType = Result<T, E>;
index b74ab28fc092a9599e276016d4af985f3e184f2d..78bf3381b4d269f8e6be66741896f2a05046023f 100644 (file)
@@ -326,6 +326,7 @@ fn rposition<P>(&mut self, mut predicate: P) -> Option<usize> where
             }
 
             #[doc(hidden)]
+            #[inline]
             unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
                 // SAFETY: the caller must guarantee that `i` is in bounds of
                 // the underlying slice, so `i` cannot overflow an `isize`, and
index 2a4030de00b4e0f70a4db3e878ab3f1708aa6ccc..a226dea54a4f2ab228512e666fb4abf7210cb742 100644 (file)
@@ -2139,6 +2139,12 @@ pub fn rsplitn_mut<F>(&mut self, n: usize, pred: F) -> RSplitNMut<'_, T, F>
 
     /// Returns `true` if the slice contains an element with the given value.
     ///
+    /// This operation is *O*(*n*).
+    ///
+    /// Note that if you have a sorted slice, [`binary_search`] may be faster.
+    ///
+    /// [`binary_search`]: slice::binary_search
+    ///
     /// # Examples
     ///
     /// ```
@@ -2298,7 +2304,8 @@ pub fn strip_suffix<P: SlicePattern<Item = T> + ?Sized>(&self, suffix: &P) -> Op
         None
     }
 
-    /// Binary searches this sorted slice for a given element.
+    /// Binary searches this slice for a given element.
+    /// This behaves similary to [`contains`] if this slice is sorted.
     ///
     /// If the value is found then [`Result::Ok`] is returned, containing the
     /// index of the matching element. If there are multiple matches, then any
@@ -2310,6 +2317,7 @@ pub fn strip_suffix<P: SlicePattern<Item = T> + ?Sized>(&self, suffix: &P) -> Op
     ///
     /// See also [`binary_search_by`], [`binary_search_by_key`], and [`partition_point`].
     ///
+    /// [`contains`]: slice::contains
     /// [`binary_search_by`]: slice::binary_search_by
     /// [`binary_search_by_key`]: slice::binary_search_by_key
     /// [`partition_point`]: slice::partition_point
@@ -2349,7 +2357,8 @@ pub fn binary_search(&self, x: &T) -> Result<usize, usize>
         self.binary_search_by(|p| p.cmp(x))
     }
 
-    /// Binary searches this sorted slice with a comparator function.
+    /// Binary searches this slice with a comparator function.
+    /// This behaves similarly to [`contains`] if this slice is sorted.
     ///
     /// The comparator function should implement an order consistent
     /// with the sort order of the underlying slice, returning an
@@ -2366,6 +2375,7 @@ pub fn binary_search(&self, x: &T) -> Result<usize, usize>
     ///
     /// See also [`binary_search`], [`binary_search_by_key`], and [`partition_point`].
     ///
+    /// [`contains`]: slice::contains
     /// [`binary_search`]: slice::binary_search
     /// [`binary_search_by_key`]: slice::binary_search_by_key
     /// [`partition_point`]: slice::partition_point
@@ -2424,7 +2434,8 @@ pub fn binary_search_by<'a, F>(&'a self, mut f: F) -> Result<usize, usize>
         Err(left)
     }
 
-    /// Binary searches this sorted slice with a key extraction function.
+    /// Binary searches this slice with a key extraction function.
+    /// This behaves similarly to [`contains`] if this slice is sorted.
     ///
     /// Assumes that the slice is sorted by the key, for instance with
     /// [`sort_by_key`] using the same key extraction function.
@@ -2439,6 +2450,7 @@ pub fn binary_search_by<'a, F>(&'a self, mut f: F) -> Result<usize, usize>
     ///
     /// See also [`binary_search`], [`binary_search_by`], and [`partition_point`].
     ///
+    /// [`contains`]: slice::contains
     /// [`sort_by_key`]: slice::sort_by_key
     /// [`binary_search`]: slice::binary_search
     /// [`binary_search_by`]: slice::binary_search_by
index 9979cc8fde4341d3579cdc600a3412c6ac3b7246..ae8b938250ec9177f680902e7de4ff0ee7876dad 100644 (file)
@@ -43,18 +43,6 @@ macro_rules! impls_defined {
 }
 
 macro_rules! test_op {
-    ($fn_name:ident, $op:ident::$method:ident($lhs:literal, $rhs:literal), $result:literal, $($t:ty),+) => {
-        #[test]
-        fn $fn_name() {
-            impls_defined!($op, $method($lhs, $rhs), $result, $($t),+);
-        }
-    };
-    ($fn_name:ident, $op:ident::$method:ident(&mut $lhs:literal, $rhs:literal), $result:literal, $($t:ty),+) => {
-        #[test]
-        fn $fn_name() {
-            impls_defined!($op, $method(&mut $lhs, $rhs), $result, $($t),+);
-        }
-    };
     ($fn_name:ident, $op:ident::$method:ident($lhs:literal), $result:literal, $($t:ty),+) => {
         #[test]
         fn $fn_name() {
index 00b8bb1eb2637706833f8bd1b6eea3909cc5c87c..f1c5eaad868e99d495224fd2cee4111f4e9c17b6 100644 (file)
@@ -704,10 +704,10 @@ pub enum Delimiter {
     #[stable(feature = "proc_macro_lib2", since = "1.29.0")]
     Bracket,
     /// `Ø ... Ø`
-    /// An implicit delimiter, that may, for example, appear around tokens coming from a
+    /// 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`.
-    /// Implicit delimiters might not survive 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 1fd59889709b211f7828314f6d52c5e814c150e5..04fa696d5e6be936a97f505aef6e14b7869587ca 100644 (file)
@@ -12,7 +12,6 @@ macro_rules! quote_tt {
     ({$($t:tt)*}) => { Group::new(Delimiter::Brace, quote!($($t)*)) };
     (,) => { Punct::new(',', Spacing::Alone) };
     (.) => { Punct::new('.', Spacing::Alone) };
-    (:) => { Punct::new(':', Spacing::Alone) };
     (;) => { Punct::new(';', Spacing::Alone) };
     (!) => { Punct::new('!', Spacing::Alone) };
     (<) => { Punct::new('<', Spacing::Alone) };
index 6b63191eb583d7602ec0455a4c5fb46e5813830c..0c638192264e6d60fee5125ccfa73211b1d68d1f 100644 (file)
 /// ]);
 /// ```
 ///
-/// `HashMap` implements an [`Entry API`](#method.entry), which allows
+/// `HashMap` implements an [`Entry` API](#method.entry), which allows
 /// for complex methods of getting, setting, updating and removing keys and
 /// their values:
 ///
index 0141a2bccdf161eac2c89aa2b8c9bfe22a94dbec..10983a3323265727545b503b261c608fa74336d0 100644 (file)
 #[stable(feature = "core_c_void", since = "1.30.0")]
 pub use core::ffi::c_void;
 
-#[unstable(feature = "core_ffi_c", issue = "94501")]
-pub use core::ffi::{
-    c_char, c_double, c_float, c_int, c_long, c_longlong, c_schar, c_short, c_uchar, c_uint,
-    c_ulong, c_ulonglong, c_ushort,
-};
-
-#[unstable(feature = "c_size_t", issue = "88345")]
-pub use core::ffi::{c_ptrdiff_t, c_size_t, c_ssize_t};
-
 #[unstable(
     feature = "c_variadic",
     reason = "the `c_variadic` feature has not been properly tested on \
index da7753216d0630b91aa893f256adf54036d96f3f..97c30c422827e3f105e50263a99aa742f6729995 100644 (file)
 #![feature(exhaustive_patterns)]
 #![feature(intra_doc_pointers)]
 #![feature(lang_items)]
+#![feature(let_chains)]
 #![feature(linkage)]
 #![feature(min_specialization)]
 #![feature(must_not_suspend)]
 // Only for re-exporting:
 #![feature(assert_matches)]
 #![feature(async_iterator)]
-#![feature(c_size_t)]
 #![feature(c_variadic)]
 #![feature(cfg_accessible)]
 #![feature(cfg_eval)]
index c597fb5df45d28fd49af6d3a20a95b0a49997d16..e512c0d81a0f3574acd1590e93eb505cc4361f9b 100644 (file)
@@ -31,6 +31,8 @@ macro_rules! panic {
 /// [`eprint!`] instead to print error and progress messages.
 ///
 /// [flush]: crate::io::Write::flush
+/// [`println!`]: crate::println
+/// [`eprint!`]: crate::eprint
 ///
 /// # Panics
 ///
@@ -77,6 +79,7 @@ macro_rules! print {
 /// [`eprintln!`] instead to print error and progress messages.
 ///
 /// [`std::fmt`]: crate::fmt
+/// [`eprintln!`]: crate::eprintln
 ///
 /// # Panics
 ///
@@ -99,9 +102,9 @@ macro_rules! println {
     () => {
         $crate::print!("\n")
     };
-    ($($arg:tt)*) => {
-        $crate::io::_print($crate::format_args_nl!($($arg)*))
-    };
+    ($($arg:tt)*) => {{
+        $crate::io::_print($crate::format_args_nl!($($arg)*));
+    }};
 }
 
 /// Prints to the standard error.
@@ -146,6 +149,7 @@ macro_rules! eprint {
 ///
 /// [`io::stderr`]: crate::io::stderr
 /// [`io::stdout`]: crate::io::stdout
+/// [`println!`]: crate::println
 ///
 /// # Panics
 ///
@@ -164,9 +168,9 @@ macro_rules! eprintln {
     () => {
         $crate::eprint!("\n")
     };
-    ($($arg:tt)*) => {
-        $crate::io::_eprint($crate::format_args_nl!($($arg)*))
-    };
+    ($($arg:tt)*) => {{
+        $crate::io::_eprint($crate::format_args_nl!($($arg)*));
+    }};
 }
 
 /// Prints and returns the value of a given expression for quick and dirty
index d95bc9b15c9c42b98aa9ad46de9dbb7ad921e44c..9a6778c0e869b1ea6852b3ff091b84367b7b2fb0 100644 (file)
@@ -24,8 +24,8 @@ pub trait CommandExt: Sealed {
     #[stable(feature = "rust1", since = "1.0.0")]
     fn uid(
         &mut self,
-        #[cfg(not(target_os = "vxworks"))] id: u32,
-        #[cfg(target_os = "vxworks")] id: u16,
+        #[cfg(not(any(target_os = "vxworks", target_os = "espidf")))] id: u32,
+        #[cfg(any(target_os = "vxworks", target_os = "espidf"))] id: u16,
     ) -> &mut process::Command;
 
     /// Similar to `uid`, but sets the group ID of the child process. This has
@@ -33,8 +33,8 @@ fn uid(
     #[stable(feature = "rust1", since = "1.0.0")]
     fn gid(
         &mut self,
-        #[cfg(not(target_os = "vxworks"))] id: u32,
-        #[cfg(target_os = "vxworks")] id: u16,
+        #[cfg(not(any(target_os = "vxworks", target_os = "espidf")))] id: u32,
+        #[cfg(any(target_os = "vxworks", target_os = "espidf"))] id: u16,
     ) -> &mut process::Command;
 
     /// Sets the supplementary group IDs for the calling process. Translates to
@@ -42,8 +42,8 @@ fn gid(
     #[unstable(feature = "setgroups", issue = "90747")]
     fn groups(
         &mut self,
-        #[cfg(not(target_os = "vxworks"))] groups: &[u32],
-        #[cfg(target_os = "vxworks")] groups: &[u16],
+        #[cfg(not(any(target_os = "vxworks", target_os = "espidf")))] groups: &[u32],
+        #[cfg(any(target_os = "vxworks", target_os = "espidf"))] groups: &[u16],
     ) -> &mut process::Command;
 
     /// Schedules a closure to be run just before the `exec` function is
@@ -160,8 +160,8 @@ fn arg0<S>(&mut self, arg: S) -> &mut process::Command
 impl CommandExt for process::Command {
     fn uid(
         &mut self,
-        #[cfg(not(target_os = "vxworks"))] id: u32,
-        #[cfg(target_os = "vxworks")] id: u16,
+        #[cfg(not(any(target_os = "vxworks", target_os = "espidf")))] id: u32,
+        #[cfg(any(target_os = "vxworks", target_os = "espidf"))] id: u16,
     ) -> &mut process::Command {
         self.as_inner_mut().uid(id);
         self
@@ -169,8 +169,8 @@ fn uid(
 
     fn gid(
         &mut self,
-        #[cfg(not(target_os = "vxworks"))] id: u32,
-        #[cfg(target_os = "vxworks")] id: u16,
+        #[cfg(not(any(target_os = "vxworks", target_os = "espidf")))] id: u32,
+        #[cfg(any(target_os = "vxworks", target_os = "espidf"))] id: u16,
     ) -> &mut process::Command {
         self.as_inner_mut().gid(id);
         self
@@ -178,8 +178,8 @@ fn gid(
 
     fn groups(
         &mut self,
-        #[cfg(not(target_os = "vxworks"))] groups: &[u32],
-        #[cfg(target_os = "vxworks")] groups: &[u16],
+        #[cfg(not(any(target_os = "vxworks", target_os = "espidf")))] groups: &[u32],
+        #[cfg(any(target_os = "vxworks", target_os = "espidf"))] groups: &[u16],
     ) -> &mut process::Command {
         self.as_inner_mut().groups(groups);
         self
index ee30cc8be6b57c442c6114d9918aa9bbdc66d0e5..f3d7be3f95c6b0db39526c217581cc6d3012923c 100644 (file)
@@ -76,7 +76,7 @@ pub struct OwnedHandle {
 /// `NULL`. This ensures that such FFI calls cannot start using the handle without
 /// checking for `NULL` first.
 ///
-/// This type concerns any value other than `NULL` to be valid, including `INVALID_HANDLE_VALUE`.
+/// This type considers any value other than `NULL` to be valid, including `INVALID_HANDLE_VALUE`.
 /// This is because APIs that use `NULL` as their sentry value don't treat `INVALID_HANDLE_VALUE`
 /// as special.
 ///
@@ -96,7 +96,7 @@ pub struct OwnedHandle {
 /// `INVALID_HANDLE_VALUE`. This ensures that such FFI calls cannot start using the handle without
 /// checking for `INVALID_HANDLE_VALUE` first.
 ///
-/// This type concerns any value other than `INVALID_HANDLE_VALUE` to be valid, including `NULL`.
+/// This type considers any value other than `INVALID_HANDLE_VALUE` to be valid, including `NULL`.
 /// This is because APIs that use `INVALID_HANDLE_VALUE` as their sentry value may return `NULL`
 /// under `windows_subsystem = "windows"` or other situations where I/O devices are detached.
 ///
@@ -143,17 +143,17 @@ pub unsafe fn borrow_raw(handle: RawHandle) -> Self {
 }
 
 impl TryFrom<HandleOrNull> for OwnedHandle {
-    type Error = ();
+    type Error = NullHandleError;
 
     #[inline]
-    fn try_from(handle_or_null: HandleOrNull) -> Result<Self, ()> {
+    fn try_from(handle_or_null: HandleOrNull) -> Result<Self, NullHandleError> {
         let owned_handle = handle_or_null.0;
         if owned_handle.handle.is_null() {
             // Don't call `CloseHandle`; it'd be harmless, except that it could
             // overwrite the `GetLastError` error.
             forget(owned_handle);
 
-            Err(())
+            Err(NullHandleError(()))
         } else {
             Ok(owned_handle)
         }
@@ -198,26 +198,74 @@ pub(crate) fn duplicate(
         })?;
         unsafe { Ok(Self::from_raw_handle(ret)) }
     }
+
+    /// Allow child processes to inherit the handle.
+    pub(crate) fn set_inheritable(&self) -> io::Result<()> {
+        cvt(unsafe {
+            c::SetHandleInformation(
+                self.as_raw_handle(),
+                c::HANDLE_FLAG_INHERIT,
+                c::HANDLE_FLAG_INHERIT,
+            )
+        })?;
+        Ok(())
+    }
 }
 
 impl TryFrom<HandleOrInvalid> for OwnedHandle {
-    type Error = ();
+    type Error = InvalidHandleError;
 
     #[inline]
-    fn try_from(handle_or_invalid: HandleOrInvalid) -> Result<Self, ()> {
+    fn try_from(handle_or_invalid: HandleOrInvalid) -> Result<Self, InvalidHandleError> {
         let owned_handle = handle_or_invalid.0;
         if owned_handle.handle == c::INVALID_HANDLE_VALUE {
             // Don't call `CloseHandle`; it'd be harmless, except that it could
             // overwrite the `GetLastError` error.
             forget(owned_handle);
 
-            Err(())
+            Err(InvalidHandleError(()))
         } else {
             Ok(owned_handle)
         }
     }
 }
 
+/// This is the error type used by [`HandleOrNull`] when attempting to convert
+/// into a handle, to indicate that the value is null.
+// The empty field prevents constructing this, and allows extending it in the future.
+#[unstable(feature = "io_safety", issue = "87074")]
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct NullHandleError(());
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl fmt::Display for NullHandleError {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        "A HandleOrNull could not be converted to a handle because it was null".fmt(fmt)
+    }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl crate::error::Error for NullHandleError {}
+
+/// This is the error type used by [`HandleOrInvalid`] when attempting to
+/// convert into a handle, to indicate that the value is
+/// `INVALID_HANDLE_VALUE`.
+// The empty field prevents constructing this, and allows extending it in the future.
+#[unstable(feature = "io_safety", issue = "87074")]
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct InvalidHandleError(());
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl fmt::Display for InvalidHandleError {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        "A HandleOrInvalid could not be converted to a handle because it was INVALID_HANDLE_VALUE"
+            .fmt(fmt)
+    }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl crate::error::Error for InvalidHandleError {}
+
 impl AsRawHandle for BorrowedHandle<'_> {
     #[inline]
     fn as_raw_handle(&self) -> RawHandle {
index 8ecea8ce07f6b7aa7560788f3945c05bfc71d6f4..c03d197e0194c9c4f2a6ea9ddc89d873ce81a290 100644 (file)
@@ -168,8 +168,8 @@ pub enum Prefix<'a> {
 
     /// Device namespace prefix, e.g., `\\.\COM42`.
     ///
-    /// Device namespace prefixes consist of `\\.\` immediately followed by the
-    /// device name.
+    /// Device namespace prefixes consist of `\\.\` (possibly using `/`
+    /// instead of `\`), immediately followed by the device name.
     #[stable(feature = "rust1", since = "1.0.0")]
     DeviceNS(#[stable(feature = "rust1", since = "1.0.0")] &'a OsStr),
 
@@ -193,7 +193,7 @@ impl<'a> Prefix<'a> {
     fn len(&self) -> usize {
         use self::Prefix::*;
         fn os_str_len(s: &OsStr) -> usize {
-            os_str_as_u8_slice(s).len()
+            s.bytes().len()
         }
         match *self {
             Verbatim(x) => 4 + os_str_len(x),
@@ -299,19 +299,17 @@ fn iter_after<'a, 'b, I, J>(mut iter: I, mut prefix: J) -> Option<I>
     }
 }
 
-// See note at the top of this module to understand why these are used:
-//
-// These casts are safe as OsStr is internally a wrapper around [u8] on all
-// platforms.
-//
-// Note that currently this relies on the special knowledge that libstd has;
-// these types are single-element structs but are not marked repr(transparent)
-// or repr(C) which would make these casts allowable outside std.
-fn os_str_as_u8_slice(s: &OsStr) -> &[u8] {
-    unsafe { &*(s as *const OsStr as *const [u8]) }
-}
 unsafe fn u8_slice_as_os_str(s: &[u8]) -> &OsStr {
-    // SAFETY: see the comment of `os_str_as_u8_slice`
+    // SAFETY: See note at the top of this module to understand why this and
+    // `OsStr::bytes` are used:
+    //
+    // This casts are safe as OsStr is internally a wrapper around [u8] on all
+    // platforms.
+    //
+    // Note that currently this relies on the special knowledge that libstd has;
+    // these types are single-element structs but are not marked
+    // repr(transparent) or repr(C) which would make these casts not allowable
+    // outside std.
     unsafe { &*(s as *const [u8] as *const OsStr) }
 }
 
@@ -332,7 +330,7 @@ fn has_physical_root(s: &[u8], prefix: Option<Prefix<'_>>) -> bool {
 
 // basic workhorse for splitting stem and extension
 fn rsplit_file_at_dot(file: &OsStr) -> (Option<&OsStr>, Option<&OsStr>) {
-    if os_str_as_u8_slice(file) == b".." {
+    if file.bytes() == b".." {
         return (Some(file), None);
     }
 
@@ -340,7 +338,7 @@ fn rsplit_file_at_dot(file: &OsStr) -> (Option<&OsStr>, Option<&OsStr>) {
     // and back. This is safe to do because (1) we only look at ASCII
     // contents of the encoding and (2) new &OsStr values are produced
     // only from ASCII-bounded slices of existing &OsStr values.
-    let mut iter = os_str_as_u8_slice(file).rsplitn(2, |b| *b == b'.');
+    let mut iter = file.bytes().rsplitn(2, |b| *b == b'.');
     let after = iter.next();
     let before = iter.next();
     if before == Some(b"") {
@@ -351,7 +349,7 @@ fn rsplit_file_at_dot(file: &OsStr) -> (Option<&OsStr>, Option<&OsStr>) {
 }
 
 fn split_file_at_dot(file: &OsStr) -> (&OsStr, Option<&OsStr>) {
-    let slice = os_str_as_u8_slice(file);
+    let slice = file.bytes();
     if slice == b".." {
         return (file, None);
     }
@@ -1445,17 +1443,17 @@ pub fn set_extension<S: AsRef<OsStr>>(&mut self, extension: S) -> bool {
     fn _set_extension(&mut self, extension: &OsStr) -> bool {
         let file_stem = match self.file_stem() {
             None => return false,
-            Some(f) => os_str_as_u8_slice(f),
+            Some(f) => f.bytes(),
         };
 
         // truncate until right after the file stem
         let end_file_stem = file_stem[file_stem.len()..].as_ptr().addr();
-        let start = os_str_as_u8_slice(&self.inner).as_ptr().addr();
+        let start = self.inner.bytes().as_ptr().addr();
         let v = self.as_mut_vec();
         v.truncate(end_file_stem.wrapping_sub(start));
 
         // add the new extension, if any
-        let new = os_str_as_u8_slice(extension);
+        let new = extension.bytes();
         if !new.is_empty() {
             v.reserve_exact(new.len() + 1);
             v.push(b'.');
@@ -1948,7 +1946,7 @@ unsafe fn from_u8_slice(s: &[u8]) -> &Path {
     }
     // The following (private!) function reveals the byte encoding used for OsStr.
     fn as_u8_slice(&self) -> &[u8] {
-        os_str_as_u8_slice(&self.inner)
+        self.inner.bytes()
     }
 
     /// Directly wraps a string slice as a `Path` slice.
index d1f59d2786e91f05f9f5cfbcb2f7208b5d938eda..0d8ea29c2be759b1580f2b36f20560d5d2b6ecb7 100644 (file)
@@ -971,15 +971,15 @@ pub fn test_decompositions_windows() {
     file_prefix: None
     );
 
-    t!("\\\\?\\C:/foo",
-    iter: ["\\\\?\\C:/foo"],
+    t!("\\\\?\\C:/foo/bar",
+    iter: ["\\\\?\\C:", "\\", "foo/bar"],
     has_root: true,
     is_absolute: true,
-    parent: None,
-    file_name: None,
-    file_stem: None,
+    parent: Some("\\\\?\\C:/"),
+    file_name: Some("foo/bar"),
+    file_stem: Some("foo/bar"),
     extension: None,
-    file_prefix: None
+    file_prefix: Some("foo/bar")
     );
 
     t!("\\\\.\\foo\\bar",
index 4f779ab4e786c65788a1e51e6c2f8a7c3ae67361..955ad68916c216ae5fc7493cbca3781309b1e6fe 100644 (file)
@@ -435,3 +435,24 @@ fn run_bat_script() {
     assert!(output.status.success());
     assert_eq!(String::from_utf8_lossy(&output.stdout).trim(), "Hello, fellow Rustaceans!");
 }
+
+// See issue #95178
+#[test]
+#[cfg(windows)]
+fn run_canonical_bat_script() {
+    let tempdir = crate::sys_common::io::test::tmpdir();
+    let script_path = tempdir.join("hello.cmd");
+
+    crate::fs::write(&script_path, "@echo Hello, %~1!").unwrap();
+
+    // Try using a canonical path
+    let output = Command::new(&script_path.canonicalize().unwrap())
+        .arg("fellow Rustaceans")
+        .stdout(crate::process::Stdio::piped())
+        .spawn()
+        .unwrap()
+        .wait_with_output()
+        .unwrap();
+    assert!(output.status.success());
+    assert_eq!(String::from_utf8_lossy(&output.stdout).trim(), "Hello, fellow Rustaceans!");
+}
index 3de7c68a6866dbde7bb55aa2f749e621a164f30b..40a645858025012070792daa8745473b903dedb5 100644 (file)
 
 use libc::{c_int, c_void};
 
+#[cfg(any(
+    target_os = "android",
+    target_os = "linux",
+    target_os = "emscripten",
+    target_os = "l4re"
+))]
+use libc::off64_t;
+#[cfg(not(any(
+    target_os = "linux",
+    target_os = "emscripten",
+    target_os = "l4re",
+    target_os = "android"
+)))]
+use libc::off_t as off64_t;
+
 #[derive(Debug)]
 pub struct FileDesc(OwnedFd);
 
@@ -109,7 +124,7 @@ pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
                 self.as_raw_fd(),
                 buf.as_mut_ptr() as *mut c_void,
                 cmp::min(buf.len(), READ_LIMIT),
-                offset as i64,
+                offset as off64_t,
             ))
             .map(|n| n as usize)
         }
@@ -176,7 +191,7 @@ pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
                 self.as_raw_fd(),
                 buf.as_ptr() as *const c_void,
                 cmp::min(buf.len(), READ_LIMIT),
-                offset as i64,
+                offset as off64_t,
             ))
             .map(|n| n as usize)
         }
index a60b19976ba4e0d4376ba9396db9229e4f45fdc2..27fc7accdaeca404dbafd7c1add31598a9c9ebd8 100644 (file)
@@ -966,7 +966,7 @@ pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> {
             SeekFrom::End(off) => (libc::SEEK_END, off),
             SeekFrom::Current(off) => (libc::SEEK_CUR, off),
         };
-        let n = cvt(unsafe { lseek64(self.as_raw_fd(), pos, whence) })?;
+        let n = cvt(unsafe { lseek64(self.as_raw_fd(), pos as off64_t, whence) })?;
         Ok(n as u64)
     }
 
index aedeb02e656d6652d9b77eadd91997865b1520be..8e909aab7f0cabae9793bac4e96677253e5947df 100644 (file)
@@ -39,6 +39,7 @@
 pub mod thread;
 pub mod thread_local_dtor;
 pub mod thread_local_key;
+pub mod thread_parker;
 pub mod time;
 
 #[cfg(target_os = "espidf")]
index 27bee714f5b4317132db508fe916c7e194d05bc5..bca1b65a7fc051862af3a3c8aeb432ea491acb83 100644 (file)
@@ -35,7 +35,8 @@
 // Android with api less than 21 define sig* functions inline, so it is not
 // available for dynamic link. Implementing sigemptyset and sigaddset allow us
 // to support older Android version (independent of libc version).
-// The following implementations are based on https://git.io/vSkNf
+// The following implementations are based on
+// https://github.com/aosp-mirror/platform_bionic/blob/ad8dcd6023294b646e5a8288c0ed431b0845da49/libc/include/android/legacy_signal_inlines.h
 cfg_if::cfg_if! {
     if #[cfg(target_os = "android")] {
         pub unsafe fn sigemptyset(set: *mut libc::sigset_t) -> libc::c_int {
diff --git a/library/std/src/sys/unix/thread_parker.rs b/library/std/src/sys/unix/thread_parker.rs
new file mode 100644 (file)
index 0000000..fd83f2f
--- /dev/null
@@ -0,0 +1,265 @@
+//! Thread parking without `futex` using the `pthread` synchronization primitives.
+
+#![cfg(not(any(
+    target_os = "linux",
+    target_os = "android",
+    all(target_os = "emscripten", target_feature = "atomics")
+)))]
+
+use crate::cell::UnsafeCell;
+use crate::marker::PhantomPinned;
+use crate::pin::Pin;
+use crate::ptr::addr_of_mut;
+use crate::sync::atomic::AtomicUsize;
+use crate::sync::atomic::Ordering::SeqCst;
+use crate::time::Duration;
+
+const EMPTY: usize = 0;
+const PARKED: usize = 1;
+const NOTIFIED: usize = 2;
+
+unsafe fn lock(lock: *mut libc::pthread_mutex_t) {
+    let r = libc::pthread_mutex_lock(lock);
+    debug_assert_eq!(r, 0);
+}
+
+unsafe fn unlock(lock: *mut libc::pthread_mutex_t) {
+    let r = libc::pthread_mutex_unlock(lock);
+    debug_assert_eq!(r, 0);
+}
+
+unsafe fn notify_one(cond: *mut libc::pthread_cond_t) {
+    let r = libc::pthread_cond_signal(cond);
+    debug_assert_eq!(r, 0);
+}
+
+unsafe fn wait(cond: *mut libc::pthread_cond_t, lock: *mut libc::pthread_mutex_t) {
+    let r = libc::pthread_cond_wait(cond, lock);
+    debug_assert_eq!(r, 0);
+}
+
+const TIMESPEC_MAX: libc::timespec =
+    libc::timespec { tv_sec: <libc::time_t>::MAX, tv_nsec: 1_000_000_000 - 1 };
+
+unsafe fn wait_timeout(
+    cond: *mut libc::pthread_cond_t,
+    lock: *mut libc::pthread_mutex_t,
+    dur: Duration,
+) {
+    // Use the system clock on systems that do not support pthread_condattr_setclock.
+    // This unfortunately results in problems when the system time changes.
+    #[cfg(any(target_os = "macos", target_os = "ios", target_os = "espidf"))]
+    let (now, dur) = {
+        use super::time::SystemTime;
+        use crate::cmp::min;
+
+        // OSX implementation of `pthread_cond_timedwait` is buggy
+        // with super long durations. When duration is greater than
+        // 0x100_0000_0000_0000 seconds, `pthread_cond_timedwait`
+        // in macOS Sierra return error 316.
+        //
+        // This program demonstrates the issue:
+        // https://gist.github.com/stepancheg/198db4623a20aad2ad7cddb8fda4a63c
+        //
+        // To work around this issue, and possible bugs of other OSes, timeout
+        // is clamped to 1000 years, which is allowable per the API of `park_timeout`
+        // because of spurious wakeups.
+        let dur = min(dur, Duration::from_secs(1000 * 365 * 86400));
+        let now = SystemTime::now().t;
+        (now, dur)
+    };
+    // Use the monotonic clock on other systems.
+    #[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "espidf")))]
+    let (now, dur) = {
+        use super::time::Timespec;
+
+        (Timespec::now(libc::CLOCK_MONOTONIC), dur)
+    };
+
+    let timeout = now.checked_add_duration(&dur).map(|t| t.t).unwrap_or(TIMESPEC_MAX);
+    let r = libc::pthread_cond_timedwait(cond, lock, &timeout);
+    debug_assert!(r == libc::ETIMEDOUT || r == 0);
+}
+
+pub struct Parker {
+    state: AtomicUsize,
+    lock: UnsafeCell<libc::pthread_mutex_t>,
+    cvar: UnsafeCell<libc::pthread_cond_t>,
+    // The `pthread` primitives require a stable address, so make this struct `!Unpin`.
+    _pinned: PhantomPinned,
+}
+
+impl Parker {
+    /// Construct the UNIX parker in-place.
+    ///
+    /// # Safety
+    /// The constructed parker must never be moved.
+    pub unsafe fn new(parker: *mut Parker) {
+        // Use the default mutex implementation to allow for simpler initialization.
+        // This could lead to undefined behaviour when deadlocking. This is avoided
+        // by not deadlocking. Note in particular the unlocking operation before any
+        // panic, as code after the panic could try to park again.
+        addr_of_mut!((*parker).state).write(AtomicUsize::new(EMPTY));
+        addr_of_mut!((*parker).lock).write(UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER));
+
+        cfg_if::cfg_if! {
+            if #[cfg(any(
+                target_os = "macos",
+                target_os = "ios",
+                target_os = "l4re",
+                target_os = "android",
+                target_os = "redox"
+            ))] {
+                addr_of_mut!((*parker).cvar).write(UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER));
+            } else if #[cfg(target_os = "espidf")] {
+                let r = libc::pthread_cond_init(addr_of_mut!((*parker).cvar).cast(), crate::ptr::null());
+                assert_eq!(r, 0);
+            } else {
+                use crate::mem::MaybeUninit;
+                let mut attr = MaybeUninit::<libc::pthread_condattr_t>::uninit();
+                let r = libc::pthread_condattr_init(attr.as_mut_ptr());
+                assert_eq!(r, 0);
+                let r = libc::pthread_condattr_setclock(attr.as_mut_ptr(), libc::CLOCK_MONOTONIC);
+                assert_eq!(r, 0);
+                let r = libc::pthread_cond_init(addr_of_mut!((*parker).cvar).cast(), attr.as_ptr());
+                assert_eq!(r, 0);
+                let r = libc::pthread_condattr_destroy(attr.as_mut_ptr());
+                assert_eq!(r, 0);
+            }
+        }
+    }
+
+    // This implementation doesn't require `unsafe`, but other implementations
+    // may assume this is only called by the thread that owns the Parker.
+    pub unsafe fn park(self: Pin<&Self>) {
+        // If we were previously notified then we consume this notification and
+        // return quickly.
+        if self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() {
+            return;
+        }
+
+        // Otherwise we need to coordinate going to sleep
+        lock(self.lock.get());
+        match self.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) {
+            Ok(_) => {}
+            Err(NOTIFIED) => {
+                // We must read here, even though we know it will be `NOTIFIED`.
+                // This is because `unpark` may have been called again since we read
+                // `NOTIFIED` in the `compare_exchange` above. We must perform an
+                // acquire operation that synchronizes with that `unpark` to observe
+                // any writes it made before the call to unpark. To do that we must
+                // read from the write it made to `state`.
+                let old = self.state.swap(EMPTY, SeqCst);
+
+                unlock(self.lock.get());
+
+                assert_eq!(old, NOTIFIED, "park state changed unexpectedly");
+                return;
+            } // should consume this notification, so prohibit spurious wakeups in next park.
+            Err(_) => {
+                unlock(self.lock.get());
+
+                panic!("inconsistent park state")
+            }
+        }
+
+        loop {
+            wait(self.cvar.get(), self.lock.get());
+
+            match self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst) {
+                Ok(_) => break, // got a notification
+                Err(_) => {}    // spurious wakeup, go back to sleep
+            }
+        }
+
+        unlock(self.lock.get());
+    }
+
+    // This implementation doesn't require `unsafe`, but other implementations
+    // may assume this is only called by the thread that owns the Parker. Use
+    // `Pin` to guarantee a stable address for the mutex and condition variable.
+    pub unsafe fn park_timeout(self: Pin<&Self>, dur: Duration) {
+        // Like `park` above we have a fast path for an already-notified thread, and
+        // afterwards we start coordinating for a sleep.
+        // return quickly.
+        if self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() {
+            return;
+        }
+
+        lock(self.lock.get());
+        match self.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) {
+            Ok(_) => {}
+            Err(NOTIFIED) => {
+                // We must read again here, see `park`.
+                let old = self.state.swap(EMPTY, SeqCst);
+                unlock(self.lock.get());
+
+                assert_eq!(old, NOTIFIED, "park state changed unexpectedly");
+                return;
+            } // should consume this notification, so prohibit spurious wakeups in next park.
+            Err(_) => {
+                unlock(self.lock.get());
+                panic!("inconsistent park_timeout state")
+            }
+        }
+
+        // Wait with a timeout, and if we spuriously wake up or otherwise wake up
+        // from a notification we just want to unconditionally set the state back to
+        // empty, either consuming a notification or un-flagging ourselves as
+        // parked.
+        wait_timeout(self.cvar.get(), self.lock.get(), dur);
+
+        match self.state.swap(EMPTY, SeqCst) {
+            NOTIFIED => unlock(self.lock.get()), // got a notification, hurray!
+            PARKED => unlock(self.lock.get()),   // no notification, alas
+            n => {
+                unlock(self.lock.get());
+                panic!("inconsistent park_timeout state: {n}")
+            }
+        }
+    }
+
+    pub fn unpark(self: Pin<&Self>) {
+        // To ensure the unparked thread will observe any writes we made
+        // before this call, we must perform a release operation that `park`
+        // can synchronize with. To do that we must write `NOTIFIED` even if
+        // `state` is already `NOTIFIED`. That is why this must be a swap
+        // rather than a compare-and-swap that returns if it reads `NOTIFIED`
+        // on failure.
+        match self.state.swap(NOTIFIED, SeqCst) {
+            EMPTY => return,    // no one was waiting
+            NOTIFIED => return, // already unparked
+            PARKED => {}        // gotta go wake someone up
+            _ => panic!("inconsistent state in unpark"),
+        }
+
+        // There is a period between when the parked thread sets `state` to
+        // `PARKED` (or last checked `state` in the case of a spurious wake
+        // up) and when it actually waits on `cvar`. If we were to notify
+        // during this period it would be ignored and then when the parked
+        // thread went to sleep it would never wake up. Fortunately, it has
+        // `lock` locked at this stage so we can acquire `lock` to wait until
+        // it is ready to receive the notification.
+        //
+        // Releasing `lock` before the call to `notify_one` means that when the
+        // parked thread wakes it doesn't get woken only to have to wait for us
+        // to release `lock`.
+        unsafe {
+            lock(self.lock.get());
+            unlock(self.lock.get());
+            notify_one(self.cvar.get());
+        }
+    }
+}
+
+impl Drop for Parker {
+    fn drop(&mut self) {
+        unsafe {
+            libc::pthread_cond_destroy(self.cvar.get_mut());
+            libc::pthread_mutex_destroy(self.lock.get_mut());
+        }
+    }
+}
+
+unsafe impl Sync for Parker {}
+unsafe impl Send for Parker {}
index 498c94d0cdcba2bad36d2f203ccf3580d0704dd0..d43ceec9c8a59528d617e20f0054455f4b5fadc7 100644 (file)
@@ -132,7 +132,7 @@ pub struct Instant {
 
     #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
     pub struct SystemTime {
-        t: Timespec,
+        pub(in crate::sys::unix) t: Timespec,
     }
 
     pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() };
@@ -279,7 +279,7 @@ pub struct Instant {
 
     #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
     pub struct SystemTime {
-        t: Timespec,
+        pub(in crate::sys::unix) t: Timespec,
     }
 
     pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() };
index 3919025b0800663c3b37e749daa27b8ba47915d0..c5918103fec254eb9d7ed6a7e23019ce07711594 100644 (file)
@@ -8,12 +8,14 @@
 
 use crate::ffi::OsString;
 use crate::fmt;
+use crate::io;
 use crate::marker::PhantomData;
 use crate::num::NonZeroU16;
 use crate::os::windows::prelude::*;
 use crate::path::PathBuf;
 use crate::ptr::NonNull;
 use crate::sys::c;
+use crate::sys::process::ensure_no_nuls;
 use crate::sys::windows::os::current_exe;
 use crate::vec;
 
@@ -234,3 +236,160 @@ fn next(&mut self) -> Option<NonZeroU16> {
         }
     }
 }
+
+#[derive(Debug)]
+pub(crate) enum Arg {
+    /// Add quotes (if needed)
+    Regular(OsString),
+    /// Append raw string without quoting
+    Raw(OsString),
+}
+
+enum Quote {
+    // Every arg is quoted
+    Always,
+    // Whitespace and empty args are quoted
+    Auto,
+    // Arg appended without any changes (#29494)
+    Never,
+}
+
+pub(crate) fn append_arg(cmd: &mut Vec<u16>, arg: &Arg, force_quotes: bool) -> io::Result<()> {
+    let (arg, quote) = match arg {
+        Arg::Regular(arg) => (arg, if force_quotes { Quote::Always } else { Quote::Auto }),
+        Arg::Raw(arg) => (arg, Quote::Never),
+    };
+
+    // If an argument has 0 characters then we need to quote it to ensure
+    // that it actually gets passed through on the command line or otherwise
+    // it will be dropped entirely when parsed on the other end.
+    ensure_no_nuls(arg)?;
+    let arg_bytes = arg.bytes();
+    let (quote, escape) = match quote {
+        Quote::Always => (true, true),
+        Quote::Auto => {
+            (arg_bytes.iter().any(|c| *c == b' ' || *c == b'\t') || arg_bytes.is_empty(), true)
+        }
+        Quote::Never => (false, false),
+    };
+    if quote {
+        cmd.push('"' as u16);
+    }
+
+    let mut backslashes: usize = 0;
+    for x in arg.encode_wide() {
+        if escape {
+            if x == '\\' as u16 {
+                backslashes += 1;
+            } else {
+                if x == '"' as u16 {
+                    // Add n+1 backslashes to total 2n+1 before internal '"'.
+                    cmd.extend((0..=backslashes).map(|_| '\\' as u16));
+                }
+                backslashes = 0;
+            }
+        }
+        cmd.push(x);
+    }
+
+    if quote {
+        // Add n backslashes to total 2n before ending '"'.
+        cmd.extend((0..backslashes).map(|_| '\\' as u16));
+        cmd.push('"' as u16);
+    }
+    Ok(())
+}
+
+pub(crate) fn make_bat_command_line(
+    script: &[u16],
+    args: &[Arg],
+    force_quotes: bool,
+) -> io::Result<Vec<u16>> {
+    // Set the start of the command line to `cmd.exe /c "`
+    // It is necessary to surround the command in an extra pair of quotes,
+    // hence the trailing quote here. It will be closed after all arguments
+    // have been added.
+    let mut cmd: Vec<u16> = "cmd.exe /c \"".encode_utf16().collect();
+
+    // Push the script name surrounded by its quote pair.
+    cmd.push(b'"' as u16);
+    // Windows file names cannot contain a `"` character or end with `\\`.
+    // If the script name does then return an error.
+    if script.contains(&(b'"' as u16)) || script.last() == Some(&(b'\\' as u16)) {
+        return Err(io::const_io_error!(
+            io::ErrorKind::InvalidInput,
+            "Windows file names may not contain `\"` or end with `\\`"
+        ));
+    }
+    cmd.extend_from_slice(script.strip_suffix(&[0]).unwrap_or(script));
+    cmd.push(b'"' as u16);
+
+    // Append the arguments.
+    // FIXME: This needs tests to ensure that the arguments are properly
+    // reconstructed by the batch script by default.
+    for arg in args {
+        cmd.push(' ' as u16);
+        append_arg(&mut cmd, arg, force_quotes)?;
+    }
+
+    // Close the quote we left opened earlier.
+    cmd.push(b'"' as u16);
+
+    Ok(cmd)
+}
+
+/// Takes a path and tries to return a non-verbatim path.
+///
+/// This is necessary because cmd.exe does not support verbatim paths.
+pub(crate) fn to_user_path(mut path: Vec<u16>) -> io::Result<Vec<u16>> {
+    use crate::ptr;
+    use crate::sys::windows::fill_utf16_buf;
+
+    // UTF-16 encoded code points, used in parsing and building UTF-16 paths.
+    // All of these are in the ASCII range so they can be cast directly to `u16`.
+    const SEP: u16 = b'\\' as _;
+    const QUERY: u16 = b'?' as _;
+    const COLON: u16 = b':' as _;
+    const U: u16 = b'U' as _;
+    const N: u16 = b'N' as _;
+    const C: u16 = b'C' as _;
+
+    // Early return if the path is too long to remove the verbatim prefix.
+    const LEGACY_MAX_PATH: usize = 260;
+    if path.len() > LEGACY_MAX_PATH {
+        return Ok(path);
+    }
+
+    match &path[..] {
+        // `\\?\C:\...` => `C:\...`
+        [SEP, SEP, QUERY, SEP, _, COLON, SEP, ..] => unsafe {
+            let lpfilename = path[4..].as_ptr();
+            fill_utf16_buf(
+                |buffer, size| c::GetFullPathNameW(lpfilename, size, buffer, ptr::null_mut()),
+                |full_path: &[u16]| {
+                    if full_path == &path[4..path.len() - 1] { full_path.into() } else { path }
+                },
+            )
+        },
+        // `\\?\UNC\...` => `\\...`
+        [SEP, SEP, QUERY, SEP, U, N, C, SEP, ..] => unsafe {
+            // Change the `C` in `UNC\` to `\` so we can get a slice that starts with `\\`.
+            path[6] = b'\\' as u16;
+            let lpfilename = path[6..].as_ptr();
+            fill_utf16_buf(
+                |buffer, size| c::GetFullPathNameW(lpfilename, size, buffer, ptr::null_mut()),
+                |full_path: &[u16]| {
+                    if full_path == &path[6..path.len() - 1] {
+                        full_path.into()
+                    } else {
+                        // Restore the 'C' in "UNC".
+                        path[6] = b'C' as u16;
+                        path
+                    }
+                },
+            )
+        },
+        // For everything else, leave the path unchanged.
+        _ => Ok(path),
+    }
+}
index 5f14edaf067c096f66039e7502d4626440373a6d..0692da1d795192d0e5358e7f2c5dc291293e7545 100644 (file)
@@ -1022,6 +1022,12 @@ pub fn WaitForMultipleObjects(
         bWaitAll: BOOL,
         dwMilliseconds: DWORD,
     ) -> DWORD;
+    pub fn CreatePipe(
+        hReadPipe: *mut HANDLE,
+        hWritePipe: *mut HANDLE,
+        lpPipeAttributes: *const SECURITY_ATTRIBUTES,
+        nSize: DWORD,
+    ) -> BOOL;
     pub fn CreateNamedPipeW(
         lpName: LPCWSTR,
         dwOpenMode: DWORD,
index ef9a8bd690031c0fbf5dda54da5d87fc6b39c858..3b609825a79da94d435213f249ccc0332a3f3c38 100644 (file)
@@ -221,6 +221,10 @@ pub fn duplicate(
         Ok(Self(self.0.duplicate(access, inherit, options)?))
     }
 
+    pub(crate) fn set_inheritable(&self) -> io::Result<()> {
+        self.0.set_inheritable()
+    }
+
     /// Performs a synchronous read.
     ///
     /// If the handle is opened for asynchronous I/O then this abort the process.
index 31c7208bbf1eef3951d9a87cbd85b387ef036730..4e9d408291d2a1402a4e34a069637b3dc72c13ec 100644 (file)
@@ -156,7 +156,13 @@ macro_rules! if_return {
 
 pub fn to_u16s<S: AsRef<OsStr>>(s: S) -> crate::io::Result<Vec<u16>> {
     fn inner(s: &OsStr) -> crate::io::Result<Vec<u16>> {
-        let mut maybe_result: Vec<u16> = s.encode_wide().collect();
+        // Most paths are ASCII, so reserve capacity for as much as there are bytes
+        // in the OsStr plus one for the null-terminating character. We are not
+        // wasting bytes here as paths created by this function are primarily used
+        // in an ephemeral fashion.
+        let mut maybe_result = Vec::with_capacity(s.len() + 1);
+        maybe_result.extend(s.encode_wide());
+
         if unrolled_find_u16s(0, &maybe_result).is_some() {
             return Err(crate::io::const_io_error!(
                 ErrorKind::InvalidInput,
@@ -190,6 +196,10 @@ fn fill_utf16_buf<F1, F2, T>(mut f1: F1, f2: F2) -> crate::io::Result<T>
 {
     // Start off with a stack buf but then spill over to the heap if we end up
     // needing more space.
+    //
+    // This initial size also works around `GetFullPathNameW` returning
+    // incorrect size hints for some short paths:
+    // https://github.com/dylni/normpath/issues/5
     let mut stack_buf = [0u16; 512];
     let mut heap_buf = Vec::new();
     unsafe {
index e54fcaed4957d8ab38d440234ed36bd123991209..a0f822070992f5032e6f54a5c16b77d19c0eaa85 100644 (file)
@@ -50,37 +50,101 @@ pub(crate) fn append_suffix(path: PathBuf, suffix: &OsStr) -> PathBuf {
     path.into()
 }
 
+struct PrefixParser<'a, const LEN: usize> {
+    path: &'a OsStr,
+    prefix: [u8; LEN],
+}
+
+impl<'a, const LEN: usize> PrefixParser<'a, LEN> {
+    #[inline]
+    fn get_prefix(path: &OsStr) -> [u8; LEN] {
+        let mut prefix = [0; LEN];
+        // SAFETY: Only ASCII characters are modified.
+        for (i, &ch) in path.bytes().iter().take(LEN).enumerate() {
+            prefix[i] = if ch == b'/' { b'\\' } else { ch };
+        }
+        prefix
+    }
+
+    fn new(path: &'a OsStr) -> Self {
+        Self { path, prefix: Self::get_prefix(path) }
+    }
+
+    fn as_slice(&self) -> PrefixParserSlice<'a, '_> {
+        PrefixParserSlice {
+            path: self.path,
+            prefix: &self.prefix[..LEN.min(self.path.len())],
+            index: 0,
+        }
+    }
+}
+
+struct PrefixParserSlice<'a, 'b> {
+    path: &'a OsStr,
+    prefix: &'b [u8],
+    index: usize,
+}
+
+impl<'a> PrefixParserSlice<'a, '_> {
+    fn strip_prefix(&self, prefix: &str) -> Option<Self> {
+        self.prefix[self.index..]
+            .starts_with(prefix.as_bytes())
+            .then(|| Self { index: self.index + prefix.len(), ..*self })
+    }
+
+    fn prefix_bytes(&self) -> &'a [u8] {
+        &self.path.bytes()[..self.index]
+    }
+
+    fn finish(self) -> &'a OsStr {
+        // SAFETY: The unsafety here stems from converting between &OsStr and
+        // &[u8] and back. This is safe to do because (1) we only look at ASCII
+        // contents of the encoding and (2) new &OsStr values are produced only
+        // from ASCII-bounded slices of existing &OsStr values.
+        unsafe { bytes_as_os_str(&self.path.bytes()[self.index..]) }
+    }
+}
+
 pub fn parse_prefix(path: &OsStr) -> Option<Prefix<'_>> {
     use Prefix::{DeviceNS, Disk, Verbatim, VerbatimDisk, VerbatimUNC, UNC};
 
-    if let Some(path) = strip_prefix(path, r"\\") {
+    let parser = PrefixParser::<8>::new(path);
+    let parser = parser.as_slice();
+    if let Some(parser) = parser.strip_prefix(r"\\") {
         // \\
-        if let Some(path) = strip_prefix(path, r"?\") {
+
+        // The meaning of verbatim paths can change when they use a different
+        // separator.
+        if let Some(parser) = parser.strip_prefix(r"?\") && !parser.prefix_bytes().iter().any(|&x| x == b'/') {
             // \\?\
-            if let Some(path) = strip_prefix(path, r"UNC\") {
+            if let Some(parser) = parser.strip_prefix(r"UNC\") {
                 // \\?\UNC\server\share
 
+                let path = parser.finish();
                 let (server, path) = parse_next_component(path, true);
                 let (share, _) = parse_next_component(path, true);
 
                 Some(VerbatimUNC(server, share))
             } else {
-                let (prefix, _) = parse_next_component(path, true);
+                let path = parser.finish();
 
                 // in verbatim paths only recognize an exact drive prefix
-                if let Some(drive) = parse_drive_exact(prefix) {
+                if let Some(drive) = parse_drive_exact(path) {
                     // \\?\C:
                     Some(VerbatimDisk(drive))
                 } else {
                     // \\?\prefix
+                    let (prefix, _) = parse_next_component(path, true);
                     Some(Verbatim(prefix))
                 }
             }
-        } else if let Some(path) = strip_prefix(path, r".\") {
+        } else if let Some(parser) = parser.strip_prefix(r".\") {
             // \\.\COM42
+            let path = parser.finish();
             let (prefix, _) = parse_next_component(path, false);
             Some(DeviceNS(prefix))
         } else {
+            let path = parser.finish();
             let (server, path) = parse_next_component(path, false);
             let (share, _) = parse_next_component(path, false);
 
@@ -102,31 +166,26 @@ pub fn parse_prefix(path: &OsStr) -> Option<Prefix<'_>> {
 }
 
 // Parses a drive prefix, e.g. "C:" and "C:\whatever"
-fn parse_drive(prefix: &OsStr) -> Option<u8> {
+fn parse_drive(path: &OsStr) -> Option<u8> {
     // In most DOS systems, it is not possible to have more than 26 drive letters.
     // See <https://en.wikipedia.org/wiki/Drive_letter_assignment#Common_assignments>.
     fn is_valid_drive_letter(drive: &u8) -> bool {
         drive.is_ascii_alphabetic()
     }
 
-    match prefix.bytes() {
+    match path.bytes() {
         [drive, b':', ..] if is_valid_drive_letter(drive) => Some(drive.to_ascii_uppercase()),
         _ => None,
     }
 }
 
 // Parses a drive prefix exactly, e.g. "C:"
-fn parse_drive_exact(prefix: &OsStr) -> Option<u8> {
+fn parse_drive_exact(path: &OsStr) -> Option<u8> {
     // only parse two bytes: the drive letter and the drive separator
-    if prefix.len() == 2 { parse_drive(prefix) } else { None }
-}
-
-fn strip_prefix<'a>(path: &'a OsStr, prefix: &str) -> Option<&'a OsStr> {
-    // `path` and `prefix` are valid wtf8 and utf8 encoded slices respectively, `path[prefix.len()]`
-    // is thus a code point boundary and `path[prefix.len()..]` is a valid wtf8 encoded slice.
-    match path.bytes().strip_prefix(prefix.as_bytes()) {
-        Some(path) => unsafe { Some(bytes_as_os_str(path)) },
-        None => None,
+    if path.bytes().get(2).map(|&x| is_sep_byte(x)).unwrap_or(true) {
+        parse_drive(path)
+    } else {
+        None
     }
 }
 
@@ -219,15 +278,7 @@ pub(crate) fn maybe_verbatim(path: &Path) -> io::Result<Vec<u16>> {
         // SAFETY: `fill_utf16_buf` ensures the `buffer` and `size` are valid.
         // `lpfilename` is a pointer to a null terminated string that is not
         // invalidated until after `GetFullPathNameW` returns successfully.
-        |buffer, size| unsafe {
-            // While the docs for `GetFullPathNameW` have the standard note
-            // about needing a `\\?\` path for a long lpfilename, this does not
-            // appear to be true in practice.
-            // See:
-            // https://stackoverflow.com/questions/38036943/getfullpathnamew-and-long-windows-file-paths
-            // https://googleprojectzero.blogspot.com/2016/02/the-definitive-guide-on-win32-to-nt.html
-            c::GetFullPathNameW(lpfilename, size, buffer, ptr::null_mut())
-        },
+        |buffer, size| unsafe { c::GetFullPathNameW(lpfilename, size, buffer, ptr::null_mut()) },
         |mut absolute| {
             path.clear();
 
@@ -263,9 +314,20 @@ pub(crate) fn maybe_verbatim(path: &Path) -> io::Result<Vec<u16>> {
 
 /// Make a Windows path absolute.
 pub(crate) fn absolute(path: &Path) -> io::Result<PathBuf> {
-    if path.as_os_str().bytes().starts_with(br"\\?\") {
-        return Ok(path.into());
+    let path = path.as_os_str();
+    let prefix = parse_prefix(path);
+    // Verbatim paths should not be modified.
+    if prefix.map(|x| x.is_verbatim()).unwrap_or(false) {
+        // NULs in verbatim paths are rejected for consistency.
+        if path.bytes().contains(&0) {
+            return Err(io::const_io_error!(
+                io::ErrorKind::InvalidInput,
+                "strings passed to WinAPI cannot contain NULs",
+            ));
+        }
+        return Ok(path.to_owned().into());
     }
+
     let path = to_u16s(path)?;
     let lpfilename = path.as_ptr();
     fill_utf16_buf(
index 425c2011b32390bdf4c3900cc873880e597e019c..8656b04e4f410320befd75d198bd9c9a1690d254 100644 (file)
@@ -94,3 +94,23 @@ fn check(path: &str, expected: &str) {
     // A path that contains null is not a valid path.
     assert!(maybe_verbatim(Path::new("\0")).is_err());
 }
+
+fn parse_prefix(path: &str) -> Option<Prefix<'_>> {
+    super::parse_prefix(OsStr::new(path))
+}
+
+#[test]
+fn test_parse_prefix_verbatim() {
+    let prefix = Some(Prefix::VerbatimDisk(b'C'));
+    assert_eq!(prefix, parse_prefix(r"\\?\C:/windows/system32/notepad.exe"));
+    assert_eq!(prefix, parse_prefix(r"\\?\C:\windows\system32\notepad.exe"));
+}
+
+#[test]
+fn test_parse_prefix_verbatim_device() {
+    let prefix = Some(Prefix::UNC(OsStr::new("?"), OsStr::new("C:")));
+    assert_eq!(prefix, parse_prefix(r"//?/C:/windows/system32/notepad.exe"));
+    assert_eq!(prefix, parse_prefix(r"//?/C:\windows\system32\notepad.exe"));
+    assert_eq!(prefix, parse_prefix(r"/\?\C:\windows\system32\notepad.exe"));
+    assert_eq!(prefix, parse_prefix(r"\\?/C:\windows\system32\notepad.exe"));
+}
index 013c776c476c361dce272d3e28a205534cae4656..928bf2439c3e1e1ac6f99b90046dc0f31557a7d8 100644 (file)
 // Anonymous pipes
 ////////////////////////////////////////////////////////////////////////////////
 
-pub struct AnonPipe {
-    inner: Handle,
+// A 64kb pipe capacity is the same as a typical Linux default.
+const PIPE_BUFFER_CAPACITY: u32 = 64 * 1024;
+
+pub enum AnonPipe {
+    Sync(Handle),
+    Async(Handle),
 }
 
 impl IntoInner<Handle> for AnonPipe {
     fn into_inner(self) -> Handle {
-        self.inner
+        match self {
+            Self::Sync(handle) => handle,
+            Self::Async(handle) => handle,
+        }
     }
 }
 
@@ -32,6 +39,35 @@ pub struct Pipes {
     pub ours: AnonPipe,
     pub theirs: AnonPipe,
 }
+impl Pipes {
+    /// Create a new pair of pipes where both pipes are synchronous.
+    ///
+    /// These must not be used asynchronously.
+    pub fn new_synchronous(
+        ours_readable: bool,
+        their_handle_inheritable: bool,
+    ) -> io::Result<Self> {
+        unsafe {
+            // If `CreatePipe` succeeds, these will be our pipes.
+            let mut read = ptr::null_mut();
+            let mut write = ptr::null_mut();
+
+            if c::CreatePipe(&mut read, &mut write, ptr::null(), PIPE_BUFFER_CAPACITY) == 0 {
+                Err(io::Error::last_os_error())
+            } else {
+                let (ours, theirs) = if ours_readable { (read, write) } else { (write, read) };
+                let ours = Handle::from_raw_handle(ours);
+                let theirs = Handle::from_raw_handle(theirs);
+
+                if their_handle_inheritable {
+                    theirs.set_inheritable()?;
+                }
+
+                Ok(Pipes { ours: AnonPipe::Sync(ours), theirs: AnonPipe::Sync(theirs) })
+            }
+        }
+    }
+}
 
 /// Although this looks similar to `anon_pipe` in the Unix module it's actually
 /// subtly different. Here we'll return two pipes in the `Pipes` return value,
@@ -53,9 +89,6 @@ pub struct Pipes {
 /// with `OVERLAPPED` instances, but also works out ok if it's only ever used
 /// once at a time (which we do indeed guarantee).
 pub fn anon_pipe(ours_readable: bool, their_handle_inheritable: bool) -> io::Result<Pipes> {
-    // A 64kb pipe capacity is the same as a typical Linux default.
-    const PIPE_BUFFER_CAPACITY: u32 = 64 * 1024;
-
     // Note that we specifically do *not* use `CreatePipe` here because
     // unfortunately the anonymous pipes returned do not support overlapped
     // operations. Instead, we create a "hopefully unique" name and create a
@@ -156,12 +189,9 @@ pub fn anon_pipe(ours_readable: bool, their_handle_inheritable: bool) -> io::Res
         };
         opts.security_attributes(&mut sa);
         let theirs = File::open(Path::new(&name), &opts)?;
-        let theirs = AnonPipe { inner: theirs.into_inner() };
+        let theirs = AnonPipe::Sync(theirs.into_inner());
 
-        Ok(Pipes {
-            ours: AnonPipe { inner: ours },
-            theirs: AnonPipe { inner: theirs.into_inner() },
-        })
+        Ok(Pipes { ours: AnonPipe::Async(ours), theirs })
     }
 }
 
@@ -171,12 +201,12 @@ pub fn anon_pipe(ours_readable: bool, their_handle_inheritable: bool) -> io::Res
 /// This is achieved by creating a new set of pipes and spawning a thread that
 /// relays messages between the source and the synchronous pipe.
 pub fn spawn_pipe_relay(
-    source: &AnonPipe,
+    source: &Handle,
     ours_readable: bool,
     their_handle_inheritable: bool,
 ) -> io::Result<AnonPipe> {
     // We need this handle to live for the lifetime of the thread spawned below.
-    let source = source.duplicate()?;
+    let source = AnonPipe::Async(source.duplicate(0, true, c::DUPLICATE_SAME_ACCESS)?);
 
     // create a new pair of anon pipes.
     let Pipes { theirs, ours } = anon_pipe(ours_readable, their_handle_inheritable)?;
@@ -227,19 +257,24 @@ fn random_number() -> usize {
 
 impl AnonPipe {
     pub fn handle(&self) -> &Handle {
-        &self.inner
+        match self {
+            Self::Async(ref handle) => handle,
+            Self::Sync(ref handle) => handle,
+        }
     }
     pub fn into_handle(self) -> Handle {
-        self.inner
-    }
-    fn duplicate(&self) -> io::Result<Self> {
-        self.inner.duplicate(0, false, c::DUPLICATE_SAME_ACCESS).map(|inner| AnonPipe { inner })
+        self.into_inner()
     }
 
     pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
         let result = unsafe {
             let len = crate::cmp::min(buf.len(), c::DWORD::MAX as usize) as c::DWORD;
-            self.alertable_io_internal(c::ReadFileEx, buf.as_mut_ptr() as _, len)
+            match self {
+                Self::Sync(ref handle) => handle.read(buf),
+                Self::Async(_) => {
+                    self.alertable_io_internal(c::ReadFileEx, buf.as_mut_ptr() as _, len)
+                }
+            }
         };
 
         match result {
@@ -253,28 +288,33 @@ pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
     }
 
     pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
-        self.inner.read_vectored(bufs)
+        io::default_read_vectored(|buf| self.read(buf), bufs)
     }
 
     #[inline]
     pub fn is_read_vectored(&self) -> bool {
-        self.inner.is_read_vectored()
+        false
     }
 
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
         unsafe {
             let len = crate::cmp::min(buf.len(), c::DWORD::MAX as usize) as c::DWORD;
-            self.alertable_io_internal(c::WriteFileEx, buf.as_ptr() as _, len)
+            match self {
+                Self::Sync(ref handle) => handle.write(buf),
+                Self::Async(_) => {
+                    self.alertable_io_internal(c::WriteFileEx, buf.as_ptr() as _, len)
+                }
+            }
         }
     }
 
     pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
-        self.inner.write_vectored(bufs)
+        io::default_write_vectored(|buf| self.write(buf), bufs)
     }
 
     #[inline]
     pub fn is_write_vectored(&self) -> bool {
-        self.inner.is_write_vectored()
+        false
     }
 
     /// Synchronizes asynchronous reads or writes using our anonymous pipe.
@@ -346,7 +386,7 @@ struct AsyncResult {
 
         // Asynchronous read of the pipe.
         // If successful, `callback` will be called once it completes.
-        let result = io(self.inner.as_handle(), buf, len, &mut overlapped, callback);
+        let result = io(self.handle().as_handle(), buf, len, &mut overlapped, callback);
         if result == c::FALSE {
             // We can return here because the call failed.
             // After this we must not return until the I/O completes.
index a0c0f5dc3ec2cf499741a2d990a163c64c93fae5..cc29d1a72fbf416cbed51c007e396b7002f55813 100644 (file)
 use crate::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle};
 use crate::path::{Path, PathBuf};
 use crate::ptr;
+use crate::sys::args::{self, Arg};
 use crate::sys::c;
 use crate::sys::c::NonZeroDWORD;
 use crate::sys::cvt;
 use crate::sys::fs::{File, OpenOptions};
 use crate::sys::handle::Handle;
 use crate::sys::path;
-use crate::sys::pipe::{self, AnonPipe};
+use crate::sys::pipe::{self, AnonPipe, Pipes};
 use crate::sys::stdio;
 use crate::sys_common::mutex::StaticMutex;
 use crate::sys_common::process::{CommandEnv, CommandEnvs};
-use crate::sys_common::{AsInner, IntoInner};
+use crate::sys_common::IntoInner;
 
 use libc::{c_void, EXIT_FAILURE, EXIT_SUCCESS};
 
@@ -147,7 +148,7 @@ fn as_ref(&self) -> &OsStr {
     }
 }
 
-fn ensure_no_nuls<T: AsRef<OsStr>>(str: T) -> io::Result<T> {
+pub(crate) fn ensure_no_nuls<T: AsRef<OsStr>>(str: T) -> io::Result<T> {
     if str.as_ref().encode_wide().any(|b| b == 0) {
         Err(io::const_io_error!(ErrorKind::InvalidInput, "nul byte found in provided data"))
     } else {
@@ -172,7 +173,7 @@ pub enum Stdio {
     Inherit,
     Null,
     MakePipe,
-    Pipe(AnonPipe),
+    AsyncPipe(Handle),
     Handle(Handle),
 }
 
@@ -182,14 +183,6 @@ pub struct StdioPipes {
     pub stderr: Option<AnonPipe>,
 }
 
-#[derive(Debug)]
-enum Arg {
-    /// Add quotes (if needed)
-    Regular(OsString),
-    /// Append raw string without quoting
-    Raw(OsString),
-}
-
 impl Command {
     pub fn new(program: &OsStr) -> Command {
         Command {
@@ -275,8 +268,19 @@ pub fn spawn(
             program.len().checked_sub(5).and_then(|i| program.get(i..)),
             Some([46, 98 | 66, 97 | 65, 116 | 84, 0] | [46, 99 | 67, 109 | 77, 100 | 68, 0])
         );
-        let mut cmd_str =
-            make_command_line(&program, &self.args, self.force_quotes_enabled, is_batch_file)?;
+        let (program, mut cmd_str) = if is_batch_file {
+            (
+                command_prompt()?,
+                args::make_bat_command_line(
+                    &args::to_user_path(program)?,
+                    &self.args,
+                    self.force_quotes_enabled,
+                )?,
+            )
+        } else {
+            let cmd_str = make_command_line(&self.program, &self.args, self.force_quotes_enabled)?;
+            (program, cmd_str)
+        };
         cmd_str.push(0); // add null terminator
 
         // stolen from the libuv code.
@@ -523,13 +527,33 @@ fn to_handle(&self, stdio_id: c::DWORD, pipe: &mut Option<AnonPipe>) -> io::Resu
             },
 
             Stdio::MakePipe => {
-                let ours_readable = stdio_id != c::STD_INPUT_HANDLE;
-                let pipes = pipe::anon_pipe(ours_readable, true)?;
+                // Handles that are passed to a child process must be synchronous
+                // because they will be read synchronously (see #95759).
+                // Therefore we prefer to make both ends of a pipe synchronous
+                // just in case our end of the pipe is passed to another process.
+                //
+                // However, we may need to read from both the child's stdout and
+                // stderr simultaneously when waiting for output. This requires
+                // async reads so as to avoid blocking either pipe.
+                //
+                // The solution used here is to make handles synchronous
+                // except for our side of the stdout and sterr pipes.
+                // If our side of those pipes do end up being given to another
+                // process then we use a "pipe relay" to synchronize access
+                // (see `Stdio::AsyncPipe` below).
+                let pipes = if stdio_id == c::STD_INPUT_HANDLE {
+                    // For stdin both sides of the pipe are synchronous.
+                    Pipes::new_synchronous(false, true)?
+                } else {
+                    // For stdout/stderr our side of the pipe is async and their side is synchronous.
+                    pipe::anon_pipe(true, true)?
+                };
                 *pipe = Some(pipes.ours);
                 Ok(pipes.theirs.into_handle())
             }
 
-            Stdio::Pipe(ref source) => {
+            Stdio::AsyncPipe(ref source) => {
+                // We need to synchronize asynchronous pipes by using a pipe relay.
                 let ours_readable = stdio_id != c::STD_INPUT_HANDLE;
                 pipe::spawn_pipe_relay(source, ours_readable, true).map(AnonPipe::into_handle)
             }
@@ -558,7 +582,13 @@ fn to_handle(&self, stdio_id: c::DWORD, pipe: &mut Option<AnonPipe>) -> io::Resu
 
 impl From<AnonPipe> for Stdio {
     fn from(pipe: AnonPipe) -> Stdio {
-        Stdio::Pipe(pipe)
+        // Note that it's very important we don't give async handles to child processes.
+        // Therefore if the pipe is asynchronous we must have a way to turn it synchronous.
+        // See #95759.
+        match pipe {
+            AnonPipe::Sync(handle) => Stdio::Handle(handle),
+            AnonPipe::Async(handle) => Stdio::AsyncPipe(handle),
+        }
     }
 }
 
@@ -730,96 +760,36 @@ fn zeroed_process_information() -> c::PROCESS_INFORMATION {
     }
 }
 
-enum Quote {
-    // Every arg is quoted
-    Always,
-    // Whitespace and empty args are quoted
-    Auto,
-    // Arg appended without any changes (#29494)
-    Never,
-}
-
 // Produces a wide string *without terminating null*; returns an error if
 // `prog` or any of the `args` contain a nul.
-fn make_command_line(
-    prog: &[u16],
-    args: &[Arg],
-    force_quotes: bool,
-    is_batch_file: bool,
-) -> io::Result<Vec<u16>> {
+fn make_command_line(argv0: &OsStr, args: &[Arg], force_quotes: bool) -> io::Result<Vec<u16>> {
     // Encode the command and arguments in a command line string such
     // that the spawned process may recover them using CommandLineToArgvW.
     let mut cmd: Vec<u16> = Vec::new();
 
-    // CreateFileW has special handling for .bat and .cmd files, which means we
-    // need to add an extra pair of quotes surrounding the whole command line
-    // so they are properly passed on to the script.
-    // See issue #91991.
-    if is_batch_file {
-        cmd.push(b'"' as u16);
-    }
-
     // Always quote the program name so CreateProcess to avoid ambiguity when
     // the child process parses its arguments.
     // Note that quotes aren't escaped here because they can't be used in arg0.
     // But that's ok because file paths can't contain quotes.
     cmd.push(b'"' as u16);
-    cmd.extend_from_slice(prog.strip_suffix(&[0]).unwrap_or(prog));
+    cmd.extend(argv0.encode_wide());
     cmd.push(b'"' as u16);
 
     for arg in args {
         cmd.push(' ' as u16);
-        let (arg, quote) = match arg {
-            Arg::Regular(arg) => (arg, if force_quotes { Quote::Always } else { Quote::Auto }),
-            Arg::Raw(arg) => (arg, Quote::Never),
-        };
-        append_arg(&mut cmd, arg, quote)?;
-    }
-    if is_batch_file {
-        cmd.push(b'"' as u16);
-    }
-    return Ok(cmd);
-
-    fn append_arg(cmd: &mut Vec<u16>, arg: &OsStr, quote: Quote) -> io::Result<()> {
-        // If an argument has 0 characters then we need to quote it to ensure
-        // that it actually gets passed through on the command line or otherwise
-        // it will be dropped entirely when parsed on the other end.
-        ensure_no_nuls(arg)?;
-        let arg_bytes = &arg.as_inner().inner.as_inner();
-        let (quote, escape) = match quote {
-            Quote::Always => (true, true),
-            Quote::Auto => {
-                (arg_bytes.iter().any(|c| *c == b' ' || *c == b'\t') || arg_bytes.is_empty(), true)
-            }
-            Quote::Never => (false, false),
-        };
-        if quote {
-            cmd.push('"' as u16);
-        }
-
-        let mut backslashes: usize = 0;
-        for x in arg.encode_wide() {
-            if escape {
-                if x == '\\' as u16 {
-                    backslashes += 1;
-                } else {
-                    if x == '"' as u16 {
-                        // Add n+1 backslashes to total 2n+1 before internal '"'.
-                        cmd.extend((0..=backslashes).map(|_| '\\' as u16));
-                    }
-                    backslashes = 0;
-                }
-            }
-            cmd.push(x);
-        }
-
-        if quote {
-            // Add n backslashes to total 2n before ending '"'.
-            cmd.extend((0..backslashes).map(|_| '\\' as u16));
-            cmd.push('"' as u16);
-        }
-        Ok(())
+        args::append_arg(&mut cmd, arg, force_quotes)?;
     }
+    Ok(cmd)
+}
+
+// Get `cmd.exe` for use with bat scripts, encoded as a UTF-16 string.
+fn command_prompt() -> io::Result<Vec<u16>> {
+    let mut system: Vec<u16> = super::fill_utf16_buf(
+        |buf, size| unsafe { c::GetSystemDirectoryW(buf, size) },
+        |buf| buf.into(),
+    )?;
+    system.extend("\\cmd.exe".encode_utf16().chain([0]));
+    Ok(system)
 }
 
 fn make_envp(maybe_env: Option<BTreeMap<EnvKey, OsString>>) -> io::Result<(*mut c_void, Vec<u16>)> {
index cd535afb4a338d6551fac02a7cd5871b5114278e..be3a0f4ed52a981ae13d23b25ad81af8d27665a0 100644 (file)
@@ -3,12 +3,11 @@
 use crate::env;
 use crate::ffi::{OsStr, OsString};
 use crate::process::Command;
-use crate::sys::to_u16s;
 
 #[test]
 fn test_raw_args() {
     let command_line = &make_command_line(
-        &to_u16s("quoted exe").unwrap(),
+        OsStr::new("quoted exe"),
         &[
             Arg::Regular(OsString::from("quote me")),
             Arg::Raw(OsString::from("quote me *not*")),
@@ -17,7 +16,6 @@ fn test_raw_args() {
             Arg::Regular(OsString::from("optional-quotes")),
         ],
         false,
-        false,
     )
     .unwrap();
     assert_eq!(
@@ -30,10 +28,9 @@ fn test_raw_args() {
 fn test_make_command_line() {
     fn test_wrapper(prog: &str, args: &[&str], force_quotes: bool) -> String {
         let command_line = &make_command_line(
-            &to_u16s(prog).unwrap(),
+            OsStr::new(prog),
             &args.iter().map(|a| Arg::Regular(OsString::from(a))).collect::<Vec<_>>(),
             force_quotes,
-            false,
         )
         .unwrap();
         String::from_utf16(command_line).unwrap()
index 3497da51deeda54d9d391bfc9064abafed912418..5144834447503414a9ea832e1b9b930ff1d44dd9 100644 (file)
@@ -58,6 +58,7 @@
 // [4]: Windows Internals, Part 1, ISBN 9780735671300
 
 use crate::convert::TryFrom;
+use crate::pin::Pin;
 use crate::ptr;
 use crate::sync::atomic::{
     AtomicI8, AtomicPtr,
@@ -95,13 +96,16 @@ pub struct Parker {
 // Ordering::Release when writing NOTIFIED (the 'token') in unpark(), and using
 // Ordering::Acquire when reading this state in park() after waking up.
 impl Parker {
-    pub fn new() -> Self {
-        Self { state: AtomicI8::new(EMPTY) }
+    /// Construct the Windows parker. The UNIX parker implementation
+    /// requires this to happen in-place.
+    pub unsafe fn new(parker: *mut Parker) {
+        parker.write(Self { state: AtomicI8::new(EMPTY) });
     }
 
     // Assumes this is only called by the thread that owns the Parker,
-    // which means that `self.state != PARKED`.
-    pub unsafe fn park(&self) {
+    // which means that `self.state != PARKED`. This implementation doesn't require `Pin`,
+    // but other implementations do.
+    pub unsafe fn park(self: Pin<&Self>) {
         // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the
         // first case.
         if self.state.fetch_sub(1, Acquire) == NOTIFIED {
@@ -132,8 +136,9 @@ pub unsafe fn park(&self) {
     }
 
     // Assumes this is only called by the thread that owns the Parker,
-    // which means that `self.state != PARKED`.
-    pub unsafe fn park_timeout(&self, timeout: Duration) {
+    // which means that `self.state != PARKED`. This implementation doesn't require `Pin`,
+    // but other implementations do.
+    pub unsafe fn park_timeout(self: Pin<&Self>, timeout: Duration) {
         // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the
         // first case.
         if self.state.fetch_sub(1, Acquire) == NOTIFIED {
@@ -184,7 +189,8 @@ pub unsafe fn park_timeout(&self, timeout: Duration) {
         }
     }
 
-    pub fn unpark(&self) {
+    // This implementation doesn't require `Pin`, but other implementations do.
+    pub fn unpark(self: Pin<&Self>) {
         // Change PARKED=>NOTIFIED, EMPTY=>NOTIFIED, or NOTIFIED=>NOTIFIED, and
         // wake the thread in the first case.
         //
index fbf6231ff4ab324e5e43815f65c224e3a78f7950..d9e2f39e3451848bea88a071b3a293d24b82e517 100644 (file)
@@ -1,3 +1,4 @@
+use crate::pin::Pin;
 use crate::sync::atomic::AtomicU32;
 use crate::sync::atomic::Ordering::{Acquire, Release};
 use crate::sys::futex::{futex_wait, futex_wake};
@@ -32,14 +33,15 @@ pub struct Parker {
 // Ordering::Release when writing NOTIFIED (the 'token') in unpark(), and using
 // Ordering::Acquire when checking for this state in park().
 impl Parker {
-    #[inline]
-    pub const fn new() -> Self {
-        Parker { state: AtomicU32::new(EMPTY) }
+    /// Construct the futex parker. The UNIX parker implementation
+    /// requires this to happen in-place.
+    pub unsafe fn new(parker: *mut Parker) {
+        parker.write(Self { state: AtomicU32::new(EMPTY) });
     }
 
     // Assumes this is only called by the thread that owns the Parker,
     // which means that `self.state != PARKED`.
-    pub unsafe fn park(&self) {
+    pub unsafe fn park(self: Pin<&Self>) {
         // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the
         // first case.
         if self.state.fetch_sub(1, Acquire) == NOTIFIED {
@@ -58,8 +60,9 @@ pub unsafe fn park(&self) {
     }
 
     // Assumes this is only called by the thread that owns the Parker,
-    // which means that `self.state != PARKED`.
-    pub unsafe fn park_timeout(&self, timeout: Duration) {
+    // which means that `self.state != PARKED`. This implementation doesn't
+    // require `Pin`, but other implementations do.
+    pub unsafe fn park_timeout(self: Pin<&Self>, timeout: Duration) {
         // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the
         // first case.
         if self.state.fetch_sub(1, Acquire) == NOTIFIED {
@@ -78,8 +81,9 @@ pub unsafe fn park_timeout(&self, timeout: Duration) {
         }
     }
 
+    // This implementation doesn't require `Pin`, but other implementations do.
     #[inline]
-    pub fn unpark(&self) {
+    pub fn unpark(self: Pin<&Self>) {
         // Change PARKED=>NOTIFIED, EMPTY=>NOTIFIED, or NOTIFIED=>NOTIFIED, and
         // wake the thread in the first case.
         //
index ffb61200e15f9b523ffaa0710edef8837d424467..f3d8b34d3fd39279b20887f50081e2788b65f470 100644 (file)
@@ -1,5 +1,6 @@
 //! Parker implementation based on a Mutex and Condvar.
 
+use crate::pin::Pin;
 use crate::sync::atomic::AtomicUsize;
 use crate::sync::atomic::Ordering::SeqCst;
 use crate::sync::{Condvar, Mutex};
@@ -16,13 +17,18 @@ pub struct Parker {
 }
 
 impl Parker {
-    pub fn new() -> Self {
-        Parker { state: AtomicUsize::new(EMPTY), lock: Mutex::new(()), cvar: Condvar::new() }
+    /// Construct the generic parker. The UNIX parker implementation
+    /// requires this to happen in-place.
+    pub unsafe fn new(parker: *mut Parker) {
+        parker.write(Parker {
+            state: AtomicUsize::new(EMPTY),
+            lock: Mutex::new(()),
+            cvar: Condvar::new(),
+        });
     }
 
-    // This implementation doesn't require `unsafe`, but other implementations
-    // may assume this is only called by the thread that owns the Parker.
-    pub unsafe fn park(&self) {
+    // This implementation doesn't require `unsafe` and `Pin`, but other implementations do.
+    pub unsafe fn park(self: Pin<&Self>) {
         // If we were previously notified then we consume this notification and
         // return quickly.
         if self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() {
@@ -55,9 +61,8 @@ pub unsafe fn park(&self) {
         }
     }
 
-    // This implementation doesn't require `unsafe`, but other implementations
-    // may assume this is only called by the thread that owns the Parker.
-    pub unsafe fn park_timeout(&self, dur: Duration) {
+    // This implementation doesn't require `unsafe` and `Pin`, but other implementations do.
+    pub unsafe fn park_timeout(self: Pin<&Self>, dur: Duration) {
         // Like `park` above we have a fast path for an already-notified thread, and
         // afterwards we start coordinating for a sleep.
         // return quickly.
@@ -88,7 +93,8 @@ pub unsafe fn park_timeout(&self, dur: Duration) {
         }
     }
 
-    pub fn unpark(&self) {
+    // This implementation doesn't require `Pin`, but other implementations do.
+    pub fn unpark(self: Pin<&Self>) {
         // To ensure the unparked thread will observe any writes we made
         // before this call, we must perform a release operation that `park`
         // can synchronize with. To do that we must write `NOTIFIED` even if
index ba896bd676b673820fda276334377e85543ba8d9..ea0204cd357ba5605b5b253a89dd8945e43e743a 100644 (file)
@@ -8,6 +8,8 @@
         pub use futex::Parker;
     } else if #[cfg(windows)] {
         pub use crate::sys::thread_parker::Parker;
+    } else if #[cfg(target_family = "unix")] {
+        pub use crate::sys::thread_parker::Parker;
     } else {
         mod generic;
         pub use generic::Parker;
index 10ef6662115c1f300297b308ab832ccccc6b9b6d..7d66973bed6f58736e13f2923ad571f6b26388cf 100644 (file)
@@ -25,7 +25,7 @@
 use crate::collections::TryReserveError;
 use crate::fmt;
 use crate::hash::{Hash, Hasher};
-use crate::iter::FromIterator;
+use crate::iter::{FromIterator, FusedIterator};
 use crate::mem;
 use crate::ops;
 use crate::rc::Rc;
@@ -899,6 +899,9 @@ fn size_hint(&self) -> (usize, Option<usize>) {
     }
 }
 
+#[stable(feature = "encode_wide_fused_iterator", since = "1.62.0")]
+impl FusedIterator for EncodeWide<'_> {}
+
 impl Hash for CodePoint {
     #[inline]
     fn hash<H: Hasher>(&self, state: &mut H) {
index 4ab8fb2e9052c6d20b0233e43d3f34495a30be8c..f4750cdf764dc3e7cbb241b46d432fc27ea21bfc 100644 (file)
@@ -21,6 +21,8 @@
 /// The [`with`] method yields a reference to the contained value which cannot be
 /// sent across threads or escape the given closure.
 ///
+/// [`thread_local!`]: crate::thread_local
+///
 /// # Initialization and Destruction
 ///
 /// Initialization is dynamically performed on the first call to [`with`]
index 5309dc47ac4e777be69d4da69cd168affbf108a2..b4b1037a3cd392a60131aa18bc65f8333c10207d 100644 (file)
 //! [`Cell`]: crate::cell::Cell
 //! [`RefCell`]: crate::cell::RefCell
 //! [`with`]: LocalKey::with
+//! [`thread_local!`]: crate::thread_local
 
 #![stable(feature = "rust1", since = "1.0.0")]
 #![deny(unsafe_op_in_unsafe_fn)]
 use crate::num::NonZeroUsize;
 use crate::panic;
 use crate::panicking;
+use crate::pin::Pin;
+use crate::ptr::addr_of_mut;
 use crate::str;
 use crate::sync::Arc;
 use crate::sys::thread as imp;
@@ -923,7 +926,7 @@ pub fn sleep(dur: Duration) {
 pub fn park() {
     // SAFETY: park_timeout is called on the parker owned by this thread.
     unsafe {
-        current().inner.parker.park();
+        current().inner.as_ref().parker().park();
     }
 }
 
@@ -987,7 +990,7 @@ pub fn park_timeout_ms(ms: u32) {
 pub fn park_timeout(dur: Duration) {
     // SAFETY: park_timeout is called on the parker owned by this thread.
     unsafe {
-        current().inner.parker.park_timeout(dur);
+        current().inner.as_ref().parker().park_timeout(dur);
     }
 }
 
@@ -1073,6 +1076,12 @@ struct Inner {
     parker: Parker,
 }
 
+impl Inner {
+    fn parker(self: Pin<&Self>) -> Pin<&Parker> {
+        unsafe { Pin::map_unchecked(self, |inner| &inner.parker) }
+    }
+}
+
 #[derive(Clone)]
 #[stable(feature = "rust1", since = "1.0.0")]
 /// A handle to a thread.
@@ -1094,14 +1103,28 @@ struct Inner {
 ///
 /// [`thread::current`]: current
 pub struct Thread {
-    inner: Arc<Inner>,
+    inner: Pin<Arc<Inner>>,
 }
 
 impl Thread {
     // Used only internally to construct a thread object without spawning
     // Panics if the name contains nuls.
     pub(crate) fn new(name: Option<CString>) -> Thread {
-        Thread { inner: Arc::new(Inner { name, id: ThreadId::new(), parker: Parker::new() }) }
+        // We have to use `unsafe` here to constuct the `Parker` in-place,
+        // which is required for the UNIX implementation.
+        //
+        // SAFETY: We pin the Arc immediately after creation, so its address never
+        // changes.
+        let inner = unsafe {
+            let mut arc = Arc::<Inner>::new_uninit();
+            let ptr = Arc::get_mut_unchecked(&mut arc).as_mut_ptr();
+            addr_of_mut!((*ptr).name).write(name);
+            addr_of_mut!((*ptr).id).write(ThreadId::new());
+            Parker::new(addr_of_mut!((*ptr).parker));
+            Pin::new_unchecked(arc.assume_init())
+        };
+
+        Thread { inner }
     }
 
     /// Atomically makes the handle's token available if it is not already.
@@ -1137,7 +1160,7 @@ pub(crate) fn new(name: Option<CString>) -> Thread {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn unpark(&self) {
-        self.inner.parker.unpark();
+        self.inner.as_ref().parker().unpark();
     }
 
     /// Gets the thread's unique identifier.
index 4c32547f0590b6178241808a0cd70440fab63598..dea8d998bdeda21ce50766a7e740a0c35868c35c 100644 (file)
@@ -42,10 +42,12 @@ cc = "1.0.69"
 libc = "0.2"
 serde = { version = "1.0.8", features = ["derive"] }
 serde_json = "1.0.2"
+tar = "0.4"
 toml = "0.5"
 ignore = "0.4.10"
 opener = "0.5"
 once_cell = "1.7.2"
+xz2 = "0.1"
 
 [target.'cfg(windows)'.dependencies.winapi]
 version = "0.3"
index 0349277a36b906ff68473089470cd369b4457a03..5f85fc5aa5903d0cbcc61bf265e1974ea7b20eaa 100644 (file)
@@ -31,8 +31,8 @@ fn main() {
 
     let mut cmd = Command::new(rustdoc);
 
-    // I am not actually sure why it's necessary to pass the sysroot for `--test`,
-    // but `test --doc --stage 0` is broken without it :(
+    // cfg(bootstrap)
+    // NOTE: the `--test` special-casing can be removed when https://github.com/rust-lang/cargo/pull/10594 lands on beta.
     if target.is_some() || args.iter().any(|x| x == "--test") {
         // The stage0 compiler has a special sysroot distinct from what we
         // actually downloaded, so we just always pass the `--sysroot` option,
@@ -65,13 +65,6 @@ fn main() {
         }
     }
 
-    // Needed to be able to run all rustdoc tests.
-    if let Some(ref x) = env::var_os("RUSTDOC_RESOURCE_SUFFIX") {
-        // This "unstable-options" can be removed when `--resource-suffix` is stabilized
-        cmd.arg("-Z").arg("unstable-options");
-        cmd.arg("--resource-suffix").arg(x);
-    }
-
     if verbose > 1 {
         eprintln!(
             "rustdoc command: {:?}={:?} {:?}",
index ac1c47524fd0e2f65c295411645e47dfafcfe69a..e38a574ca2310de1b230e2c0009a9e9d4f31d414 100644 (file)
@@ -500,81 +500,6 @@ class RustBuild(object):
                 with output(self.rustfmt_stamp()) as rustfmt_stamp:
                     rustfmt_stamp.write(self.stage0_rustfmt.channel())
 
-        # Avoid downloading LLVM twice (once for stage0 and once for the master rustc)
-        if self.downloading_llvm() and stage0:
-            # We want the most recent LLVM submodule update to avoid downloading
-            # LLVM more often than necessary.
-            #
-            # This git command finds that commit SHA, looking for bors-authored
-            # commits that modified src/llvm-project or other relevant version
-            # stamp files.
-            #
-            # This works even in a repository that has not yet initialized
-            # submodules.
-            top_level = subprocess.check_output([
-                "git", "rev-parse", "--show-toplevel",
-            ]).decode(sys.getdefaultencoding()).strip()
-            llvm_sha = subprocess.check_output([
-                "git", "rev-list", "--author=bors@rust-lang.org", "-n1",
-                "--first-parent", "HEAD",
-                "--",
-                "{}/src/llvm-project".format(top_level),
-                "{}/src/bootstrap/download-ci-llvm-stamp".format(top_level),
-                # the LLVM shared object file is named `LLVM-12-rust-{version}-nightly`
-                "{}/src/version".format(top_level)
-            ]).decode(sys.getdefaultencoding()).strip()
-            llvm_assertions = self.get_toml('assertions', 'llvm') == 'true'
-            llvm_root = self.llvm_root()
-            llvm_lib = os.path.join(llvm_root, "lib")
-            if self.program_out_of_date(self.llvm_stamp(), llvm_sha + str(llvm_assertions)):
-                self._download_ci_llvm(llvm_sha, llvm_assertions)
-                for binary in ["llvm-config", "FileCheck"]:
-                    self.fix_bin_or_dylib(os.path.join(llvm_root, "bin", binary))
-                for lib in os.listdir(llvm_lib):
-                    if lib.endswith(".so"):
-                        self.fix_bin_or_dylib(os.path.join(llvm_lib, lib))
-                with output(self.llvm_stamp()) as llvm_stamp:
-                    llvm_stamp.write(llvm_sha + str(llvm_assertions))
-
-    def downloading_llvm(self):
-        opt = self.get_toml('download-ci-llvm', 'llvm')
-        # This is currently all tier 1 targets and tier 2 targets with host tools
-        # (since others may not have CI artifacts)
-        # https://doc.rust-lang.org/rustc/platform-support.html#tier-1
-        supported_platforms = [
-            # tier 1
-            "aarch64-unknown-linux-gnu",
-            "i686-pc-windows-gnu",
-            "i686-pc-windows-msvc",
-            "i686-unknown-linux-gnu",
-            "x86_64-unknown-linux-gnu",
-            "x86_64-apple-darwin",
-            "x86_64-pc-windows-gnu",
-            "x86_64-pc-windows-msvc",
-            # tier 2 with host tools
-            "aarch64-apple-darwin",
-            "aarch64-pc-windows-msvc",
-            "aarch64-unknown-linux-musl",
-            "arm-unknown-linux-gnueabi",
-            "arm-unknown-linux-gnueabihf",
-            "armv7-unknown-linux-gnueabihf",
-            "mips-unknown-linux-gnu",
-            "mips64-unknown-linux-gnuabi64",
-            "mips64el-unknown-linux-gnuabi64",
-            "mipsel-unknown-linux-gnu",
-            "powerpc-unknown-linux-gnu",
-            "powerpc64-unknown-linux-gnu",
-            "powerpc64le-unknown-linux-gnu",
-            "riscv64gc-unknown-linux-gnu",
-            "s390x-unknown-linux-gnu",
-            "x86_64-unknown-freebsd",
-            "x86_64-unknown-illumos",
-            "x86_64-unknown-linux-musl",
-            "x86_64-unknown-netbsd",
-        ]
-        return opt == "true" \
-            or (opt == "if-available" and self.build in supported_platforms)
-
     def _download_component_helper(
         self, filename, pattern, tarball_suffix, stage0=True, key=None
     ):
@@ -606,53 +531,6 @@ class RustBuild(object):
             )
         unpack(tarball, tarball_suffix, self.bin_root(stage0), match=pattern, verbose=self.verbose)
 
-    def _download_ci_llvm(self, llvm_sha, llvm_assertions):
-        if not llvm_sha:
-            print("error: could not find commit hash for downloading LLVM")
-            print("help: maybe your repository history is too shallow?")
-            print("help: consider disabling `download-ci-llvm`")
-            print("help: or fetch enough history to include one upstream commit")
-            exit(1)
-        cache_prefix = "llvm-{}-{}".format(llvm_sha, llvm_assertions)
-        cache_dst = os.path.join(self.build_dir, "cache")
-        rustc_cache = os.path.join(cache_dst, cache_prefix)
-        if not os.path.exists(rustc_cache):
-            os.makedirs(rustc_cache)
-
-        base = "https://ci-artifacts.rust-lang.org"
-        url = "rustc-builds/{}".format(llvm_sha)
-        if llvm_assertions:
-            url = url.replace('rustc-builds', 'rustc-builds-alt')
-        # ci-artifacts are only stored as .xz, not .gz
-        if not support_xz():
-            print("error: XZ support is required to download LLVM")
-            print("help: consider disabling `download-ci-llvm` or using python3")
-            exit(1)
-        tarball_suffix = '.tar.xz'
-        filename = "rust-dev-nightly-" + self.build + tarball_suffix
-        tarball = os.path.join(rustc_cache, filename)
-        if not os.path.exists(tarball):
-            help_on_error = "error: failed to download llvm from ci"
-            help_on_error += "\nhelp: old builds get deleted after a certain time"
-            help_on_error += "\nhelp: if trying to compile an old commit of rustc,"
-            help_on_error += " disable `download-ci-llvm` in config.toml:"
-            help_on_error += "\n"
-            help_on_error += "\n[llvm]"
-            help_on_error += "\ndownload-ci-llvm = false"
-            help_on_error += "\n"
-            get(
-                base,
-                "{}/{}".format(url, filename),
-                tarball,
-                self.checksums_sha256,
-                verbose=self.verbose,
-                do_verify=False,
-                help_on_error=help_on_error,
-            )
-        unpack(tarball, tarball_suffix, self.llvm_root(),
-                match="rust-dev",
-                verbose=self.verbose)
-
     def fix_bin_or_dylib(self, fname):
         """Modifies the interpreter section of 'fname' to fix the dynamic linker,
         or the RPATH section, to fix the dynamic library search path
@@ -816,17 +694,6 @@ class RustBuild(object):
         """
         return os.path.join(self.bin_root(True), '.rustfmt-stamp')
 
-    def llvm_stamp(self):
-        """Return the path for .llvm-stamp
-
-        >>> rb = RustBuild()
-        >>> rb.build_dir = "build"
-        >>> rb.llvm_stamp() == os.path.join("build", "ci-llvm", ".llvm-stamp")
-        True
-        """
-        return os.path.join(self.llvm_root(), '.llvm-stamp')
-
-
     def program_out_of_date(self, stamp_path, key):
         """Check if the given program stamp is out of date"""
         if not os.path.exists(stamp_path) or self.clean:
@@ -856,22 +723,6 @@ class RustBuild(object):
             subdir = "ci-rustc"
         return os.path.join(self.build_dir, self.build, subdir)
 
-    def llvm_root(self):
-        """Return the CI LLVM root directory
-
-        >>> rb = RustBuild()
-        >>> rb.build_dir = "build"
-        >>> rb.llvm_root() == os.path.join("build", "ci-llvm")
-        True
-
-        When the 'build' property is given should be a nested directory:
-
-        >>> rb.build = "devel"
-        >>> rb.llvm_root() == os.path.join("build", "devel", "ci-llvm")
-        True
-        """
-        return os.path.join(self.build_dir, self.build, "ci-llvm")
-
     def get_toml(self, key, section=None):
         """Returns the value of the given key in config.toml, otherwise returns None
 
index 310da7c646aa058b4c8bbc629ec22eda25907c80..edfe31319e8d0ab10735d109b45fc5f0c6a31048 100644 (file)
@@ -1,9 +1,9 @@
-use std::any::Any;
+use std::any::{type_name, Any};
 use std::cell::{Cell, RefCell};
 use std::collections::BTreeSet;
 use std::env;
 use std::ffi::OsStr;
-use std::fmt::Debug;
+use std::fmt::{Debug, Write};
 use std::fs;
 use std::hash::Hash;
 use std::ops::Deref;
@@ -12,7 +12,6 @@
 use std::time::{Duration, Instant};
 
 use crate::cache::{Cache, Interned, INTERNER};
-use crate::check;
 use crate::compile;
 use crate::config::{SplitDebuginfo, TargetSelection};
 use crate::dist;
@@ -25,6 +24,7 @@
 use crate::tool::{self, SourceType};
 use crate::util::{self, add_dylib_path, add_link_lib_path, exe, libdir, output, t};
 use crate::EXTRA_CHECK_CFGS;
+use crate::{check, Config};
 use crate::{Build, CLang, DocTests, GitRepo, Mode};
 
 pub use crate::Compiler;
@@ -125,7 +125,8 @@ pub fn parse(path: impl Into<PathBuf>) -> TaskPath {
                     if found_kind.is_empty() {
                         panic!("empty kind in task path {}", path.display());
                     }
-                    kind = Some(Kind::parse(found_kind));
+                    kind = Kind::parse(found_kind);
+                    assert!(kind.is_some());
                     path = Path::new(found_prefix).join(components.as_path());
                 }
             }
@@ -431,43 +432,53 @@ pub enum Kind {
     Check,
     Clippy,
     Fix,
+    Format,
     Test,
     Bench,
-    Dist,
     Doc,
+    Clean,
+    Dist,
     Install,
     Run,
+    Setup,
 }
 
 impl Kind {
-    fn parse(string: &str) -> Kind {
-        match string {
-            "build" => Kind::Build,
-            "check" => Kind::Check,
+    pub fn parse(string: &str) -> Option<Kind> {
+        // these strings, including the one-letter aliases, must match the x.py help text
+        Some(match string {
+            "build" | "b" => Kind::Build,
+            "check" | "c" => Kind::Check,
             "clippy" => Kind::Clippy,
             "fix" => Kind::Fix,
-            "test" => Kind::Test,
+            "fmt" => Kind::Format,
+            "test" | "t" => Kind::Test,
             "bench" => Kind::Bench,
+            "doc" | "d" => Kind::Doc,
+            "clean" => Kind::Clean,
             "dist" => Kind::Dist,
-            "doc" => Kind::Doc,
             "install" => Kind::Install,
-            "run" => Kind::Run,
-            other => panic!("unknown kind: {}", other),
-        }
+            "run" | "r" => Kind::Run,
+            "setup" => Kind::Setup,
+            _ => return None,
+        })
     }
 
-    fn as_str(&self) -> &'static str {
+    pub fn as_str(&self) -> &'static str {
         match self {
             Kind::Build => "build",
             Kind::Check => "check",
             Kind::Clippy => "clippy",
             Kind::Fix => "fix",
+            Kind::Format => "fmt",
             Kind::Test => "test",
             Kind::Bench => "bench",
-            Kind::Dist => "dist",
             Kind::Doc => "doc",
+            Kind::Clean => "clean",
+            Kind::Dist => "dist",
             Kind::Install => "install",
             Kind::Run => "run",
+            Kind::Setup => "setup",
         }
     }
 }
@@ -511,7 +522,7 @@ macro_rules! describe {
                 native::Lld,
                 native::CrtBeginEnd
             ),
-            Kind::Check | Kind::Clippy { .. } | Kind::Fix => describe!(
+            Kind::Check => describe!(
                 check::Std,
                 check::Rustc,
                 check::Rustdoc,
@@ -603,7 +614,6 @@ macro_rules! describe {
                 dist::RustcDocs,
                 dist::Mingw,
                 dist::Rustc,
-                dist::DebuggerScripts,
                 dist::Std,
                 dist::RustcDev,
                 dist::Analysis,
@@ -641,32 +651,29 @@ macro_rules! describe {
                 install::Rustc
             ),
             Kind::Run => describe!(run::ExpandYamlAnchors, run::BuildManifest, run::BumpStage0),
+            // These commands either don't use paths, or they're special-cased in Build::build()
+            Kind::Clean | Kind::Clippy | Kind::Fix | Kind::Format | Kind::Setup => vec![],
         }
     }
 
-    pub fn get_help(build: &Build, subcommand: &str) -> Option<String> {
-        let kind = match subcommand {
-            "build" | "b" => Kind::Build,
-            "doc" | "d" => Kind::Doc,
-            "test" | "t" => Kind::Test,
-            "bench" => Kind::Bench,
-            "dist" => Kind::Dist,
-            "install" => Kind::Install,
-            _ => return None,
-        };
+    pub fn get_help(build: &Build, kind: Kind) -> Option<String> {
+        let step_descriptions = Builder::get_step_descriptions(kind);
+        if step_descriptions.is_empty() {
+            return None;
+        }
 
         let builder = Self::new_internal(build, kind, vec![]);
         let builder = &builder;
         // The "build" kind here is just a placeholder, it will be replaced with something else in
         // the following statement.
         let mut should_run = ShouldRun::new(builder, Kind::Build);
-        for desc in Builder::get_step_descriptions(builder.kind) {
+        for desc in step_descriptions {
             should_run.kind = desc.kind;
             should_run = (desc.should_run)(should_run);
         }
         let mut help = String::from("Available paths:\n");
         let mut add_path = |path: &Path| {
-            help.push_str(&format!("    ./x.py {} {}\n", subcommand, path.display()));
+            t!(write!(help, "    ./x.py {} {}\n", kind.as_str(), path.display()));
         };
         for pathset in should_run.paths {
             match pathset {
@@ -952,6 +959,11 @@ fn llvm_config(&self, target: TargetSelection) -> Option<PathBuf> {
         None
     }
 
+    /// Convenience wrapper to allow `builder.llvm_link_shared()` instead of `builder.config.llvm_link_shared(&builder)`.
+    pub(crate) fn llvm_link_shared(&self) -> bool {
+        Config::llvm_link_shared(self)
+    }
+
     /// Prepares an invocation of `cargo` to be run.
     ///
     /// This will create a `Command` that represents a pending execution of
@@ -1755,7 +1767,16 @@ pub fn ensure<S: Step>(&'a self, step: S) -> S::Output {
         };
 
         if self.config.print_step_timings && !self.config.dry_run {
-            println!("[TIMING] {:?} -- {}.{:03}", step, dur.as_secs(), dur.subsec_millis());
+            let step_string = format!("{:?}", step);
+            let brace_index = step_string.find("{").unwrap_or(0);
+            let type_string = type_name::<S>();
+            println!(
+                "[TIMING] {} {} -- {}.{:03}",
+                &type_string.strip_prefix("bootstrap::").unwrap_or(type_string),
+                &step_string[brace_index..],
+                dur.as_secs(),
+                dur.subsec_millis()
+            );
         }
 
         {
index a59f72ed968b4bac5f5f486efb0b378cc40c934f..3b6cd7564f08ae57e77365128feefc9908217ba3 100644 (file)
@@ -7,6 +7,7 @@ fn configure(cmd: &str, host: &[&str], target: &[&str]) -> Config {
     // don't save toolstates
     config.save_toolstates = None;
     config.dry_run = true;
+    config.submodules = Some(false);
     config.ninja_in_file = false;
     // try to avoid spurious failures in dist where we create/delete each others file
     // HACK: rather than pull in `tempdir`, use the one that cargo has conveniently created for us
@@ -25,36 +26,74 @@ fn first<A, B>(v: Vec<(A, B)>) -> Vec<A> {
     v.into_iter().map(|(a, _)| a).collect::<Vec<_>>()
 }
 
+fn run_build(paths: &[PathBuf], config: Config) -> Cache {
+    let kind = config.cmd.kind();
+    let build = Build::new(config);
+    let builder = Builder::new(&build);
+    builder.run_step_descriptions(&Builder::get_step_descriptions(kind), paths);
+    builder.cache
+}
+
+#[test]
+fn test_exclude() {
+    let mut config = configure("test", &["A"], &["A"]);
+    config.exclude = vec![TaskPath::parse("src/tools/tidy")];
+    let cache = run_build(&[], config);
+
+    // Ensure we have really excluded tidy
+    assert!(!cache.contains::<test::Tidy>());
+
+    // Ensure other tests are not affected.
+    assert!(cache.contains::<test::RustdocUi>());
+}
+
+#[test]
+fn test_exclude_kind() {
+    let path = PathBuf::from("src/tools/cargotest");
+    let exclude = TaskPath::parse("test::src/tools/cargotest");
+    assert_eq!(exclude, TaskPath { kind: Some(Kind::Test), path: path.clone() });
+
+    let mut config = configure("test", &["A"], &["A"]);
+    // Ensure our test is valid, and `test::Cargotest` would be run without the exclude.
+    assert!(run_build(&[path.clone()], config.clone()).contains::<test::Cargotest>());
+    // Ensure tests for cargotest are skipped.
+    config.exclude = vec![exclude.clone()];
+    assert!(!run_build(&[path.clone()], config).contains::<test::Cargotest>());
+
+    // Ensure builds for cargotest are not skipped.
+    let mut config = configure("build", &["A"], &["A"]);
+    config.exclude = vec![exclude];
+    assert!(run_build(&[path], config).contains::<tool::CargoTest>());
+}
+
 mod defaults {
-    use super::{configure, first};
+    use super::{configure, first, run_build};
     use crate::builder::*;
     use crate::Config;
     use pretty_assertions::assert_eq;
 
     #[test]
     fn build_default() {
-        let build = Build::new(configure("build", &["A"], &["A"]));
-        let mut builder = Builder::new(&build);
-        builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]);
+        let mut cache = run_build(&[], configure("build", &["A"], &["A"]));
 
         let a = TargetSelection::from_user("A");
         assert_eq!(
-            first(builder.cache.all::<compile::Std>()),
+            first(cache.all::<compile::Std>()),
             &[
                 compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a },
                 compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
             ]
         );
-        assert!(!builder.cache.all::<compile::Assemble>().is_empty());
+        assert!(!cache.all::<compile::Assemble>().is_empty());
         // Make sure rustdoc is only built once.
         assert_eq!(
-            first(builder.cache.all::<tool::Rustdoc>()),
+            first(cache.all::<tool::Rustdoc>()),
             // Recall that rustdoc stages are off-by-one
             // - this is the compiler it's _linked_ to, not built with.
             &[tool::Rustdoc { compiler: Compiler { host: a, stage: 1 } }],
         );
         assert_eq!(
-            first(builder.cache.all::<compile::Rustc>()),
+            first(cache.all::<compile::Rustc>()),
             &[compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a },]
         );
     }
@@ -62,31 +101,27 @@ fn build_default() {
     #[test]
     fn build_stage_0() {
         let config = Config { stage: 0, ..configure("build", &["A"], &["A"]) };
-        let build = Build::new(config);
-        let mut builder = Builder::new(&build);
-        builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]);
+        let mut cache = run_build(&[], config);
 
         let a = TargetSelection::from_user("A");
         assert_eq!(
-            first(builder.cache.all::<compile::Std>()),
+            first(cache.all::<compile::Std>()),
             &[compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a },]
         );
-        assert!(!builder.cache.all::<compile::Assemble>().is_empty());
+        assert!(!cache.all::<compile::Assemble>().is_empty());
         assert_eq!(
-            first(builder.cache.all::<tool::Rustdoc>()),
+            first(cache.all::<tool::Rustdoc>()),
             // This is the beta rustdoc.
             // Add an assert here to make sure this is the only rustdoc built.
             &[tool::Rustdoc { compiler: Compiler { host: a, stage: 0 } }],
         );
-        assert!(builder.cache.all::<compile::Rustc>().is_empty());
+        assert!(cache.all::<compile::Rustc>().is_empty());
     }
 
     #[test]
     fn build_cross_compile() {
         let config = Config { stage: 1, ..configure("build", &["A", "B"], &["A", "B"]) };
-        let build = Build::new(config);
-        let mut builder = Builder::new(&build);
-        builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]);
+        let mut cache = run_build(&[], config);
 
         let a = TargetSelection::from_user("A");
         let b = TargetSelection::from_user("B");
@@ -97,7 +132,7 @@ fn build_cross_compile() {
         // (since we're producing stage 1 libraries/binaries).  But currently
         // rustbuild is just a bit buggy here; this should be fixed though.
         assert_eq!(
-            first(builder.cache.all::<compile::Std>()),
+            first(cache.all::<compile::Std>()),
             &[
                 compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a },
                 compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
@@ -106,7 +141,7 @@ fn build_cross_compile() {
             ]
         );
         assert_eq!(
-            first(builder.cache.all::<compile::Assemble>()),
+            first(cache.all::<compile::Assemble>()),
             &[
                 compile::Assemble { target_compiler: Compiler { host: a, stage: 0 } },
                 compile::Assemble { target_compiler: Compiler { host: a, stage: 1 } },
@@ -114,14 +149,14 @@ fn build_cross_compile() {
             ]
         );
         assert_eq!(
-            first(builder.cache.all::<tool::Rustdoc>()),
+            first(cache.all::<tool::Rustdoc>()),
             &[
                 tool::Rustdoc { compiler: Compiler { host: a, stage: 1 } },
                 tool::Rustdoc { compiler: Compiler { host: b, stage: 1 } },
             ],
         );
         assert_eq!(
-            first(builder.cache.all::<compile::Rustc>()),
+            first(cache.all::<compile::Rustc>()),
             &[
                 compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a },
                 compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: b },
@@ -134,33 +169,28 @@ fn doc_default() {
         let mut config = configure("doc", &["A"], &["A"]);
         config.compiler_docs = true;
         config.cmd = Subcommand::Doc { paths: Vec::new(), open: false };
-        let build = Build::new(config);
-        let mut builder = Builder::new(&build);
-        builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Doc), &[]);
+        let mut cache = run_build(&[], config);
         let a = TargetSelection::from_user("A");
 
         // error_index_generator uses stage 0 to share rustdoc artifacts with the
         // rustdoc tool.
+        assert_eq!(first(cache.all::<doc::ErrorIndex>()), &[doc::ErrorIndex { target: a },]);
         assert_eq!(
-            first(builder.cache.all::<doc::ErrorIndex>()),
-            &[doc::ErrorIndex { target: a },]
-        );
-        assert_eq!(
-            first(builder.cache.all::<tool::ErrorIndex>()),
+            first(cache.all::<tool::ErrorIndex>()),
             &[tool::ErrorIndex { compiler: Compiler { host: a, stage: 0 } }]
         );
         // docs should be built with the beta compiler, not with the stage0 artifacts.
         // recall that rustdoc is off-by-one: `stage` is the compiler rustdoc is _linked_ to,
         // not the one it was built by.
         assert_eq!(
-            first(builder.cache.all::<tool::Rustdoc>()),
+            first(cache.all::<tool::Rustdoc>()),
             &[tool::Rustdoc { compiler: Compiler { host: a, stage: 0 } },]
         );
     }
 }
 
 mod dist {
-    use super::{first, Config};
+    use super::{first, run_build, Config};
     use crate::builder::*;
     use pretty_assertions::assert_eq;
 
@@ -170,94 +200,88 @@ fn configure(host: &[&str], target: &[&str]) -> Config {
 
     #[test]
     fn dist_baseline() {
-        let build = Build::new(configure(&["A"], &["A"]));
-        let mut builder = Builder::new(&build);
-        builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
+        let mut cache = run_build(&[], configure(&["A"], &["A"]));
 
         let a = TargetSelection::from_user("A");
 
-        assert_eq!(first(builder.cache.all::<dist::Docs>()), &[dist::Docs { host: a },]);
-        assert_eq!(first(builder.cache.all::<dist::Mingw>()), &[dist::Mingw { host: a },]);
+        assert_eq!(first(cache.all::<dist::Docs>()), &[dist::Docs { host: a },]);
+        assert_eq!(first(cache.all::<dist::Mingw>()), &[dist::Mingw { host: a },]);
         assert_eq!(
-            first(builder.cache.all::<dist::Rustc>()),
+            first(cache.all::<dist::Rustc>()),
             &[dist::Rustc { compiler: Compiler { host: a, stage: 2 } },]
         );
         assert_eq!(
-            first(builder.cache.all::<dist::Std>()),
+            first(cache.all::<dist::Std>()),
             &[dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a },]
         );
-        assert_eq!(first(builder.cache.all::<dist::Src>()), &[dist::Src]);
+        assert_eq!(first(cache.all::<dist::Src>()), &[dist::Src]);
         // Make sure rustdoc is only built once.
         assert_eq!(
-            first(builder.cache.all::<tool::Rustdoc>()),
+            first(cache.all::<tool::Rustdoc>()),
             &[tool::Rustdoc { compiler: Compiler { host: a, stage: 2 } },]
         );
     }
 
     #[test]
     fn dist_with_targets() {
-        let build = Build::new(configure(&["A"], &["A", "B"]));
-        let mut builder = Builder::new(&build);
-        builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
+        let mut cache = run_build(&[], configure(&["A"], &["A", "B"]));
 
         let a = TargetSelection::from_user("A");
         let b = TargetSelection::from_user("B");
 
         assert_eq!(
-            first(builder.cache.all::<dist::Docs>()),
+            first(cache.all::<dist::Docs>()),
             &[dist::Docs { host: a }, dist::Docs { host: b },]
         );
         assert_eq!(
-            first(builder.cache.all::<dist::Mingw>()),
+            first(cache.all::<dist::Mingw>()),
             &[dist::Mingw { host: a }, dist::Mingw { host: b },]
         );
         assert_eq!(
-            first(builder.cache.all::<dist::Rustc>()),
+            first(cache.all::<dist::Rustc>()),
             &[dist::Rustc { compiler: Compiler { host: a, stage: 2 } },]
         );
         assert_eq!(
-            first(builder.cache.all::<dist::Std>()),
+            first(cache.all::<dist::Std>()),
             &[
                 dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
                 dist::Std { compiler: Compiler { host: a, stage: 2 }, target: b },
             ]
         );
-        assert_eq!(first(builder.cache.all::<dist::Src>()), &[dist::Src]);
+        assert_eq!(first(cache.all::<dist::Src>()), &[dist::Src]);
     }
 
     #[test]
     fn dist_with_hosts() {
-        let build = Build::new(configure(&["A", "B"], &["A", "B"]));
-        let mut builder = Builder::new(&build);
-        builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
+        let mut cache = run_build(&[], configure(&["A", "B"], &["A", "B"]));
 
         let a = TargetSelection::from_user("A");
         let b = TargetSelection::from_user("B");
 
         assert_eq!(
-            first(builder.cache.all::<dist::Docs>()),
+            first(cache.all::<dist::Docs>()),
             &[dist::Docs { host: a }, dist::Docs { host: b },]
         );
         assert_eq!(
-            first(builder.cache.all::<dist::Mingw>()),
+            first(cache.all::<dist::Mingw>()),
             &[dist::Mingw { host: a }, dist::Mingw { host: b },]
         );
         assert_eq!(
-            first(builder.cache.all::<dist::Rustc>()),
+            first(cache.all::<dist::Rustc>()),
             &[
                 dist::Rustc { compiler: Compiler { host: a, stage: 2 } },
                 dist::Rustc { compiler: Compiler { host: b, stage: 2 } },
             ]
         );
         assert_eq!(
-            first(builder.cache.all::<dist::Std>()),
+            first(cache.all::<dist::Std>()),
             &[
                 dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
                 dist::Std { compiler: Compiler { host: a, stage: 1 }, target: b },
             ]
         );
         assert_eq!(
-            first(builder.cache.all::<compile::Std>()),
+            first(cache.all::<compile::Std>()),
             &[
                 compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a },
                 compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
@@ -266,26 +290,25 @@ fn dist_with_hosts() {
                 compile::Std { compiler: Compiler { host: a, stage: 2 }, target: b },
             ],
         );
-        assert_eq!(first(builder.cache.all::<dist::Src>()), &[dist::Src]);
+        assert_eq!(first(cache.all::<dist::Src>()), &[dist::Src]);
     }
 
     #[test]
     fn dist_only_cross_host() {
         let a = TargetSelection::from_user("A");
         let b = TargetSelection::from_user("B");
-        let mut build = Build::new(configure(&["A", "B"], &["A", "B"]));
-        build.config.docs = false;
-        build.config.extended = true;
-        build.hosts = vec![b];
-        let mut builder = Builder::new(&build);
-        builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
+        let mut config = configure(&["A", "B"], &["A", "B"]);
+        config.docs = false;
+        config.extended = true;
+        config.hosts = vec![b];
+        let mut cache = run_build(&[], config);
 
         assert_eq!(
-            first(builder.cache.all::<dist::Rustc>()),
+            first(cache.all::<dist::Rustc>()),
             &[dist::Rustc { compiler: Compiler { host: b, stage: 2 } },]
         );
         assert_eq!(
-            first(builder.cache.all::<compile::Rustc>()),
+            first(cache.all::<compile::Rustc>()),
             &[
                 compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a },
                 compile::Rustc { compiler: Compiler { host: a, stage: 1 }, target: b },
@@ -295,92 +318,86 @@ fn dist_only_cross_host() {
 
     #[test]
     fn dist_with_targets_and_hosts() {
-        let build = Build::new(configure(&["A", "B"], &["A", "B", "C"]));
-        let mut builder = Builder::new(&build);
-        builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
+        let mut cache = run_build(&[], configure(&["A", "B"], &["A", "B", "C"]));
 
         let a = TargetSelection::from_user("A");
         let b = TargetSelection::from_user("B");
         let c = TargetSelection::from_user("C");
 
         assert_eq!(
-            first(builder.cache.all::<dist::Docs>()),
+            first(cache.all::<dist::Docs>()),
             &[dist::Docs { host: a }, dist::Docs { host: b }, dist::Docs { host: c },]
         );
         assert_eq!(
-            first(builder.cache.all::<dist::Mingw>()),
+            first(cache.all::<dist::Mingw>()),
             &[dist::Mingw { host: a }, dist::Mingw { host: b }, dist::Mingw { host: c },]
         );
         assert_eq!(
-            first(builder.cache.all::<dist::Rustc>()),
+            first(cache.all::<dist::Rustc>()),
             &[
                 dist::Rustc { compiler: Compiler { host: a, stage: 2 } },
                 dist::Rustc { compiler: Compiler { host: b, stage: 2 } },
             ]
         );
         assert_eq!(
-            first(builder.cache.all::<dist::Std>()),
+            first(cache.all::<dist::Std>()),
             &[
                 dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
                 dist::Std { compiler: Compiler { host: a, stage: 1 }, target: b },
                 dist::Std { compiler: Compiler { host: a, stage: 2 }, target: c },
             ]
         );
-        assert_eq!(first(builder.cache.all::<dist::Src>()), &[dist::Src]);
+        assert_eq!(first(cache.all::<dist::Src>()), &[dist::Src]);
     }
 
     #[test]
     fn dist_with_empty_host() {
         let config = configure(&[], &["C"]);
-        let build = Build::new(config);
-        let mut builder = Builder::new(&build);
-        builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
+        let mut cache = run_build(&[], config);
 
         let a = TargetSelection::from_user("A");
         let c = TargetSelection::from_user("C");
 
-        assert_eq!(first(builder.cache.all::<dist::Docs>()), &[dist::Docs { host: c },]);
-        assert_eq!(first(builder.cache.all::<dist::Mingw>()), &[dist::Mingw { host: c },]);
+        assert_eq!(first(cache.all::<dist::Docs>()), &[dist::Docs { host: c },]);
+        assert_eq!(first(cache.all::<dist::Mingw>()), &[dist::Mingw { host: c },]);
         assert_eq!(
-            first(builder.cache.all::<dist::Std>()),
+            first(cache.all::<dist::Std>()),
             &[dist::Std { compiler: Compiler { host: a, stage: 2 }, target: c },]
         );
     }
 
     #[test]
     fn dist_with_same_targets_and_hosts() {
-        let build = Build::new(configure(&["A", "B"], &["A", "B"]));
-        let mut builder = Builder::new(&build);
-        builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
+        let mut cache = run_build(&[], configure(&["A", "B"], &["A", "B"]));
 
         let a = TargetSelection::from_user("A");
         let b = TargetSelection::from_user("B");
 
         assert_eq!(
-            first(builder.cache.all::<dist::Docs>()),
+            first(cache.all::<dist::Docs>()),
             &[dist::Docs { host: a }, dist::Docs { host: b },]
         );
         assert_eq!(
-            first(builder.cache.all::<dist::Mingw>()),
+            first(cache.all::<dist::Mingw>()),
             &[dist::Mingw { host: a }, dist::Mingw { host: b },]
         );
         assert_eq!(
-            first(builder.cache.all::<dist::Rustc>()),
+            first(cache.all::<dist::Rustc>()),
             &[
                 dist::Rustc { compiler: Compiler { host: a, stage: 2 } },
                 dist::Rustc { compiler: Compiler { host: b, stage: 2 } },
             ]
         );
         assert_eq!(
-            first(builder.cache.all::<dist::Std>()),
+            first(cache.all::<dist::Std>()),
             &[
                 dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
                 dist::Std { compiler: Compiler { host: a, stage: 1 }, target: b },
             ]
         );
-        assert_eq!(first(builder.cache.all::<dist::Src>()), &[dist::Src]);
+        assert_eq!(first(cache.all::<dist::Src>()), &[dist::Src]);
         assert_eq!(
-            first(builder.cache.all::<compile::Std>()),
+            first(cache.all::<compile::Std>()),
             &[
                 compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a },
                 compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
@@ -390,7 +407,7 @@ fn dist_with_same_targets_and_hosts() {
             ]
         );
         assert_eq!(
-            first(builder.cache.all::<compile::Assemble>()),
+            first(cache.all::<compile::Assemble>()),
             &[
                 compile::Assemble { target_compiler: Compiler { host: a, stage: 0 } },
                 compile::Assemble { target_compiler: Compiler { host: a, stage: 1 } },
@@ -514,35 +531,6 @@ fn test_with_no_doc_stage0() {
         );
     }
 
-    #[test]
-    fn test_exclude() {
-        let mut config = configure(&["A"], &["A"]);
-        config.exclude = vec![TaskPath::parse("src/tools/tidy")];
-        config.cmd = Subcommand::Test {
-            paths: Vec::new(),
-            test_args: Vec::new(),
-            rustc_args: Vec::new(),
-            fail_fast: true,
-            doc_tests: DocTests::No,
-            bless: false,
-            force_rerun: false,
-            compare_mode: None,
-            rustfix_coverage: false,
-            pass: None,
-            run: None,
-        };
-
-        let build = Build::new(config);
-        let builder = Builder::new(&build);
-        builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Test), &[]);
-
-        // Ensure we have really excluded tidy
-        assert!(!builder.cache.contains::<test::Tidy>());
-
-        // Ensure other tests are not affected.
-        assert!(builder.cache.contains::<test::RustdocUi>());
-    }
-
     #[test]
     fn doc_ci() {
         let mut config = configure(&["A"], &["A"]);
index 432a6c34ed58415c934989acf542546a3cc13c4a..731ebc41bb9a00b075022cbf9eba827bdf189f71 100644 (file)
@@ -64,7 +64,7 @@ impl Step for Std {
     const DEFAULT: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.all_krates("test")
+        run.all_krates("test").path("library")
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -162,7 +162,7 @@ impl Step for Rustc {
     const DEFAULT: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.all_krates("rustc-main")
+        run.all_krates("rustc-main").path("compiler")
     }
 
     fn make_run(run: RunConfig<'_>) {
index 45991381dc0fe1d9a70b64062d40b78624326bce..53933e4cd7d200299444a550d6fc2e0d6951fda4 100644 (file)
@@ -43,7 +43,7 @@ fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
         // When downloading stage1, the standard library has already been copied to the sysroot, so
         // there's no need to rebuild it.
         let download_rustc = run.builder.config.download_rustc;
-        run.all_krates("test").default_condition(!download_rustc)
+        run.all_krates("test").path("library").default_condition(!download_rustc)
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -737,7 +737,7 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetS
             );
             cargo.env("LLVM_STATIC_STDCPP", file);
         }
-        if builder.config.llvm_link_shared {
+        if builder.llvm_link_shared() {
             cargo.env("LLVM_LINK_SHARED", "1");
         }
         if builder.config.llvm_use_libcxx {
@@ -1047,7 +1047,7 @@ impl Step for Assemble {
     const ONLY_HOSTS: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.path("compiler/rustc")
+        run.path("compiler/rustc").path("compiler")
     }
 
     fn make_run(run: RunConfig<'_>) {
index f273fb42215e95873c8e48d9b86a0e8d4fb14a87..e39c9fa1c5a6d6b30e4d325bc17870da43ce84dd 100644 (file)
@@ -3,6 +3,7 @@
 //! This module implements parsing `config.toml` configuration files to tweak
 //! how the build runs.
 
+use std::cell::Cell;
 use std::cmp;
 use std::collections::{HashMap, HashSet};
 use std::env;
@@ -11,7 +12,7 @@
 use std::path::{Path, PathBuf};
 use std::str::FromStr;
 
-use crate::builder::TaskPath;
+use crate::builder::{Builder, TaskPath};
 use crate::cache::{Interned, INTERNER};
 use crate::channel::GitInfo;
 pub use crate::flags::Subcommand;
@@ -41,6 +42,7 @@ macro_rules! check_ci_llvm {
 /// each field, see the corresponding fields in
 /// `config.toml.example`.
 #[derive(Default)]
+#[cfg_attr(test, derive(Clone))]
 pub struct Config {
     pub changelog_seen: Option<usize>,
     pub ccache: Option<String>,
@@ -68,13 +70,14 @@ pub struct Config {
     pub test_compare_mode: bool,
     pub llvm_libunwind: LlvmLibunwind,
     pub color: Color,
+    pub patch_binaries_for_nix: bool,
 
     pub on_fail: Option<String>,
     pub stage: u32,
     pub keep_stage: Vec<u32>,
     pub keep_stage_std: Vec<u32>,
     pub src: PathBuf,
-    // defaults to `config.toml`
+    /// defaults to `config.toml`
     pub config: PathBuf,
     pub jobs: Option<u32>,
     pub cmd: Subcommand,
@@ -95,7 +98,11 @@ pub struct Config {
     pub llvm_release_debuginfo: bool,
     pub llvm_version_check: bool,
     pub llvm_static_stdcpp: bool,
-    pub llvm_link_shared: bool,
+    /// `None` if `llvm_from_ci` is true and we haven't yet downloaded llvm.
+    #[cfg(not(test))]
+    llvm_link_shared: Cell<Option<bool>>,
+    #[cfg(test)]
+    pub llvm_link_shared: Cell<Option<bool>>,
     pub llvm_clang_cl: Option<String>,
     pub llvm_targets: Option<String>,
     pub llvm_experimental_targets: Option<String>,
@@ -330,6 +337,7 @@ fn eq(&self, other: &&str) -> bool {
 
 /// Per-target configuration stored in the global configuration structure.
 #[derive(Default)]
+#[cfg_attr(test, derive(Clone))]
 pub struct Target {
     /// Some(path to llvm-config) if using an external LLVM.
     pub llvm_config: Option<PathBuf>,
@@ -856,6 +864,7 @@ pub fn parse(args: &[String]) -> Config {
         set(&mut config.local_rebuild, build.local_rebuild);
         set(&mut config.print_step_timings, build.print_step_timings);
         set(&mut config.print_step_rusage, build.print_step_rusage);
+        set(&mut config.patch_binaries_for_nix, build.patch_binaries_for_nix);
 
         config.verbose = cmp::max(config.verbose, flags.verbose);
 
@@ -911,7 +920,9 @@ pub fn parse(args: &[String]) -> Config {
             set(&mut config.llvm_release_debuginfo, llvm.release_debuginfo);
             set(&mut config.llvm_version_check, llvm.version_check);
             set(&mut config.llvm_static_stdcpp, llvm.static_libstdcpp);
-            set(&mut config.llvm_link_shared, llvm.link_shared);
+            if let Some(v) = llvm.link_shared {
+                config.llvm_link_shared.set(Some(v));
+            }
             config.llvm_targets = llvm.targets.clone();
             config.llvm_experimental_targets = llvm.experimental_targets.clone();
             config.llvm_link_jobs = llvm.link_jobs;
@@ -981,6 +992,7 @@ pub fn parse(args: &[String]) -> Config {
                 check_ci_llvm!(llvm.optimize);
                 check_ci_llvm!(llvm.thin_lto);
                 check_ci_llvm!(llvm.release_debuginfo);
+                // CI-built LLVM can be either dynamic or static. We won't know until we download it.
                 check_ci_llvm!(llvm.link_shared);
                 check_ci_llvm!(llvm.static_libstdcpp);
                 check_ci_llvm!(llvm.targets);
@@ -998,26 +1010,14 @@ pub fn parse(args: &[String]) -> Config {
                 check_ci_llvm!(llvm.clang);
                 check_ci_llvm!(llvm.build_config);
                 check_ci_llvm!(llvm.plugins);
-
-                // CI-built LLVM can be either dynamic or static.
-                let ci_llvm = config.out.join(&*config.build.triple).join("ci-llvm");
-                config.llvm_link_shared = if config.dry_run {
-                    // just assume dynamic for now
-                    true
-                } else {
-                    let link_type = t!(
-                        std::fs::read_to_string(ci_llvm.join("link-type.txt")),
-                        format!("CI llvm missing: {}", ci_llvm.display())
-                    );
-                    link_type == "dynamic"
-                };
             }
 
+            // NOTE: can never be hit when downloading from CI, since we call `check_ci_llvm!(thin_lto)` above.
             if config.llvm_thin_lto && llvm.link_shared.is_none() {
                 // If we're building with ThinLTO on, by default we want to link
                 // to LLVM shared, to avoid re-doing ThinLTO (which happens in
                 // the link step) with each stage.
-                config.llvm_link_shared = true;
+                config.llvm_link_shared.set(Some(true));
             }
         }
 
@@ -1272,6 +1272,42 @@ pub fn libdir_relative(&self) -> Option<&Path> {
         }
     }
 
+    /// The absolute path to the downloaded LLVM artifacts.
+    pub(crate) fn ci_llvm_root(&self) -> PathBuf {
+        assert!(self.llvm_from_ci);
+        self.out.join(&*self.build.triple).join("ci-llvm")
+    }
+
+    /// Determine whether llvm should be linked dynamically.
+    ///
+    /// If `false`, llvm should be linked statically.
+    /// This is computed on demand since LLVM might have to first be downloaded from CI.
+    pub(crate) fn llvm_link_shared(builder: &Builder<'_>) -> bool {
+        let mut opt = builder.config.llvm_link_shared.get();
+        if opt.is_none() && builder.config.dry_run {
+            // just assume static for now - dynamic linking isn't supported on all platforms
+            return false;
+        }
+
+        let llvm_link_shared = *opt.get_or_insert_with(|| {
+            if builder.config.llvm_from_ci {
+                crate::native::maybe_download_ci_llvm(builder);
+                let ci_llvm = builder.config.ci_llvm_root();
+                let link_type = t!(
+                    std::fs::read_to_string(ci_llvm.join("link-type.txt")),
+                    format!("CI llvm missing: {}", ci_llvm.display())
+                );
+                link_type == "dynamic"
+            } else {
+                // unclear how thought-through this default is, but it maintains compatibility with
+                // previous behavior
+                false
+            }
+        });
+        builder.config.llvm_link_shared.set(opt);
+        llvm_link_shared
+    }
+
     pub fn verbose(&self) -> bool {
         self.verbose > 0
     }
index e3287e35227b9915cb1825f21e0dcdfb78bd15a9..d37a59426f895f69f7a37b9a84f1027b800823b7 100644 (file)
@@ -456,16 +456,7 @@ impl Step for DebuggerScripts {
     type Output = ();
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.path("src/etc/lldb_batchmode.py")
-    }
-
-    fn make_run(run: RunConfig<'_>) {
-        run.builder.ensure(DebuggerScripts {
-            sysroot: run
-                .builder
-                .sysroot(run.builder.compiler(run.builder.top_stage, run.build_triple())),
-            host: run.target,
-        });
+        run.never()
     }
 
     /// Copies debugger scripts for `target` into the `sysroot` specified.
@@ -1904,7 +1895,7 @@ fn maybe_install_llvm(builder: &Builder<'_>, target: TargetSelection, dst_libdir
     // clear why this is the case, though. llvm-config will emit the versioned
     // paths and we don't want those in the sysroot (as we're expecting
     // unversioned paths).
-    if target.contains("apple-darwin") && builder.config.llvm_link_shared {
+    if target.contains("apple-darwin") && builder.llvm_link_shared() {
         let src_libdir = builder.llvm_out(target).join("lib");
         let llvm_dylib_path = src_libdir.join("libLLVM.dylib");
         if llvm_dylib_path.exists() {
@@ -1939,7 +1930,7 @@ pub fn maybe_install_llvm_target(builder: &Builder<'_>, target: TargetSelection,
     // We do not need to copy LLVM files into the sysroot if it is not
     // dynamically linked; it is already included into librustc_llvm
     // statically.
-    if builder.config.llvm_link_shared {
+    if builder.llvm_link_shared() {
         maybe_install_llvm(builder, target, &dst_libdir);
     }
 }
@@ -1951,7 +1942,7 @@ pub fn maybe_install_llvm_runtime(builder: &Builder<'_>, target: TargetSelection
     // We do not need to copy LLVM files into the sysroot if it is not
     // dynamically linked; it is already included into librustc_llvm
     // statically.
-    if builder.config.llvm_link_shared {
+    if builder.llvm_link_shared() {
         maybe_install_llvm(builder, target, &dst_libdir);
     }
 }
@@ -2077,7 +2068,7 @@ fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
         // compiler libraries.
         let dst_libdir = tarball.image_dir().join("lib");
         maybe_install_llvm(builder, target, &dst_libdir);
-        let link_type = if builder.config.llvm_link_shared { "dynamic" } else { "static" };
+        let link_type = if builder.llvm_link_shared() { "dynamic" } else { "static" };
         t!(std::fs::write(tarball.image_dir().join("link-type.txt"), link_type), dst_libdir);
 
         Some(tarball.generate())
index a2802f76008a37f994d9a169e5fd6883864899b6..fcef784d2d1fa3547379fac1cd135784f4ecc060 100644 (file)
@@ -416,7 +416,7 @@ impl Step for Std {
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
         let builder = run.builder;
-        run.all_krates("test").default_condition(builder.config.docs)
+        run.all_krates("test").path("library").default_condition(builder.config.docs)
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -477,11 +477,14 @@ fn run(self, builder: &Builder<'_>) {
             .iter()
             .map(components_simplified)
             .filter_map(|path| {
-                if path.get(0) == Some(&"library") {
+                if path.len() >= 2 && path.get(0) == Some(&"library") {
+                    // single crate
                     Some(path[1].to_owned())
                 } else if !path.is_empty() {
+                    // ??
                     Some(path[0].to_owned())
                 } else {
+                    // all library crates
                     None
                 }
             })
index 1a4e6a9688803b544295aa7d1c7ba0d5d2d9c2d0..58571ea129c1940b68766ae64f5b78c9a78a19a7 100644 (file)
@@ -8,12 +8,13 @@
 
 use getopts::Options;
 
-use crate::builder::Builder;
+use crate::builder::{Builder, Kind};
 use crate::config::{Config, TargetSelection};
 use crate::setup::Profile;
 use crate::util::t;
 use crate::{Build, DocTests};
 
+#[derive(Copy, Clone)]
 pub enum Color {
     Always,
     Never,
@@ -79,6 +80,7 @@ pub struct Flags {
     pub llvm_profile_generate: bool,
 }
 
+#[cfg_attr(test, derive(Clone))]
 pub enum Subcommand {
     Build {
         paths: Vec<PathBuf>,
@@ -243,27 +245,7 @@ pub fn parse(args: &[String]) -> Flags {
         // the subcommand. Therefore we must manually identify the subcommand first, so that we can
         // complete the definition of the options.  Then we can use the getopt::Matches object from
         // there on out.
-        let subcommand = args.iter().find(|&s| {
-            (s == "build")
-                || (s == "b")
-                || (s == "check")
-                || (s == "c")
-                || (s == "clippy")
-                || (s == "fix")
-                || (s == "fmt")
-                || (s == "test")
-                || (s == "t")
-                || (s == "bench")
-                || (s == "doc")
-                || (s == "d")
-                || (s == "clean")
-                || (s == "dist")
-                || (s == "install")
-                || (s == "run")
-                || (s == "r")
-                || (s == "setup")
-        });
-        let subcommand = match subcommand {
+        let subcommand = match args.iter().find_map(|s| Kind::parse(&s)) {
             Some(s) => s,
             None => {
                 // No or an invalid subcommand -- show the general usage and subcommand help
@@ -276,8 +258,8 @@ pub fn parse(args: &[String]) -> Flags {
         };
 
         // Some subcommands get extra options
-        match subcommand.as_str() {
-            "test" | "t" => {
+        match subcommand {
+            Kind::Test => {
                 opts.optflag("", "no-fail-fast", "Run all tests regardless of failure");
                 opts.optmulti(
                     "",
@@ -316,22 +298,22 @@ pub fn parse(args: &[String]) -> Flags {
                         `/<build_base>/rustfix_missing_coverage.txt`",
                 );
             }
-            "check" | "c" => {
+            Kind::Check => {
                 opts.optflag("", "all-targets", "Check all targets");
             }
-            "bench" => {
+            Kind::Bench => {
                 opts.optmulti("", "test-args", "extra arguments", "ARGS");
             }
-            "clippy" => {
+            Kind::Clippy => {
                 opts.optflag("", "fix", "automatically apply lint suggestions");
             }
-            "doc" | "d" => {
+            Kind::Doc => {
                 opts.optflag("", "open", "open the docs in a browser");
             }
-            "clean" => {
+            Kind::Clean => {
                 opts.optflag("", "all", "clean all build artifacts");
             }
-            "fmt" => {
+            Kind::Format => {
                 opts.optflag("", "check", "check formatting instead of applying.");
             }
             _ => {}
@@ -339,25 +321,22 @@ pub fn parse(args: &[String]) -> Flags {
 
         // fn usage()
         let usage = |exit_code: i32, opts: &Options, verbose: bool, subcommand_help: &str| -> ! {
-            let mut extra_help = String::new();
-
-            // All subcommands except `clean` can have an optional "Available paths" section
-            if verbose {
-                let config = Config::parse(&["build".to_string()]);
-                let build = Build::new(config);
-
-                let maybe_rules_help = Builder::get_help(&build, subcommand.as_str());
-                extra_help.push_str(maybe_rules_help.unwrap_or_default().as_str());
-            } else if !(subcommand.as_str() == "clean" || subcommand.as_str() == "fmt") {
-                extra_help.push_str(
-                    format!("Run `./x.py {} -h -v` to see a list of available paths.", subcommand)
-                        .as_str(),
-                );
-            }
+            let config = Config::parse(&["build".to_string()]);
+            let build = Build::new(config);
+            let paths = Builder::get_help(&build, subcommand);
 
             println!("{}", opts.usage(subcommand_help));
-            if !extra_help.is_empty() {
-                println!("{}", extra_help);
+            if let Some(s) = paths {
+                if verbose {
+                    println!("{}", s);
+                } else {
+                    println!(
+                        "Run `./x.py {} -h -v` to see a list of available paths.",
+                        subcommand.as_str()
+                    );
+                }
+            } else if verbose {
+                panic!("No paths available for subcommand `{}`", subcommand.as_str());
             }
             process::exit(exit_code);
         };
@@ -375,7 +354,7 @@ pub fn parse(args: &[String]) -> Flags {
         //            ^-- option  ^     ^- actual subcommand
         //                        \_ arg to option could be mistaken as subcommand
         let mut pass_sanity_check = true;
-        match matches.free.get(0) {
+        match matches.free.get(0).and_then(|s| Kind::parse(&s)) {
             Some(check_subcommand) => {
                 if check_subcommand != subcommand {
                     pass_sanity_check = false;
@@ -394,8 +373,8 @@ pub fn parse(args: &[String]) -> Flags {
             process::exit(1);
         }
         // Extra help text for some commands
-        match subcommand.as_str() {
-            "build" | "b" => {
+        match subcommand {
+            Kind::Build => {
                 subcommand_help.push_str(
                     "\n
 Arguments:
@@ -415,7 +394,7 @@ pub fn parse(args: &[String]) -> Flags {
         ./x.py build ",
                 );
             }
-            "check" | "c" => {
+            Kind::Check => {
                 subcommand_help.push_str(
                     "\n
 Arguments:
@@ -427,7 +406,7 @@ pub fn parse(args: &[String]) -> Flags {
     If no arguments are passed then many artifacts are checked.",
                 );
             }
-            "clippy" => {
+            Kind::Clippy => {
                 subcommand_help.push_str(
                     "\n
 Arguments:
@@ -438,7 +417,7 @@ pub fn parse(args: &[String]) -> Flags {
         ./x.py clippy library/core library/proc_macro",
                 );
             }
-            "fix" => {
+            Kind::Fix => {
                 subcommand_help.push_str(
                     "\n
 Arguments:
@@ -449,7 +428,7 @@ pub fn parse(args: &[String]) -> Flags {
         ./x.py fix library/core library/proc_macro",
                 );
             }
-            "fmt" => {
+            Kind::Format => {
                 subcommand_help.push_str(
                     "\n
 Arguments:
@@ -460,7 +439,7 @@ pub fn parse(args: &[String]) -> Flags {
         ./x.py fmt --check",
                 );
             }
-            "test" | "t" => {
+            Kind::Test => {
                 subcommand_help.push_str(
                     "\n
 Arguments:
@@ -488,7 +467,7 @@ pub fn parse(args: &[String]) -> Flags {
         ./x.py test --stage 1",
                 );
             }
-            "doc" | "d" => {
+            Kind::Doc => {
                 subcommand_help.push_str(
                     "\n
 Arguments:
@@ -506,7 +485,7 @@ pub fn parse(args: &[String]) -> Flags {
         ./x.py doc --stage 1",
                 );
             }
-            "run" | "r" => {
+            Kind::Run => {
                 subcommand_help.push_str(
                     "\n
 Arguments:
@@ -518,7 +497,7 @@ pub fn parse(args: &[String]) -> Flags {
     At least a tool needs to be called.",
                 );
             }
-            "setup" => {
+            Kind::Setup => {
                 subcommand_help.push_str(&format!(
                     "\n
 x.py setup creates a `config.toml` which changes the defaults for x.py itself.
@@ -535,7 +514,7 @@ pub fn parse(args: &[String]) -> Flags {
                     Profile::all_for_help("        ").trim_end()
                 ));
             }
-            _ => {}
+            Kind::Bench | Kind::Clean | Kind::Dist | Kind::Install => {}
         };
         // Get any optional paths which occur after the subcommand
         let mut paths = matches.free[1..].iter().map(|p| p.into()).collect::<Vec<PathBuf>>();
@@ -547,9 +526,9 @@ pub fn parse(args: &[String]) -> Flags {
             usage(0, &opts, verbose, &subcommand_help);
         }
 
-        let cmd = match subcommand.as_str() {
-            "build" | "b" => Subcommand::Build { paths },
-            "check" | "c" => {
+        let cmd = match subcommand {
+            Kind::Build => Subcommand::Build { paths },
+            Kind::Check => {
                 if matches.opt_present("all-targets") {
                     eprintln!(
                         "Warning: --all-targets is now on by default and does not need to be passed explicitly."
@@ -557,9 +536,9 @@ pub fn parse(args: &[String]) -> Flags {
                 }
                 Subcommand::Check { paths }
             }
-            "clippy" => Subcommand::Clippy { paths, fix: matches.opt_present("fix") },
-            "fix" => Subcommand::Fix { paths },
-            "test" | "t" => Subcommand::Test {
+            Kind::Clippy => Subcommand::Clippy { paths, fix: matches.opt_present("fix") },
+            Kind::Fix => Subcommand::Fix { paths },
+            Kind::Test => Subcommand::Test {
                 paths,
                 bless: matches.opt_present("bless"),
                 force_rerun: matches.opt_present("force-rerun"),
@@ -578,9 +557,9 @@ pub fn parse(args: &[String]) -> Flags {
                     DocTests::Yes
                 },
             },
-            "bench" => Subcommand::Bench { paths, test_args: matches.opt_strs("test-args") },
-            "doc" | "d" => Subcommand::Doc { paths, open: matches.opt_present("open") },
-            "clean" => {
+            Kind::Bench => Subcommand::Bench { paths, test_args: matches.opt_strs("test-args") },
+            Kind::Doc => Subcommand::Doc { paths, open: matches.opt_present("open") },
+            Kind::Clean => {
                 if !paths.is_empty() {
                     println!("\nclean does not take a path argument\n");
                     usage(1, &opts, verbose, &subcommand_help);
@@ -588,17 +567,17 @@ pub fn parse(args: &[String]) -> Flags {
 
                 Subcommand::Clean { all: matches.opt_present("all") }
             }
-            "fmt" => Subcommand::Format { check: matches.opt_present("check"), paths },
-            "dist" => Subcommand::Dist { paths },
-            "install" => Subcommand::Install { paths },
-            "run" | "r" => {
+            Kind::Format => Subcommand::Format { check: matches.opt_present("check"), paths },
+            Kind::Dist => Subcommand::Dist { paths },
+            Kind::Install => Subcommand::Install { paths },
+            Kind::Run => {
                 if paths.is_empty() {
                     println!("\nrun requires at least a path!\n");
                     usage(1, &opts, verbose, &subcommand_help);
                 }
                 Subcommand::Run { paths }
             }
-            "setup" => {
+            Kind::Setup => {
                 let profile = if paths.len() > 1 {
                     println!("\nat most one profile can be passed to setup\n");
                     usage(1, &opts, verbose, &subcommand_help)
@@ -618,9 +597,6 @@ pub fn parse(args: &[String]) -> Flags {
                 };
                 Subcommand::Setup { profile }
             }
-            _ => {
-                usage(1, &opts, verbose, &subcommand_help);
-            }
         };
 
         if let Subcommand::Check { .. } = &cmd {
@@ -694,6 +670,24 @@ pub fn parse(args: &[String]) -> Flags {
 }
 
 impl Subcommand {
+    pub fn kind(&self) -> Kind {
+        match self {
+            Subcommand::Bench { .. } => Kind::Bench,
+            Subcommand::Build { .. } => Kind::Build,
+            Subcommand::Check { .. } => Kind::Check,
+            Subcommand::Clippy { .. } => Kind::Clippy,
+            Subcommand::Doc { .. } => Kind::Doc,
+            Subcommand::Fix { .. } => Kind::Fix,
+            Subcommand::Format { .. } => Kind::Format,
+            Subcommand::Test { .. } => Kind::Test,
+            Subcommand::Clean { .. } => Kind::Clean,
+            Subcommand::Dist { .. } => Kind::Dist,
+            Subcommand::Install { .. } => Kind::Install,
+            Subcommand::Run { .. } => Kind::Run,
+            Subcommand::Setup { .. } => Kind::Setup,
+        }
+    }
+
     pub fn test_args(&self) -> Vec<&str> {
         match *self {
             Subcommand::Test { ref test_args, .. } | Subcommand::Bench { ref test_args, .. } => {
index 59102ad9f50b8fdd39ba352c235c823c8342f049..b4b973b42479e942099f69a109786506371b737f 100644 (file)
@@ -1391,6 +1391,16 @@ fn read_stamp_file(&self, stamp: &Path) -> Vec<(PathBuf, DependencyType)> {
         paths
     }
 
+    /// Create a temporary directory in `out` and return its path.
+    ///
+    /// NOTE: this temporary directory is shared between all steps;
+    /// if you need an empty directory, create a new subdirectory inside it.
+    fn tempdir(&self) -> PathBuf {
+        let tmp = self.out.join("tmp");
+        t!(fs::create_dir_all(&tmp));
+        tmp
+    }
+
     /// Copies a file from `src` to `dst`
     pub fn copy(&self, src: &Path, dst: &Path) {
         if self.config.dry_run {
index 73fb2dad1e3c23ea3d39cbba0d68dd3169054d7b..64e25f803b27f68141cda943297c4de7a7a67c49 100644 (file)
 use std::env::consts::EXE_EXTENSION;
 use std::ffi::{OsStr, OsString};
 use std::fs::{self, File};
-use std::io;
+use std::io::{self, BufRead, BufReader, ErrorKind};
 use std::path::{Path, PathBuf};
-use std::process::Command;
+use std::process::{Command, Stdio};
+
+use once_cell::sync::OnceCell;
+use xz2::bufread::XzDecoder;
 
 use crate::builder::{Builder, RunConfig, ShouldRun, Step};
 use crate::config::TargetSelection;
@@ -62,6 +65,8 @@ pub fn prebuilt_llvm_config(
     builder: &Builder<'_>,
     target: TargetSelection,
 ) -> Result<PathBuf, Meta> {
+    maybe_download_ci_llvm(builder);
+
     // If we're using a custom LLVM bail out here, but we can only use a
     // custom LLVM for the build triple.
     if let Some(config) = builder.config.target_config.get(&target) {
@@ -111,6 +116,285 @@ pub fn prebuilt_llvm_config(
     Err(Meta { stamp, build_llvm_config, out_dir, root: root.into() })
 }
 
+pub(crate) fn maybe_download_ci_llvm(builder: &Builder<'_>) {
+    let config = &builder.config;
+    if !config.llvm_from_ci {
+        return;
+    }
+    let mut rev_list = Command::new("git");
+    rev_list.args(&[
+        PathBuf::from("rev-list"),
+        "--author=bors@rust-lang.org".into(),
+        "-n1".into(),
+        "--first-parent".into(),
+        "HEAD".into(),
+        "--".into(),
+        builder.src.join("src/llvm-project"),
+        builder.src.join("src/bootstrap/download-ci-llvm-stamp"),
+        // the LLVM shared object file is named `LLVM-12-rust-{version}-nightly`
+        builder.src.join("src/version"),
+    ]);
+    let llvm_sha = output(&mut rev_list);
+    let llvm_sha = llvm_sha.trim();
+
+    if llvm_sha == "" {
+        println!("error: could not find commit hash for downloading LLVM");
+        println!("help: maybe your repository history is too shallow?");
+        println!("help: consider disabling `download-ci-llvm`");
+        println!("help: or fetch enough history to include one upstream commit");
+        panic!();
+    }
+
+    let llvm_root = config.ci_llvm_root();
+    let llvm_stamp = llvm_root.join(".llvm-stamp");
+    let key = format!("{}{}", llvm_sha, config.llvm_assertions);
+    if program_out_of_date(&llvm_stamp, &key) && !config.dry_run {
+        download_ci_llvm(builder, &llvm_sha);
+        for binary in ["llvm-config", "FileCheck"] {
+            fix_bin_or_dylib(builder, &llvm_root.join("bin").join(binary));
+        }
+        let llvm_lib = llvm_root.join("lib");
+        for entry in t!(fs::read_dir(&llvm_lib)) {
+            let lib = t!(entry).path();
+            if lib.ends_with(".so") {
+                fix_bin_or_dylib(builder, &lib);
+            }
+        }
+        t!(fs::write(llvm_stamp, key));
+    }
+}
+
+fn download_ci_llvm(builder: &Builder<'_>, llvm_sha: &str) {
+    let llvm_assertions = builder.config.llvm_assertions;
+
+    let cache_prefix = format!("llvm-{}-{}", llvm_sha, llvm_assertions);
+    let cache_dst = builder.out.join("cache");
+    let rustc_cache = cache_dst.join(cache_prefix);
+    if !rustc_cache.exists() {
+        t!(fs::create_dir_all(&rustc_cache));
+    }
+    let base = "https://ci-artifacts.rust-lang.org";
+    let url = if llvm_assertions {
+        format!("rustc-builds-alt/{}", llvm_sha)
+    } else {
+        format!("rustc-builds/{}", llvm_sha)
+    };
+    let filename = format!("rust-dev-nightly-{}.tar.xz", builder.build.build.triple);
+    let tarball = rustc_cache.join(&filename);
+    if !tarball.exists() {
+        download_component(builder, base, &format!("{}/{}", url, filename), &tarball);
+    }
+    let llvm_root = builder.config.ci_llvm_root();
+    unpack(builder, &tarball, &llvm_root);
+}
+
+/// Modifies the interpreter section of 'fname' to fix the dynamic linker,
+/// or the RPATH section, to fix the dynamic library search path
+///
+/// This is only required on NixOS and uses the PatchELF utility to
+/// change the interpreter/RPATH of ELF executables.
+///
+/// Please see https://nixos.org/patchelf.html for more information
+fn fix_bin_or_dylib(builder: &Builder<'_>, fname: &Path) {
+    // FIXME: cache NixOS detection?
+    match Command::new("uname").arg("-s").stderr(Stdio::inherit()).output() {
+        Err(_) => return,
+        Ok(output) if !output.status.success() => return,
+        Ok(output) => {
+            let mut s = output.stdout;
+            if s.last() == Some(&b'\n') {
+                s.pop();
+            }
+            if s != b"Linux" {
+                return;
+            }
+        }
+    }
+
+    // If the user has asked binaries to be patched for Nix, then
+    // don't check for NixOS or `/lib`, just continue to the patching.
+    // FIXME: shouldn't this take precedence over the `uname` check above?
+    if !builder.config.patch_binaries_for_nix {
+        // Use `/etc/os-release` instead of `/etc/NIXOS`.
+        // The latter one does not exist on NixOS when using tmpfs as root.
+        const NIX_IDS: &[&str] = &["ID=nixos", "ID='nixos'", "ID=\"nixos\""];
+        let os_release = match File::open("/etc/os-release") {
+            Err(e) if e.kind() == ErrorKind::NotFound => return,
+            Err(e) => panic!("failed to access /etc/os-release: {}", e),
+            Ok(f) => f,
+        };
+        if !BufReader::new(os_release).lines().any(|l| NIX_IDS.contains(&t!(l).trim())) {
+            return;
+        }
+        if Path::new("/lib").exists() {
+            return;
+        }
+    }
+
+    // At this point we're pretty sure the user is running NixOS or using Nix
+    println!("info: you seem to be using Nix. Attempting to patch {}", fname.display());
+
+    // Only build `.nix-deps` once.
+    static NIX_DEPS_DIR: OnceCell<PathBuf> = OnceCell::new();
+    let mut nix_build_succeeded = true;
+    let nix_deps_dir = NIX_DEPS_DIR.get_or_init(|| {
+        // Run `nix-build` to "build" each dependency (which will likely reuse
+        // the existing `/nix/store` copy, or at most download a pre-built copy).
+        //
+        // Importantly, we create a gc-root called `.nix-deps` in the `build/`
+        // directory, but still reference the actual `/nix/store` path in the rpath
+        // as it makes it significantly more robust against changes to the location of
+        // the `.nix-deps` location.
+        //
+        // bintools: Needed for the path of `ld-linux.so` (via `nix-support/dynamic-linker`).
+        // zlib: Needed as a system dependency of `libLLVM-*.so`.
+        // patchelf: Needed for patching ELF binaries (see doc comment above).
+        let nix_deps_dir = builder.out.join(".nix-deps");
+        const NIX_EXPR: &str = "
+        with (import <nixpkgs> {});
+        symlinkJoin {
+            name = \"rust-stage0-dependencies\";
+            paths = [
+                zlib
+                patchelf
+                stdenv.cc.bintools
+            ];
+        }
+        ";
+        nix_build_succeeded = builder.try_run(Command::new("nix-build").args(&[
+            Path::new("-E"),
+            Path::new(NIX_EXPR),
+            Path::new("-o"),
+            &nix_deps_dir,
+        ]));
+        nix_deps_dir
+    });
+    if !nix_build_succeeded {
+        return;
+    }
+
+    let mut patchelf = Command::new(nix_deps_dir.join("bin/patchelf"));
+    let rpath_entries = {
+        // ORIGIN is a relative default, all binary and dynamic libraries we ship
+        // appear to have this (even when `../lib` is redundant).
+        // NOTE: there are only two paths here, delimited by a `:`
+        let mut entries = OsString::from("$ORIGIN/../lib:");
+        entries.push(t!(fs::canonicalize(nix_deps_dir)));
+        entries.push("/lib");
+        entries
+    };
+    patchelf.args(&[OsString::from("--set-rpath"), rpath_entries]);
+    if !fname.ends_with(".so") {
+        // Finally, set the corret .interp for binaries
+        let dynamic_linker_path = nix_deps_dir.join("nix-support/dynamic-linker");
+        // FIXME: can we support utf8 here? `args` doesn't accept Vec<u8>, only OsString ...
+        let dynamic_linker = t!(String::from_utf8(t!(fs::read(dynamic_linker_path))));
+        patchelf.args(&["--set-interpreter", dynamic_linker.trim_end()]);
+    }
+
+    builder.try_run(patchelf.arg(fname));
+}
+
+fn download_component(builder: &Builder<'_>, base: &str, url: &str, dest_path: &Path) {
+    // Use a temporary file in case we crash while downloading, to avoid a corrupt download in cache/.
+    let tempfile = builder.tempdir().join(dest_path.file_name().unwrap());
+    // FIXME: support `do_verify` (only really needed for nightly rustfmt)
+    // FIXME: support non-utf8 paths?
+    download_with_retries(builder, tempfile.to_str().unwrap(), &format!("{}/{}", base, url));
+    t!(std::fs::rename(&tempfile, dest_path));
+}
+
+fn download_with_retries(builder: &Builder<'_>, tempfile: &str, url: &str) {
+    println!("downloading {}", url);
+
+    // FIXME: check if curl is installed instead of skipping straight to powershell
+    if builder.build.build.contains("windows-msvc") {
+        for _ in 0..3 {
+            if builder.try_run(Command::new("PowerShell.exe").args(&[
+                "/nologo",
+                "-Command",
+                "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;",
+                &format!(
+                    "(New-Object System.Net.WebClient).DownloadFile('{}', '{}')",
+                    url, tempfile
+                ),
+            ])) {
+                return;
+            }
+            println!("\nspurious failure, trying again");
+        }
+    } else {
+        builder.run(Command::new("curl").args(&[
+            "-#",
+            "-y",
+            "30",
+            "-Y",
+            "10", // timeout if speed is < 10 bytes/sec for > 30 seconds
+            "--connect-timeout",
+            "30", // timeout if cannot connect within 30 seconds
+            "--retry",
+            "3",
+            "-Sf",
+            "-o",
+            tempfile,
+            url,
+        ]));
+    }
+}
+
+fn unpack(builder: &Builder<'_>, tarball: &Path, dst: &Path) {
+    println!("extracting {} to {}", tarball.display(), dst.display());
+    if !dst.exists() {
+        t!(fs::create_dir_all(dst));
+    }
+
+    // FIXME: will need to be a parameter once `download-rustc` is moved to rustbuild
+    const MATCH: &str = "rust-dev";
+
+    // `tarball` ends with `.tar.xz`; strip that suffix
+    // example: `rust-dev-nightly-x86_64-unknown-linux-gnu`
+    let uncompressed_filename =
+        Path::new(tarball.file_name().expect("missing tarball filename")).file_stem().unwrap();
+    let directory_prefix = Path::new(Path::new(uncompressed_filename).file_stem().unwrap());
+
+    // decompress the file
+    let data = t!(File::open(tarball));
+    let decompressor = XzDecoder::new(BufReader::new(data));
+
+    let mut tar = tar::Archive::new(decompressor);
+    for member in t!(tar.entries()) {
+        let mut member = t!(member);
+        let original_path = t!(member.path()).into_owned();
+        // skip the top-level directory
+        if original_path == directory_prefix {
+            continue;
+        }
+        let mut short_path = t!(original_path.strip_prefix(directory_prefix));
+        if !short_path.starts_with(MATCH) {
+            continue;
+        }
+        short_path = t!(short_path.strip_prefix(MATCH));
+        let dst_path = dst.join(short_path);
+        builder.verbose(&format!("extracting {} to {}", original_path.display(), dst.display()));
+        if !t!(member.unpack_in(dst)) {
+            panic!("path traversal attack ??");
+        }
+        let src_path = dst.join(original_path);
+        if src_path.is_dir() && dst_path.exists() {
+            continue;
+        }
+        t!(fs::rename(src_path, dst_path));
+    }
+    t!(fs::remove_dir_all(dst.join(directory_prefix)));
+}
+
+fn program_out_of_date(stamp: &Path, key: &str) -> bool {
+    if !stamp.exists() {
+        return true;
+    }
+    t!(fs::read_to_string(stamp)) != key
+}
+
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct Llvm {
     pub target: TargetSelection,
@@ -153,7 +437,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
             };
 
         builder.update_submodule(&Path::new("src").join("llvm-project"));
-        if builder.config.llvm_link_shared
+        if builder.llvm_link_shared()
             && (target.contains("windows") || target.contains("apple-darwin"))
         {
             panic!("shared linking to LLVM is not currently supported on {}", target.triple);
@@ -255,7 +539,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
         //
         // If we're not linking rustc to a dynamic LLVM, though, then don't link
         // tools to it.
-        if builder.llvm_link_tools_dynamically(target) && builder.config.llvm_link_shared {
+        if builder.llvm_link_tools_dynamically(target) && builder.llvm_link_shared() {
             cfg.define("LLVM_LINK_LLVM_DYLIB", "ON");
         }
 
index c743c5188e7545f47d7f858b74005107e731c01e..689b4819cdd36622eebecc552347c25458a77baa 100644 (file)
@@ -262,11 +262,13 @@ pub(crate) fn bare(self) -> GeneratedTarball {
         t!(std::fs::rename(&self.image_dir, &dest));
 
         self.run(|this, cmd| {
+            let distdir = crate::dist::distdir(this.builder);
+            t!(std::fs::create_dir_all(&distdir));
             cmd.arg("tarball")
                 .arg("--input")
                 .arg(&dest)
                 .arg("--output")
-                .arg(crate::dist::distdir(this.builder).join(this.package_name()));
+                .arg(distdir.join(this.package_name()));
         })
     }
 
index da4689098119f0030c01809bb7a2376846c1785a..4dfc02dea460572b8a724338f2f95319fd36b1f0 100644 (file)
@@ -1400,9 +1400,7 @@ fn run(self, builder: &Builder<'_>) {
         targetflags.extend(builder.lld_flags(target));
         cmd.arg("--target-rustcflags").arg(targetflags.join(" "));
 
-        cmd.arg("--docck-python").arg(builder.python());
-
-        cmd.arg("--lldb-python").arg(builder.python());
+        cmd.arg("--python").arg(builder.python());
 
         if let Some(ref gdb) = builder.config.gdb {
             cmd.arg("--gdb").arg(gdb);
@@ -1577,9 +1575,7 @@ fn run(self, builder: &Builder<'_>) {
             cmd.env("RUSTC_PROFILER_SUPPORT", "1");
         }
 
-        let tmp = builder.out.join("tmp");
-        std::fs::create_dir_all(&tmp).unwrap();
-        cmd.env("RUST_TEST_TMPDIR", tmp);
+        cmd.env("RUST_TEST_TMPDIR", builder.tempdir());
 
         cmd.arg("--adb-path").arg("adb");
         cmd.arg("--adb-test-dir").arg(ADB_TEST_DIR);
@@ -2259,14 +2255,13 @@ fn run(self, builder: &Builder<'_>) {
         builder.ensure(compile::Std { compiler, target });
 
         builder.info(&format!("REMOTE copy libs to emulator ({})", target));
-        t!(fs::create_dir_all(builder.out.join("tmp")));
 
         let server = builder.ensure(tool::RemoteTestServer { compiler, target });
 
         // Spawn the emulator and wait for it to come online
         let tool = builder.tool_exe(Tool::RemoteTestClient);
         let mut cmd = Command::new(&tool);
-        cmd.arg("spawn-emulator").arg(target.triple).arg(&server).arg(builder.out.join("tmp"));
+        cmd.arg("spawn-emulator").arg(target.triple).arg(&server).arg(builder.tempdir());
         if let Some(rootfs) = builder.qemu_rootfs(target) {
             cmd.arg(rootfs);
         }
@@ -2300,7 +2295,7 @@ fn make_run(run: RunConfig<'_>) {
     /// Runs "distcheck", a 'make check' from a tarball
     fn run(self, builder: &Builder<'_>) {
         builder.info("Distcheck");
-        let dir = builder.out.join("tmp").join("distcheck");
+        let dir = builder.tempdir().join("distcheck");
         let _ = fs::remove_dir_all(&dir);
         t!(fs::create_dir_all(&dir));
 
@@ -2326,7 +2321,7 @@ fn run(self, builder: &Builder<'_>) {
 
         // Now make sure that rust-src has all of libstd's dependencies
         builder.info("Distcheck rust-src");
-        let dir = builder.out.join("tmp").join("distcheck-src");
+        let dir = builder.tempdir().join("distcheck-src");
         let _ = fs::remove_dir_all(&dir);
         t!(fs::create_dir_all(&dir));
 
@@ -2364,6 +2359,7 @@ fn run(self, builder: &Builder<'_>) {
             .env("RUSTFLAGS", "-Cdebuginfo=2")
             .env("CARGO_TARGET_DIR", builder.out.join("bootstrap"))
             .env("RUSTC_BOOTSTRAP", "1")
+            .env("RUSTDOC", builder.rustdoc(builder.compiler(0, builder.build.build)))
             .env("RUSTC", &builder.initial_rustc);
         if let Some(flags) = option_env!("RUSTFLAGS") {
             // Use the same rustc flags for testing as for "normal" compilation,
@@ -2374,6 +2370,16 @@ fn run(self, builder: &Builder<'_>) {
         if !builder.fail_fast {
             cmd.arg("--no-fail-fast");
         }
+        match builder.doc_tests {
+            DocTests::Only => {
+                cmd.arg("--doc");
+            }
+            DocTests::No => {
+                cmd.args(&["--lib", "--bins", "--examples", "--tests", "--benches"]);
+            }
+            DocTests::Yes => {}
+        }
+
         cmd.arg("--").args(&builder.config.cmd.test_args());
         // rustbuild tests are racy on directory creation so just run them one at a time.
         // Since there's not many this shouldn't be a problem.
index 562be752f846d5971d2c03f8472d2d3fa63b1390..495c539d06988fa59c1f1605611d89582ed3e568 100755 (executable)
@@ -4,7 +4,7 @@ set -ex
 
 source shared.sh
 
-LLVM=llvmorg-13.0.0
+LLVM=llvmorg-14.0.2
 
 mkdir llvm-project
 cd llvm-project
@@ -30,7 +30,12 @@ hide_output \
       -DCMAKE_BUILD_TYPE=Release \
       -DCMAKE_INSTALL_PREFIX=/rustroot \
       -DCOMPILER_RT_BUILD_SANITIZERS=OFF \
+      -DCOMPILER_RT_BUILD_XRAY=OFF \
+      -DCOMPILER_RT_BUILD_MEMPROF=OFF \
       -DLLVM_TARGETS_TO_BUILD=X86 \
+      -DLLVM_INCLUDE_BENCHMARKS=OFF \
+      -DLLVM_INCLUDE_TESTS=OFF \
+      -DLLVM_INCLUDE_EXAMPLES=OFF \
       -DLLVM_ENABLE_PROJECTS="clang;lld;compiler-rt" \
       -DC_INCLUDE_DIRS="$INC"
 
index 3a03eb2bdc8384557067160e5ece530535a21f0d..7992ec3b991883718bd02999f92d173b2e908e4d 100755 (executable)
@@ -3,7 +3,7 @@ set -ex
 
 source shared.sh
 
-GCC=5.5.0
+GCC=7.5.0
 
 curl https://ftp.gnu.org/gnu/gcc/gcc-$GCC/gcc-$GCC.tar.xz | xzcat | tar xf -
 cd gcc-$GCC
index bbde4bee23f26c58aac827c8ca1b38719f9f2729..899f24fc754a14b89617093824d258aaa3aa2943 100644 (file)
@@ -1 +1 @@
-0.8.5
\ No newline at end of file
+0.9.0
\ No newline at end of file
index 765318b844569a642ceef7bf1adab9639cbf6af3..de0dbffc5812fd885700874e8d258dd334733ac4 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 765318b844569a642ceef7bf1adab9639cbf6af3
+Subproject commit de0dbffc5812fd885700874e8d258dd334733ac4
index a6de8b6e3ea5d4f0de8b7b9a7e5c1405dc2c2ddb..f7cefbb995eec8c6148f213235e9e2e03268e775 160000 (submodule)
@@ -1 +1 @@
-Subproject commit a6de8b6e3ea5d4f0de8b7b9a7e5c1405dc2c2ddb
+Subproject commit f7cefbb995eec8c6148f213235e9e2e03268e775
index c2a98d9fc5d29c481d42052fbeccfde15ed03116..44a80e8d8bfc5881c9bd69a2cb3a570776ee4181 160000 (submodule)
@@ -1 +1 @@
-Subproject commit c2a98d9fc5d29c481d42052fbeccfde15ed03116
+Subproject commit 44a80e8d8bfc5881c9bd69a2cb3a570776ee4181
index eeb5a83c15b6ae60df3e4f19207376b22c6fbc4c..043e60f4f191651e9f8bf52fa32df14defbb23d9 160000 (submodule)
@@ -1 +1 @@
-Subproject commit eeb5a83c15b6ae60df3e4f19207376b22c6fbc4c
+Subproject commit 043e60f4f191651e9f8bf52fa32df14defbb23d9
index 7838696cc128b72c44bccc3fedb0506877468034..bee9a8d808fb4afcdb47a9091981661b9349c1f7 100644 (file)
@@ -80,8 +80,8 @@ to `/WHOLEARCHIVE` for `link.exe`, and to `-force_load` for `ld64`.
 The modifier does nothing for linkers that don't support it.
 
 The default for this modifier is `-whole-archive`. \
-NOTE: The default may currently be different when building dylibs for some targets,
-but it is not guaranteed.
+NOTE: The default may currently be different in some cases for backward compatibility,
+but it is not guaranteed. If you need whole archive semantics use `+whole-archive` explicitly.
 
 <a id="option-crate-type"></a>
 ## `--crate-type`: a list of types of crates for the compiler to emit
index cc580ca9b4232ee869a07c809f99ad5850a721f2..ab698c82ba92295b17bca75ff528f9d85c547a21 100644 (file)
@@ -17,7 +17,7 @@ standard library does not ship with CET enabled by default, so you may need to r
 modules with a `cargo` command like:
 
 ```sh
-$ RUSTFLAGS="-Z cf-protection=full" RUSTC="rustc-custom" cargo +nightly build -Z build-std --target x86_64-unknown-linux-gnu
+$ RUSTFLAGS="-Z cf-protection=full" cargo +nightly build -Z build-std --target x86_64-unknown-linux-gnu
 ```
 
 ### Detection
diff --git a/src/doc/unstable-book/src/language-features/yeet-expr.md b/src/doc/unstable-book/src/language-features/yeet-expr.md
new file mode 100644 (file)
index 0000000..bc1ba4c
--- /dev/null
@@ -0,0 +1,26 @@
+# `yeet_expr`
+
+The tracking issue for this feature is: [#96373]
+
+[#96373]: https://github.com/rust-lang/rust/issues/96373
+
+------------------------
+
+The `yeet_expr` feature adds support for `do yeet` expressions,
+which can be used to early-exit from a function or `try` block.
+
+These are highly experimental, thus the placeholder syntax.
+
+```rust,edition2021
+#![feature(yeet_expr)]
+
+fn foo() -> Result<String, i32> {
+    do yeet 4;
+}
+assert_eq!(foo(), Err(4));
+
+fn bar() -> Option<String> {
+    do yeet;
+}
+assert_eq!(bar(), None);
+```
index 89696f392621b60d8601403499b53b7bf5a09f16..343dd0387f47987c011c2334c80f0c8d0f914ea4 100644 (file)
@@ -49,8 +49,6 @@ def check_generic_param(param):
         ty = param["kind"]["type"]
         if ty["default"]:
             check_type(ty["default"])
-        for bound in ty["bounds"]:
-            check_generic_bound(bound)
     elif "const" in param["kind"]:
         check_type(param["kind"]["const"])
 
index cc5c583bea8e25d81dda1b114b6e96a04dffeedf..21efd040663b8aa9e848aa6ff3456f1fa864fa89 100644 (file)
@@ -22,6 +22,7 @@ regex = "1"
 rustdoc-json-types = { path = "../rustdoc-json-types" }
 tracing = "0.1"
 tracing-tree = "0.2.0"
+once_cell = "1.10.0"
 
 [dependencies.tracing-subscriber]
 version = "0.3.3"
index a070cef227252b5b3bf25001bba3fc2ebd82f249..eea4eef90654796db86af4b8fc1bc8e741ffdff5 100644 (file)
@@ -238,9 +238,12 @@ fn clean(&self, _cx: &mut DocContext<'_>) -> Option<Lifetime> {
     }
 }
 
-impl Clean<WherePredicate> for hir::WherePredicate<'_> {
-    fn clean(&self, cx: &mut DocContext<'_>) -> WherePredicate {
-        match *self {
+impl Clean<Option<WherePredicate>> for hir::WherePredicate<'_> {
+    fn clean(&self, cx: &mut DocContext<'_>) -> Option<WherePredicate> {
+        if !self.in_where_clause() {
+            return None;
+        }
+        Some(match *self {
             hir::WherePredicate::BoundPredicate(ref wbp) => {
                 let bound_params = wbp
                     .bound_generic_params
@@ -250,11 +253,7 @@ fn clean(&self, cx: &mut DocContext<'_>) -> WherePredicate {
                         // Higher-ranked lifetimes can't have bounds.
                         assert_matches!(
                             param,
-                            hir::GenericParam {
-                                kind: hir::GenericParamKind::Lifetime { .. },
-                                bounds: [],
-                                ..
-                            }
+                            hir::GenericParam { kind: hir::GenericParamKind::Lifetime { .. }, .. }
                         );
                         Lifetime(param.name.ident().name)
                     })
@@ -275,7 +274,7 @@ fn clean(&self, cx: &mut DocContext<'_>) -> WherePredicate {
                 lhs: wrp.lhs_ty.clean(cx),
                 rhs: wrp.rhs_ty.clean(cx).into(),
             },
-        }
+        })
     }
 }
 
@@ -422,7 +421,7 @@ fn clean(&self, cx: &mut DocContext<'_>) -> GenericParamDef {
                     // `self_def_id` set, we override it here.
                     // See https://github.com/rust-lang/rust/issues/85454
                     if let QPath { ref mut self_def_id, .. } = default {
-                        *self_def_id = cx.tcx.parent(self.def_id);
+                        *self_def_id = Some(cx.tcx.parent(self.def_id));
                     }
 
                     Some(default)
@@ -456,44 +455,75 @@ fn clean(&self, cx: &mut DocContext<'_>) -> GenericParamDef {
     }
 }
 
-impl Clean<GenericParamDef> for hir::GenericParam<'_> {
-    fn clean(&self, cx: &mut DocContext<'_>) -> GenericParamDef {
-        let (name, kind) = match self.kind {
-            hir::GenericParamKind::Lifetime { .. } => {
-                let outlives = self
-                    .bounds
+fn clean_generic_param(
+    cx: &mut DocContext<'_>,
+    generics: Option<&hir::Generics<'_>>,
+    param: &hir::GenericParam<'_>,
+) -> GenericParamDef {
+    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()
+                    })
                     .map(|bound| match bound {
                         hir::GenericBound::Outlives(lt) => lt.clean(cx),
                         _ => panic!(),
                     })
-                    .collect();
-                (self.name.ident().name, GenericParamDefKind::Lifetime { outlives })
-            }
-            hir::GenericParamKind::Type { ref default, synthetic } => (
-                self.name.ident().name,
+                    .collect()
+            } else {
+                Vec::new()
+            };
+            (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)
+                    .filter(|bp| !bp.in_where_clause)
+                    .flat_map(|bp| bp.bounds)
+                    .filter_map(|x| x.clean(cx))
+                    .collect()
+            } else {
+                Vec::new()
+            };
+            (
+                param.name.ident().name,
                 GenericParamDefKind::Type {
-                    did: cx.tcx.hir().local_def_id(self.hir_id).to_def_id(),
-                    bounds: self.bounds.iter().filter_map(|x| x.clean(cx)).collect(),
+                    did: did.to_def_id(),
+                    bounds,
                     default: default.map(|t| t.clean(cx)).map(Box::new),
                     synthetic,
                 },
-            ),
-            hir::GenericParamKind::Const { ref ty, default } => (
-                self.name.ident().name,
-                GenericParamDefKind::Const {
-                    did: cx.tcx.hir().local_def_id(self.hir_id).to_def_id(),
-                    ty: Box::new(ty.clean(cx)),
-                    default: default.map(|ct| {
-                        let def_id = cx.tcx.hir().local_def_id(ct.hir_id);
-                        Box::new(ty::Const::from_anon_const(cx.tcx, def_id).to_string())
-                    }),
-                },
-            ),
-        };
+            )
+        }
+        hir::GenericParamKind::Const { ref ty, default } => (
+            param.name.ident().name,
+            GenericParamDefKind::Const {
+                did: cx.tcx.hir().local_def_id(param.hir_id).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);
+                    Box::new(ty::Const::from_anon_const(cx.tcx, def_id).to_string())
+                }),
+            },
+        ),
+    };
 
-        GenericParamDef { name, kind }
-    }
+    GenericParamDef { name, kind }
 }
 
 impl Clean<Generics> for hir::Generics<'_> {
@@ -524,7 +554,7 @@ fn is_elided_lifetime(param: &hir::GenericParam<'_>) -> bool {
             .iter()
             .filter(|param| is_impl_trait(param))
             .map(|param| {
-                let param: GenericParamDef = param.clean(cx);
+                let param = clean_generic_param(cx, Some(self), param);
                 match param.kind {
                     GenericParamDefKind::Lifetime { .. } => unreachable!(),
                     GenericParamDefKind::Type { did, ref bounds, .. } => {
@@ -538,14 +568,14 @@ fn is_elided_lifetime(param: &hir::GenericParam<'_>) -> bool {
 
         let mut params = Vec::with_capacity(self.params.len());
         for p in self.params.iter().filter(|p| !is_impl_trait(p) && !is_elided_lifetime(p)) {
-            let p = p.clean(cx);
+            let p = clean_generic_param(cx, Some(self), p);
             params.push(p);
         }
         params.extend(impl_trait_params);
 
         let mut generics = Generics {
             params,
-            where_predicates: self.where_clause.predicates.iter().map(|x| x.clean(cx)).collect(),
+            where_predicates: self.predicates.iter().filter_map(|x| x.clean(cx)).collect(),
         };
 
         // Some duplicates are generated for ?Sized bounds between type params and where
@@ -954,7 +984,11 @@ impl Clean<PolyTrait> for hir::PolyTraitRef<'_> {
     fn clean(&self, cx: &mut DocContext<'_>) -> PolyTrait {
         PolyTrait {
             trait_: self.trait_ref.clean(cx),
-            generic_params: self.bound_generic_params.iter().map(|x| x.clean(cx)).collect(),
+            generic_params: self
+                .bound_generic_params
+                .iter()
+                .map(|x| clean_generic_param(cx, None, x))
+                .collect(),
         }
     }
 }
@@ -1034,7 +1068,7 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Item {
             let mut what_rustc_thinks =
                 Item::from_def_id_and_parts(local_did, Some(self.ident.name), inner, cx);
 
-            let impl_ref = cx.tcx.parent(local_did).and_then(|did| cx.tcx.impl_trait_ref(did));
+            let impl_ref = cx.tcx.impl_trait_ref(cx.tcx.local_parent(self.def_id));
 
             // Trait impl items always inherit the impl's visibility --
             // we don't want to show `pub`.
@@ -1226,7 +1260,7 @@ fn param_eq_arg(param: &GenericParamDef, arg: &GenericArg) -> bool {
         let mut what_rustc_thinks =
             Item::from_def_id_and_parts(self.def_id, Some(self.name), kind, cx);
 
-        let impl_ref = tcx.parent(self.def_id).and_then(|did| tcx.impl_trait_ref(did));
+        let impl_ref = tcx.impl_trait_ref(tcx.parent(self.def_id));
 
         // Trait impl items always inherit the impl's visibility --
         // we don't want to show `pub`.
@@ -1305,7 +1339,7 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type {
 fn maybe_expand_private_type_alias(cx: &mut DocContext<'_>, path: &hir::Path<'_>) -> Option<Type> {
     let Res::Def(DefKind::TyAlias, def_id) = path.res else { return None };
     // Substitute private type aliases
-    let Some(def_id) = def_id.as_local() else { return None };
+    let def_id = def_id.as_local()?;
     let alias = if !cx.cache.access_levels.is_exported(def_id.to_def_id()) {
         &cx.tcx.hir().expect_item(def_id).kind
     } else {
@@ -1708,9 +1742,7 @@ fn clean_field(def_id: DefId, name: Symbol, ty: Type, cx: &mut DocContext<'_>) -
 }
 
 fn is_field_vis_inherited(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
-    let parent = tcx
-        .parent(def_id)
-        .expect("is_field_vis_inherited can only be called on struct or variant fields");
+    let parent = tcx.parent(def_id);
     match tcx.def_kind(parent) {
         DefKind::Struct | DefKind::Union => false,
         DefKind::Variant => true,
@@ -1823,7 +1855,8 @@ impl Clean<BareFunctionDecl> for hir::BareFnTy<'_> {
     fn clean(&self, cx: &mut DocContext<'_>) -> BareFunctionDecl {
         let (generic_params, decl) = enter_impl_trait(cx, |cx| {
             // NOTE: generics must be cleaned before args
-            let generic_params = self.generic_params.iter().map(|x| x.clean(cx)).collect();
+            let generic_params =
+                self.generic_params.iter().map(|x| clean_generic_param(cx, None, x)).collect();
             let args = clean_args_from_types_and_names(cx, self.decl.inputs, self.param_names);
             let decl = clean_fn_decl_with_args(cx, self.decl, args);
             (generic_params, decl)
index 58ca8869ea9d7b745a73875103f284e3e7b196df..a9c0fe6f0797147f96b7c76f7230d474fbfe7466 100644 (file)
@@ -1,4 +1,4 @@
-use rustc_ast::token::{self, BinOpToken, DelimToken};
+use rustc_ast::token::{self, BinOpToken, Delimiter};
 use rustc_ast::tokenstream::{TokenStream, TokenTree};
 use rustc_ast_pretty::pprust::state::State as Printer;
 use rustc_ast_pretty::pprust::PrintState;
@@ -104,11 +104,11 @@ fn print_tt(printer: &mut Printer<'_>, tt: &TokenTree) {
             let open_delim = printer.token_kind_to_string(&token::OpenDelim(*delim));
             printer.word(open_delim);
             if !tts.is_empty() {
-                if *delim == DelimToken::Brace {
+                if *delim == Delimiter::Brace {
                     printer.space();
                 }
                 print_tts(printer, tts);
-                if *delim == DelimToken::Brace {
+                if *delim == Delimiter::Brace {
                     printer.space();
                 }
             }
@@ -162,9 +162,9 @@ enum State {
                 (_, _) => (true, Other),
             },
             TokenTree::Delimited(_, delim, _) => match (state, delim) {
-                (Dollar, DelimToken::Paren) => (false, DollarParen),
-                (Pound | PoundBang, DelimToken::Bracket) => (false, Other),
-                (Ident, DelimToken::Paren | DelimToken::Bracket) => (false, Other),
+                (Dollar, Delimiter::Parenthesis) => (false, DollarParen),
+                (Pound | PoundBang, Delimiter::Bracket) => (false, Other),
+                (Ident, Delimiter::Parenthesis | Delimiter::Bracket) => (false, Other),
                 (_, _) => (true, Other),
             },
         };
index 95ac3ab622a149bbdc2ba9b37291902655cdacc6..2b65b8f910c7069b74c23d24c4847a5240898dc8 100644 (file)
@@ -1,13 +1,11 @@
 use std::cell::RefCell;
 use std::default::Default;
-use std::fmt;
 use std::hash::Hash;
-use std::iter;
 use std::lazy::SyncOnceCell as OnceCell;
 use std::path::PathBuf;
 use std::rc::Rc;
 use std::sync::Arc;
-use std::vec;
+use std::{cmp, fmt, iter};
 
 use arrayvec::ArrayVec;
 
@@ -55,6 +53,9 @@
 };
 crate use self::Visibility::{Inherited, Public};
 
+#[cfg(test)]
+mod tests;
+
 crate type ItemIdSet = FxHashSet<ItemId>;
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)]
@@ -1028,6 +1029,86 @@ fn add_doc_fragment(out: &mut String, frag: &DocFragment) {
     acc
 }
 
+/// Removes excess indentation on comments in order for the Markdown
+/// to be parsed correctly. This is necessary because the convention for
+/// writing documentation is to provide a space between the /// or //! marker
+/// and the doc text, but Markdown is whitespace-sensitive. For example,
+/// a block of text with four-space indentation is parsed as a code block,
+/// so if we didn't unindent comments, these list items
+///
+/// /// A list:
+/// ///
+/// ///    - Foo
+/// ///    - Bar
+///
+/// would be parsed as if they were in a code block, which is likely not what the user intended.
+fn unindent_doc_fragments(docs: &mut Vec<DocFragment>) {
+    // `add` is used in case the most common sugared doc syntax is used ("/// "). The other
+    // fragments kind's lines are never starting with a whitespace unless they are using some
+    // markdown formatting requiring it. Therefore, if the doc block have a mix between the two,
+    // we need to take into account the fact that the minimum indent minus one (to take this
+    // whitespace into account).
+    //
+    // For example:
+    //
+    // /// hello!
+    // #[doc = "another"]
+    //
+    // In this case, you want "hello! another" and not "hello!  another".
+    let add = if docs.windows(2).any(|arr| arr[0].kind != arr[1].kind)
+        && docs.iter().any(|d| d.kind == DocFragmentKind::SugaredDoc)
+    {
+        // In case we have a mix of sugared doc comments and "raw" ones, we want the sugared one to
+        // "decide" how much the minimum indent will be.
+        1
+    } else {
+        0
+    };
+
+    // `min_indent` is used to know how much whitespaces from the start of each lines must be
+    // removed. Example:
+    //
+    // ///     hello!
+    // #[doc = "another"]
+    //
+    // In here, the `min_indent` is 1 (because non-sugared fragment are always counted with minimum
+    // 1 whitespace), meaning that "hello!" will be considered a codeblock because it starts with 4
+    // (5 - 1) whitespaces.
+    let Some(min_indent) = docs
+        .iter()
+        .map(|fragment| {
+            fragment.doc.as_str().lines().fold(usize::MAX, |min_indent, line| {
+                if line.chars().all(|c| c.is_whitespace()) {
+                    min_indent
+                } else {
+                    // Compare against either space or tab, ignoring whether they are
+                    // mixed or not.
+                    let whitespace = line.chars().take_while(|c| *c == ' ' || *c == '\t').count();
+                    cmp::min(min_indent, whitespace)
+                        + if fragment.kind == DocFragmentKind::SugaredDoc { 0 } else { add }
+                }
+            })
+        })
+        .min()
+    else {
+        return;
+    };
+
+    for fragment in docs {
+        if fragment.doc == kw::Empty {
+            continue;
+        }
+
+        let min_indent = if fragment.kind != DocFragmentKind::SugaredDoc && min_indent > 0 {
+            min_indent - add
+        } else {
+            min_indent
+        };
+
+        fragment.indent = min_indent;
+    }
+}
+
 /// A link that has not yet been rendered.
 ///
 /// This link will be turned into a rendered link by [`Item::links`].
@@ -1119,6 +1200,8 @@ impl Attributes {
             }
         }
 
+        unindent_doc_fragments(&mut doc_strings);
+
         Attributes { doc_strings, other_attrs }
     }
 
diff --git a/src/librustdoc/clean/types/tests.rs b/src/librustdoc/clean/types/tests.rs
new file mode 100644 (file)
index 0000000..71eddf4
--- /dev/null
@@ -0,0 +1,70 @@
+use super::*;
+
+use crate::clean::collapse_doc_fragments;
+
+use rustc_span::create_default_session_globals_then;
+use rustc_span::source_map::DUMMY_SP;
+use rustc_span::symbol::Symbol;
+
+fn create_doc_fragment(s: &str) -> Vec<DocFragment> {
+    vec![DocFragment {
+        span: DUMMY_SP,
+        parent_module: None,
+        doc: Symbol::intern(s),
+        kind: DocFragmentKind::SugaredDoc,
+        indent: 0,
+    }]
+}
+
+#[track_caller]
+fn run_test(input: &str, expected: &str) {
+    create_default_session_globals_then(|| {
+        let mut s = create_doc_fragment(input);
+        unindent_doc_fragments(&mut s);
+        assert_eq!(collapse_doc_fragments(&s), expected);
+    });
+}
+
+#[test]
+fn should_unindent() {
+    run_test("    line1\n    line2", "line1\nline2");
+}
+
+#[test]
+fn should_unindent_multiple_paragraphs() {
+    run_test("    line1\n\n    line2", "line1\n\nline2");
+}
+
+#[test]
+fn should_leave_multiple_indent_levels() {
+    // Line 2 is indented another level beyond the
+    // base indentation and should be preserved
+    run_test("    line1\n\n        line2", "line1\n\n    line2");
+}
+
+#[test]
+fn should_ignore_first_line_indent() {
+    run_test("line1\n    line2", "line1\n    line2");
+}
+
+#[test]
+fn should_not_ignore_first_line_indent_in_a_single_line_para() {
+    run_test("line1\n\n    line2", "line1\n\n    line2");
+}
+
+#[test]
+fn should_unindent_tabs() {
+    run_test("\tline1\n\tline2", "line1\nline2");
+}
+
+#[test]
+fn should_trim_mixed_indentation() {
+    run_test("\t    line1\n\t    line2", "line1\nline2");
+    run_test("    \tline1\n    \tline2", "line1\nline2");
+}
+
+#[test]
+fn should_not_trim() {
+    run_test("\t    line1  \n\t    line2", "line1  \nline2");
+    run_test("    \tline1  \n    \tline2", "line1  \nline2");
+}
index abfc5b80a3ef0f8bda47c6216c36db0557fcd67c..3a2f24d719c937b2221efd169472d7a0b53dccfd 100644 (file)
@@ -455,7 +455,7 @@ fn print_const_with_custom_print_scalar(tcx: TyCtxt<'_>, ct: ty::Const<'_>) -> S
         let mut current = def_id;
         // The immediate parent might not always be a module.
         // Find the first parent which is.
-        while let Some(parent) = tcx.parent(current) {
+        while let Some(parent) = tcx.opt_parent(current) {
             if tcx.def_kind(parent) == DefKind::Mod {
                 return Some(parent);
             }
index cee3dcb416f80128d7d43acb8c9f3dd836d6f39b..1ff2c8191e562ef3a79bbd2c3e5dbdaadfe307d1 100644 (file)
@@ -10,7 +10,9 @@
     self, parse_crate_types_from_list, parse_externs, parse_target_triple, CrateType,
 };
 use rustc_session::config::{get_cmd_lint_options, nightly_options};
-use rustc_session::config::{CodegenOptions, DebuggingOptions, ErrorOutputType, Externs};
+use rustc_session::config::{
+    CodegenOptions, DebuggingOptions, ErrorOutputType, Externs, JsonUnusedExterns,
+};
 use rustc_session::getopts;
 use rustc_session::lint::Level;
 use rustc_session::search_paths::SearchPath;
@@ -147,7 +149,7 @@ fn try_from(value: &str) -> Result<Self, Self::Error> {
     /// documentation.
     crate run_check: bool,
     /// Whether doctests should emit unused externs
-    crate json_unused_externs: bool,
+    crate json_unused_externs: JsonUnusedExterns,
     /// Whether to skip capturing stdout and stderr of tests.
     crate nocapture: bool,
 
index 618268445743acbb10d3959b33aafffbc3d8e832..82e367427ef6ff757d9a6838e3a03cb4c828bf1e 100644 (file)
 
     // Collect and warn about unused externs, but only if we've gotten
     // reports for each doctest
-    if json_unused_externs {
+    if json_unused_externs.is_enabled() {
         let unused_extern_reports: Vec<_> =
             std::mem::take(&mut unused_extern_reports.lock().unwrap());
         if unused_extern_reports.len() == compiling_test_count {
@@ -337,7 +337,7 @@ fn run_test(
     if lang_string.test_harness {
         compiler.arg("--test");
     }
-    if rustdoc_options.json_unused_externs && !lang_string.compile_fail {
+    if rustdoc_options.json_unused_externs.is_enabled() && !lang_string.compile_fail {
         compiler.arg("--error-format=json");
         compiler.arg("--json").arg("unused-externs");
         compiler.arg("-Z").arg("unstable-options");
@@ -1174,8 +1174,6 @@ fn visit_testable<F: FnOnce(&mut Self)>(
         nested: F,
     ) {
         let ast_attrs = self.tcx.hir().attrs(hir_id);
-        let mut attrs = Attributes::from_ast(ast_attrs, None);
-
         if let Some(ref cfg) = ast_attrs.cfg(self.tcx, &FxHashSet::default()) {
             if !cfg.matches(&self.sess.parse_sess, Some(self.sess.features_untracked())) {
                 return;
@@ -1187,9 +1185,9 @@ fn visit_testable<F: FnOnce(&mut Self)>(
             self.collector.names.push(name);
         }
 
-        attrs.unindent_doc_comments();
         // The collapse-docs pass won't combine sugared/raw doc attributes, or included files with
         // anything else, this will combine them for us.
+        let attrs = Attributes::from_ast(ast_attrs, None);
         if let Some(doc) = attrs.collapsed_doc_value() {
             // Use the outermost invocation, so that doctest names come from where the docs were written.
             let span = ast_attrs
index fd6d675dc8b8c5247ee16a9a55a49daea15e3323..528eb6410cb371b5adf392f536e4308677854ea6 100644 (file)
@@ -18,6 +18,7 @@
 use rustc_middle::ty;
 use rustc_middle::ty::DefIdTree;
 use rustc_middle::ty::TyCtxt;
+use rustc_span::symbol::kw;
 use rustc_span::{sym, Symbol};
 use rustc_target::spec::abi::Abi;
 
@@ -267,6 +268,8 @@ impl clean::Generics {
     indent: usize,
     end_newline: bool,
 ) -> impl fmt::Display + 'a + Captures<'tcx> {
+    use fmt::Write;
+
     display_fn(move |f| {
         let mut where_predicates = gens.where_predicates.iter().filter(|pred| {
             !matches!(pred, clean::WherePredicate::BoundPredicate { bounds, .. } if bounds.is_empty())
@@ -280,56 +283,44 @@ impl clean::Generics {
 
                 match pred {
                     clean::WherePredicate::BoundPredicate { ty, bounds, bound_params } => {
-                        let bounds = bounds;
-                        let for_prefix = if bound_params.is_empty() {
-                            String::new()
-                        } else if f.alternate() {
-                            format!(
-                                "for&lt;{:#}&gt; ",
-                                comma_sep(bound_params.iter().map(|lt| lt.print()), true)
-                            )
-                        } else {
-                            format!(
-                                "for&lt;{}&gt; ",
-                                comma_sep(bound_params.iter().map(|lt| lt.print()), true)
-                            )
-                        };
+                        let ty_cx = ty.print(cx);
+                        let generic_bounds = print_generic_bounds(bounds, cx);
 
-                        if f.alternate() {
-                            write!(
-                                f,
-                                "{}{:#}: {:#}",
-                                for_prefix,
-                                ty.print(cx),
-                                print_generic_bounds(bounds, cx)
-                            )
+                        if bound_params.is_empty() {
+                            if f.alternate() {
+                                write!(f, "{ty_cx:#}: {generic_bounds:#}")
+                            } else {
+                                write!(f, "{ty_cx}: {generic_bounds}")
+                            }
                         } else {
-                            write!(
-                                f,
-                                "{}{}: {}",
-                                for_prefix,
-                                ty.print(cx),
-                                print_generic_bounds(bounds, cx)
-                            )
+                            if f.alternate() {
+                                write!(
+                                    f,
+                                    "for<{:#}> {ty_cx:#}: {generic_bounds:#}",
+                                    comma_sep(bound_params.iter().map(|lt| lt.print()), true)
+                                )
+                            } else {
+                                write!(
+                                    f,
+                                    "for&lt;{}&gt; {ty_cx}: {generic_bounds}",
+                                    comma_sep(bound_params.iter().map(|lt| lt.print()), true)
+                                )
+                            }
                         }
                     }
                     clean::WherePredicate::RegionPredicate { lifetime, bounds } => {
-                        write!(
-                            f,
-                            "{}: {}",
-                            lifetime.print(),
-                            bounds
-                                .iter()
-                                .map(|b| b.print(cx).to_string())
-                                .collect::<Vec<_>>()
-                                .join(" + ")
-                        )
+                        let mut bounds_display = String::new();
+                        for bound in bounds.iter().map(|b| b.print(cx)) {
+                            write!(bounds_display, "{bound} + ")?;
+                        }
+                        bounds_display.truncate(bounds_display.len() - " + ".len());
+                        write!(f, "{}: {bounds_display}", lifetime.print())
                     }
                     clean::WherePredicate::EqPredicate { lhs, rhs } => {
                         if f.alternate() {
-                            write!(f, "{:#} == {:#}", lhs.print(cx), rhs.print(cx),)
+                            write!(f, "{:#} == {:#}", lhs.print(cx), rhs.print(cx))
                         } else {
-                            write!(f, "{} == {}", lhs.print(cx), rhs.print(cx),)
+                            write!(f, "{} == {}", lhs.print(cx), rhs.print(cx))
                         }
                     }
                 }
@@ -340,41 +331,43 @@ impl clean::Generics {
             return Ok(());
         }
 
-        let mut clause = String::new();
-
-        if f.alternate() {
-            clause.push_str(" where");
-        } else {
+        let where_preds = comma_sep(where_predicates, false);
+        let clause = if f.alternate() {
             if end_newline {
-                clause.push_str(" <span class=\"where fmt-newline\">where");
+                // add a space so stripping <br> tags and breaking spaces still renders properly
+                format!(" where{where_preds}, ")
             } else {
-                clause.push_str(" <span class=\"where\">where");
+                format!(" where{where_preds}")
             }
-        }
-
-        clause.push_str(&comma_sep(where_predicates, false).to_string());
-
-        if end_newline {
-            clause.push(',');
-            // add a space so stripping <br> tags and breaking spaces still renders properly
-            if f.alternate() {
-                clause.push(' ');
-            } else {
-                clause.push_str("&nbsp;");
+        } else {
+            let mut br_with_padding = String::with_capacity(6 * indent + 28);
+            br_with_padding.push_str("<br>");
+            for _ in 0..indent + 4 {
+                br_with_padding.push_str("&nbsp;");
             }
-        }
+            let where_preds = where_preds.to_string().replace("<br>", &br_with_padding);
 
-        if !f.alternate() {
-            clause.push_str("</span>");
-            let padding = "&nbsp;".repeat(indent + 4);
-            clause = clause.replace("<br>", &format!("<br>{}", padding));
-            clause.insert_str(0, &"&nbsp;".repeat(indent.saturating_sub(1)));
-            if !end_newline {
-                // we insert the <br> after a single space but before multiple spaces at the start
-                clause.insert_str(if indent == 0 { 1 } else { 0 }, "<br>");
+            if end_newline {
+                let mut clause = "&nbsp;".repeat(indent.saturating_sub(1));
+                // add a space so stripping <br> tags and breaking spaces still renders properly
+                write!(
+                    clause,
+                    " <span class=\"where fmt-newline\">where{where_preds},&nbsp;</span>"
+                )?;
+                clause
+            } else {
+                // insert a <br> tag after a single space but before multiple spaces at the start
+                if indent == 0 {
+                    format!(" <br><span class=\"where\">where{where_preds}</span>")
+                } else {
+                    let mut clause = br_with_padding;
+                    clause.truncate(clause.len() - 5 * "&nbsp;".len());
+                    write!(clause, " <span class=\"where\">where{where_preds}</span>")?;
+                    clause
+                }
             }
-        }
-        write!(f, "{}", clause)
+        };
+        write!(f, "{clause}")
     })
 }
 
@@ -570,7 +563,7 @@ fn print<'a, 'tcx: 'a>(
     let did = match def_kind {
         DefKind::AssocTy | DefKind::AssocFn | DefKind::AssocConst | DefKind::Variant => {
             // documented on their parent's page
-            tcx.parent(did).unwrap()
+            tcx.parent(did)
         }
         _ => did,
     };
@@ -687,7 +680,7 @@ fn resolved_path<'cx>(
 
     if print_all {
         for seg in &path.segments[..path.segments.len() - 1] {
-            write!(w, "{}::", seg.name)?;
+            write!(w, "{}::", if seg.name == kw::PathRoot { "" } else { seg.name.as_str() })?;
         }
     }
     if w.alternate() {
index b0f7836a8340c1c87e74cdd97535dd2e6903d9c6..56a085c2982508b3f50c988d5188f787413e0708 100644 (file)
@@ -32,6 +32,7 @@
 use rustc_span::edition::Edition;
 use rustc_span::Span;
 
+use once_cell::sync::Lazy;
 use std::borrow::Cow;
 use std::cell::RefCell;
 use std::collections::VecDeque;
@@ -1429,62 +1430,68 @@ fn markdown_summary_with_limit(
 
 #[derive(Clone, Default, Debug)]
 pub struct IdMap {
-    map: FxHashMap<String, usize>,
+    map: FxHashMap<Cow<'static, str>, usize>,
 }
 
-fn init_id_map() -> FxHashMap<String, usize> {
+// The map is pre-initialized and cloned each time to avoid reinitializing it repeatedly.
+static DEFAULT_ID_MAP: Lazy<FxHashMap<Cow<'static, str>, usize>> = Lazy::new(|| init_id_map());
+
+fn init_id_map() -> FxHashMap<Cow<'static, str>, usize> {
     let mut map = FxHashMap::default();
     // This is the list of IDs used in Javascript.
-    map.insert("help".to_owned(), 1);
+    map.insert("help".into(), 1);
+    map.insert("settings".into(), 1);
+    map.insert("not-displayed".into(), 1);
+    map.insert("alternative-display".into(), 1);
+    map.insert("search".into(), 1);
     // This is the list of IDs used in HTML generated in Rust (including the ones
     // used in tera template files).
-    map.insert("mainThemeStyle".to_owned(), 1);
-    map.insert("themeStyle".to_owned(), 1);
-    map.insert("theme-picker".to_owned(), 1);
-    map.insert("theme-choices".to_owned(), 1);
-    map.insert("settings-menu".to_owned(), 1);
-    map.insert("help-button".to_owned(), 1);
-    map.insert("main-content".to_owned(), 1);
-    map.insert("search".to_owned(), 1);
-    map.insert("crate-search".to_owned(), 1);
-    map.insert("render-detail".to_owned(), 1);
-    map.insert("toggle-all-docs".to_owned(), 1);
-    map.insert("all-types".to_owned(), 1);
-    map.insert("default-settings".to_owned(), 1);
-    map.insert("rustdoc-vars".to_owned(), 1);
-    map.insert("sidebar-vars".to_owned(), 1);
-    map.insert("copy-path".to_owned(), 1);
-    map.insert("TOC".to_owned(), 1);
+    map.insert("mainThemeStyle".into(), 1);
+    map.insert("themeStyle".into(), 1);
+    map.insert("theme-picker".into(), 1);
+    map.insert("theme-choices".into(), 1);
+    map.insert("settings-menu".into(), 1);
+    map.insert("help-button".into(), 1);
+    map.insert("main-content".into(), 1);
+    map.insert("crate-search".into(), 1);
+    map.insert("render-detail".into(), 1);
+    map.insert("toggle-all-docs".into(), 1);
+    map.insert("all-types".into(), 1);
+    map.insert("default-settings".into(), 1);
+    map.insert("rustdoc-vars".into(), 1);
+    map.insert("sidebar-vars".into(), 1);
+    map.insert("copy-path".into(), 1);
+    map.insert("TOC".into(), 1);
     // This is the list of IDs used by rustdoc sections (but still generated by
     // rustdoc).
-    map.insert("fields".to_owned(), 1);
-    map.insert("variants".to_owned(), 1);
-    map.insert("implementors-list".to_owned(), 1);
-    map.insert("synthetic-implementors-list".to_owned(), 1);
-    map.insert("foreign-impls".to_owned(), 1);
-    map.insert("implementations".to_owned(), 1);
-    map.insert("trait-implementations".to_owned(), 1);
-    map.insert("synthetic-implementations".to_owned(), 1);
-    map.insert("blanket-implementations".to_owned(), 1);
-    map.insert("required-associated-types".to_owned(), 1);
-    map.insert("provided-associated-types".to_owned(), 1);
-    map.insert("provided-associated-consts".to_owned(), 1);
-    map.insert("required-associated-consts".to_owned(), 1);
-    map.insert("required-methods".to_owned(), 1);
-    map.insert("provided-methods".to_owned(), 1);
-    map.insert("implementors".to_owned(), 1);
-    map.insert("synthetic-implementors".to_owned(), 1);
-    map.insert("implementations-list".to_owned(), 1);
-    map.insert("trait-implementations-list".to_owned(), 1);
-    map.insert("synthetic-implementations-list".to_owned(), 1);
-    map.insert("blanket-implementations-list".to_owned(), 1);
-    map.insert("deref-methods".to_owned(), 1);
+    map.insert("fields".into(), 1);
+    map.insert("variants".into(), 1);
+    map.insert("implementors-list".into(), 1);
+    map.insert("synthetic-implementors-list".into(), 1);
+    map.insert("foreign-impls".into(), 1);
+    map.insert("implementations".into(), 1);
+    map.insert("trait-implementations".into(), 1);
+    map.insert("synthetic-implementations".into(), 1);
+    map.insert("blanket-implementations".into(), 1);
+    map.insert("required-associated-types".into(), 1);
+    map.insert("provided-associated-types".into(), 1);
+    map.insert("provided-associated-consts".into(), 1);
+    map.insert("required-associated-consts".into(), 1);
+    map.insert("required-methods".into(), 1);
+    map.insert("provided-methods".into(), 1);
+    map.insert("implementors".into(), 1);
+    map.insert("synthetic-implementors".into(), 1);
+    map.insert("implementations-list".into(), 1);
+    map.insert("trait-implementations-list".into(), 1);
+    map.insert("synthetic-implementations-list".into(), 1);
+    map.insert("blanket-implementations-list".into(), 1);
+    map.insert("deref-methods".into(), 1);
     map
 }
 
 impl IdMap {
     pub fn new() -> Self {
-        IdMap { map: init_id_map() }
+        IdMap { map: DEFAULT_ID_MAP.clone() }
     }
 
     crate fn derive<S: AsRef<str> + ToString>(&mut self, candidate: S) -> String {
@@ -1497,7 +1504,7 @@ pub fn new() -> Self {
             }
         };
 
-        self.map.insert(id.clone(), 1);
+        self.map.insert(id.clone().into(), 1);
         id
     }
 }
index 8e643107353ddadc1de5887ab3eeee002445157d..a30c533aa48c8f04bfd64e9155e6bc368c2dc1e7 100644 (file)
@@ -17,8 +17,8 @@
 use super::search_index::build_index;
 use super::write_shared::write_shared;
 use super::{
-    collect_spans_and_sources, print_sidebar, scrape_examples_help, settings, AllTypes,
-    LinkFromSrc, NameDoc, StylePath, BASIC_KEYWORDS,
+    collect_spans_and_sources, print_sidebar, scrape_examples_help, AllTypes, LinkFromSrc, NameDoc,
+    StylePath, BASIC_KEYWORDS,
 };
 
 use crate::clean::{self, types::ExternalLocation, ExternalCrate};
@@ -589,21 +589,18 @@ fn after_krate(&mut self) -> Result<(), Error> {
         page.root_path = "./";
 
         let sidebar = "<h2 class=\"location\">Settings</h2><div class=\"sidebar-elems\"></div>";
-        let theme_names: Vec<String> = self
-            .shared
-            .style_files
-            .iter()
-            .map(StylePath::basename)
-            .collect::<Result<_, Error>>()?;
         let v = layout::render(
             &self.shared.layout,
             &page,
             sidebar,
-            settings(
-                self.shared.static_root_path.as_deref().unwrap_or("./"),
-                &self.shared.resource_suffix,
-                theme_names,
-            )?,
+            |buf: &mut Buffer| {
+                write!(
+                    buf,
+                    "<script defer src=\"{}settings{}.js\"></script>",
+                    page.static_root_path.unwrap_or(""),
+                    page.resource_suffix
+                )
+            },
             &self.shared.style_files,
         );
         self.shared.fs.write(settings_file, v)?;
index 7a4289b8e60e9eebd0caa60683b1039887c35882..fedeb449b2e0e9a39aa96eda57a8efa388e818da 100644 (file)
@@ -334,134 +334,6 @@ fn print_entries(f: &mut Buffer, e: &FxHashSet<ItemEntry>, title: &str, class: &
     }
 }
 
-#[derive(Debug)]
-enum Setting {
-    Section {
-        description: &'static str,
-        sub_settings: Vec<Setting>,
-    },
-    Toggle {
-        js_data_name: &'static str,
-        description: &'static str,
-        default_value: bool,
-    },
-    Select {
-        js_data_name: &'static str,
-        description: &'static str,
-        default_value: &'static str,
-        options: Vec<String>,
-    },
-}
-
-impl Setting {
-    fn display(&self, root_path: &str, suffix: &str) -> String {
-        match *self {
-            Setting::Section { description, ref sub_settings } => format!(
-                "<div class=\"setting-line\">\
-                     <div class=\"title\">{}</div>\
-                     <div class=\"sub-settings\">{}</div>
-                 </div>",
-                description,
-                sub_settings.iter().map(|s| s.display(root_path, suffix)).collect::<String>()
-            ),
-            Setting::Toggle { js_data_name, description, default_value } => format!(
-                "<div class=\"setting-line\">\
-                     <label class=\"toggle\">\
-                     <input type=\"checkbox\" id=\"{}\" {}>\
-                     <span class=\"slider\"></span>\
-                     </label>\
-                     <div>{}</div>\
-                 </div>",
-                js_data_name,
-                if default_value { " checked" } else { "" },
-                description,
-            ),
-            Setting::Select { js_data_name, description, default_value, ref options } => format!(
-                "<div class=\"setting-line\"><div class=\"radio-line\" id=\"{}\"><span class=\"setting-name\">{}</span><div class=\"choices\">{}</div></div></div>",
-                js_data_name,
-                description,
-                options
-                    .iter()
-                    .map(|opt| format!(
-                        "<label for=\"{js_data_name}-{name}\" class=\"choice\">
-                           <input type=\"radio\" name=\"{js_data_name}\" id=\"{js_data_name}-{name}\" value=\"{name}\" {checked}>\
-                           {name}\
-                         </label>",
-                        js_data_name = js_data_name,
-                        name = opt,
-                        checked = if opt == default_value { "checked" } else { "" },
-                    ))
-                    .collect::<String>(),
-            ),
-        }
-    }
-}
-
-impl From<(&'static str, &'static str, bool)> for Setting {
-    fn from(values: (&'static str, &'static str, bool)) -> Setting {
-        Setting::Toggle { js_data_name: values.0, description: values.1, default_value: values.2 }
-    }
-}
-
-impl<T: Into<Setting>> From<(&'static str, Vec<T>)> for Setting {
-    fn from(values: (&'static str, Vec<T>)) -> Setting {
-        Setting::Section {
-            description: values.0,
-            sub_settings: values.1.into_iter().map(|v| v.into()).collect::<Vec<_>>(),
-        }
-    }
-}
-
-fn settings(root_path: &str, suffix: &str, theme_names: Vec<String>) -> Result<String, Error> {
-    // (id, explanation, default value)
-    let settings: &[Setting] = &[
-        Setting::from(("use-system-theme", "Use system theme", true)),
-        Setting::Select {
-            js_data_name: "theme",
-            description: "Theme",
-            default_value: "light",
-            options: theme_names.clone(),
-        },
-        Setting::Select {
-            js_data_name: "preferred-light-theme",
-            description: "Preferred light theme",
-            default_value: "light",
-            options: theme_names.clone(),
-        },
-        Setting::Select {
-            js_data_name: "preferred-dark-theme",
-            description: "Preferred dark theme",
-            default_value: "dark",
-            options: theme_names,
-        },
-        ("auto-hide-large-items", "Auto-hide item contents for large items.", true).into(),
-        ("auto-hide-method-docs", "Auto-hide item methods' documentation", false).into(),
-        ("auto-hide-trait-implementations", "Auto-hide trait implementation documentation", false)
-            .into(),
-        ("go-to-only-result", "Directly go to item in search if there is only one result", false)
-            .into(),
-        ("line-numbers", "Show line numbers on code examples", false).into(),
-        ("disable-shortcuts", "Disable keyboard shortcuts", false).into(),
-    ];
-
-    Ok(format!(
-        "<div class=\"main-heading\">
-            <h1 class=\"fqn\">\
-                <span class=\"in-band\">Rustdoc settings</span>\
-            </h1>\
-            <span class=\"out-of-band\">\
-            <a id=\"back\" href=\"javascript:void(0)\">Back</a>\
-            </span>\
-        </div>\
-        <div class=\"settings\">{}</div>\
-        <link rel=\"stylesheet\" href=\"{root_path}settings{suffix}.css\">\
-        <script src=\"{root_path}settings{suffix}.js\"></script>",
-        settings.iter().map(|s| s.display(root_path, suffix)).collect::<String>(),
-        root_path = root_path,
-        suffix = suffix
-    ))
-}
-
 fn scrape_examples_help(shared: &SharedContext<'_>) -> String {
     let mut content = SCRAPE_EXAMPLES_HELP_MD.to_owned();
     content.push_str(&format!(
index 06c63ec97d7f2f41f0a5f235e4fa77dfd85b1b1b..b5502309560eeb8712b6bc926b3183ec04234485 100644 (file)
@@ -5,7 +5,7 @@
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{ExprKind, GenericParam, GenericParamKind, HirId, Mod, Node};
+use rustc_hir::{ExprKind, GenericParam, HirId, Mod, Node};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::Span;
@@ -100,16 +100,7 @@ fn nested_visit_map(&mut self) -> Self::Map {
         self.tcx.hir()
     }
 
-    fn visit_generic_param(&mut self, p: &'tcx GenericParam<'tcx>) {
-        if !matches!(p.kind, GenericParamKind::Type { .. }) {
-            return;
-        }
-        for bound in p.bounds {
-            if let Some(trait_ref) = bound.trait_ref() {
-                self.handle_path(trait_ref.path, None);
-            }
-        }
-    }
+    fn visit_generic_param(&mut self, _: &'tcx GenericParam<'tcx>) {}
 
     fn visit_path(&mut self, path: &'tcx rustc_hir::Path<'tcx>, _id: HirId) {
         self.handle_path(path, None);
index 371d0e84087544d4223a3427721fd102570702a6..7c202e471adbe22d86121716c37bb3a41cdae78c 100644 (file)
 
 static FILES_UNVERSIONED: Lazy<FxHashMap<&str, &[u8]>> = Lazy::new(|| {
     map! {
-        "FiraSans-Regular.woff2" => static_files::fira_sans::REGULAR2,
-        "FiraSans-Medium.woff2" => static_files::fira_sans::MEDIUM2,
-        "FiraSans-Regular.woff" => static_files::fira_sans::REGULAR,
-        "FiraSans-Medium.woff" => static_files::fira_sans::MEDIUM,
+        "FiraSans-Regular.woff2" => static_files::fira_sans::REGULAR,
+        "FiraSans-Medium.woff2" => static_files::fira_sans::MEDIUM,
         "FiraSans-LICENSE.txt" => static_files::fira_sans::LICENSE,
-        "SourceSerif4-Regular.ttf.woff2" => static_files::source_serif_4::REGULAR2,
-        "SourceSerif4-Bold.ttf.woff2" => static_files::source_serif_4::BOLD2,
-        "SourceSerif4-It.ttf.woff2" => static_files::source_serif_4::ITALIC2,
-        "SourceSerif4-Regular.ttf.woff" => static_files::source_serif_4::REGULAR,
-        "SourceSerif4-Bold.ttf.woff" => static_files::source_serif_4::BOLD,
-        "SourceSerif4-It.ttf.woff" => static_files::source_serif_4::ITALIC,
+        "SourceSerif4-Regular.ttf.woff2" => static_files::source_serif_4::REGULAR,
+        "SourceSerif4-Bold.ttf.woff2" => static_files::source_serif_4::BOLD,
+        "SourceSerif4-It.ttf.woff2" => static_files::source_serif_4::ITALIC,
         "SourceSerif4-LICENSE.md" => static_files::source_serif_4::LICENSE,
-        "SourceCodePro-Regular.ttf.woff2" => static_files::source_code_pro::REGULAR2,
-        "SourceCodePro-Semibold.ttf.woff2" => static_files::source_code_pro::SEMIBOLD2,
-        "SourceCodePro-It.ttf.woff2" => static_files::source_code_pro::ITALIC2,
-        "SourceCodePro-Regular.ttf.woff" => static_files::source_code_pro::REGULAR,
-        "SourceCodePro-Semibold.ttf.woff" => static_files::source_code_pro::SEMIBOLD,
-        "SourceCodePro-It.ttf.woff" => static_files::source_code_pro::ITALIC,
+        "SourceCodePro-Regular.ttf.woff2" => static_files::source_code_pro::REGULAR,
+        "SourceCodePro-Semibold.ttf.woff2" => static_files::source_code_pro::SEMIBOLD,
+        "SourceCodePro-It.ttf.woff2" => static_files::source_code_pro::ITALIC,
         "SourceCodePro-LICENSE.txt" => static_files::source_code_pro::LICENSE,
-        "NanumBarunGothic.ttf.woff2" => static_files::nanum_barun_gothic::REGULAR2,
-        "NanumBarunGothic.ttf.woff" => static_files::nanum_barun_gothic::REGULAR,
+        "NanumBarunGothic.ttf.woff2" => static_files::nanum_barun_gothic::REGULAR,
         "NanumBarunGothic-LICENSE.txt" => static_files::nanum_barun_gothic::LICENSE,
         "LICENSE-MIT.txt" => static_files::LICENSE_MIT,
         "LICENSE-APACHE.txt" => static_files::LICENSE_APACHE,
index c2629a83f7092f112f3916d63a840be14d9ea759..34e48134cc34c9295fe78ce55d383c842b9f076d 100644 (file)
@@ -2,8 +2,7 @@ These documentation pages include resources by third parties. This copyright
 file applies only to those resources. The following third party resources are
 included, and carry their own copyright notices and license terms:
 
-* Fira Sans (FiraSans-Regular.woff2, FiraSans-Medium.woff2,
-    FiraSans-Regular.woff, FiraSans-Medium.woff):
+* Fira Sans (FiraSans-Regular.woff2, FiraSans-Medium.woff2):
 
     Copyright (c) 2014, Mozilla Foundation https://mozilla.org/
     with Reserved Font Name Fira Sans.
@@ -25,9 +24,7 @@ included, and carry their own copyright notices and license terms:
     Licensed under the MIT license (see LICENSE-MIT.txt).
 
 * Source Code Pro (SourceCodePro-Regular.ttf.woff2,
-    SourceCodePro-Semibold.ttf.woff2, SourceCodePro-It.ttf.woff2,
-    SourceCodePro-Regular.ttf.woff, SourceCodePro-Semibold.ttf.woff,
-    SourceCodePro-It.ttf.woff):
+    SourceCodePro-Semibold.ttf.woff2, SourceCodePro-It.ttf.woff2):
 
     Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/),
     with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark
@@ -37,8 +34,7 @@ included, and carry their own copyright notices and license terms:
     See SourceCodePro-LICENSE.txt.
 
 * Source Serif 4 (SourceSerif4-Regular.ttf.woff2, SourceSerif4-Bold.ttf.woff2,
-    SourceSerif4-It.ttf.woff2, SourceSerif4-Regular.ttf.woff,
-    SourceSerif4-Bold.ttf.woff, SourceSerif4-It.ttf.woff):
+    SourceSerif4-It.ttf.woff2):
 
     Copyright 2014-2021 Adobe (http://www.adobe.com/), with Reserved Font Name
     'Source'. All Rights Reserved. Source is a trademark of Adobe in the United
index 48cb0a46ad6270f7d37ed23ca5088ceb4ef0a79f..81c12be8e83c0cdf7d4f99264465c608e4da4dc5 100644 (file)
@@ -4,8 +4,7 @@
        font-style: normal;
        font-weight: 400;
        src: local('Fira Sans'),
-               url("FiraSans-Regular.woff2") format("woff2"),
-               url("FiraSans-Regular.woff") format('woff');
+               url("FiraSans-Regular.woff2") format("woff2");
        font-display: swap;
 }
 @font-face {
@@ -13,8 +12,7 @@
        font-style: normal;
        font-weight: 500;
        src: local('Fira Sans Medium'),
-               url("FiraSans-Medium.woff2") format("woff2"),
-               url("FiraSans-Medium.woff") format('woff');
+               url("FiraSans-Medium.woff2") format("woff2");
        font-display: swap;
 }
 
@@ -24,8 +22,7 @@
        font-style: normal;
        font-weight: 400;
        src: local('Source Serif 4'),
-               url("SourceSerif4-Regular.ttf.woff2") format("woff2"),
-               url("SourceSerif4-Regular.ttf.woff") format("woff");
+               url("SourceSerif4-Regular.ttf.woff2") format("woff2");
        font-display: swap;
 }
 @font-face {
@@ -33,8 +30,7 @@
        font-style: italic;
        font-weight: 400;
        src: local('Source Serif 4 Italic'),
-               url("SourceSerif4-It.ttf.woff2") format("woff2"),
-               url("SourceSerif4-It.ttf.woff") format("woff");
+               url("SourceSerif4-It.ttf.woff2") format("woff2");
        font-display: swap;
 }
 @font-face {
@@ -42,8 +38,7 @@
        font-style: normal;
        font-weight: 700;
        src: local('Source Serif 4 Bold'),
-               url("SourceSerif4-Bold.ttf.woff2") format("woff2"),
-               url("SourceSerif4-Bold.ttf.woff") format("woff");
+               url("SourceSerif4-Bold.ttf.woff2") format("woff2");
        font-display: swap;
 }
 
        font-weight: 400;
        /* Avoid using locally installed font because bad versions are in circulation:
         * see https://github.com/rust-lang/rust/issues/24355 */
-       src: url("SourceCodePro-Regular.ttf.woff2") format("woff2"),
-               url("SourceCodePro-Regular.ttf.woff") format("woff");
+       src: url("SourceCodePro-Regular.ttf.woff2") format("woff2");
        font-display: swap;
 }
 @font-face {
        font-family: 'Source Code Pro';
        font-style: italic;
        font-weight: 400;
-       src: url("SourceCodePro-It.ttf.woff2") format("woff2"),
-               url("SourceCodePro-It.ttf.woff") format("woff");
+       src: url("SourceCodePro-It.ttf.woff2") format("woff2");
        font-display: swap;
 }
 @font-face {
        font-family: 'Source Code Pro';
        font-style: normal;
        font-weight: 600;
-       src: url("SourceCodePro-Semibold.ttf.woff2") format("woff2"),
-               url("SourceCodePro-Semibold.ttf.woff") format("woff");
+       src: url("SourceCodePro-Semibold.ttf.woff2") format("woff2");
        font-display: swap;
 }
 
 /* Avoid using legacy CJK serif fonts in Windows like Batang. */
 @font-face {
        font-family: 'NanumBarunGothic';
-       src: url("NanumBarunGothic.ttf.woff2") format("woff2"),
-               url("NanumBarunGothic.ttf.woff") format("woff");
+       src: url("NanumBarunGothic.ttf.woff2") format("woff2");
        font-display: swap;
        unicode-range: U+AC00-D7AF, U+1100-11FF, U+3130-318F, U+A960-A97F, U+D7B0-D7FF;
 }
diff --git a/src/librustdoc/html/static/fonts/FiraSans-Medium.woff b/src/librustdoc/html/static/fonts/FiraSans-Medium.woff
deleted file mode 100644 (file)
index 7d742c5..0000000
Binary files a/src/librustdoc/html/static/fonts/FiraSans-Medium.woff and /dev/null differ
diff --git a/src/librustdoc/html/static/fonts/FiraSans-Regular.woff b/src/librustdoc/html/static/fonts/FiraSans-Regular.woff
deleted file mode 100644 (file)
index d8e0363..0000000
Binary files a/src/librustdoc/html/static/fonts/FiraSans-Regular.woff and /dev/null differ
diff --git a/src/librustdoc/html/static/fonts/NanumBarunGothic.ttf.woff b/src/librustdoc/html/static/fonts/NanumBarunGothic.ttf.woff
deleted file mode 100644 (file)
index fb063e8..0000000
Binary files a/src/librustdoc/html/static/fonts/NanumBarunGothic.ttf.woff and /dev/null differ
diff --git a/src/librustdoc/html/static/fonts/SourceCodePro-It.ttf.woff b/src/librustdoc/html/static/fonts/SourceCodePro-It.ttf.woff
deleted file mode 100644 (file)
index 8d68f2f..0000000
Binary files a/src/librustdoc/html/static/fonts/SourceCodePro-It.ttf.woff and /dev/null differ
diff --git a/src/librustdoc/html/static/fonts/SourceCodePro-Regular.ttf.woff b/src/librustdoc/html/static/fonts/SourceCodePro-Regular.ttf.woff
deleted file mode 100644 (file)
index 7be076e..0000000
Binary files a/src/librustdoc/html/static/fonts/SourceCodePro-Regular.ttf.woff and /dev/null differ
diff --git a/src/librustdoc/html/static/fonts/SourceCodePro-Semibold.ttf.woff b/src/librustdoc/html/static/fonts/SourceCodePro-Semibold.ttf.woff
deleted file mode 100644 (file)
index 61bc67b..0000000
Binary files a/src/librustdoc/html/static/fonts/SourceCodePro-Semibold.ttf.woff and /dev/null differ
diff --git a/src/librustdoc/html/static/fonts/SourceSerif4-Bold.ttf.woff b/src/librustdoc/html/static/fonts/SourceSerif4-Bold.ttf.woff
deleted file mode 100644 (file)
index 8ad4188..0000000
Binary files a/src/librustdoc/html/static/fonts/SourceSerif4-Bold.ttf.woff and /dev/null differ
diff --git a/src/librustdoc/html/static/fonts/SourceSerif4-It.ttf.woff b/src/librustdoc/html/static/fonts/SourceSerif4-It.ttf.woff
deleted file mode 100644 (file)
index 2a34b5c..0000000
Binary files a/src/librustdoc/html/static/fonts/SourceSerif4-It.ttf.woff and /dev/null differ
diff --git a/src/librustdoc/html/static/fonts/SourceSerif4-Regular.ttf.woff b/src/librustdoc/html/static/fonts/SourceSerif4-Regular.ttf.woff
deleted file mode 100644 (file)
index 45a5521..0000000
Binary files a/src/librustdoc/html/static/fonts/SourceSerif4-Regular.ttf.woff and /dev/null differ
index 0fe0fdadbd21050b3c27aa51331e81797a5a74b5..de881dbd0812a633beecfe0770515421bb874a84 100644 (file)
@@ -1,9 +1,12 @@
 // This file contains type definitions that are processed by the Closure Compiler but are
 // not put into the JavaScript we include as part of the documentation. It is used for
 // type checking. See README.md in this directory for more info.
+/* eslint-env es6 */
+/* eslint no-var: "error" */
+/* eslint prefer-const: "error" */
 
 /* eslint-disable */
-var searchState;
+let searchState;
 function initSearch(searchIndex){}
 
 /**
@@ -15,7 +18,7 @@ function initSearch(searchIndex){}
  *     generics: Array<QueryElement>,
  * }}
  */
-var QueryElement;
+let QueryElement;
 
 /**
  * @typedef {{
@@ -25,7 +28,7 @@ var QueryElement;
  *      userQuery: string,
  * }}
  */
-var ParserState;
+let ParserState;
 
 /**
  * @typedef {{
@@ -38,7 +41,7 @@ var ParserState;
  *     foundElems: number,
  * }}
  */
-var ParsedQuery;
+let ParsedQuery;
 
 /**
  * @typedef {{
@@ -53,7 +56,7 @@ var ParsedQuery;
  *    type: (Array<?>|null)
  * }}
  */
-var Row;
+let Row;
 
 /**
  * @typedef {{
@@ -63,7 +66,7 @@ var Row;
  *    query: ParsedQuery,
  * }}
  */
-var ResultsTable;
+let ResultsTable;
 
 /**
  * @typedef {{
@@ -80,4 +83,4 @@ var ResultsTable;
  *     ty: number,
  * }}
  */
-var Results;
+let Results;
index 90592335d5ddfa83cfa03112873620992a04047f..f20061c65dd1b6f94cdfd37d2f371ef819ffaeb9 100644 (file)
@@ -1,3 +1,6 @@
+/* eslint-env es6 */
+/* eslint no-var: "error" */
+/* eslint prefer-const: "error" */
 // Local js definitions:
 /* global addClass, getSettingValue, hasClass, searchState */
 /* global onEach, onEachLazy, removeClass */
@@ -11,7 +14,7 @@ if (!String.prototype.startsWith) {
 }
 if (!String.prototype.endsWith) {
     String.prototype.endsWith = function(suffix, length) {
-        var l = length || this.length;
+        const l = length || this.length;
         return this.indexOf(suffix, l - suffix.length) !== -1;
     };
 }
@@ -40,7 +43,7 @@ if (!DOMTokenList.prototype.remove) {
 // Get a value from the rustdoc-vars div, which is used to convey data from
 // Rust to the JS. If there is no such element, return null.
 function getVar(name) {
-    var el = document.getElementById("rustdoc-vars");
+    const el = document.getElementById("rustdoc-vars");
     if (el) {
         return el.attributes["data-" + name].value;
     } else {
@@ -54,12 +57,21 @@ function resourcePath(basename, extension) {
     return getVar("root-path") + basename + getVar("resource-suffix") + extension;
 }
 
+function hideMain() {
+    addClass(document.getElementById(MAIN_ID), "hidden");
+}
+
+function showMain() {
+    removeClass(document.getElementById(MAIN_ID), "hidden");
+}
+
 (function () {
     window.rootPath = getVar("root-path");
     window.currentCrate = getVar("current-crate");
     window.searchJS =  resourcePath("search", ".js");
     window.searchIndexJS = resourcePath("search-index", ".js");
-    var sidebarVars = document.getElementById("sidebar-vars");
+    window.settingsJS = resourcePath("settings", ".js");
+    const sidebarVars = document.getElementById("sidebar-vars");
     if (sidebarVars) {
         window.sidebarCurrent = {
             name: sidebarVars.attributes["data-name"].value,
@@ -68,8 +80,8 @@ function resourcePath(basename, extension) {
         };
         // FIXME: It would be nicer to generate this text content directly in HTML,
         // but with the current code it's hard to get the right information in the right place.
-        var mobileLocationTitle = document.querySelector(".mobile-topbar h2.location");
-        var locationTitle = document.querySelector(".sidebar h2.location");
+        const mobileLocationTitle = document.querySelector(".mobile-topbar h2.location");
+        const locationTitle = document.querySelector(".sidebar h2.location");
         if (mobileLocationTitle && locationTitle) {
             mobileLocationTitle.innerHTML = locationTitle.innerHTML;
         }
@@ -91,16 +103,19 @@ function getVirtualKey(ev) {
         return ev.key;
     }
 
-    var c = ev.charCode || ev.keyCode;
+    const c = ev.charCode || ev.keyCode;
     if (c == 27) {
         return "Escape";
     }
     return String.fromCharCode(c);
 }
 
-var THEME_PICKER_ELEMENT_ID = "theme-picker";
-var THEMES_ELEMENT_ID = "theme-choices";
-var MAIN_ID = "main-content";
+const THEME_PICKER_ELEMENT_ID = "theme-picker";
+const THEMES_ELEMENT_ID = "theme-choices";
+const MAIN_ID = "main-content";
+const SETTINGS_BUTTON_ID = "settings-menu";
+const ALTERNATIVE_DISPLAY_ID = "alternative-display";
+const NOT_DISPLAYED_ID = "not-displayed";
 
 function getThemesElement() {
     return document.getElementById(THEMES_ELEMENT_ID);
@@ -110,14 +125,18 @@ function getThemePickerElement() {
     return document.getElementById(THEME_PICKER_ELEMENT_ID);
 }
 
+function getSettingsButton() {
+    return document.getElementById(SETTINGS_BUTTON_ID);
+}
+
 // Returns the current URL without any query parameter or hash.
 function getNakedUrl() {
     return window.location.href.split("?")[0].split("#")[0];
 }
 
 function showThemeButtonState() {
-    var themePicker = getThemePickerElement();
-    var themeChoices = getThemesElement();
+    const themePicker = getThemePickerElement();
+    const themeChoices = getThemesElement();
 
     themeChoices.style.display = "block";
     themePicker.style.borderBottomRightRadius = "0";
@@ -125,22 +144,26 @@ function showThemeButtonState() {
 }
 
 function hideThemeButtonState() {
-    var themePicker = getThemePickerElement();
-    var themeChoices = getThemesElement();
+    const themePicker = getThemePickerElement();
+    const themeChoices = getThemesElement();
 
     themeChoices.style.display = "none";
     themePicker.style.borderBottomRightRadius = "3px";
     themePicker.style.borderBottomLeftRadius = "3px";
 }
 
+window.hideSettings = function() {
+    // Does nothing by default.
+};
+
 // Set up the theme picker list.
 (function () {
     if (!document.location.href.startsWith("file:///")) {
         return;
     }
-    var themeChoices = getThemesElement();
-    var themePicker = getThemePickerElement();
-    var availableThemes = getVar("themes").split(",");
+    const themeChoices = getThemesElement();
+    const themePicker = getThemePickerElement();
+    const availableThemes = getVar("themes").split(",");
 
     removeClass(themeChoices.parentElement, "hidden");
 
@@ -153,8 +176,8 @@ function hideThemeButtonState() {
     }
 
     function handleThemeButtonsBlur(e) {
-        var active = document.activeElement;
-        var related = e.relatedTarget;
+        const active = document.activeElement;
+        const related = e.relatedTarget;
 
         if (active.id !== THEME_PICKER_ELEMENT_ID &&
             (!active.parentNode || active.parentNode.id !== THEMES_ELEMENT_ID) &&
@@ -168,7 +191,7 @@ function hideThemeButtonState() {
     themePicker.onclick = switchThemeButtonState;
     themePicker.onblur = handleThemeButtonsBlur;
     availableThemes.forEach(function(item) {
-        var but = document.createElement("button");
+        const but = document.createElement("button");
         but.textContent = item;
         but.onclick = function() {
             switchTheme(window.currentTheme, window.mainTheme, item, true);
@@ -179,14 +202,120 @@ function hideThemeButtonState() {
     });
 }());
 
+/**
+ * This function inserts `newNode` after `referenceNode`. It doesn't work if `referenceNode`
+ * doesn't have a parent node.
+ *
+ * @param {HTMLElement} newNode
+ * @param {HTMLElement} referenceNode
+ */
+function insertAfter(newNode, referenceNode) {
+    referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
+}
+
+/**
+ * This function creates a new `<section>` with the given `id` and `classes` if it doesn't already
+ * exist.
+ *
+ * More information about this in `switchDisplayedElement` documentation.
+ *
+ * @param {string} id
+ * @param {string} classes
+ */
+function getOrCreateSection(id, classes) {
+    let el = document.getElementById(id);
+
+    if (!el) {
+        el = document.createElement("section");
+        el.id = id;
+        el.className = classes;
+        insertAfter(el, document.getElementById(MAIN_ID));
+    }
+    return el;
+}
+
+/**
+ * Returns the `<section>` element which contains the displayed element.
+ *
+ * @return {HTMLElement}
+ */
+function getAlternativeDisplayElem() {
+    return getOrCreateSection(ALTERNATIVE_DISPLAY_ID, "content hidden");
+}
+
+/**
+ * Returns the `<section>` element which contains the not-displayed elements.
+ *
+ * @return {HTMLElement}
+ */
+function getNotDisplayedElem() {
+    return getOrCreateSection(NOT_DISPLAYED_ID, "hidden");
+}
+
+/**
+ * To nicely switch between displayed "extra" elements (such as search results or settings menu)
+ * and to alternate between the displayed and not displayed elements, we hold them in two different
+ * `<section>` elements. They work in pair: one holds the hidden elements while the other
+ * contains the displayed element (there can be only one at the same time!). So basically, we switch
+ * elements between the two `<section>` elements.
+ *
+ * @param {HTMLElement} elemToDisplay
+ */
+function switchDisplayedElement(elemToDisplay) {
+    const el = getAlternativeDisplayElem();
+
+    if (el.children.length > 0) {
+        getNotDisplayedElem().appendChild(el.firstElementChild);
+    }
+    if (elemToDisplay === null) {
+        addClass(el, "hidden");
+        showMain();
+        return;
+    }
+    el.appendChild(elemToDisplay);
+    hideMain();
+    removeClass(el, "hidden");
+}
+
+function browserSupportsHistoryApi() {
+    return window.history && typeof window.history.pushState === "function";
+}
+
+// eslint-disable-next-line no-unused-vars
+function loadCss(cssFileName) {
+    const link = document.createElement("link");
+    link.href = resourcePath(cssFileName, ".css");
+    link.type = "text/css";
+    link.rel = "stylesheet";
+    document.getElementsByTagName("head")[0].appendChild(link);
+}
+
 (function() {
     "use strict";
 
+    function loadScript(url) {
+        const script = document.createElement('script');
+        script.src = url;
+        document.head.append(script);
+    }
+
+
+    getSettingsButton().onclick = function(event) {
+        event.preventDefault();
+        loadScript(window.settingsJS);
+    };
+
     window.searchState = {
         loadingText: "Loading search results...",
         input: document.getElementsByClassName("search-input")[0],
         outputElement: function() {
-            return document.getElementById("search");
+            let el = document.getElementById("search");
+            if (!el) {
+                el = document.createElement("section");
+                el.id = "search";
+                getNotDisplayedElem().appendChild(el);
+            }
+            return el;
         },
         title: document.title,
         titleBeforeSearch: document.title,
@@ -205,6 +334,9 @@ function hideThemeButtonState() {
                 searchState.timeout = null;
             }
         },
+        isDisplayed: function() {
+            return searchState.outputElement().parentElement.id === ALTERNATIVE_DISPLAY_ID;
+        },
         // Sets the focus on the search bar at the top of the page
         focus: function() {
             searchState.input.focus();
@@ -217,49 +349,35 @@ function hideThemeButtonState() {
             if (search === null || typeof search === 'undefined') {
                 search = searchState.outputElement();
             }
-            addClass(main, "hidden");
-            removeClass(search, "hidden");
+            switchDisplayedElement(search);
             searchState.mouseMovedAfterSearch = false;
             document.title = searchState.title;
         },
-        hideResults: function(search) {
-            if (search === null || typeof search === 'undefined') {
-                search = searchState.outputElement();
-            }
-            addClass(search, "hidden");
-            removeClass(main, "hidden");
+        hideResults: function() {
+            switchDisplayedElement(null);
             document.title = searchState.titleBeforeSearch;
             // We also remove the query parameter from the URL.
-            if (searchState.browserSupportsHistoryApi()) {
+            if (browserSupportsHistoryApi()) {
                 history.replaceState(null, window.currentCrate + " - Rust",
                     getNakedUrl() + window.location.hash);
             }
         },
         getQueryStringParams: function() {
-            var params = {};
+            const params = {};
             window.location.search.substring(1).split("&").
                 map(function(s) {
-                    var pair = s.split("=");
+                    const pair = s.split("=");
                     params[decodeURIComponent(pair[0])] =
                         typeof pair[1] === "undefined" ? null : decodeURIComponent(pair[1]);
                 });
             return params;
         },
-        browserSupportsHistoryApi: function() {
-            return window.history && typeof window.history.pushState === "function";
-        },
         setup: function() {
-            var search_input = searchState.input;
+            const search_input = searchState.input;
             if (!searchState.input) {
                 return;
             }
-            function loadScript(url) {
-                var script = document.createElement('script');
-                script.src = url;
-                document.head.append(script);
-            }
-
-            var searchLoaded = false;
+            let searchLoaded = false;
             function loadSearch() {
                 if (!searchLoaded) {
                     searchLoaded = true;
@@ -278,9 +396,9 @@ function hideThemeButtonState() {
                 loadSearch();
             }
 
-            var params = searchState.getQueryStringParams();
+            const params = searchState.getQueryStringParams();
             if (params.search !== undefined) {
-                var search = searchState.outputElement();
+                const search = searchState.outputElement();
                 search.innerHTML = "<h3 class=\"search-loading\">" +
                     searchState.loadingText + "</h3>";
                 searchState.showResults(search);
@@ -291,7 +409,7 @@ function hideThemeButtonState() {
 
     function getPageId() {
         if (window.location.hash) {
-            var tmp = window.location.hash.replace(/^#/, "");
+            const tmp = window.location.hash.replace(/^#/, "");
             if (tmp.length > 0) {
                 return tmp;
             }
@@ -299,24 +417,21 @@ function hideThemeButtonState() {
         return null;
     }
 
-    var toggleAllDocsId = "toggle-all-docs";
-    var main = document.getElementById(MAIN_ID);
-    var savedHash = "";
+    const toggleAllDocsId = "toggle-all-docs";
+    let savedHash = "";
 
     function handleHashes(ev) {
-        var elem;
-        var search = searchState.outputElement();
-        if (ev !== null && search && !hasClass(search, "hidden") && ev.newURL) {
+        if (ev !== null && searchState.isDisplayed() && ev.newURL) {
             // This block occurs when clicking on an element in the navbar while
             // in a search.
-            searchState.hideResults(search);
-            var hash = ev.newURL.slice(ev.newURL.indexOf("#") + 1);
-            if (searchState.browserSupportsHistoryApi()) {
+            switchDisplayedElement(null);
+            const hash = ev.newURL.slice(ev.newURL.indexOf("#") + 1);
+            if (browserSupportsHistoryApi()) {
                 // `window.location.search`` contains all the query parameters, not just `search`.
                 history.replaceState(null, "",
                     getNakedUrl() + window.location.search + "#" + hash);
             }
-            elem = document.getElementById(hash);
+            const elem = document.getElementById(hash);
             if (elem) {
                 elem.scrollIntoView();
             }
@@ -333,7 +448,7 @@ function hideThemeButtonState() {
 
     function onHashChange(ev) {
         // If we're in mobile mode, we should hide the sidebar in any case.
-        var sidebar = document.getElementsByClassName("sidebar")[0];
+        const sidebar = document.getElementsByClassName("sidebar")[0];
         removeClass(sidebar, "shown");
         handleHashes(ev);
     }
@@ -386,26 +501,31 @@ function hideThemeButtonState() {
     }
 
     function handleEscape(ev) {
-        var help = getHelpElement(false);
-        var search = searchState.outputElement();
+        searchState.clearInputTimeout();
+        const help = getHelpElement(false);
         if (help && !hasClass(help, "hidden")) {
             displayHelp(false, ev, help);
-        } else if (search && !hasClass(search, "hidden")) {
-            searchState.clearInputTimeout();
+        } else {
+            switchDisplayedElement(null);
+            if (browserSupportsHistoryApi()) {
+                history.replaceState(null, window.currentCrate + " - Rust",
+                    getNakedUrl() + window.location.hash);
+            }
             ev.preventDefault();
-            searchState.hideResults(search);
         }
         searchState.defocus();
         hideThemeButtonState();
     }
 
-    var disableShortcuts = getSettingValue("disable-shortcuts") === "true";
+    const disableShortcuts = getSettingValue("disable-shortcuts") === "true";
     function handleShortcut(ev) {
         // Don't interfere with browser shortcuts
         if (ev.ctrlKey || ev.altKey || ev.metaKey || disableShortcuts) {
             return;
         }
 
+        let themePicker;
+
         if (document.activeElement.tagName === "INPUT") {
             switch (getVirtualKey(ev)) {
             case "Escape":
@@ -439,7 +559,7 @@ function hideThemeButtonState() {
             case "T":
                 displayHelp(false, ev);
                 ev.preventDefault();
-                var themePicker = getThemePickerElement();
+                themePicker = getThemePickerElement();
                 themePicker.click();
                 themePicker.focus();
                 break;
@@ -453,8 +573,8 @@ function hideThemeButtonState() {
     }
 
     function handleThemeKeyDown(ev) {
-        var active = document.activeElement;
-        var themes = getThemesElement();
+        const active = document.activeElement;
+        const themes = getThemesElement();
         switch (getVirtualKey(ev)) {
         case "ArrowUp":
             ev.preventDefault();
@@ -499,36 +619,11 @@ function hideThemeButtonState() {
     document.addEventListener("keypress", handleShortcut);
     document.addEventListener("keydown", handleShortcut);
 
-    (function() {
-        var x = document.getElementsByClassName("version-selector");
-        if (x.length > 0) {
-            x[0].onchange = function() {
-                var i, match,
-                    url = document.location.href,
-                    stripped = "",
-                    len = window.rootPath.match(/\.\.\//g).length + 1;
-
-                for (i = 0; i < len; ++i) {
-                    match = url.match(/\/[^/]*$/);
-                    if (i < len - 1) {
-                        stripped = match[0] + stripped;
-                    }
-                    url = url.substring(0, url.length - match[0].length);
-                }
-
-                var selectedVersion = document.getElementsByClassName("version-selector")[0].value;
-                url += "/" + selectedVersion + stripped;
-
-                document.location.href = url;
-            };
-        }
-    }());
-
     // delayed sidebar rendering.
     window.initSidebarItems = function(items) {
-        var sidebar = document.getElementsByClassName("sidebar-elems")[0];
-        var others;
-        var current = window.sidebarCurrent;
+        const sidebar = document.getElementsByClassName("sidebar-elems")[0];
+        let others;
+        const current = window.sidebarCurrent;
 
         function addSidebarCrates(crates) {
             if (!hasClass(document.body, "crate")) {
@@ -536,23 +631,23 @@ function hideThemeButtonState() {
                 return;
             }
             // Draw a convenient sidebar of known crates if we have a listing
-            var div = document.createElement("div");
+            const div = document.createElement("div");
             div.className = "block crate";
             div.innerHTML = "<h3>Crates</h3>";
-            var ul = document.createElement("ul");
+            const ul = document.createElement("ul");
             div.appendChild(ul);
 
-            for (var i = 0; i < crates.length; ++i) {
-                var klass = "crate";
-                if (window.rootPath !== "./" && crates[i] === window.currentCrate) {
+            for (const crate of crates) {
+                let klass = "crate";
+                if (window.rootPath !== "./" && crate === window.currentCrate) {
                     klass += " current";
                 }
-                var link = document.createElement("a");
-                link.href = window.rootPath + crates[i] + "/index.html";
+                const link = document.createElement("a");
+                link.href = window.rootPath + crate + "/index.html";
                 link.className = klass;
-                link.textContent = crates[i];
+                link.textContent = crate;
 
-                var li = document.createElement("li");
+                const li = document.createElement("li");
                 li.appendChild(link);
                 ul.appendChild(li);
             }
@@ -568,39 +663,38 @@ function hideThemeButtonState() {
          *                          "Modules", or "Macros".
          */
         function block(shortty, id, longty) {
-            var filtered = items[shortty];
+            const filtered = items[shortty];
             if (!filtered) {
                 return;
             }
 
-            var div = document.createElement("div");
+            const div = document.createElement("div");
             div.className = "block " + shortty;
-            var h3 = document.createElement("h3");
+            const h3 = document.createElement("h3");
             h3.innerHTML = `<a href="index.html#${id}">${longty}</a>`;
             div.appendChild(h3);
-            var ul = document.createElement("ul");
+            const ul = document.createElement("ul");
 
-            for (var i = 0, len = filtered.length; i < len; ++i) {
-                var item = filtered[i];
-                var name = item[0];
-                var desc = item[1]; // can be null
+            for (const item of filtered) {
+                const name = item[0];
+                const desc = item[1]; // can be null
 
-                var klass = shortty;
+                let klass = shortty;
                 if (name === current.name && shortty === current.ty) {
                     klass += " current";
                 }
-                var path;
+                let path;
                 if (shortty === "mod") {
                     path = name + "/index.html";
                 } else {
                     path = shortty + "." + name + ".html";
                 }
-                var link = document.createElement("a");
+                const link = document.createElement("a");
                 link.href = current.relpath + path;
                 link.title = desc;
                 link.className = klass;
                 link.textContent = name;
-                var li = document.createElement("li");
+                const li = document.createElement("li");
                 li.appendChild(link);
                 ul.appendChild(li);
             }
@@ -613,7 +707,7 @@ function hideThemeButtonState() {
             others.className = "others";
             sidebar.appendChild(others);
 
-            var isModule = hasClass(document.body, "mod");
+            const isModule = hasClass(document.body, "mod");
             if (!isModule) {
                 block("primitive", "primitives", "Primitive Types");
                 block("mod", "modules", "Modules");
@@ -638,8 +732,9 @@ function hideThemeButtonState() {
     };
 
     window.register_implementors = function(imp) {
-        var implementors = document.getElementById("implementors-list");
-        var synthetic_implementors = document.getElementById("synthetic-implementors-list");
+        const implementors = document.getElementById("implementors-list");
+        const synthetic_implementors = document.getElementById("synthetic-implementors-list");
+        const inlined_types = new Set();
 
         if (synthetic_implementors) {
             // This `inlined_types` variable is used to avoid having the same implementation
@@ -647,9 +742,8 @@ function hideThemeButtonState() {
             //
             // By the way, this is only used by and useful for traits implemented automatically
             // (like "Send" and "Sync").
-            var inlined_types = new Set();
             onEachLazy(synthetic_implementors.getElementsByClassName("impl"), function(el) {
-                var aliases = el.getAttribute("data-aliases");
+                const aliases = el.getAttribute("data-aliases");
                 if (!aliases) {
                     return;
                 }
@@ -659,48 +753,48 @@ function hideThemeButtonState() {
             });
         }
 
-        var currentNbImpls = implementors.getElementsByClassName("impl").length;
-        var traitName = document.querySelector("h1.fqn > .in-band > .trait").textContent;
-        var baseIdName = "impl-" + traitName + "-";
-        var libs = Object.getOwnPropertyNames(imp);
-        for (var i = 0, llength = libs.length; i < llength; ++i) {
-            if (libs[i] === window.currentCrate) { continue; }
-            var structs = imp[libs[i]];
+        let currentNbImpls = implementors.getElementsByClassName("impl").length;
+        const traitName = document.querySelector("h1.fqn > .in-band > .trait").textContent;
+        const baseIdName = "impl-" + traitName + "-";
+        const libs = Object.getOwnPropertyNames(imp);
+        for (const lib of libs) {
+            if (lib === window.currentCrate) {
+                continue;
+            }
+            const structs = imp[lib];
 
             struct_loop:
-            for (var j = 0, slength = structs.length; j < slength; ++j) {
-                var struct = structs[j];
-
-                var list = struct.synthetic ? synthetic_implementors : implementors;
+            for (const struct of structs) {
+                const list = struct.synthetic ? synthetic_implementors : implementors;
 
                 if (struct.synthetic) {
-                    for (var k = 0, stlength = struct.types.length; k < stlength; k++) {
-                        if (inlined_types.has(struct.types[k])) {
+                    for (const struct_type of struct.types) {
+                        if (inlined_types.has(struct_type)) {
                             continue struct_loop;
                         }
-                        inlined_types.add(struct.types[k]);
+                        inlined_types.add(struct_type);
                     }
                 }
 
-                var code = document.createElement("h3");
+                const code = document.createElement("h3");
                 code.innerHTML = struct.text;
                 addClass(code, "code-header");
                 addClass(code, "in-band");
 
                 onEachLazy(code.getElementsByTagName("a"), function(elem) {
-                    var href = elem.getAttribute("href");
+                    const href = elem.getAttribute("href");
 
                     if (href && href.indexOf("http") !== 0) {
                         elem.setAttribute("href", window.rootPath + href);
                     }
                 });
 
-                var currentId = baseIdName + currentNbImpls;
-                var anchor = document.createElement("a");
+                const currentId = baseIdName + currentNbImpls;
+                const anchor = document.createElement("a");
                 anchor.href = "#" + currentId;
                 addClass(anchor, "anchor");
 
-                var display = document.createElement("div");
+                const display = document.createElement("div");
                 display.id = currentId;
                 addClass(display, "impl");
                 display.appendChild(anchor);
@@ -725,11 +819,11 @@ function hideThemeButtonState() {
     }
 
     function toggleAllDocs() {
-        var innerToggle = document.getElementById(toggleAllDocsId);
+        const innerToggle = document.getElementById(toggleAllDocsId);
         if (!innerToggle) {
             return;
         }
-        var sectionIsCollapsed = false;
+        let sectionIsCollapsed = false;
         if (hasClass(innerToggle, "will-expand")) {
             removeClass(innerToggle, "will-expand");
             onEachLazy(document.getElementsByClassName("rustdoc-toggle"), function(e) {
@@ -754,22 +848,18 @@ function hideThemeButtonState() {
         innerToggle.children[0].innerText = labelForToggleButton(sectionIsCollapsed);
     }
 
-    function insertAfter(newNode, referenceNode) {
-        referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
-    }
-
     (function() {
-        var toggles = document.getElementById(toggleAllDocsId);
+        const toggles = document.getElementById(toggleAllDocsId);
         if (toggles) {
             toggles.onclick = toggleAllDocs;
         }
 
-        var hideMethodDocs = getSettingValue("auto-hide-method-docs") === "true";
-        var hideImplementations = getSettingValue("auto-hide-trait-implementations") === "true";
-        var hideLargeItemContents = getSettingValue("auto-hide-large-items") !== "false";
+        const hideMethodDocs = getSettingValue("auto-hide-method-docs") === "true";
+        const hideImplementations = getSettingValue("auto-hide-trait-implementations") === "true";
+        const hideLargeItemContents = getSettingValue("auto-hide-large-items") !== "false";
 
         function setImplementorsTogglesOpen(id, open) {
-            var list = document.getElementById(id);
+            const list = document.getElementById(id);
             if (list !== null) {
                 onEachLazy(list.getElementsByClassName("implementors-toggle"), function(e) {
                     e.open = open;
@@ -792,7 +882,7 @@ function hideThemeButtonState() {
 
         });
 
-        var pageId = getPageId();
+        const pageId = getPageId();
         if (pageId !== null) {
             expandSection(pageId);
         }
@@ -800,15 +890,15 @@ function hideThemeButtonState() {
 
     (function() {
         // To avoid checking on "rustdoc-line-numbers" value on every loop...
-        var lineNumbersFunc = function() {};
+        let lineNumbersFunc = function() {};
         if (getSettingValue("line-numbers") === "true") {
             lineNumbersFunc = function(x) {
-                var count = x.textContent.split("\n").length;
-                var elems = [];
-                for (var i = 0; i < count; ++i) {
+                const count = x.textContent.split("\n").length;
+                const elems = [];
+                for (let i = 0; i < count; ++i) {
                     elems.push(i + 1);
                 }
-                var node = document.createElement("pre");
+                const node = document.createElement("pre");
                 addClass(node, "line-number");
                 node.innerHTML = elems.join("\n");
                 x.parentNode.insertBefore(node, x);
@@ -835,12 +925,12 @@ function hideThemeButtonState() {
     }());
 
     function hideSidebar() {
-        var sidebar = document.getElementsByClassName("sidebar")[0];
+        const sidebar = document.getElementsByClassName("sidebar")[0];
         removeClass(sidebar, "shown");
     }
 
     function handleClick(id, f) {
-        var elem = document.getElementById(id);
+        const elem = document.getElementById(id);
         if (elem) {
             elem.addEventListener("click", f);
         }
@@ -879,10 +969,10 @@ function hideThemeButtonState() {
         };
     });
 
-    var sidebar_menu_toggle = document.getElementsByClassName("sidebar-menu-toggle")[0];
+    const sidebar_menu_toggle = document.getElementsByClassName("sidebar-menu-toggle")[0];
     if (sidebar_menu_toggle) {
         sidebar_menu_toggle.addEventListener("click", function() {
-            var sidebar = document.getElementsByClassName("sidebar")[0];
+            const sidebar = document.getElementsByClassName("sidebar")[0];
             if (!hasClass(sidebar, "shown")) {
                 addClass(sidebar, "shown");
             } else {
@@ -891,8 +981,8 @@ function hideThemeButtonState() {
         });
     }
 
-    var buildHelperPopup = function() {
-        var popup = document.createElement("aside");
+    let buildHelperPopup = function() {
+        const popup = document.createElement("aside");
         addClass(popup, "hidden");
         popup.id = "help";
 
@@ -903,13 +993,13 @@ function hideThemeButtonState() {
             }
         });
 
-        var book_info = document.createElement("span");
+        const book_info = document.createElement("span");
         book_info.className = "top";
         book_info.innerHTML = "You can find more information in \
             <a href=\"https://doc.rust-lang.org/rustdoc/\">the rustdoc book</a>.";
 
-        var container = document.createElement("div");
-        var shortcuts = [
+        const container = document.createElement("div");
+        const shortcuts = [
             ["?", "Show this help dialog"],
             ["S", "Focus the search field"],
             ["T", "Focus the theme picker menu"],
@@ -927,11 +1017,11 @@ function hideThemeButtonState() {
                     })
                     .join("") + "</dt><dd>" + x[1] + "</dd>";
         }).join("");
-        var div_shortcuts = document.createElement("div");
+        const div_shortcuts = document.createElement("div");
         addClass(div_shortcuts, "shortcuts");
         div_shortcuts.innerHTML = "<h2>Keyboard Shortcuts</h2><dl>" + shortcuts + "</dl></div>";
 
-        var infos = [
+        const infos = [
             "Prefix searches with a type followed by a colon (e.g., <code>fn:</code>) to \
              restrict the search to a given item kind.",
             "Accepted kinds are: <code>fn</code>, <code>mod</code>, <code>struct</code>, \
@@ -947,7 +1037,7 @@ function hideThemeButtonState() {
         ].map(function(x) {
             return "<p>" + x + "</p>";
         }).join("");
-        var div_infos = document.createElement("div");
+        const div_infos = document.createElement("div");
         addClass(div_infos, "infos");
         div_infos.innerHTML = "<h2>Search Tricks</h2>" + infos;
 
@@ -955,9 +1045,9 @@ function hideThemeButtonState() {
         container.appendChild(div_shortcuts);
         container.appendChild(div_infos);
 
-        var rustdoc_version = document.createElement("span");
+        const rustdoc_version = document.createElement("span");
         rustdoc_version.className = "bottom";
-        var rustdoc_version_code = document.createElement("code");
+        const rustdoc_version_code = document.createElement("code");
         rustdoc_version_code.innerText = "rustdoc " + getVar("rustdoc-version");
         rustdoc_version.appendChild(rustdoc_version_code);
 
@@ -975,11 +1065,11 @@ function hideThemeButtonState() {
 }());
 
 (function () {
-    var reset_button_timeout = null;
+    let reset_button_timeout = null;
 
     window.copy_path = function(but) {
-        var parent = but.parentElement;
-        var path = [];
+        const parent = but.parentElement;
+        const path = [];
 
         onEach(parent.childNodes, function(child) {
             if (child.tagName === 'A') {
@@ -987,7 +1077,7 @@ function hideThemeButtonState() {
             }
         });
 
-        var el = document.createElement('textarea');
+        const el = document.createElement('textarea');
         el.value = path.join('::');
         el.setAttribute('readonly', '');
         // To not make it appear on the screen.
@@ -1002,7 +1092,7 @@ function hideThemeButtonState() {
         // There is always one children, but multiple childNodes.
         but.children[0].style.display = 'none';
 
-        var tmp;
+        let tmp;
         if (but.childNodes.length < 2) {
             tmp = document.createTextNode('✓');
             but.appendChild(tmp);
index a28fb46172990d79ce08c4a73550d24b08292c76..865ed7190f36e86ee85fb8dbffabdeb02e75d1fb 100644 (file)
@@ -1,4 +1,7 @@
-/* global addClass, hasClass, removeClass, onEach */
+/* eslint-env es6 */
+/* eslint no-var: "error" */
+/* eslint prefer-const: "error" */
+/* global addClass, hasClass, removeClass, onEachLazy */
 
 (function () {
     // Number of lines shown when code viewer is not expanded
@@ -6,19 +9,19 @@
 
     // Scroll code block to the given code location
     function scrollToLoc(elt, loc) {
-        var lines = elt.querySelector('.line-numbers');
-        var scrollOffset;
+        const lines = elt.querySelector('.line-numbers');
+        let scrollOffset;
 
         // If the block is greater than the size of the viewer,
         // then scroll to the top of the block. Otherwise scroll
         // to the middle of the block.
         if (loc[1] - loc[0] > MAX_LINES) {
-            var line = Math.max(0, loc[0] - 1);
+            const line = Math.max(0, loc[0] - 1);
             scrollOffset = lines.children[line].offsetTop;
         } else {
-            var wrapper = elt.querySelector(".code-wrapper");
-            var halfHeight = wrapper.offsetHeight / 2;
-            var offsetMid = (lines.children[loc[0]].offsetTop
+            const wrapper = elt.querySelector(".code-wrapper");
+            const halfHeight = wrapper.offsetHeight / 2;
+            const offsetMid = (lines.children[loc[0]].offsetTop
                              + lines.children[loc[1]].offsetTop) / 2;
             scrollOffset = offsetMid - halfHeight;
         }
     }
 
     function updateScrapedExample(example) {
-        var locs = JSON.parse(example.attributes.getNamedItem("data-locs").textContent);
-        var locIndex = 0;
-        var highlights = example.querySelectorAll('.highlight');
-        var link = example.querySelector('.scraped-example-title a');
+        const locs = JSON.parse(example.attributes.getNamedItem("data-locs").textContent);
+        let locIndex = 0;
+        const highlights = Array.prototype.slice.call(example.querySelectorAll('.highlight'));
+        const link = example.querySelector('.scraped-example-title a');
 
         if (locs.length > 1) {
             // Toggle through list of examples in a given file
-            var onChangeLoc = function(changeIndex) {
+            const onChangeLoc = function(changeIndex) {
                 removeClass(highlights[locIndex], 'focus');
                 changeIndex();
                 scrollToLoc(example, locs[locIndex][0]);
                 addClass(highlights[locIndex], 'focus');
 
-                var url = locs[locIndex][1];
-                var title = locs[locIndex][2];
+                const url = locs[locIndex][1];
+                const title = locs[locIndex][2];
 
                 link.href = url;
                 link.innerHTML = title;
@@ -63,7 +66,7 @@
                 });
         }
 
-        var expandButton = example.querySelector('.expand');
+        const expandButton = example.querySelector('.expand');
         if (expandButton) {
             expandButton.addEventListener('click', function () {
                 if (hasClass(example, "expanded")) {
         scrollToLoc(example, locs[0][0]);
     }
 
-    var firstExamples = document.querySelectorAll('.scraped-example-list > .scraped-example');
-    onEach(firstExamples, updateScrapedExample);
-    onEach(document.querySelectorAll('.more-examples-toggle'), function(toggle) {
+    const firstExamples = document.querySelectorAll('.scraped-example-list > .scraped-example');
+    onEachLazy(firstExamples, updateScrapedExample);
+    onEachLazy(document.querySelectorAll('.more-examples-toggle'), function(toggle) {
         // Allow users to click the left border of the <details> section to close it,
         // since the section can be large and finding the [+] button is annoying.
-        toggle.querySelectorAll('.toggle-line, .hide-more').forEach(button => {
+        onEachLazy(toggle.querySelectorAll('.toggle-line, .hide-more'), button => {
             button.addEventListener('click', function() {
                 toggle.open = false;
             });
         });
 
-        var moreExamples = toggle.querySelectorAll('.scraped-example');
+        const moreExamples = toggle.querySelectorAll('.scraped-example');
         toggle.querySelector('summary').addEventListener('click', function() {
             // Wrapping in setTimeout ensures the update happens after the elements are actually
             // visible. This is necessary since updateScrapedExample calls scrollToLoc which
             // depends on offsetHeight, a property that requires an element to be visible to
             // compute correctly.
-            setTimeout(function() { onEach(moreExamples, updateScrapedExample); });
+            setTimeout(function() { onEachLazy(moreExamples, updateScrapedExample); });
         }, {once: true});
     });
 })();
index 0d4e0a0b3289dac7f763875b074733448725459c..84600fa3e094f6bfc96fe868e0c8f538033979a8 100644 (file)
@@ -1,10 +1,13 @@
+/* eslint-env es6 */
+/* eslint no-var: "error" */
+/* eslint prefer-const: "error" */
 /* global addClass, getNakedUrl, getSettingValue, hasOwnPropertyRustdoc, initSearch, onEach */
-/* global onEachLazy, removeClass, searchState, hasClass */
+/* global onEachLazy, removeClass, searchState, browserSupportsHistoryApi */
 
 (function() {
 // This mapping table should match the discriminants of
 // `rustdoc::formats::item_type::ItemType` type in Rust.
-var itemTypes = [
+const itemTypes = [
     "mod",
     "externcrate",
     "import",
@@ -34,15 +37,15 @@ var itemTypes = [
 ];
 
 // used for special search precedence
-var TY_PRIMITIVE = itemTypes.indexOf("primitive");
-var TY_KEYWORD = itemTypes.indexOf("keyword");
+const TY_PRIMITIVE = itemTypes.indexOf("primitive");
+const TY_KEYWORD = itemTypes.indexOf("keyword");
 
 // In the search display, allows to switch between tabs.
 function printTab(nb) {
     if (nb === 0 || nb === 1 || nb === 2) {
         searchState.currentTab = nb;
     }
-    var nb_copy = nb;
+    let nb_copy = nb;
     onEachLazy(document.getElementById("titles").childNodes, function(elem) {
         if (nb_copy === 0) {
             addClass(elem, "selected");
@@ -68,14 +71,15 @@ function printTab(nb) {
  * This code is an unmodified version of the code written by Marco de Wit
  * and was found at https://stackoverflow.com/a/18514751/745719
  */
-var levenshtein_row2 = [];
+const levenshtein_row2 = [];
 function levenshtein(s1, s2) {
     if (s1 === s2) {
         return 0;
     }
-    var s1_len = s1.length, s2_len = s2.length;
+    const s1_len = s1.length, s2_len = s2.length;
     if (s1_len && s2_len) {
-        var i1 = 0, i2 = 0, a, b, c, c2, row = levenshtein_row2;
+        let i1 = 0, i2 = 0, a, b, c, c2;
+        const row = levenshtein_row2;
         while (i1 < s1_len) {
             row[i1] = ++i1;
         }
@@ -97,24 +101,20 @@ function levenshtein(s1, s2) {
 }
 
 window.initSearch = function(rawSearchIndex) {
-    var MAX_LEV_DISTANCE = 3;
-    var MAX_RESULTS = 200;
-    var GENERICS_DATA = 2;
-    var NAME = 0;
-    var INPUTS_DATA = 0;
-    var OUTPUT_DATA = 1;
-    var NO_TYPE_FILTER = -1;
+    const MAX_LEV_DISTANCE = 3;
+    const MAX_RESULTS = 200;
+    const GENERICS_DATA = 2;
+    const NAME = 0;
+    const INPUTS_DATA = 0;
+    const OUTPUT_DATA = 1;
+    const NO_TYPE_FILTER = -1;
     /**
      *  @type {Array<Row>}
      */
-    var searchIndex;
-    /**
-     *  @type {Array<string>}
-     */
-    var searchWords;
-    var currentResults;
-    var ALIASES = {};
-    var params = searchState.getQueryStringParams();
+    let searchIndex;
+    let currentResults;
+    const ALIASES = {};
+    const params = searchState.getQueryStringParams();
 
     // Populate search bar with query string search term when provided,
     // but only if the input bar is empty. This avoid the obnoxious issue
@@ -145,7 +145,7 @@ window.initSearch = function(rawSearchIndex) {
     }
 
     function itemTypeFromName(typename) {
-        for (var i = 0, len = itemTypes.length; i < len; ++i) {
+        for (let i = 0, len = itemTypes.length; i < len; ++i) {
             if (itemTypes[i] === typename) {
                 return i;
             }
@@ -176,8 +176,8 @@ window.initSearch = function(rawSearchIndex) {
             throw new Error("Cannot use literal search when there is more than one element");
         }
         parserState.pos += 1;
-        var start = parserState.pos;
-        var end = getIdentEndPosition(parserState);
+        const start = parserState.pos;
+        const end = getIdentEndPosition(parserState);
         if (parserState.pos >= parserState.length) {
             throw new Error("Unclosed `\"`");
         } else if (parserState.userQuery[end] !== "\"") {
@@ -264,10 +264,10 @@ window.initSearch = function(rawSearchIndex) {
         if (query.literalSearch && parserState.totalElems - parserState.genericsElems > 0) {
             throw new Error("You cannot have more than one element if you use quotes");
         }
-        var pathSegments = name.split("::");
+        const pathSegments = name.split("::");
         if (pathSegments.length > 1) {
-            for (var i = 0, len = pathSegments.length; i < len; ++i) {
-                var pathSegment = pathSegments[i];
+            for (let i = 0, len = pathSegments.length; i < len; ++i) {
+                const pathSegment = pathSegments[i];
 
                 if (pathSegment.length === 0) {
                     if (i === 0) {
@@ -305,11 +305,21 @@ window.initSearch = function(rawSearchIndex) {
      * @return {integer}
      */
     function getIdentEndPosition(parserState) {
-        var end = parserState.pos;
+        let end = parserState.pos;
+        let foundExclamation = false;
         while (parserState.pos < parserState.length) {
-            var c = parserState.userQuery[parserState.pos];
+            const c = parserState.userQuery[parserState.pos];
             if (!isIdentCharacter(c)) {
-                if (isErrorCharacter(c)) {
+                if (c === "!") {
+                    if (foundExclamation) {
+                        throw new Error("Cannot have more than one `!` in an ident");
+                    } else if (parserState.pos + 1 < parserState.length &&
+                        isIdentCharacter(parserState.userQuery[parserState.pos + 1]))
+                    {
+                        throw new Error("`!` can only be at the end of an ident");
+                    }
+                    foundExclamation = true;
+                } else if (isErrorCharacter(c)) {
                     throw new Error(`Unexpected \`${c}\``);
                 } else if (
                     isStopCharacter(c) ||
@@ -325,6 +335,7 @@ window.initSearch = function(rawSearchIndex) {
                     }
                     // Skip current ":".
                     parserState.pos += 1;
+                    foundExclamation = false;
                 } else {
                     throw new Error(`Unexpected \`${c}\``);
                 }
@@ -342,10 +353,10 @@ window.initSearch = function(rawSearchIndex) {
      * @param {boolean} isInGenerics
      */
     function getNextElem(query, parserState, elems, isInGenerics) {
-        var generics = [];
+        const generics = [];
 
-        var start = parserState.pos;
-        var end;
+        let start = parserState.pos;
+        let end;
         // We handle the strings on their own mostly to make code easier to follow.
         if (parserState.userQuery[parserState.pos] === "\"") {
             start += 1;
@@ -393,10 +404,10 @@ window.initSearch = function(rawSearchIndex) {
      *                                      character.
      */
     function getItemsBefore(query, parserState, elems, endChar) {
-        var foundStopChar = true;
+        let foundStopChar = true;
 
         while (parserState.pos < parserState.length) {
-            var c = parserState.userQuery[parserState.pos];
+            const c = parserState.userQuery[parserState.pos];
             if (c === endChar) {
                 break;
             } else if (isSeparatorCharacter(c)) {
@@ -406,7 +417,7 @@ window.initSearch = function(rawSearchIndex) {
             } else if (c === ":" && isPathStart(parserState)) {
                 throw new Error("Unexpected `::`: paths cannot start with `::`");
             } else if (c === ":" || isEndCharacter(c)) {
-                var extra = "";
+                let extra = "";
                 if (endChar === ">") {
                     extra = "`<`";
                 } else if (endChar === "") {
@@ -420,7 +431,7 @@ window.initSearch = function(rawSearchIndex) {
                 }
                 throw new Error(`Expected \`,\` or \` \`, found \`${c}\``);
             }
-            var posBefore = parserState.pos;
+            const posBefore = parserState.pos;
             getNextElem(query, parserState, elems, endChar === ">");
             // This case can be encountered if `getNextElem` encounted a "stop character" right from
             // the start. For example if you have `,,` or `<>`. In this case, we simply move up the
@@ -442,9 +453,9 @@ window.initSearch = function(rawSearchIndex) {
      * @param {ParserState} parserState
      */
     function checkExtraTypeFilterCharacters(parserState) {
-        var query = parserState.userQuery;
+        const query = parserState.userQuery;
 
-        for (var pos = 0; pos < parserState.pos; ++pos) {
+        for (let pos = 0; pos < parserState.pos; ++pos) {
             if (!isIdentCharacter(query[pos]) && !isWhitespaceCharacter(query[pos])) {
                 throw new Error(`Unexpected \`${query[pos]}\` in type filter`);
             }
@@ -459,8 +470,8 @@ window.initSearch = function(rawSearchIndex) {
      * @param {ParserState} parserState
      */
     function parseInput(query, parserState) {
-        var c, before;
-        var foundStopChar = true;
+        let c, before;
+        let foundStopChar = true;
 
         while (parserState.pos < parserState.length) {
             c = parserState.userQuery[parserState.pos];
@@ -557,7 +568,7 @@ window.initSearch = function(rawSearchIndex) {
      * @return {string}
      */
     function buildUrl(search, filterCrates) {
-        var extra = "?search=" + encodeURIComponent(search);
+        let extra = "?search=" + encodeURIComponent(search);
 
         if (filterCrates !== null) {
             extra += "&filter-crate=" + encodeURIComponent(filterCrates);
@@ -571,7 +582,7 @@ window.initSearch = function(rawSearchIndex) {
      * @return {string|null}
      */
     function getFilterCrates() {
-        var elem = document.getElementById("crate-search");
+        const elem = document.getElementById("crate-search");
 
         if (elem &&
             elem.value !== "All crates" &&
@@ -587,7 +598,7 @@ window.initSearch = function(rawSearchIndex) {
      *
      * The supported syntax by this parser is as follow:
      *
-     * ident = *(ALPHA / DIGIT / "_")
+     * ident = *(ALPHA / DIGIT / "_") [!]
      * path = ident *(DOUBLE-COLON ident)
      * arg = path [generics]
      * arg-without-generic = path
@@ -650,7 +661,7 @@ window.initSearch = function(rawSearchIndex) {
      */
     function parseQuery(userQuery) {
         userQuery = userQuery.trim();
-        var parserState = {
+        const parserState = {
             length: userQuery.length,
             pos: 0,
             // Total number of elements (includes generics).
@@ -659,12 +670,12 @@ window.initSearch = function(rawSearchIndex) {
             typeFilter: null,
             userQuery: userQuery.toLowerCase(),
         };
-        var query = newParsedQuery(userQuery);
+        let query = newParsedQuery(userQuery);
 
         try {
             parseInput(query, parserState);
             if (parserState.typeFilter !== null) {
-                var typeFilter = parserState.typeFilter;
+                let typeFilter = parserState.typeFilter;
                 if (typeFilter === "const") {
                     typeFilter = "constant";
                 }
@@ -715,19 +726,17 @@ window.initSearch = function(rawSearchIndex) {
      * @return {ResultsTable}
      */
     function execQuery(parsedQuery, searchWords, filterCrates) {
-        var results_others = {}, results_in_args = {}, results_returned = {};
+        const results_others = {}, results_in_args = {}, results_returned = {};
 
         function transformResults(results) {
-            var duplicates = {};
-            var out = [];
-
-            for (var i = 0, len = results.length; i < len; ++i) {
-                var result = results[i];
+            const duplicates = {};
+            const out = [];
 
+            for (const result of results) {
                 if (result.id > -1) {
-                    var obj = searchIndex[result.id];
+                    const obj = searchIndex[result.id];
                     obj.lev = result.lev;
-                    var res = buildHrefAndPath(obj);
+                    const res = buildHrefAndPath(obj);
                     obj.displayPath = pathSplitter(res[0]);
                     obj.fullPath = obj.displayPath + obj.name;
                     // To be sure than it some items aren't considered as duplicate.
@@ -749,11 +758,11 @@ window.initSearch = function(rawSearchIndex) {
         }
 
         function sortResults(results, isType) {
-            var userQuery = parsedQuery.userQuery;
-            var ar = [];
-            for (var entry in results) {
+            const userQuery = parsedQuery.userQuery;
+            const ar = [];
+            for (const entry in results) {
                 if (hasOwnPropertyRustdoc(results, entry)) {
-                    var result = results[entry];
+                    const result = results[entry];
                     result.word = searchWords[result.id];
                     result.item = searchIndex[result.id] || {};
                     ar.push(result);
@@ -766,7 +775,7 @@ window.initSearch = function(rawSearchIndex) {
             }
 
             results.sort(function(aaa, bbb) {
-                var a, b;
+                let a, b;
 
                 // sort by exact match with regard to the last word (mismatch goes later)
                 a = (aaa.word !== userQuery);
@@ -832,20 +841,18 @@ window.initSearch = function(rawSearchIndex) {
                 return 0;
             });
 
-            var nameSplit = null;
+            let nameSplit = null;
             if (parsedQuery.elems.length === 1) {
-                var hasPath = typeof parsedQuery.elems[0].path === "undefined";
+                const hasPath = typeof parsedQuery.elems[0].path === "undefined";
                 nameSplit = hasPath ? null : parsedQuery.elems[0].path;
             }
 
-            for (var i = 0, len = results.length; i < len; ++i) {
-                result = results[i];
-
+            for (const result of results) {
                 // this validation does not make sense when searching by types
                 if (result.dontValidate) {
                     continue;
                 }
-                var name = result.item.name.toLowerCase(),
+                const name = result.item.name.toLowerCase(),
                     path = result.item.path.toLowerCase(),
                     parent = result.item.parent;
 
@@ -877,15 +884,14 @@ window.initSearch = function(rawSearchIndex) {
             }
             // The names match, but we need to be sure that all generics kinda
             // match as well.
-            var elem_name;
+            let elem_name;
             if (elem.generics.length > 0 && row[GENERICS_DATA].length >= elem.generics.length) {
-                var elems = Object.create(null);
-                for (var x = 0, length = row[GENERICS_DATA].length; x < length; ++x) {
-                    elem_name = row[GENERICS_DATA][x][NAME];
+                const elems = Object.create(null);
+                for (const entry of row[GENERICS_DATA]) {
+                    elem_name = entry[NAME];
                     if (elem_name === "") {
                         // Pure generic, needs to check into it.
-                        if (checkGenerics(
-                                row[GENERICS_DATA][x], elem, MAX_LEV_DISTANCE + 1) !== 0) {
+                        if (checkGenerics(entry, elem, MAX_LEV_DISTANCE + 1) !== 0) {
                             return MAX_LEV_DISTANCE + 1;
                         }
                         continue;
@@ -897,9 +903,8 @@ window.initSearch = function(rawSearchIndex) {
                 }
                 // We need to find the type that matches the most to remove it in order
                 // to move forward.
-                for (x = 0, length = elem.generics.length; x < length; ++x) {
-                    var generic = elem.generics[x];
-                    var match = null;
+                for (const generic of elem.generics) {
+                    let match = null;
                     if (elems[generic.name]) {
                         match = generic.name;
                     } else {
@@ -936,12 +941,12 @@ window.initSearch = function(rawSearchIndex) {
           * @return {integer} - Returns a Levenshtein distance to the best match.
           */
         function checkIfInGenerics(row, elem) {
-            var lev = MAX_LEV_DISTANCE + 1;
-            for (var x = 0, length = row[GENERICS_DATA].length; x < length && lev !== 0; ++x) {
-                lev = Math.min(
-                    checkType(row[GENERICS_DATA][x], elem, true),
-                    lev
-                );
+            let lev = MAX_LEV_DISTANCE + 1;
+            for (const entry of row[GENERICS_DATA]) {
+                lev = Math.min(checkType(entry, elem, true), lev);
+                if (lev === 0) {
+                    break;
+                }
             }
             return lev;
         }
@@ -966,12 +971,12 @@ window.initSearch = function(rawSearchIndex) {
                 return MAX_LEV_DISTANCE + 1;
             }
 
-            var lev = levenshtein(row[NAME], elem.name);
+            let lev = levenshtein(row[NAME], elem.name);
             if (literalSearch) {
                 if (lev !== 0) {
                     // The name didn't match, let's try to check if the generics do.
                     if (elem.generics.length === 0) {
-                        var checkGeneric = (row.length > GENERICS_DATA &&
+                        const checkGeneric = (row.length > GENERICS_DATA &&
                             row[GENERICS_DATA].length > 0);
                         if (checkGeneric && row[GENERICS_DATA].findIndex(function(tmp_elem) {
                             return tmp_elem[NAME] === elem.name;
@@ -1004,7 +1009,7 @@ window.initSearch = function(rawSearchIndex) {
                 } else {
                     // At this point, the name kinda match and we have generics to check, so
                     // let's go!
-                    var tmp_lev = checkGenerics(row, elem, lev);
+                    const tmp_lev = checkGenerics(row, elem, lev);
                     if (tmp_lev > MAX_LEV_DISTANCE) {
                         return MAX_LEV_DISTANCE + 1;
                     }
@@ -1032,16 +1037,14 @@ window.initSearch = function(rawSearchIndex) {
          *                      match, returns `MAX_LEV_DISTANCE + 1`.
          */
         function findArg(row, elem, typeFilter) {
-            var lev = MAX_LEV_DISTANCE + 1;
+            let lev = MAX_LEV_DISTANCE + 1;
 
             if (row && row.type && row.type[INPUTS_DATA] && row.type[INPUTS_DATA].length > 0) {
-                var length = row.type[INPUTS_DATA].length;
-                for (var i = 0; i < length; i++) {
-                    var tmp = row.type[INPUTS_DATA][i];
-                    if (!typePassesFilter(typeFilter, tmp[1])) {
+                for (const input of row.type[INPUTS_DATA]) {
+                    if (!typePassesFilter(typeFilter, input[1])) {
                         continue;
                     }
-                    lev = Math.min(lev, checkType(tmp, elem, parsedQuery.literalSearch));
+                    lev = Math.min(lev, checkType(input, elem, parsedQuery.literalSearch));
                     if (lev === 0) {
                         return 0;
                     }
@@ -1061,19 +1064,18 @@ window.initSearch = function(rawSearchIndex) {
          *                      match, returns `MAX_LEV_DISTANCE + 1`.
          */
         function checkReturned(row, elem, typeFilter) {
-            var lev = MAX_LEV_DISTANCE + 1;
+            let lev = MAX_LEV_DISTANCE + 1;
 
             if (row && row.type && row.type.length > OUTPUT_DATA) {
-                var ret = row.type[OUTPUT_DATA];
+                let ret = row.type[OUTPUT_DATA];
                 if (typeof ret[0] === "string") {
                     ret = [ret];
                 }
-                for (var x = 0, len = ret.length; x < len; ++x) {
-                    var tmp = ret[x];
-                    if (!typePassesFilter(typeFilter, tmp[1])) {
+                for (const ret_ty of ret) {
+                    if (!typePassesFilter(typeFilter, ret_ty[1])) {
                         continue;
                     }
-                    lev = Math.min(lev, checkType(tmp, elem, parsedQuery.literalSearch));
+                    lev = Math.min(lev, checkType(ret_ty, elem, parsedQuery.literalSearch));
                     if (lev === 0) {
                         return 0;
                     }
@@ -1086,26 +1088,26 @@ window.initSearch = function(rawSearchIndex) {
             if (contains.length === 0) {
                 return 0;
             }
-            var ret_lev = MAX_LEV_DISTANCE + 1;
-            var path = ty.path.split("::");
+            let ret_lev = MAX_LEV_DISTANCE + 1;
+            const path = ty.path.split("::");
 
             if (ty.parent && ty.parent.name) {
                 path.push(ty.parent.name.toLowerCase());
             }
 
-            var length = path.length;
-            var clength = contains.length;
+            const length = path.length;
+            const clength = contains.length;
             if (clength > length) {
                 return MAX_LEV_DISTANCE + 1;
             }
-            for (var i = 0; i < length; ++i) {
+            for (let i = 0; i < length; ++i) {
                 if (i + clength > length) {
                     break;
                 }
-                var lev_total = 0;
-                var aborted = false;
-                for (var x = 0; x < clength; ++x) {
-                    var lev = levenshtein(path[i + x], contains[x]);
+                let lev_total = 0;
+                let aborted = false;
+                for (let x = 0; x < clength; ++x) {
+                    const lev = levenshtein(path[i + x], contains[x]);
                     if (lev > MAX_LEV_DISTANCE) {
                         aborted = true;
                         break;
@@ -1124,7 +1126,7 @@ window.initSearch = function(rawSearchIndex) {
             if (filter <= NO_TYPE_FILTER || filter === type) return true;
 
             // Match related items
-            var name = itemTypes[type];
+            const name = itemTypes[type];
             switch (itemTypes[filter]) {
                 case "constant":
                     return name === "associatedconstant";
@@ -1154,33 +1156,31 @@ window.initSearch = function(rawSearchIndex) {
         }
 
         function handleAliases(ret, query, filterCrates) {
-            var lowerQuery = query.toLowerCase();
+            const lowerQuery = query.toLowerCase();
             // We separate aliases and crate aliases because we want to have current crate
             // aliases to be before the others in the displayed results.
-            var aliases = [];
-            var crateAliases = [];
+            const aliases = [];
+            const crateAliases = [];
             if (filterCrates !== null) {
                 if (ALIASES[filterCrates] && ALIASES[filterCrates][lowerQuery]) {
-                    var query_aliases = ALIASES[filterCrates][lowerQuery];
-                    var len = query_aliases.length;
-                    for (var i = 0; i < len; ++i) {
-                        aliases.push(createAliasFromItem(searchIndex[query_aliases[i]]));
+                    const query_aliases = ALIASES[filterCrates][lowerQuery];
+                    for (const alias of query_aliases) {
+                        aliases.push(createAliasFromItem(searchIndex[alias]));
                     }
                 }
             } else {
                 Object.keys(ALIASES).forEach(function(crate) {
                     if (ALIASES[crate][lowerQuery]) {
-                        var pushTo = crate === window.currentCrate ? crateAliases : aliases;
-                        var query_aliases = ALIASES[crate][lowerQuery];
-                        var len = query_aliases.length;
-                        for (var i = 0; i < len; ++i) {
-                            pushTo.push(createAliasFromItem(searchIndex[query_aliases[i]]));
+                        const pushTo = crate === window.currentCrate ? crateAliases : aliases;
+                        const query_aliases = ALIASES[crate][lowerQuery];
+                        for (const alias of query_aliases) {
+                            pushTo.push(createAliasFromItem(searchIndex[alias]));
                         }
                     }
                 });
             }
 
-            var sortFunc = function(aaa, bbb) {
+            const sortFunc = function(aaa, bbb) {
                 if (aaa.path < bbb.path) {
                     return 1;
                 } else if (aaa.path === bbb.path) {
@@ -1191,9 +1191,9 @@ window.initSearch = function(rawSearchIndex) {
             crateAliases.sort(sortFunc);
             aliases.sort(sortFunc);
 
-            var pushFunc = function(alias) {
+            const pushFunc = function(alias) {
                 alias.alias = query;
-                var res = buildHrefAndPath(alias);
+                const res = buildHrefAndPath(alias);
                 alias.displayPath = pathSplitter(res[0]);
                 alias.fullPath = alias.displayPath + alias.name;
                 alias.href = res[1];
@@ -1230,7 +1230,7 @@ window.initSearch = function(rawSearchIndex) {
         function addIntoResults(results, fullId, id, index, lev) {
             if (lev === 0 || (!parsedQuery.literalSearch && lev <= MAX_LEV_DISTANCE)) {
                 if (results[fullId] !== undefined) {
-                    var result = results[fullId];
+                    const result = results[fullId];
                     if (result.dontValidate || result.lev <= lev) {
                         return;
                     }
@@ -1270,11 +1270,11 @@ window.initSearch = function(rawSearchIndex) {
             if (!row || (filterCrates !== null && row.crate !== filterCrates)) {
                 return;
             }
-            var lev, lev_add = 0, index = -1;
-            var fullId = row.id;
+            let lev, lev_add = 0, index = -1;
+            const fullId = row.id;
 
-            var in_args = findArg(row, elem, parsedQuery.typeFilter);
-            var returned = checkReturned(row, elem, parsedQuery.typeFilter);
+            const in_args = findArg(row, elem, parsedQuery.typeFilter);
+            const returned = checkReturned(row, elem, parsedQuery.typeFilter);
 
             addIntoResults(results_in_args, fullId, pos, index, in_args);
             addIntoResults(results_returned, fullId, pos, index, returned);
@@ -1282,7 +1282,7 @@ window.initSearch = function(rawSearchIndex) {
             if (!typePassesFilter(parsedQuery.typeFilter, row.ty)) {
                 return;
             }
-            var searchWord = searchWords[pos];
+            const searchWord = searchWords[pos];
 
             if (parsedQuery.literalSearch) {
                 if (searchWord === elem.name) {
@@ -1352,16 +1352,14 @@ window.initSearch = function(rawSearchIndex) {
                 return;
             }
 
-            var totalLev = 0;
-            var nbLev = 0;
-            var lev;
+            let totalLev = 0;
+            let nbLev = 0;
 
             // If the result is too "bad", we return false and it ends this search.
             function checkArgs(elems, callback) {
-                for (var i = 0, len = elems.length; i < len; ++i) {
-                    var elem = elems[i];
+                for (const elem of elems) {
                     // There is more than one parameter to the query so all checks should be "exact"
-                    lev = callback(row, elem, NO_TYPE_FILTER);
+                    const lev = callback(row, elem, NO_TYPE_FILTER);
                     if (lev <= 1) {
                         nbLev += 1;
                         totalLev += lev;
@@ -1381,12 +1379,12 @@ window.initSearch = function(rawSearchIndex) {
             if (nbLev === 0) {
                 return;
             }
-            lev = Math.round(totalLev / nbLev);
+            const lev = Math.round(totalLev / nbLev);
             addIntoResults(results, row.id, pos, 0, lev);
         }
 
         function innerRunQuery() {
-            var elem, i, nSearchWords, in_returned, row;
+            let elem, i, nSearchWords, in_returned, row;
 
             if (parsedQuery.foundElems === 1) {
                 if (parsedQuery.elems.length === 1) {
@@ -1413,7 +1411,7 @@ window.initSearch = function(rawSearchIndex) {
                     }
                 }
             } else if (parsedQuery.foundElems > 0) {
-                var container = results_others;
+                let container = results_others;
                 // In the special case where only a "returned" information is available, we want to
                 // put the information into the "results_returned" dict.
                 if (parsedQuery.returned.length !== 0 && parsedQuery.elems.length === 0) {
@@ -1429,7 +1427,7 @@ window.initSearch = function(rawSearchIndex) {
             innerRunQuery();
         }
 
-        var ret = createQueryResults(
+        const ret = createQueryResults(
             sortResults(results_in_args, true),
             sortResults(results_returned, true),
             sortResults(results_others, false),
@@ -1462,18 +1460,18 @@ window.initSearch = function(rawSearchIndex) {
         if (!keys || !keys.length) {
             return true;
         }
-        for (var i = 0, len = keys.length; i < len; ++i) {
+        for (const key of keys) {
             // each check is for validation so we negate the conditions and invalidate
             if (!(
                 // check for an exact name match
-                name.indexOf(keys[i]) > -1 ||
+                name.indexOf(key) > -1 ||
                 // then an exact path match
-                path.indexOf(keys[i]) > -1 ||
+                path.indexOf(key) > -1 ||
                 // next if there is a parent, check for exact parent match
                 (parent !== undefined && parent.name !== undefined &&
-                    parent.name.toLowerCase().indexOf(keys[i]) > -1) ||
+                    parent.name.toLowerCase().indexOf(key) > -1) ||
                 // lastly check to see if the name was a levenshtein match
-                levenshtein(name, keys[i]) <= MAX_LEV_DISTANCE)) {
+                levenshtein(name, key) <= MAX_LEV_DISTANCE)) {
                 return false;
             }
         }
@@ -1481,7 +1479,7 @@ window.initSearch = function(rawSearchIndex) {
     }
 
     function nextTab(direction) {
-        var next = (searchState.currentTab + direction + 3) % searchState.focusedByTab.length;
+        const next = (searchState.currentTab + direction + 3) % searchState.focusedByTab.length;
         searchState.focusedByTab[searchState.currentTab] = document.activeElement;
         printTab(next);
         focusSearchResult();
@@ -1490,7 +1488,7 @@ window.initSearch = function(rawSearchIndex) {
     // Focus the first search result on the active tab, or the result that
     // was focused last time this tab was active.
     function focusSearchResult() {
-        var target = searchState.focusedByTab[searchState.currentTab] ||
+        const target = searchState.focusedByTab[searchState.currentTab] ||
             document.querySelectorAll(".search-results.active a").item(0) ||
             document.querySelectorAll("#titles > button").item(searchState.currentTab);
         if (target) {
@@ -1499,11 +1497,11 @@ window.initSearch = function(rawSearchIndex) {
     }
 
     function buildHrefAndPath(item) {
-        var displayPath;
-        var href;
-        var type = itemTypes[item.ty];
-        var name = item.name;
-        var path = item.path;
+        let displayPath;
+        let href;
+        const type = itemTypes[item.ty];
+        const name = item.name;
+        let path = item.path;
 
         if (type === "mod") {
             displayPath = path + "::";
@@ -1517,19 +1515,19 @@ window.initSearch = function(rawSearchIndex) {
             displayPath = "";
             href = window.rootPath + name + "/index.html";
         } else if (item.parent !== undefined) {
-            var myparent = item.parent;
-            var anchor = "#" + type + "." + name;
-            var parentType = itemTypes[myparent.ty];
-            var pageType = parentType;
-            var pageName = myparent.name;
+            const myparent = item.parent;
+            let anchor = "#" + type + "." + name;
+            const parentType = itemTypes[myparent.ty];
+            let pageType = parentType;
+            let pageName = myparent.name;
 
             if (parentType === "primitive") {
                 displayPath = myparent.name + "::";
             } else if (type === "structfield" && parentType === "variant") {
                 // Structfields belonging to variants are special: the
                 // final path element is the enum name.
-                var enumNameIdx = item.path.lastIndexOf("::");
-                var enumName = item.path.substr(enumNameIdx + 2);
+                const enumNameIdx = item.path.lastIndexOf("::");
+                const enumName = item.path.substr(enumNameIdx + 2);
                 path = item.path.substr(0, enumNameIdx);
                 displayPath = path + "::" + enumName + "::" + myparent.name + "::";
                 anchor = "#variant." + myparent.name + ".field." + name;
@@ -1551,13 +1549,13 @@ window.initSearch = function(rawSearchIndex) {
     }
 
     function escape(content) {
-        var h1 = document.createElement("h1");
+        const h1 = document.createElement("h1");
         h1.textContent = content;
         return h1.innerHTML;
     }
 
     function pathSplitter(path) {
-        var tmp = "<span>" + path.replace(/::/g, "::</span><span>");
+        const tmp = "<span>" + path.replace(/::/g, "::</span><span>");
         if (tmp.endsWith("<span>")) {
             return tmp.slice(0, tmp.length - 6);
         }
@@ -1571,42 +1569,42 @@ window.initSearch = function(rawSearchIndex) {
      * @param {boolean}     display - True if this is the active tab
      */
     function addTab(array, query, display) {
-        var extraClass = "";
+        let extraClass = "";
         if (display === true) {
             extraClass = " active";
         }
 
-        var output = document.createElement("div");
-        var length = 0;
+        const output = document.createElement("div");
+        let length = 0;
         if (array.length > 0) {
             output.className = "search-results " + extraClass;
 
             array.forEach(function(item) {
-                var name = item.name;
-                var type = itemTypes[item.ty];
+                const name = item.name;
+                const type = itemTypes[item.ty];
 
                 length += 1;
 
-                var extra = "";
+                let extra = "";
                 if (type === "primitive") {
                     extra = " <i>(primitive type)</i>";
                 } else if (type === "keyword") {
                     extra = " <i>(keyword)</i>";
                 }
 
-                var link = document.createElement("a");
+                const link = document.createElement("a");
                 link.className = "result-" + type;
                 link.href = item.href;
 
-                var wrapper = document.createElement("div");
-                var resultName = document.createElement("div");
+                const wrapper = document.createElement("div");
+                const resultName = document.createElement("div");
                 resultName.className = "result-name";
 
                 if (item.is_alias) {
-                    var alias = document.createElement("span");
+                    const alias = document.createElement("span");
                     alias.className = "alias";
 
-                    var bold = document.createElement("b");
+                    const bold = document.createElement("b");
                     bold.innerText = item.alias;
                     alias.appendChild(bold);
 
@@ -1621,9 +1619,9 @@ window.initSearch = function(rawSearchIndex) {
                     item.displayPath + "<span class=\"" + type + "\">" + name + extra + "</span>");
                 wrapper.appendChild(resultName);
 
-                var description = document.createElement("div");
+                const description = document.createElement("div");
                 description.className = "desc";
-                var spanDesc = document.createElement("span");
+                const spanDesc = document.createElement("span");
                 spanDesc.insertAdjacentHTML("beforeend", item.desc);
 
                 description.appendChild(spanDesc);
@@ -1664,7 +1662,7 @@ window.initSearch = function(rawSearchIndex) {
      * @param {string} filterCrates
      */
     function showResults(results, go_to_first, filterCrates) {
-        var search = searchState.outputElement();
+        const search = searchState.outputElement();
         if (go_to_first || (results.others.length === 1
             && getSettingValue("go-to-only-result") === "true"
             // By default, the search DOM element is "empty" (meaning it has no children not
@@ -1672,7 +1670,7 @@ window.initSearch = function(rawSearchIndex) {
             // ESC or empty the search input (which also "cancels" the search).
             && (!search.firstChild || search.firstChild.innerText !== searchState.loadingText)))
         {
-            var elem = document.createElement("a");
+            const elem = document.createElement("a");
             elem.href = results.others[0].href;
             removeClass(elem, "active");
             // For firefox, we need the element to be in the DOM so it can be clicked.
@@ -1686,14 +1684,14 @@ window.initSearch = function(rawSearchIndex) {
 
         currentResults = results.query.userQuery;
 
-        var ret_others = addTab(results.others, results.query, true);
-        var ret_in_args = addTab(results.in_args, results.query, false);
-        var ret_returned = addTab(results.returned, results.query, false);
+        const ret_others = addTab(results.others, results.query, true);
+        const ret_in_args = addTab(results.in_args, results.query, false);
+        const ret_returned = addTab(results.returned, results.query, false);
 
         // Navigate to the relevant tab if the current tab is empty, like in case users search
         // for "-> String". If they had selected another tab previously, they have to click on
         // it again.
-        var currentTab = searchState.currentTab;
+        let currentTab = searchState.currentTab;
         if ((currentTab === 0 && ret_others[1] === 0) ||
                 (currentTab === 1 && ret_in_args[1] === 0) ||
                 (currentTab === 2 && ret_returned[1] === 0)) {
@@ -1709,18 +1707,18 @@ window.initSearch = function(rawSearchIndex) {
         let crates = "";
         if (window.ALL_CRATES.length > 1) {
             crates = ` in <select id="crate-search"><option value="All crates">All crates</option>`;
-            for (let c of window.ALL_CRATES) {
+            for (const c of window.ALL_CRATES) {
                 crates += `<option value="${c}" ${c == filterCrates && "selected"}>${c}</option>`;
             }
             crates += `</select>`;
         }
 
-        var typeFilter = "";
+        let typeFilter = "";
         if (results.query.typeFilter !== NO_TYPE_FILTER) {
             typeFilter = " (type: " + escape(itemTypes[results.query.typeFilter]) + ")";
         }
 
-        var output = `<div id="search-settings">` +
+        let output = `<div id="search-settings">` +
             `<h1 class="search-results-title">Results for ${escape(results.query.userQuery)}` +
             `${typeFilter}</h1> in ${crates} </div>`;
         if (results.query.error !== null) {
@@ -1732,14 +1730,14 @@ window.initSearch = function(rawSearchIndex) {
             makeTabHeader(2, "In Return Types", ret_returned[1]) +
             "</div>";
 
-        var resultsElem = document.createElement("div");
+        const resultsElem = document.createElement("div");
         resultsElem.id = "results";
         resultsElem.appendChild(ret_others[0]);
         resultsElem.appendChild(ret_in_args[0]);
         resultsElem.appendChild(ret_returned[0]);
 
         search.innerHTML = output;
-        let crateSearch = document.getElementById("crate-search");
+        const crateSearch = document.getElementById("crate-search");
         if (crateSearch) {
             crateSearch.addEventListener("input", updateCrate);
         }
@@ -1747,7 +1745,7 @@ window.initSearch = function(rawSearchIndex) {
         // Reset focused elements.
         searchState.focusedByTab = [null, null, null];
         searchState.showResults(search);
-        var elems = document.getElementById("titles").childNodes;
+        const elems = document.getElementById("titles").childNodes;
         elems[0].onclick = function() { printTab(0); };
         elems[1].onclick = function() { printTab(1); };
         elems[2].onclick = function() { printTab(2); };
@@ -1761,8 +1759,8 @@ window.initSearch = function(rawSearchIndex) {
      * @param {boolean} [forced]
      */
     function search(e, forced) {
-        var params = searchState.getQueryStringParams();
-        var query = parseQuery(searchState.input.value.trim());
+        const params = searchState.getQueryStringParams();
+        const query = parseQuery(searchState.input.value.trim());
 
         if (e) {
             e.preventDefault();
@@ -1775,7 +1773,7 @@ window.initSearch = function(rawSearchIndex) {
             return;
         }
 
-        var filterCrates = getFilterCrates();
+        let filterCrates = getFilterCrates();
 
         // In case we have no information about the saved crate and there is a URL query parameter,
         // we override it with the URL query parameter.
@@ -1788,8 +1786,9 @@ window.initSearch = function(rawSearchIndex) {
 
         // Because searching is incremental by character, only the most
         // recent search query is added to the browser history.
-        if (searchState.browserSupportsHistoryApi()) {
-            var newURL = buildUrl(query.original, filterCrates);
+        if (browserSupportsHistoryApi()) {
+            const newURL = buildUrl(query.original, filterCrates);
+
             if (!history.state && !params.search) {
                 history.pushState(null, "", newURL);
             } else {
@@ -1808,17 +1807,17 @@ window.initSearch = function(rawSearchIndex) {
         /**
          * @type {Array<string>}
          */
-        var searchWords = [];
-        var i, word;
-        var currentIndex = 0;
-        var id = 0;
+        const searchWords = [];
+        let i, word;
+        let currentIndex = 0;
+        let id = 0;
 
-        for (var crate in rawSearchIndex) {
+        for (const crate in rawSearchIndex) {
             if (!hasOwnPropertyRustdoc(rawSearchIndex, crate)) {
                 continue;
             }
 
-            var crateSize = 0;
+            let crateSize = 0;
 
             /**
              * The raw search data for a given crate. `n`, `t`, `d`, and `q`, `i`, and `f`
@@ -1850,13 +1849,13 @@ window.initSearch = function(rawSearchIndex) {
              *   p: Array<Object>,
              * }}
              */
-            var crateCorpus = rawSearchIndex[crate];
+            const crateCorpus = rawSearchIndex[crate];
 
             searchWords.push(crate);
             // This object should have exactly the same set of fields as the "row"
             // object defined below. Your JavaScript runtime will thank you.
             // https://mathiasbynens.be/notes/shapes-ics
-            var crateRow = {
+            const crateRow = {
                 crate: crate,
                 ty: 1, // == ExternCrate
                 name: crate,
@@ -1872,26 +1871,26 @@ window.initSearch = function(rawSearchIndex) {
             currentIndex += 1;
 
             // an array of (Number) item types
-            var itemTypes = crateCorpus.t;
+            const itemTypes = crateCorpus.t;
             // an array of (String) item names
-            var itemNames = crateCorpus.n;
+            const itemNames = crateCorpus.n;
             // an array of (String) full paths (or empty string for previous path)
-            var itemPaths = crateCorpus.q;
+            const itemPaths = crateCorpus.q;
             // an array of (String) descriptions
-            var itemDescs = crateCorpus.d;
+            const itemDescs = crateCorpus.d;
             // an array of (Number) the parent path index + 1 to `paths`, or 0 if none
-            var itemParentIdxs = crateCorpus.i;
+            const itemParentIdxs = crateCorpus.i;
             // an array of (Object | null) the type of the function, if any
-            var itemFunctionSearchTypes = crateCorpus.f;
+            const itemFunctionSearchTypes = crateCorpus.f;
             // an array of [(Number) item type,
             //              (String) name]
-            var paths = crateCorpus.p;
+            const paths = crateCorpus.p;
             // an array of [(String) alias name
             //             [Number] index to items]
-            var aliases = crateCorpus.a;
+            const aliases = crateCorpus.a;
 
             // convert `rawPaths` entries into object form
-            var len = paths.length;
+            let len = paths.length;
             for (i = 0; i < len; ++i) {
                 paths[i] = {ty: paths[i][0], name: paths[i][1]};
             }
@@ -1904,7 +1903,7 @@ window.initSearch = function(rawSearchIndex) {
             // all other search operations have access to this cached data for
             // faster analysis operations
             len = itemTypes.length;
-            var lastPath = "";
+            let lastPath = "";
             for (i = 0; i < len; ++i) {
                 // This object should have exactly the same set of fields as the "crateRow"
                 // object defined above.
@@ -1915,7 +1914,7 @@ window.initSearch = function(rawSearchIndex) {
                     word = "";
                     searchWords.push("");
                 }
-                var row = {
+                const row = {
                     crate: crate,
                     ty: itemTypes[i],
                     name: itemNames[i],
@@ -1934,8 +1933,7 @@ window.initSearch = function(rawSearchIndex) {
 
             if (aliases) {
                 ALIASES[crate] = {};
-                var j, local_aliases;
-                for (var alias_name in aliases) {
+                for (const alias_name in aliases) {
                     if (!hasOwnPropertyRustdoc(aliases, alias_name)) {
                         continue;
                     }
@@ -1943,9 +1941,8 @@ window.initSearch = function(rawSearchIndex) {
                     if (!hasOwnPropertyRustdoc(ALIASES[crate], alias_name)) {
                         ALIASES[crate][alias_name] = [];
                     }
-                    local_aliases = aliases[alias_name];
-                    for (j = 0, len = local_aliases.length; j < len; ++j) {
-                        ALIASES[crate][alias_name].push(local_aliases[j] + currentIndex);
+                    for (const local_alias of aliases[alias_name]) {
+                        ALIASES[crate][alias_name].push(local_alias + currentIndex);
                     }
                 }
             }
@@ -1965,14 +1962,13 @@ window.initSearch = function(rawSearchIndex) {
     }
 
     function putBackSearch() {
-        var search_input = searchState.input;
+        const search_input = searchState.input;
         if (!searchState.input) {
             return;
         }
-        var search = searchState.outputElement();
-        if (search_input.value !== "" && hasClass(search, "hidden")) {
-            searchState.showResults(search);
-            if (searchState.browserSupportsHistoryApi()) {
+        if (search_input.value !== "" && !searchState.isDisplayed()) {
+            searchState.showResults();
+            if (browserSupportsHistoryApi()) {
                 history.replaceState(null, "",
                     buildUrl(search_input.value, getFilterCrates()));
             }
@@ -1981,10 +1977,10 @@ window.initSearch = function(rawSearchIndex) {
     }
 
     function registerSearchEvents() {
-        var searchAfter500ms = function() {
+        const searchAfter500ms = function() {
             searchState.clearInputTimeout();
             if (searchState.input.value.length === 0) {
-                if (searchState.browserSupportsHistoryApi()) {
+                if (browserSupportsHistoryApi()) {
                     history.replaceState(null, window.currentCrate + " - Rust",
                         getNakedUrl() + window.location.hash);
                 }
@@ -2019,7 +2015,7 @@ window.initSearch = function(rawSearchIndex) {
             // up and down arrow select next/previous search result, or the
             // search box if we're already at the top.
             if (e.which === 38) { // up
-                var previous = document.activeElement.previousElementSibling;
+                const previous = document.activeElement.previousElementSibling;
                 if (previous) {
                     previous.focus();
                 } else {
@@ -2027,11 +2023,11 @@ window.initSearch = function(rawSearchIndex) {
                 }
                 e.preventDefault();
             } else if (e.which === 40) { // down
-                var next = document.activeElement.nextElementSibling;
+                const next = document.activeElement.nextElementSibling;
                 if (next) {
                     next.focus();
                 }
-                var rect = document.activeElement.getBoundingClientRect();
+                const rect = document.activeElement.getBoundingClientRect();
                 if (window.innerHeight - rect.bottom < rect.height) {
                     window.scrollBy(0, rect.height);
                 }
@@ -2062,12 +2058,12 @@ window.initSearch = function(rawSearchIndex) {
 
         // Push and pop states are used to add search results to the browser
         // history.
-        if (searchState.browserSupportsHistoryApi()) {
+        if (browserSupportsHistoryApi()) {
             // Store the previous <title> so we can revert back to it later.
-            var previousTitle = document.title;
+            const previousTitle = document.title;
 
             window.addEventListener("popstate", function(e) {
-                var params = searchState.getQueryStringParams();
+                const params = searchState.getQueryStringParams();
                 // Revert to the previous title manually since the History
                 // API ignores the title parameter.
                 document.title = previousTitle;
@@ -2103,7 +2099,7 @@ window.initSearch = function(rawSearchIndex) {
         // that try to sync state between the URL and the search input. To work around it,
         // do a small amount of re-init on page show.
         window.onpageshow = function(){
-            var qSearch = searchState.getQueryStringParams().search;
+            const qSearch = searchState.getQueryStringParams().search;
             if (searchState.input.value === "" && qSearch) {
                 searchState.input.value = qSearch;
             }
@@ -2114,8 +2110,8 @@ window.initSearch = function(rawSearchIndex) {
     function updateCrate(ev) {
         if (ev.target.value === "All crates") {
             // If we don't remove it from the URL, it'll be picked up again by the search.
-            var params = searchState.getQueryStringParams();
-            var query = searchState.input.value.trim();
+            const params = searchState.getQueryStringParams();
+            const query = searchState.input.value.trim();
             if (!history.state && !params.search) {
                 history.pushState(null, "", buildUrl(query, null));
             } else {
@@ -2129,7 +2125,10 @@ window.initSearch = function(rawSearchIndex) {
         search(undefined, true);
     }
 
-    searchWords = buildIndex(rawSearchIndex);
+    /**
+     *  @type {Array<string>}
+     */
+    const searchWords = buildIndex(rawSearchIndex);
     registerSearchEvents();
 
     function runSearchIfNeeded() {
index 139fa5c9a11a62e4db3586a604a1dd849c7a729c..a2f8d56fb320b8b3fa8198eecbea0bd1bca7477e 100644 (file)
@@ -1,8 +1,14 @@
+/* eslint-env es6 */
+/* eslint no-var: "error" */
+/* eslint prefer-const: "error" */
 // Local js definitions:
-/* global getSettingValue, getVirtualKey, onEachLazy, updateLocalStorage, updateSystemTheme */
-/* global addClass, removeClass */
+/* global getSettingValue, getVirtualKey, updateLocalStorage, updateSystemTheme, loadCss */
+/* global addClass, removeClass, onEach, onEachLazy, NOT_DISPLAYED_ID */
+/* global MAIN_ID, getVar, getSettingsButton, switchDisplayedElement, getNotDisplayedElem */
 
 (function () {
+    const isSettingsPage = window.location.pathname.endsWith("/settings.html");
+
     function changeSetting(settingName, value) {
         updateLocalStorage(settingName, value);
 
         }
     }
 
-    function setEvents() {
+    function setEvents(settingsElement) {
         updateLightAndDark();
-        onEachLazy(document.getElementsByClassName("slider"), function(elem) {
-            var toggle = elem.previousElementSibling;
-            var settingId = toggle.id;
-            var settingValue = getSettingValue(settingId);
+        onEachLazy(settingsElement.getElementsByClassName("slider"), function(elem) {
+            const toggle = elem.previousElementSibling;
+            const settingId = toggle.id;
+            const settingValue = getSettingValue(settingId);
             if (settingValue !== null) {
                 toggle.checked = settingValue === "true";
             }
             toggle.onkeyup = handleKey;
             toggle.onkeyrelease = handleKey;
         });
-        onEachLazy(document.getElementsByClassName("select-wrapper"), function(elem) {
-            var select = elem.getElementsByTagName("select")[0];
-            var settingId = select.id;
-            var settingValue = getSettingValue(settingId);
+        onEachLazy(settingsElement.getElementsByClassName("select-wrapper"), function(elem) {
+            const select = elem.getElementsByTagName("select")[0];
+            const settingId = select.id;
+            const settingValue = getSettingValue(settingId);
             if (settingValue !== null) {
                 select.value = settingValue;
             }
@@ -78,7 +84,7 @@
                 changeSetting(this.id, this.value);
             };
         });
-        onEachLazy(document.querySelectorAll("input[type=\"radio\"]"), function(elem) {
+        onEachLazy(settingsElement.querySelectorAll("input[type=\"radio\"]"), function(elem) {
             const settingId = elem.name;
             const settingValue = getSettingValue(settingId);
             if (settingValue !== null && settingValue !== "null") {
                 changeSetting(ev.target.name, ev.target.value);
             });
         });
-        document.getElementById("back").addEventListener("click", function() {
-            history.back();
-        });
     }
 
-    window.addEventListener("DOMContentLoaded", setEvents);
+    /**
+     * This function builds the sections inside the "settings page". It takes a `settings` list
+     * as argument which describes each setting and how to render it. It returns a string
+     * representing the raw HTML.
+     *
+     * @param {Array<Object>} settings
+     *
+     * @return {string}
+     */
+    function buildSettingsPageSections(settings) {
+        let output = "";
+
+        for (const setting of settings) {
+            output += `<div class="setting-line">`;
+            const js_data_name = setting["js_name"];
+            const setting_name = setting["name"];
+
+            if (setting["options"] !== undefined) {
+                // This is a select setting.
+                output += `<div class="radio-line" id="${js_data_name}">\
+                        <span class="setting-name">${setting_name}</span>\
+                        <div class="choices">`;
+                onEach(setting["options"], function(option) {
+                    const checked = option === setting["default"] ? " checked" : "";
+
+                    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}\
+                         </label>`;
+                });
+                output += "</div></div>";
+            } else {
+                // This is a toggle.
+                const checked = setting["default"] === true ? " checked" : "";
+                output += `
+                    <label class="toggle">
+                        <input type="checkbox" id="${js_data_name}"${checked}>
+                        <span class="slider"></span>
+                    </label>
+                    <div>${setting_name}</div>`;
+            }
+            output += "</div>";
+        }
+        return output;
+    }
+
+    /**
+     * This function builds the "settings page" and returns the generated HTML element.
+     *
+     * @return {HTMLElement}
+     */
+    function buildSettingsPage() {
+        const themes = getVar("themes").split(",");
+        const settings = [
+            {
+                "name": "Use system theme",
+                "js_name": "use-system-theme",
+                "default": true,
+            },
+            {
+                "name": "Theme",
+                "js_name": "theme",
+                "default": "light",
+                "options": themes,
+            },
+            {
+                "name": "Preferred light theme",
+                "js_name": "preferred-light-theme",
+                "default": "light",
+                "options": themes,
+            },
+            {
+                "name": "Preferred dark theme",
+                "js_name": "preferred-dark-theme",
+                "default": "dark",
+                "options": themes,
+            },
+            {
+                "name": "Auto-hide item contents for large items",
+                "js_name": "auto-hide-large-items",
+                "default": true,
+            },
+            {
+                "name": "Auto-hide item methods' documentation",
+                "js_name": "auto-hide-method-docs",
+                "default": false,
+            },
+            {
+                "name": "Auto-hide trait implementation documentation",
+                "js_name": "auto-hide-trait-implementations",
+                "default": false,
+            },
+            {
+                "name": "Directly go to item in search if there is only one result",
+                "js_name": "go-to-only-result",
+                "default": false,
+            },
+            {
+                "name": "Show line numbers on code examples",
+                "js_name": "line-numbers",
+                "default": false,
+            },
+            {
+                "name": "Disable keyboard shortcuts",
+                "js_name": "disable-shortcuts",
+                "default": false,
+            },
+        ];
+
+        // First, we add the settings.css file.
+        loadCss("settings");
+
+        // Then we build the DOM.
+        const el = document.createElement("section");
+        el.id = "settings";
+        let innerHTML = `
+            <div class="main-heading">
+                <h1 class="fqn">
+                    <span class="in-band">Rustdoc settings</span>
+                </h1>
+                <span class="out-of-band">`;
+
+        if (isSettingsPage) {
+            innerHTML +=
+                `<a id="back" href="javascript:void(0)" onclick="history.back();">Back</a>`;
+        } else {
+            innerHTML +=
+                `<a id="back" href="javascript:void(0)" onclick="switchDisplayedElement(null);">\
+                    Back</a>`;
+        }
+        innerHTML += `</span>
+            </div>
+            <div class="settings">${buildSettingsPageSections(settings)}</div>`;
+
+        el.innerHTML = innerHTML;
+
+        if (isSettingsPage) {
+            document.getElementById(MAIN_ID).appendChild(el);
+        } else {
+            getNotDisplayedElem().appendChild(el);
+        }
+        return el;
+    }
+
+    const settingsMenu = buildSettingsPage();
+
+    if (isSettingsPage) {
+        // We replace the existing "onclick" callback to do nothing if clicked.
+        getSettingsButton().onclick = function(event) {
+            event.preventDefault();
+        };
+    } else {
+        // We replace the existing "onclick" callback.
+        const settingsButton = getSettingsButton();
+        settingsButton.onclick = function(event) {
+            event.preventDefault();
+            if (settingsMenu.parentElement.id === NOT_DISPLAYED_ID) {
+                switchDisplayedElement(settingsMenu);
+            } else {
+                window.hideSettings();
+            }
+        };
+        window.hideSettings = function() {
+            switchDisplayedElement(null);
+        };
+    }
+
+    // We now wait a bit for the web browser to end re-computing the DOM...
+    setTimeout(function() {
+        setEvents(settingsMenu);
+        // The setting menu is already displayed if we're on the settings page.
+        if (!isSettingsPage) {
+            switchDisplayedElement(settingsMenu);
+        }
+    }, 0);
 })();
index aa77e62ba5acb03e4a4527f248d9ff9f9a8f9cef..6aee0da69f8de58898c71f97c40af9b817c8e2c0 100644 (file)
@@ -1,21 +1,25 @@
+/* eslint-env es6 */
+/* eslint no-var: "error" */
+/* eslint prefer-const: "error" */
+
 // From rust:
 /* global search, sourcesIndex */
 
 // Local js definitions:
-/* global addClass, getCurrentValue, hasClass, onEachLazy, removeClass, searchState */
+/* global addClass, getCurrentValue, hasClass, onEachLazy, removeClass, browserSupportsHistoryApi */
 /* global updateLocalStorage */
 (function() {
 
 function getCurrentFilePath() {
-    var parts = window.location.pathname.split("/");
-    var rootPathParts = window.rootPath.split("/");
+    const parts = window.location.pathname.split("/");
+    const rootPathParts = window.rootPath.split("/");
 
-    for (var i = 0, len = rootPathParts.length; i < len; ++i) {
-        if (rootPathParts[i] === "..") {
+    for (const rootPathPart of rootPathParts) {
+        if (rootPathPart === "..") {
             parts.pop();
         }
     }
-    var file = window.location.pathname.substring(parts.join("/").length);
+    let file = window.location.pathname.substring(parts.join("/").length);
     if (file.startsWith("/")) {
         file = file.substring(1);
     }
@@ -23,7 +27,7 @@ function getCurrentFilePath() {
 }
 
 function createDirEntry(elem, parent, fullPath, currentFile, hasFoundFile) {
-    var name = document.createElement("div");
+    const name = document.createElement("div");
     name.className = "name";
 
     fullPath += elem["name"] + "/";
@@ -37,16 +41,13 @@ function createDirEntry(elem, parent, fullPath, currentFile, hasFoundFile) {
     };
     name.innerText = elem["name"];
 
-    var i, len;
-
-    var children = document.createElement("div");
+    const children = document.createElement("div");
     children.className = "children";
-    var folders = document.createElement("div");
+    const folders = document.createElement("div");
     folders.className = "folders";
     if (elem.dirs) {
-        for (i = 0, len = elem.dirs.length; i < len; ++i) {
-            if (createDirEntry(elem.dirs[i], folders, fullPath, currentFile,
-                               hasFoundFile)) {
+        for (const dir of elem.dirs) {
+            if (createDirEntry(dir, folders, fullPath, currentFile, hasFoundFile)) {
                 addClass(name, "expand");
                 hasFoundFile = true;
             }
@@ -54,14 +55,14 @@ function createDirEntry(elem, parent, fullPath, currentFile, hasFoundFile) {
     }
     children.appendChild(folders);
 
-    var files = document.createElement("div");
+    const files = document.createElement("div");
     files.className = "files";
     if (elem.files) {
-        for (i = 0, len = elem.files.length; i < len; ++i) {
-            var file = document.createElement("a");
-            file.innerText = elem.files[i];
-            file.href = window.rootPath + "src/" + fullPath + elem.files[i] + ".html";
-            if (!hasFoundFile && currentFile === fullPath + elem.files[i]) {
+        for (const file_text of elem.files) {
+            const file = document.createElement("a");
+            file.innerText = file_text;
+            file.href = window.rootPath + "src/" + fullPath + file_text + ".html";
+            if (!hasFoundFile && currentFile === fullPath + file_text) {
                 file.className = "selected";
                 addClass(name, "expand");
                 hasFoundFile = true;
@@ -77,8 +78,8 @@ function createDirEntry(elem, parent, fullPath, currentFile, hasFoundFile) {
 }
 
 function toggleSidebar() {
-    var sidebar = document.querySelector("nav.sidebar");
-    var child = this.children[0];
+    const sidebar = document.querySelector("nav.sidebar");
+    const child = this.children[0];
     if (child.innerText === ">") {
         sidebar.classList.add("expanded");
         child.innerText = "<";
@@ -91,11 +92,11 @@ function toggleSidebar() {
 }
 
 function createSidebarToggle() {
-    var sidebarToggle = document.createElement("div");
+    const sidebarToggle = document.createElement("div");
     sidebarToggle.id = "sidebar-toggle";
     sidebarToggle.onclick = toggleSidebar;
 
-    var inner = document.createElement("div");
+    const inner = document.createElement("div");
 
     if (getCurrentValue("source-sidebar-show") === "true") {
         inner.innerText = "<";
@@ -113,12 +114,12 @@ function createSourceSidebar() {
     if (!window.rootPath.endsWith("/")) {
         window.rootPath += "/";
     }
-    var container = document.querySelector("nav.sidebar");
+    const container = document.querySelector("nav.sidebar");
 
-    var sidebarToggle = createSidebarToggle();
+    const sidebarToggle = createSidebarToggle();
     container.insertBefore(sidebarToggle, container.firstChild);
 
-    var sidebar = document.createElement("div");
+    const sidebar = document.createElement("div");
     sidebar.id = "source-sidebar";
     if (getCurrentValue("source-sidebar-show") !== "true") {
         container.classList.remove("expanded");
@@ -126,10 +127,10 @@ function createSourceSidebar() {
         container.classList.add("expanded");
     }
 
-    var currentFile = getCurrentFilePath();
-    var hasFoundFile = false;
+    const currentFile = getCurrentFilePath();
+    let hasFoundFile = false;
 
-    var title = document.createElement("div");
+    const title = document.createElement("div");
     title.className = "title";
     title.innerText = "Files";
     sidebar.appendChild(title);
@@ -141,13 +142,13 @@ function createSourceSidebar() {
 
     container.appendChild(sidebar);
     // Focus on the current file in the source files sidebar.
-    var selected_elem = sidebar.getElementsByClassName("selected")[0];
+    const selected_elem = sidebar.getElementsByClassName("selected")[0];
     if (typeof selected_elem !== "undefined") {
         selected_elem.focus();
     }
 }
 
-var lineNumbersRegex = /^#?(\d+)(?:-(\d+))?$/;
+const lineNumbersRegex = /^#?(\d+)(?:-(\d+))?$/;
 
 function highlightSourceLines(match) {
     if (typeof match === "undefined") {
@@ -156,21 +157,21 @@ function highlightSourceLines(match) {
     if (!match) {
         return;
     }
-    var from = parseInt(match[1], 10);
-    var to = from;
+    let from = parseInt(match[1], 10);
+    let to = from;
     if (typeof match[2] !== "undefined") {
         to = parseInt(match[2], 10);
     }
     if (to < from) {
-        var tmp = to;
+        const tmp = to;
         to = from;
         from = tmp;
     }
-    var elem = document.getElementById(from);
+    let elem = document.getElementById(from);
     if (!elem) {
         return;
     }
-    var x = document.getElementById(from);
+    const x = document.getElementById(from);
     if (x) {
         x.scrollIntoView();
     }
@@ -179,7 +180,7 @@ function highlightSourceLines(match) {
             removeClass(i_e, "line-highlighted");
         });
     });
-    for (var i = from; i <= to; ++i) {
+    for (let i = from; i <= to; ++i) {
         elem = document.getElementById(i);
         if (!elem) {
             break;
@@ -188,13 +189,13 @@ function highlightSourceLines(match) {
     }
 }
 
-var handleSourceHighlight = (function() {
-    var prev_line_id = 0;
+const handleSourceHighlight = (function() {
+    let prev_line_id = 0;
 
-    var set_fragment = function(name) {
-        var x = window.scrollX,
+    const set_fragment = function(name) {
+        const x = window.scrollX,
             y = window.scrollY;
-        if (searchState.browserSupportsHistoryApi()) {
+        if (browserSupportsHistoryApi()) {
             history.replaceState(null, null, "#" + name);
             highlightSourceLines();
         } else {
@@ -205,13 +206,13 @@ var handleSourceHighlight = (function() {
     };
 
     return function(ev) {
-        var cur_line_id = parseInt(ev.target.id, 10);
+        let cur_line_id = parseInt(ev.target.id, 10);
         ev.preventDefault();
 
         if (ev.shiftKey && prev_line_id) {
             // Swap selection if needed
             if (prev_line_id > cur_line_id) {
-                var tmp = prev_line_id;
+                const tmp = prev_line_id;
                 prev_line_id = cur_line_id;
                 cur_line_id = tmp;
             }
@@ -226,7 +227,7 @@ var handleSourceHighlight = (function() {
 }());
 
 window.addEventListener("hashchange", function() {
-    var match = window.location.hash.match(lineNumbersRegex);
+    const match = window.location.hash.match(lineNumbersRegex);
     if (match) {
         return highlightSourceLines(match);
     }
index ccf3d0a581a171e3fd4dc5e59fd981db5e1a3b25..ae670ed989426ea5ffe146756f5e8d93de75f603 100644 (file)
@@ -1,13 +1,17 @@
-var darkThemes = ["dark", "ayu"];
+/* eslint-env es6 */
+/* eslint no-var: "error" */
+/* eslint prefer-const: "error" */
+
+const darkThemes = ["dark", "ayu"];
 window.currentTheme = document.getElementById("themeStyle");
 window.mainTheme = document.getElementById("mainThemeStyle");
 
-var settingsDataset = (function () {
-    var settingsElement = document.getElementById("default-settings");
+const settingsDataset = (function () {
+    const settingsElement = document.getElementById("default-settings");
     if (settingsElement === null) {
         return null;
     }
-    var dataset = settingsElement.dataset;
+    const dataset = settingsElement.dataset;
     if (dataset === undefined) {
         return null;
     }
@@ -15,14 +19,14 @@ var settingsDataset = (function () {
 })();
 
 function getSettingValue(settingName) {
-    var current = getCurrentValue(settingName);
+    const current = getCurrentValue(settingName);
     if (current !== null) {
         return current;
     }
     if (settingsDataset !== null) {
         // See the comment for `default_settings.into_iter()` etc. in
         // `Options::from_matches` in `librustdoc/config.rs`.
-        var def = settingsDataset[settingName.replace(/-/g,'_')];
+        const def = settingsDataset[settingName.replace(/-/g,'_')];
         if (def !== undefined) {
             return def;
         }
@@ -30,9 +34,9 @@ function getSettingValue(settingName) {
     return null;
 }
 
-var localStoredTheme = getSettingValue("theme");
+const localStoredTheme = getSettingValue("theme");
 
-var savedHref = [];
+const savedHref = [];
 
 // eslint-disable-next-line no-unused-vars
 function hasClass(elem, className) {
@@ -63,17 +67,16 @@ function removeClass(elem, className) {
  */
 function onEach(arr, func, reversed) {
     if (arr && arr.length > 0 && func) {
-        var length = arr.length;
-        var i;
         if (reversed) {
-            for (i = length - 1; i >= 0; --i) {
+            const length = arr.length;
+            for (let i = length - 1; i >= 0; --i) {
                 if (func(arr[i])) {
                     return true;
                 }
             }
         } else {
-            for (i = 0; i < length; ++i) {
-                if (func(arr[i])) {
+            for (const elem of arr) {
+                if (func(elem)) {
                     return true;
                 }
             }
@@ -121,7 +124,7 @@ function getCurrentValue(name) {
 }
 
 function switchTheme(styleElem, mainStyleElem, newTheme, saveTheme) {
-    var newHref = mainStyleElem.href.replace(
+    const newHref = mainStyleElem.href.replace(
         /\/rustdoc([^/]*)\.css/, "/" + newTheme + "$1" + ".css");
 
     // If this new value comes from a system setting or from the previously
@@ -134,7 +137,7 @@ function switchTheme(styleElem, mainStyleElem, newTheme, saveTheme) {
         return;
     }
 
-    var found = false;
+    let found = false;
     if (savedHref.length === 0) {
         onEachLazy(document.getElementsByTagName("link"), function(el) {
             savedHref.push(el.href);
@@ -161,17 +164,17 @@ function useSystemTheme(value) {
     updateLocalStorage("use-system-theme", value);
 
     // update the toggle if we're on the settings page
-    var toggle = document.getElementById("use-system-theme");
+    const toggle = document.getElementById("use-system-theme");
     if (toggle && toggle instanceof HTMLInputElement) {
         toggle.checked = value;
     }
 }
 
-var updateSystemTheme = (function() {
+const updateSystemTheme = (function() {
     if (!window.matchMedia) {
         // fallback to the CSS computed value
         return function() {
-            var cssTheme = getComputedStyle(document.documentElement)
+            const cssTheme = getComputedStyle(document.documentElement)
                 .getPropertyValue('content');
 
             switchTheme(
@@ -184,16 +187,16 @@ var updateSystemTheme = (function() {
     }
 
     // only listen to (prefers-color-scheme: dark) because light is the default
-    var mql = window.matchMedia("(prefers-color-scheme: dark)");
+    const mql = window.matchMedia("(prefers-color-scheme: dark)");
 
     function handlePreferenceChange(mql) {
-        let use = function(theme) {
+        const use = function(theme) {
             switchTheme(window.currentTheme, window.mainTheme, theme, true);
         };
         // maybe the user has disabled the setting in the meantime!
         if (getSettingValue("use-system-theme") !== "false") {
-            var lightTheme = getSettingValue("preferred-light-theme") || "light";
-            var darkTheme = getSettingValue("preferred-dark-theme") || "dark";
+            const lightTheme = getSettingValue("preferred-light-theme") || "light";
+            const darkTheme = getSettingValue("preferred-dark-theme") || "dark";
 
             if (mql.matches) {
                 use(darkTheme);
index 1837e4a3b650ab53efc57d674e75344d9f56441d..bec5c083fed225b7f3afd6fbd55ca5866f2c6a10 100644 (file)
 
 /// Files related to the Fira Sans font.
 crate mod fira_sans {
-    /// The file `FiraSans-Regular.woff`, the Regular variant of the Fira Sans font.
-    crate static REGULAR: &[u8] = include_bytes!("static/fonts/FiraSans-Regular.woff");
-
     /// The file `FiraSans-Regular.woff2`, the Regular variant of the Fira Sans font in woff2.
-    crate static REGULAR2: &[u8] = include_bytes!("static/fonts/FiraSans-Regular.woff2");
-
-    /// The file `FiraSans-Medium.woff`, the Medium variant of the Fira Sans font.
-    crate static MEDIUM: &[u8] = include_bytes!("static/fonts/FiraSans-Medium.woff");
+    crate static REGULAR: &[u8] = include_bytes!("static/fonts/FiraSans-Regular.woff2");
 
     /// The file `FiraSans-Medium.woff2`, the Medium variant of the Fira Sans font in woff2.
-    crate static MEDIUM2: &[u8] = include_bytes!("static/fonts/FiraSans-Medium.woff2");
+    crate static MEDIUM: &[u8] = include_bytes!("static/fonts/FiraSans-Medium.woff2");
 
     /// The file `FiraSans-LICENSE.txt`, the license text for the Fira Sans font.
     crate static LICENSE: &[u8] = include_bytes!("static/fonts/FiraSans-LICENSE.txt");
 
 /// Files related to the Source Serif 4 font.
 crate mod source_serif_4 {
-    /// The file `SourceSerif4-Regular.ttf.woff`, the Regular variant of the Source Serif 4 font.
-    crate static REGULAR: &[u8] = include_bytes!("static/fonts/SourceSerif4-Regular.ttf.woff");
-
     /// The file `SourceSerif4-Regular.ttf.woff2`, the Regular variant of the Source Serif 4 font in
     /// woff2.
-    crate static REGULAR2: &[u8] = include_bytes!("static/fonts/SourceSerif4-Regular.ttf.woff2");
-
-    /// The file `SourceSerif4-Bold.ttf.woff`, the Bold variant of the Source Serif 4 font.
-    crate static BOLD: &[u8] = include_bytes!("static/fonts/SourceSerif4-Bold.ttf.woff");
+    crate static REGULAR: &[u8] = include_bytes!("static/fonts/SourceSerif4-Regular.ttf.woff2");
 
     /// The file `SourceSerif4-Bold.ttf.woff2`, the Bold variant of the Source Serif 4 font in
     /// woff2.
-    crate static BOLD2: &[u8] = include_bytes!("static/fonts/SourceSerif4-Bold.ttf.woff2");
-
-    /// The file `SourceSerif4-It.ttf.woff`, the Italic variant of the Source Serif 4 font.
-    crate static ITALIC: &[u8] = include_bytes!("static/fonts/SourceSerif4-It.ttf.woff");
+    crate static BOLD: &[u8] = include_bytes!("static/fonts/SourceSerif4-Bold.ttf.woff2");
 
     /// The file `SourceSerif4-It.ttf.woff2`, the Italic variant of the Source Serif 4 font in
     /// woff2.
-    crate static ITALIC2: &[u8] = include_bytes!("static/fonts/SourceSerif4-It.ttf.woff2");
+    crate static ITALIC: &[u8] = include_bytes!("static/fonts/SourceSerif4-It.ttf.woff2");
 
     /// The file `SourceSerif4-LICENSE.txt`, the license text for the Source Serif 4 font.
     crate static LICENSE: &[u8] = include_bytes!("static/fonts/SourceSerif4-LICENSE.md");
 
 /// Files related to the Source Code Pro font.
 crate mod source_code_pro {
-    /// The file `SourceCodePro-Regular.ttf.woff`, the Regular variant of the Source Code Pro font.
-    crate static REGULAR: &[u8] = include_bytes!("static/fonts/SourceCodePro-Regular.ttf.woff");
-
     /// The file `SourceCodePro-Regular.ttf.woff2`, the Regular variant of the Source Code Pro font
     /// in woff2.
-    crate static REGULAR2: &[u8] = include_bytes!("static/fonts/SourceCodePro-Regular.ttf.woff2");
-
-    /// The file `SourceCodePro-Semibold.ttf.woff`, the Semibold variant of the Source Code Pro
-    /// font.
-    crate static SEMIBOLD: &[u8] = include_bytes!("static/fonts/SourceCodePro-Semibold.ttf.woff");
+    crate static REGULAR: &[u8] = include_bytes!("static/fonts/SourceCodePro-Regular.ttf.woff2");
 
     /// The file `SourceCodePro-Semibold.ttf.woff2`, the Semibold variant of the Source Code Pro
     /// font in woff2.
-    crate static SEMIBOLD2: &[u8] = include_bytes!("static/fonts/SourceCodePro-Semibold.ttf.woff2");
-
-    /// The file `SourceCodePro-It.ttf.woff`, the Italic variant of the Source Code Pro font.
-    crate static ITALIC: &[u8] = include_bytes!("static/fonts/SourceCodePro-It.ttf.woff");
+    crate static SEMIBOLD: &[u8] = include_bytes!("static/fonts/SourceCodePro-Semibold.ttf.woff2");
 
     /// The file `SourceCodePro-It.ttf.woff2`, the Italic variant of the Source Code Pro font in
     /// woff2.
-    crate static ITALIC2: &[u8] = include_bytes!("static/fonts/SourceCodePro-It.ttf.woff2");
+    crate static ITALIC: &[u8] = include_bytes!("static/fonts/SourceCodePro-It.ttf.woff2");
 
     /// The file `SourceCodePro-LICENSE.txt`, the license text of the Source Code Pro font.
     crate static LICENSE: &[u8] = include_bytes!("static/fonts/SourceCodePro-LICENSE.txt");
 /// ```sh
 /// pyftsubset NanumBarunGothic.ttf \
 /// --unicodes=U+AC00-D7AF,U+1100-11FF,U+3130-318F,U+A960-A97F,U+D7B0-D7FF \
-/// --output-file=NanumBarunGothic.ttf.woff --flavor=woff
-/// ```
-/// ```sh
-/// pyftsubset NanumBarunGothic.ttf \
-/// --unicodes=U+AC00-D7AF,U+1100-11FF,U+3130-318F,U+A960-A97F,U+D7B0-D7FF \
 /// --output-file=NanumBarunGothic.ttf.woff2 --flavor=woff2
 /// ```
 crate mod nanum_barun_gothic {
-    /// The file `NanumBarunGothic.ttf.woff`, the Regular variant of the Nanum Barun Gothic font.
-    crate static REGULAR: &[u8] = include_bytes!("static/fonts/NanumBarunGothic.ttf.woff");
-
     /// The file `NanumBarunGothic.ttf.woff2`, the Regular variant of the Nanum Barun Gothic font.
-    crate static REGULAR2: &[u8] = include_bytes!("static/fonts/NanumBarunGothic.ttf.woff2");
+    crate static REGULAR: &[u8] = include_bytes!("static/fonts/NanumBarunGothic.ttf.woff2");
 
     /// The file `NanumBarunGothic-LICENSE.txt`, the license text of the Nanum Barun Gothic font.
     crate static LICENSE: &[u8] = include_bytes!("static/fonts/NanumBarunGothic-LICENSE.txt");
index 564731ab7354b1ad7ea7e25b5d130f2b485582da..470cce93a5020fca5d4c8ea410e48b830eaa168f 100644 (file)
                 </nav> {#- -#}
             </div> {#- -#}
             <section id="main-content" class="content">{{- content|safe -}}</section> {#- -#}
-            <section id="search" class="content hidden"></section> {#- -#}
         </div> {#- -#}
     </main> {#- -#}
     {{- layout.external_html.after_content|safe -}}
index 0fcfabba4c0a12bec4075833fbad95ba14ed0ddc..cd196a01847991d108335f367f35fe0f28b7e68b 100644 (file)
@@ -795,6 +795,7 @@ fn main_options(options: config::Options) -> MainResult {
                 let resolver_caches = resolver.borrow_mut().access(|resolver| {
                     collect_intra_doc_links::early_resolve_intra_doc_links(
                         resolver,
+                        sess,
                         krate,
                         externs,
                         document_private,
index 33d83aa339d95313441d9f47a2e6cab5285b5ac9..0d40ef4c60003b156a8d8c1a79d3404c861b5ac2 100644 (file)
@@ -239,7 +239,7 @@ fn visit_item(&mut self, i: &clean::Item) {
                 let should_be_ignored = i
                     .item_id
                     .as_def_id()
-                    .and_then(|def_id| self.ctx.tcx.parent(def_id))
+                    .and_then(|def_id| self.ctx.tcx.opt_parent(def_id))
                     .and_then(|def_id| self.ctx.tcx.hir().get_if_local(def_id))
                     .map(|node| {
                         matches!(
index 42e87f3f9610b1b54cb855fce0679998e7cce810..22b2f8c0c8ec36df99af16f79dec42097f2dd987 100644 (file)
@@ -12,6 +12,7 @@
 use rustc_hir::Mutability;
 use rustc_middle::ty::{DefIdTree, Ty, TyCtxt};
 use rustc_middle::{bug, span_bug, ty};
+use rustc_resolve::ParentScope;
 use rustc_session::lint::Lint;
 use rustc_span::hygiene::MacroKind;
 use rustc_span::symbol::{sym, Ident, Symbol};
@@ -333,7 +334,7 @@ fn from_assoc_item(item: &ty::AssocItem) -> Self {
                     FragmentKind::StructField => write!(s, "structfield.{}", name),
                     FragmentKind::Variant => write!(s, "variant.{}", name),
                     FragmentKind::VariantField => {
-                        let variant = tcx.item_name(tcx.parent(def_id).unwrap());
+                        let variant = tcx.item_name(tcx.parent(def_id));
                         write!(s, "variant.{}.field.{}", variant, name)
                     }
                 }
@@ -508,10 +509,10 @@ fn resolve_self_ty(&self, path_str: &str, ns: Namespace, item_id: ItemId) -> Opt
                 | DefKind::AssocTy
                 | DefKind::Variant
                 | DefKind::Field) => {
-                    let parent_def_id = tcx.parent(def_id).expect("nested item has no parent");
+                    let parent_def_id = tcx.parent(def_id);
                     if def_kind == DefKind::Field && tcx.def_kind(parent_def_id) == DefKind::Variant
                     {
-                        tcx.parent(parent_def_id).expect("variant has no parent")
+                        tcx.parent(parent_def_id)
                     } else {
                         parent_def_id
                     }
@@ -564,7 +565,9 @@ fn resolve_path(
             .copied()
             .unwrap_or_else(|| {
                 self.cx.enter_resolver(|resolver| {
-                    resolver.resolve_rustdoc_path(path_str, ns, module_id)
+                    let parent_scope =
+                        ParentScope::module(resolver.expect_module(module_id), resolver);
+                    resolver.resolve_rustdoc_path(path_str, ns, parent_scope)
                 })
             })
             .and_then(|res| res.try_into().ok())
@@ -2333,14 +2336,10 @@ fn handle_variant(
     cx: &DocContext<'_>,
     res: Res,
 ) -> Result<(Res, Option<ItemFragment>), ErrorKind<'static>> {
-    cx.tcx
-        .parent(res.def_id(cx.tcx))
-        .map(|parent| {
-            let parent_def = Res::Def(DefKind::Enum, parent);
-            let variant = cx.tcx.expect_variant_res(res.as_hir_res().unwrap());
-            (parent_def, Some(ItemFragment(FragmentKind::Variant, variant.def_id)))
-        })
-        .ok_or_else(|| ResolutionFailure::NoParentItem.into())
+    let parent = cx.tcx.parent(res.def_id(cx.tcx));
+    let parent_def = Res::Def(DefKind::Enum, parent);
+    let variant = cx.tcx.expect_variant_res(res.as_hir_res().unwrap());
+    Ok((parent_def, Some(ItemFragment(FragmentKind::Variant, variant.def_id))))
 }
 
 /// Resolve a primitive type or value.
index e2359da870edc21ba6edefa2cfa5250d0e1b373e..1d2ef832db77be99662a9d2339740b0080d65ab0 100644 (file)
@@ -1,7 +1,7 @@
 use crate::clean::Attributes;
 use crate::core::ResolverCaches;
 use crate::passes::collect_intra_doc_links::preprocessed_markdown_links;
-use crate::passes::collect_intra_doc_links::PreprocessedMarkdownLink;
+use crate::passes::collect_intra_doc_links::{Disambiguator, PreprocessedMarkdownLink};
 
 use rustc_ast::visit::{self, AssocCtxt, Visitor};
 use rustc_ast::{self as ast, ItemKind};
@@ -9,11 +9,13 @@
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def::Namespace::*;
 use rustc_hir::def::{DefKind, Namespace, Res};
-use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LocalDefId, CRATE_DEF_ID};
+use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, CRATE_DEF_ID};
 use rustc_hir::TraitCandidate;
 use rustc_middle::ty::{DefIdTree, Visibility};
 use rustc_resolve::{ParentScope, Resolver};
 use rustc_session::config::Externs;
+use rustc_session::Session;
+use rustc_span::symbol::sym;
 use rustc_span::{Symbol, SyntaxContext};
 
 use std::collections::hash_map::Entry;
 
 crate fn early_resolve_intra_doc_links(
     resolver: &mut Resolver<'_>,
+    sess: &Session,
     krate: &ast::Crate,
     externs: Externs,
     document_private_items: bool,
 ) -> ResolverCaches {
+    let parent_scope =
+        ParentScope::module(resolver.expect_module(CRATE_DEF_ID.to_def_id()), resolver);
     let mut link_resolver = EarlyDocLinkResolver {
         resolver,
-        current_mod: CRATE_DEF_ID,
+        sess,
+        parent_scope,
         visited_mods: Default::default(),
         markdown_links: Default::default(),
         doc_link_resolutions: Default::default(),
@@ -49,7 +55,7 @@
     // DO NOT REMOVE THIS without first testing on the reproducer in
     // https://github.com/jyn514/objr/commit/edcee7b8124abf0e4c63873e8422ff81beb11ebb
     for (extern_name, _) in externs.iter().filter(|(_, entry)| entry.add_prelude) {
-        link_resolver.resolver.resolve_rustdoc_path(extern_name, TypeNS, CRATE_DEF_ID.to_def_id());
+        link_resolver.resolver.resolve_rustdoc_path(extern_name, TypeNS, parent_scope);
     }
 
     ResolverCaches {
 }
 
 fn doc_attrs<'a>(attrs: impl Iterator<Item = &'a ast::Attribute>) -> Attributes {
-    let mut attrs = Attributes::from_ast_iter(attrs.map(|attr| (attr, None)), true);
-    attrs.unindent_doc_comments();
-    attrs
+    Attributes::from_ast_iter(attrs.map(|attr| (attr, None)), true)
 }
 
 struct EarlyDocLinkResolver<'r, 'ra> {
     resolver: &'r mut Resolver<'ra>,
-    current_mod: LocalDefId,
+    sess: &'r Session,
+    parent_scope: ParentScope<'ra>,
     visited_mods: DefIdSet,
     markdown_links: FxHashMap<String, Vec<PreprocessedMarkdownLink>>,
     doc_link_resolutions: FxHashMap<(Symbol, Namespace, DefId), Option<Res<ast::NodeId>>>,
@@ -80,7 +85,7 @@ struct EarlyDocLinkResolver<'r, 'ra> {
     document_private_items: bool,
 }
 
-impl EarlyDocLinkResolver<'_, '_> {
+impl<'ra> EarlyDocLinkResolver<'_, 'ra> {
     fn add_traits_in_scope(&mut self, def_id: DefId) {
         // Calls to `traits_in_scope` are expensive, so try to avoid them if only possible.
         // Keys in the `traits_in_scope` cache are always module IDs.
@@ -167,18 +172,26 @@ fn process_extern_impls(&mut self) {
         }
     }
 
-    fn resolve_doc_links_extern_impl(&mut self, def_id: DefId, _is_inherent: bool) {
-        // FIXME: Resolve links in associated items in addition to traits themselves,
-        // `force` is used to provide traits in scope for the associated items.
-        self.resolve_doc_links_extern_outer(def_id, def_id, true);
+    fn resolve_doc_links_extern_impl(&mut self, def_id: DefId, is_inherent: bool) {
+        self.resolve_doc_links_extern_outer(def_id, def_id);
+        let assoc_item_def_ids = Vec::from_iter(
+            self.resolver.cstore().associated_item_def_ids_untracked(def_id, self.sess),
+        );
+        for assoc_def_id in assoc_item_def_ids {
+            if !is_inherent
+                || self.resolver.cstore().visibility_untracked(assoc_def_id) == Visibility::Public
+            {
+                self.resolve_doc_links_extern_outer(assoc_def_id, def_id);
+            }
+        }
     }
 
-    fn resolve_doc_links_extern_outer(&mut self, def_id: DefId, scope_id: DefId, force: bool) {
-        if !force && !self.resolver.cstore().may_have_doc_links_untracked(def_id) {
+    fn resolve_doc_links_extern_outer(&mut self, def_id: DefId, scope_id: DefId) {
+        if !self.resolver.cstore().may_have_doc_links_untracked(def_id) {
             return;
         }
         // FIXME: actually resolve links, not just add traits in scope.
-        if let Some(parent_id) = self.resolver.parent(scope_id) {
+        if let Some(parent_id) = self.resolver.opt_parent(scope_id) {
             self.add_traits_in_scope(parent_id);
         }
     }
@@ -195,34 +208,64 @@ fn resolve_doc_links_local(&mut self, attrs: &[ast::Attribute]) {
         if !attrs.iter().any(|attr| attr.may_have_doc_links()) {
             return;
         }
-        let module_id = self.current_mod.to_def_id();
-        self.resolve_doc_links(doc_attrs(attrs.iter()), module_id);
+        self.resolve_doc_links(doc_attrs(attrs.iter()), self.parent_scope);
     }
 
-    fn resolve_doc_links(&mut self, attrs: Attributes, module_id: DefId) {
+    fn resolve_and_cache(
+        &mut self,
+        path_str: &str,
+        ns: Namespace,
+        parent_scope: &ParentScope<'ra>,
+    ) -> bool {
+        // FIXME: This caching may be incorrect in case of multiple `macro_rules`
+        // items with the same name in the same module.
+        self.doc_link_resolutions
+            .entry((Symbol::intern(path_str), ns, parent_scope.module.def_id()))
+            .or_insert_with_key(|(path, ns, _)| {
+                self.resolver.resolve_rustdoc_path(path.as_str(), *ns, *parent_scope)
+            })
+            .is_some()
+    }
+
+    fn resolve_doc_links(&mut self, attrs: Attributes, parent_scope: ParentScope<'ra>) {
         let mut need_traits_in_scope = false;
         for (doc_module, doc) in attrs.prepare_to_doc_link_resolution() {
             assert_eq!(doc_module, None);
-            let links = self
-                .markdown_links
-                .entry(doc)
-                .or_insert_with_key(|doc| preprocessed_markdown_links(doc));
+            let mut tmp_links = mem::take(&mut self.markdown_links);
+            let links =
+                tmp_links.entry(doc).or_insert_with_key(|doc| preprocessed_markdown_links(doc));
             for PreprocessedMarkdownLink(pp_link, _) in links {
                 if let Ok(pinfo) = pp_link {
-                    // FIXME: Resolve the path in all namespaces and resolve its prefixes too.
-                    let ns = TypeNS;
-                    self.doc_link_resolutions
-                        .entry((Symbol::intern(&pinfo.path_str), ns, module_id))
-                        .or_insert_with_key(|(path, ns, module_id)| {
-                            self.resolver.resolve_rustdoc_path(path.as_str(), *ns, *module_id)
-                        });
-                    need_traits_in_scope = true;
+                    // The logic here is a conservative approximation for path resolution in
+                    // `resolve_with_disambiguator`.
+                    if let Some(ns) = pinfo.disambiguator.map(Disambiguator::ns) {
+                        if self.resolve_and_cache(&pinfo.path_str, ns, &parent_scope) {
+                            continue;
+                        }
+                    }
+
+                    // Resolve all namespaces due to no disambiguator or for diagnostics.
+                    let mut any_resolved = false;
+                    let mut need_assoc = false;
+                    for ns in [TypeNS, ValueNS, MacroNS] {
+                        if self.resolve_and_cache(&pinfo.path_str, ns, &parent_scope) {
+                            any_resolved = true;
+                        } else if ns != MacroNS {
+                            need_assoc = true;
+                        }
+                    }
+
+                    // FIXME: Resolve all prefixes for type-relative resolution or for diagnostics.
+                    if (need_assoc || !any_resolved) && pinfo.path_str.contains("::") {
+                        need_traits_in_scope = true;
+                    }
                 }
             }
+            self.markdown_links = tmp_links;
         }
 
         if need_traits_in_scope {
-            self.add_traits_in_scope(module_id);
+            self.add_traits_in_scope(parent_scope.module.def_id());
         }
     }
 
@@ -243,10 +286,10 @@ fn process_module_children_or_reexports(&mut self, module_id: DefId) {
             {
                 if let Some(def_id) = child.res.opt_def_id() && !def_id.is_local() {
                     let scope_id = match child.res {
-                        Res::Def(DefKind::Variant, ..) => self.resolver.parent(def_id).unwrap(),
+                        Res::Def(DefKind::Variant, ..) => self.resolver.parent(def_id),
                         _ => def_id,
                     };
-                    self.resolve_doc_links_extern_outer(def_id, scope_id, false); // Outer attribute scope
+                    self.resolve_doc_links_extern_outer(def_id, scope_id); // Outer attribute scope
                     if let Res::Def(DefKind::Mod, ..) = child.res {
                         self.resolve_doc_links_extern_inner(def_id); // Inner attribute scope
                     }
@@ -264,19 +307,33 @@ impl Visitor<'_> for EarlyDocLinkResolver<'_, '_> {
     fn visit_item(&mut self, item: &ast::Item) {
         self.resolve_doc_links_local(&item.attrs); // Outer attribute scope
         if let ItemKind::Mod(..) = item.kind {
-            let old_mod = mem::replace(&mut self.current_mod, self.resolver.local_def_id(item.id));
+            let module_def_id = self.resolver.local_def_id(item.id).to_def_id();
+            let module = self.resolver.expect_module(module_def_id);
+            let old_module = mem::replace(&mut self.parent_scope.module, module);
+            let old_macro_rules = self.parent_scope.macro_rules;
             self.resolve_doc_links_local(&item.attrs); // Inner attribute scope
-            self.process_module_children_or_reexports(self.current_mod.to_def_id());
+            self.process_module_children_or_reexports(module_def_id);
             visit::walk_item(self, item);
-            self.current_mod = old_mod;
+            if item
+                .attrs
+                .iter()
+                .all(|attr| !attr.has_name(sym::macro_use) && !attr.has_name(sym::macro_escape))
+            {
+                self.parent_scope.macro_rules = old_macro_rules;
+            }
+            self.parent_scope.module = old_module;
         } else {
-            match item.kind {
+            match &item.kind {
                 ItemKind::Trait(..) => {
                     self.all_traits.push(self.resolver.local_def_id(item.id).to_def_id());
                 }
                 ItemKind::Impl(box ast::Impl { of_trait: Some(..), .. }) => {
                     self.all_trait_impls.push(self.resolver.local_def_id(item.id).to_def_id());
                 }
+                ItemKind::MacroDef(macro_def) if macro_def.macro_rules => {
+                    self.parent_scope.macro_rules =
+                        self.resolver.macro_rules_scope(self.resolver.local_def_id(item.id));
+                }
                 _ => {}
             }
             visit::walk_item(self, item);
@@ -303,6 +360,12 @@ fn visit_field_def(&mut self, field: &ast::FieldDef) {
         visit::walk_field_def(self, field)
     }
 
+    fn visit_block(&mut self, block: &ast::Block) {
+        let old_macro_rules = self.parent_scope.macro_rules;
+        visit::walk_block(self, block);
+        self.parent_scope.macro_rules = old_macro_rules;
+    }
+
     // NOTE: if doc-comments are ever allowed on other nodes (e.g. function parameters),
     // then this will have to implement other visitor methods too.
 }
index 65459913eeaa80d09415c56d2e78ba28f2890358..d245c3750ec08d64e153f08e16bdadbf5aed33fa 100644 (file)
         coll.items
     };
 
-    let mut new_items = Vec::new();
+    let mut new_items_external = Vec::new();
+    let mut new_items_local = Vec::new();
 
     // External trait impls.
     cx.with_all_trait_impls(|cx, all_trait_impls| {
         let _prof_timer = cx.tcx.sess.prof.generic_activity("build_extern_trait_impls");
         for &impl_def_id in all_trait_impls.iter().skip_while(|def_id| def_id.is_local()) {
-            inline::build_impl(cx, None, impl_def_id, None, &mut new_items);
+            inline::build_impl(cx, None, impl_def_id, None, &mut new_items_external);
+        }
+    });
+
+    // Local trait impls.
+    cx.with_all_trait_impls(|cx, all_trait_impls| {
+        let _prof_timer = cx.tcx.sess.prof.generic_activity("build_local_trait_impls");
+        let mut attr_buf = Vec::new();
+        for &impl_def_id in all_trait_impls.iter().take_while(|def_id| def_id.is_local()) {
+            let mut parent = Some(cx.tcx.parent(impl_def_id));
+            while let Some(did) = parent {
+                attr_buf.extend(
+                    cx.tcx
+                        .get_attrs(did)
+                        .iter()
+                        .filter(|attr| attr.has_name(sym::doc))
+                        .filter(|attr| {
+                            if let Some([attr]) = attr.meta_item_list().as_deref() {
+                                attr.has_name(sym::cfg)
+                            } else {
+                                false
+                            }
+                        })
+                        .cloned(),
+                );
+                parent = cx.tcx.opt_parent(did);
+            }
+            inline::build_impl(cx, None, impl_def_id, Some(&attr_buf), &mut new_items_local);
+            attr_buf.clear();
         }
     });
 
-    // Also try to inline primitive impls from other crates.
     cx.tcx.sess.prof.generic_activity("build_primitive_trait_impls").run(|| {
         for def_id in PrimitiveType::all_impls(cx.tcx) {
+            // Try to inline primitive impls from other crates.
             if !def_id.is_local() {
-                inline::build_impl(cx, None, def_id, None, &mut new_items);
-
-                // FIXME(eddyb) is this `doc(hidden)` check needed?
-                if !cx.tcx.is_doc_hidden(def_id) {
+                inline::build_impl(cx, None, def_id, None, &mut new_items_external);
+            }
+        }
+        for (prim, did) in PrimitiveType::primitive_locations(cx.tcx) {
+            // 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.
+            if did.is_local() {
+                for def_id in prim.impls(cx.tcx) {
                     let impls = get_auto_trait_and_blanket_impls(cx, def_id);
-                    new_items.extend(impls.filter(|i| cx.inlined.insert(i.item_id)));
+                    new_items_external.extend(impls.filter(|i| cx.inlined.insert(i.item_id)));
                 }
             }
         }
@@ -66,6 +100,7 @@ fn add_deref_target(
         cx: &DocContext<'_>,
         map: &FxHashMap<DefId, &Type>,
         cleaner: &mut BadImplStripper<'_>,
+        targets: &mut FxHashSet<DefId>,
         type_did: DefId,
     ) {
         if let Some(target) = map.get(&type_did) {
@@ -74,18 +109,18 @@ fn add_deref_target(
                 cleaner.prims.insert(target_prim);
             } else if let Some(target_did) = target.def_id(&cx.cache) {
                 // `impl Deref<Target = S> for S`
-                if target_did == type_did {
+                if !targets.insert(target_did) {
                     // Avoid infinite cycles
                     return;
                 }
                 cleaner.items.insert(target_did.into());
-                add_deref_target(cx, map, cleaner, target_did);
+                add_deref_target(cx, map, cleaner, targets, target_did);
             }
         }
     }
 
     // scan through included items ahead of time to splice in Deref targets to the "valid" sets
-    for it in &new_items {
+    for it in new_items_external.iter().chain(new_items_local.iter()) {
         if let ImplItem(Impl { ref for_, ref trait_, ref items, .. }) = *it.kind {
             if trait_.as_ref().map(|t| t.def_id()) == cx.tcx.lang_items().deref_trait()
                 && cleaner.keep_impl(for_, true)
@@ -109,7 +144,15 @@ fn add_deref_target(
                         // `Deref` target type and the impl for type positions, this map of types is keyed by
                         // `DefId` and for convenience uses a special cleaner that accepts `DefId`s directly.
                         if cleaner.keep_impl_with_def_id(for_did.into()) {
-                            add_deref_target(cx, &type_did_to_deref_target, &mut cleaner, for_did);
+                            let mut targets = FxHashSet::default();
+                            targets.insert(for_did);
+                            add_deref_target(
+                                cx,
+                                &type_did_to_deref_target,
+                                &mut cleaner,
+                                &mut targets,
+                                for_did,
+                            );
                         }
                     }
                 }
@@ -117,7 +160,8 @@ fn add_deref_target(
         }
     }
 
-    new_items.retain(|it| {
+    // Filter out external items that are not needed
+    new_items_external.retain(|it| {
         if let ImplItem(Impl { ref for_, ref trait_, ref kind, .. }) = *it.kind {
             cleaner.keep_impl(
                 for_,
@@ -129,37 +173,10 @@ fn add_deref_target(
         }
     });
 
-    // Local trait impls.
-    cx.with_all_trait_impls(|cx, all_trait_impls| {
-        let _prof_timer = cx.tcx.sess.prof.generic_activity("build_local_trait_impls");
-        let mut attr_buf = Vec::new();
-        for &impl_def_id in all_trait_impls.iter().take_while(|def_id| def_id.is_local()) {
-            let mut parent = cx.tcx.parent(impl_def_id);
-            while let Some(did) = parent {
-                attr_buf.extend(
-                    cx.tcx
-                        .get_attrs(did)
-                        .iter()
-                        .filter(|attr| attr.has_name(sym::doc))
-                        .filter(|attr| {
-                            if let Some([attr]) = attr.meta_item_list().as_deref() {
-                                attr.has_name(sym::cfg)
-                            } else {
-                                false
-                            }
-                        })
-                        .cloned(),
-                );
-                parent = cx.tcx.parent(did);
-            }
-            inline::build_impl(cx, None, impl_def_id, Some(&attr_buf), &mut new_items);
-            attr_buf.clear();
-        }
-    });
-
     if let ModuleItem(Module { items, .. }) = &mut *krate.module.kind {
         items.extend(synth_impls);
-        items.extend(new_items);
+        items.extend(new_items_external);
+        items.extend(new_items_local);
     } else {
         panic!("collect-trait-impls can't run");
     };
index 5db2d0747c83bb7f9de930dae440fac140f95d75..97a436c7500701f626c4136227d91759ddaffea2 100644 (file)
@@ -24,9 +24,6 @@
 mod strip_priv_imports;
 crate use self::strip_priv_imports::STRIP_PRIV_IMPORTS;
 
-mod unindent_comments;
-crate use self::unindent_comments::UNINDENT_COMMENTS;
-
 mod propagate_doc_cfg;
 crate use self::propagate_doc_cfg::PROPAGATE_DOC_CFG;
 
@@ -81,7 +78,6 @@
 crate const PASSES: &[Pass] = &[
     CHECK_DOC_TEST_VISIBILITY,
     STRIP_HIDDEN,
-    UNINDENT_COMMENTS,
     STRIP_PRIVATE,
     STRIP_PRIV_IMPORTS,
     PROPAGATE_DOC_CFG,
@@ -96,7 +92,6 @@
 /// The list of passes run by default.
 crate const DEFAULT_PASSES: &[ConditionalPass] = &[
     ConditionalPass::always(COLLECT_TRAIT_IMPLS),
-    ConditionalPass::always(UNINDENT_COMMENTS),
     ConditionalPass::always(CHECK_DOC_TEST_VISIBILITY),
     ConditionalPass::new(STRIP_HIDDEN, WhenNotDocumentHidden),
     ConditionalPass::new(STRIP_PRIVATE, WhenNotDocumentPrivate),
diff --git a/src/librustdoc/passes/unindent_comments.rs b/src/librustdoc/passes/unindent_comments.rs
deleted file mode 100644 (file)
index 0f60415..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-//! Removes excess indentation on comments in order for the Markdown
-//! to be parsed correctly. This is necessary because the convention for
-//! writing documentation is to provide a space between the /// or //! marker
-//! and the doc text, but Markdown is whitespace-sensitive. For example,
-//! a block of text with four-space indentation is parsed as a code block,
-//! so if we didn't unindent comments, these list items
-//!
-//! /// A list:
-//! ///
-//! ///    - Foo
-//! ///    - Bar
-//!
-//! would be parsed as if they were in a code block, which is likely not what the user intended.
-use std::cmp;
-
-use rustc_span::symbol::kw;
-
-use crate::clean::{self, DocFragment, DocFragmentKind, Item};
-use crate::core::DocContext;
-use crate::fold::{self, DocFolder};
-use crate::passes::Pass;
-
-#[cfg(test)]
-mod tests;
-
-crate const UNINDENT_COMMENTS: Pass = Pass {
-    name: "unindent-comments",
-    run: unindent_comments,
-    description: "removes excess indentation on comments in order for markdown to like it",
-};
-
-crate fn unindent_comments(krate: clean::Crate, _: &mut DocContext<'_>) -> clean::Crate {
-    CommentCleaner.fold_crate(krate)
-}
-
-struct CommentCleaner;
-
-impl fold::DocFolder for CommentCleaner {
-    fn fold_item(&mut self, mut i: Item) -> Option<Item> {
-        i.attrs.unindent_doc_comments();
-        Some(self.fold_item_recur(i))
-    }
-}
-
-impl clean::Attributes {
-    crate fn unindent_doc_comments(&mut self) {
-        unindent_fragments(&mut self.doc_strings);
-    }
-}
-
-fn unindent_fragments(docs: &mut Vec<DocFragment>) {
-    // `add` is used in case the most common sugared doc syntax is used ("/// "). The other
-    // fragments kind's lines are never starting with a whitespace unless they are using some
-    // markdown formatting requiring it. Therefore, if the doc block have a mix between the two,
-    // we need to take into account the fact that the minimum indent minus one (to take this
-    // whitespace into account).
-    //
-    // For example:
-    //
-    // /// hello!
-    // #[doc = "another"]
-    //
-    // In this case, you want "hello! another" and not "hello!  another".
-    let add = if docs.windows(2).any(|arr| arr[0].kind != arr[1].kind)
-        && docs.iter().any(|d| d.kind == DocFragmentKind::SugaredDoc)
-    {
-        // In case we have a mix of sugared doc comments and "raw" ones, we want the sugared one to
-        // "decide" how much the minimum indent will be.
-        1
-    } else {
-        0
-    };
-
-    // `min_indent` is used to know how much whitespaces from the start of each lines must be
-    // removed. Example:
-    //
-    // ///     hello!
-    // #[doc = "another"]
-    //
-    // In here, the `min_indent` is 1 (because non-sugared fragment are always counted with minimum
-    // 1 whitespace), meaning that "hello!" will be considered a codeblock because it starts with 4
-    // (5 - 1) whitespaces.
-    let Some(min_indent) = docs
-        .iter()
-        .map(|fragment| {
-            fragment.doc.as_str().lines().fold(usize::MAX, |min_indent, line| {
-                if line.chars().all(|c| c.is_whitespace()) {
-                    min_indent
-                } else {
-                    // Compare against either space or tab, ignoring whether they are
-                    // mixed or not.
-                    let whitespace = line.chars().take_while(|c| *c == ' ' || *c == '\t').count();
-                    cmp::min(min_indent, whitespace)
-                        + if fragment.kind == DocFragmentKind::SugaredDoc { 0 } else { add }
-                }
-            })
-        })
-        .min()
-    else {
-        return;
-    };
-
-    for fragment in docs {
-        if fragment.doc == kw::Empty {
-            continue;
-        }
-
-        let min_indent = if fragment.kind != DocFragmentKind::SugaredDoc && min_indent > 0 {
-            min_indent - add
-        } else {
-            min_indent
-        };
-
-        fragment.indent = min_indent;
-    }
-}
diff --git a/src/librustdoc/passes/unindent_comments/tests.rs b/src/librustdoc/passes/unindent_comments/tests.rs
deleted file mode 100644 (file)
index baff839..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-use super::*;
-
-use crate::clean::collapse_doc_fragments;
-
-use rustc_span::create_default_session_globals_then;
-use rustc_span::source_map::DUMMY_SP;
-use rustc_span::symbol::Symbol;
-
-fn create_doc_fragment(s: &str) -> Vec<DocFragment> {
-    vec![DocFragment {
-        span: DUMMY_SP,
-        parent_module: None,
-        doc: Symbol::intern(s),
-        kind: DocFragmentKind::SugaredDoc,
-        indent: 0,
-    }]
-}
-
-#[track_caller]
-fn run_test(input: &str, expected: &str) {
-    create_default_session_globals_then(|| {
-        let mut s = create_doc_fragment(input);
-        unindent_fragments(&mut s);
-        assert_eq!(collapse_doc_fragments(&s), expected);
-    });
-}
-
-#[test]
-fn should_unindent() {
-    run_test("    line1\n    line2", "line1\nline2");
-}
-
-#[test]
-fn should_unindent_multiple_paragraphs() {
-    run_test("    line1\n\n    line2", "line1\n\nline2");
-}
-
-#[test]
-fn should_leave_multiple_indent_levels() {
-    // Line 2 is indented another level beyond the
-    // base indentation and should be preserved
-    run_test("    line1\n\n        line2", "line1\n\n    line2");
-}
-
-#[test]
-fn should_ignore_first_line_indent() {
-    run_test("line1\n    line2", "line1\n    line2");
-}
-
-#[test]
-fn should_not_ignore_first_line_indent_in_a_single_line_para() {
-    run_test("line1\n\n    line2", "line1\n\n    line2");
-}
-
-#[test]
-fn should_unindent_tabs() {
-    run_test("\tline1\n\tline2", "line1\nline2");
-}
-
-#[test]
-fn should_trim_mixed_indentation() {
-    run_test("\t    line1\n\t    line2", "line1\nline2");
-    run_test("    \tline1\n    \tline2", "line1\nline2");
-}
-
-#[test]
-fn should_not_trim() {
-    run_test("\t    line1  \n\t    line2", "line1  \nline2");
-    run_test("    \tline1  \n    \tline2", "line1  \nline2");
-}
index fd336816c3a6d228dcef22171c43140f6fa7656f..fc10370ef7d91babf512c10505f8f2176bc8519d 160000 (submodule)
@@ -1 +1 @@
-Subproject commit fd336816c3a6d228dcef22171c43140f6fa7656f
+Subproject commit fc10370ef7d91babf512c10505f8f2176bc8519d
diff --git a/src/test/assembly/nvptx-kernel-abi/nvptx-kernel-args-abi-v7.rs b/src/test/assembly/nvptx-kernel-abi/nvptx-kernel-args-abi-v7.rs
new file mode 100644 (file)
index 0000000..5bf44f9
--- /dev/null
@@ -0,0 +1,254 @@
+// assembly-output: ptx-linker
+// compile-flags: --crate-type cdylib -C target-cpu=sm_86
+// only-nvptx64
+// ignore-nvptx64
+
+// The following ABI tests are made with nvcc 11.6 does.
+//
+// The PTX ABI stability is tied to major versions of the PTX ISA
+// These tests assume major version 7
+//
+//
+// The following correspondence between types are assumed:
+// u<N> - uint<N>_t
+// i<N> - int<N>_t
+// [T, N] - std::array<T, N>
+// &T - T const*
+// &mut T - T*
+
+// CHECK: .version 7
+
+#![feature(abi_ptx, lang_items, no_core)]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+#[lang = "copy"]
+trait Copy {}
+
+#[repr(C)]
+pub struct SingleU8 {
+    f: u8,
+}
+
+#[repr(C)]
+pub struct DoubleU8 {
+    f: u8,
+    g: u8,
+}
+
+#[repr(C)]
+pub struct TripleU8 {
+    f: u8,
+    g: u8,
+    h: u8,
+}
+
+#[repr(C)]
+pub struct TripleU16 {
+    f: u16,
+    g: u16,
+    h: u16,
+}
+#[repr(C)]
+pub struct TripleU32 {
+    f: u32,
+    g: u32,
+    h: u32,
+}
+#[repr(C)]
+pub struct TripleU64 {
+    f: u64,
+    g: u64,
+    h: u64,
+}
+
+#[repr(C)]
+pub struct DoubleFloat {
+    f: f32,
+    g: f32,
+}
+
+#[repr(C)]
+pub struct TripleFloat {
+    f: f32,
+    g: f32,
+    h: f32,
+}
+
+#[repr(C)]
+pub struct TripleDouble {
+    f: f64,
+    g: f64,
+    h: f64,
+}
+
+#[repr(C)]
+pub struct ManyIntegers {
+    f: u8,
+    g: u16,
+    h: u32,
+    i: u64,
+}
+
+#[repr(C)]
+pub struct ManyNumerics {
+    f: u8,
+    g: u16,
+    h: u32,
+    i: u64,
+    j: f32,
+    k: f64,
+}
+
+// CHECK: .visible .entry f_u8_arg(
+// CHECK: .param .u8 f_u8_arg_param_0
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_u8_arg(_a: u8) {}
+
+// CHECK: .visible .entry f_u16_arg(
+// CHECK: .param .u16 f_u16_arg_param_0
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_u16_arg(_a: u16) {}
+
+// CHECK: .visible .entry f_u32_arg(
+// CHECK: .param .u32 f_u32_arg_param_0
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_u32_arg(_a: u32) {}
+
+// CHECK: .visible .entry f_u64_arg(
+// CHECK: .param .u64 f_u64_arg_param_0
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_u64_arg(_a: u64) {}
+
+// CHECK: .visible .entry f_u128_arg(
+// CHECK: .param .align 16 .b8 f_u128_arg_param_0[16]
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_u128_arg(_a: u128) {}
+
+// CHECK: .visible .entry f_i8_arg(
+// CHECK: .param .u8 f_i8_arg_param_0
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_i8_arg(_a: i8) {}
+
+// CHECK: .visible .entry f_i16_arg(
+// CHECK: .param .u16 f_i16_arg_param_0
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_i16_arg(_a: i16) {}
+
+// CHECK: .visible .entry f_i32_arg(
+// CHECK: .param .u32 f_i32_arg_param_0
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_i32_arg(_a: i32) {}
+
+// CHECK: .visible .entry f_i64_arg(
+// CHECK: .param .u64 f_i64_arg_param_0
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_i64_arg(_a: i64) {}
+
+// CHECK: .visible .entry f_i128_arg(
+// CHECK: .param .align 16 .b8 f_i128_arg_param_0[16]
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_i128_arg(_a: i128) {}
+
+// CHECK: .visible .entry f_f32_arg(
+// CHECK: .param .f32 f_f32_arg_param_0
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_f32_arg(_a: f32) {}
+
+// CHECK: .visible .entry f_f64_arg(
+// CHECK: .param .f64 f_f64_arg_param_0
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_f64_arg(_a: f64) {}
+
+// CHECK: .visible .entry f_single_u8_arg(
+// CHECK: .param .align 1 .b8 f_single_u8_arg_param_0[1]
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_single_u8_arg(_a: SingleU8) {}
+
+// CHECK: .visible .entry f_double_u8_arg(
+// CHECK: .param .align 1 .b8 f_double_u8_arg_param_0[2]
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_double_u8_arg(_a: DoubleU8) {}
+
+// CHECK: .visible .entry f_triple_u8_arg(
+// CHECK: .param .align 1 .b8 f_triple_u8_arg_param_0[3]
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_triple_u8_arg(_a: TripleU8) {}
+
+// CHECK: .visible .entry f_triple_u16_arg(
+// CHECK: .param .align 2 .b8 f_triple_u16_arg_param_0[6]
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_triple_u16_arg(_a: TripleU16) {}
+
+// CHECK: .visible .entry f_triple_u32_arg(
+// CHECK: .param .align 4 .b8 f_triple_u32_arg_param_0[12]
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_triple_u32_arg(_a: TripleU32) {}
+
+// CHECK: .visible .entry f_triple_u64_arg(
+// CHECK: .param .align 8 .b8 f_triple_u64_arg_param_0[24]
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_triple_u64_arg(_a: TripleU64) {}
+
+// CHECK: .visible .entry f_many_integers_arg(
+// CHECK: .param .align 8 .b8 f_many_integers_arg_param_0[16]
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_many_integers_arg(_a: ManyIntegers) {}
+
+// CHECK: .visible .entry f_double_float_arg(
+// CHECK: .param .align 4 .b8 f_double_float_arg_param_0[8]
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_double_float_arg(_a: DoubleFloat) {}
+
+// CHECK: .visible .entry f_triple_float_arg(
+// CHECK: .param .align 4 .b8 f_triple_float_arg_param_0[12]
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_triple_float_arg(_a: TripleFloat) {}
+
+// CHECK: .visible .entry f_triple_double_arg(
+// CHECK: .param .align 8 .b8 f_triple_double_arg_param_0[24]
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_triple_double_arg(_a: TripleDouble) {}
+
+// CHECK: .visible .entry f_many_numerics_arg(
+// CHECK: .param .align 8 .b8 f_many_numerics_arg_param_0[32]
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_many_numerics_arg(_a: ManyNumerics) {}
+
+// CHECK: .visible .entry f_byte_array_arg(
+// CHECK: .param .align 1 .b8 f_byte_array_arg_param_0[5]
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_byte_array_arg(_a: [u8; 5]) {}
+
+// CHECK: .visible .entry f_float_array_arg(
+// CHECK: .param .align 4 .b8 f_float_array_arg_param_0[20]
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_float_array_arg(_a: [f32; 5]) {}
+
+// CHECK: .visible .entry f_u128_array_arg(
+// CHECK: .param .align 16 .b8 f_u128_array_arg_param_0[80]
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_u128_array_arg(_a: [u128; 5]) {}
+
+// CHECK: .visible .entry f_u32_slice_arg(
+// CHECK: .param .u64 f_u32_slice_arg_param_0
+// CHECK: .param .u64 f_u32_slice_arg_param_1
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_u32_slice_arg(_a: &[u32]) {}
+
+// CHECK: .visible .entry f_tuple_u8_u8_arg(
+// CHECK: .param .align 1 .b8 f_tuple_u8_u8_arg_param_0[2]
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_tuple_u8_u8_arg(_a: (u8, u8)) {}
+
+// CHECK: .visible .entry f_tuple_u32_u32_arg(
+// CHECK: .param .align 4 .b8 f_tuple_u32_u32_arg_param_0[8]
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_tuple_u32_u32_arg(_a: (u32, u32)) {}
+
+
+// CHECK: .visible .entry f_tuple_u8_u8_u32_arg(
+// CHECK: .param .align 4 .b8 f_tuple_u8_u8_u32_arg_param_0[8]
+#[no_mangle]
+pub unsafe extern "ptx-kernel" fn f_tuple_u8_u8_u32_arg(_a: (u8, u8, u32)) {}
index 39f73c4e3967eff439afc494819ca778521d7a91..7a84484c41996906a75af3073afb4f81be5e17ec 100644 (file)
@@ -1,14 +1,12 @@
-// compile-flags: -Z panic-in-drop=abort -O -Z new-llvm-pass-manager=no
+// compile-flags: -Z panic-in-drop=abort -O
+// ignore-msvc
 
 // Ensure that unwinding code paths are eliminated from the output after
 // optimization.
 
-// This test uses -Z new-llvm-pass-manager=no, because the expected optimization does not happen
-// on targets using SEH exceptions (i.e. MSVC) anymore. The core issue is that Rust promises that
-// the drop_in_place() function can't unwind, but implements it in a way that *can*, because we
-// currently go out of our way to allow longjmps, which also use the unwinding mechanism on MSVC
-// targets. We should either forbid longjmps, or not assume nounwind, making this optimization
-// incompatible with the current behavior of running cleanuppads on longjmp unwinding.
+// This test uses ignore-msvc, because the expected optimization does not happen on targets using
+// SEH exceptions with the new LLVM pass manager anymore, see
+// https://github.com/llvm/llvm-project/issues/51311.
 
 // CHECK-NOT: {{(call|invoke).*}}should_not_appear_in_output
 
index 698dfe6b4f3419e76f7770b06136dfe13e53294d..b13d576295c605f968df697caaf99d9c48be21e4 100644 (file)
@@ -22,7 +22,7 @@ fn main() {
 }
 
 // Here we check that local debuginfo is mapped correctly.
-// CHECK: !DIFile(filename: "/the/src/remap_path_prefix/main.rs", directory: "/the/cwd/"
+// CHECK: !DIFile(filename: "/the/src/remap_path_prefix/main.rs", directory: "/the/cwd"
 
 // And here that debuginfo from other crates are expanded to absolute paths.
 // CHECK: !DIFile(filename: "/the/aux-src/remap_path_prefix_aux.rs", directory: ""
diff --git a/src/test/codegen/vec-calloc.rs b/src/test/codegen/vec-calloc.rs
new file mode 100644 (file)
index 0000000..c616e9f
--- /dev/null
@@ -0,0 +1,32 @@
+// compile-flags: -O
+// only-x86_64
+// ignore-debug
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @vec_zero_scalar
+#[no_mangle]
+pub fn vec_zero_scalar(n: usize) -> Vec<i32> {
+    // CHECK-NOT: __rust_alloc(
+    // CHECK: __rust_alloc_zeroed(
+    // CHECK-NOT: __rust_alloc(
+    vec![0; n]
+}
+
+// CHECK-LABEL: @vec_zero_rgb48
+#[no_mangle]
+pub fn vec_zero_rgb48(n: usize) -> Vec<[u16; 3]> {
+    // CHECK-NOT: __rust_alloc(
+    // CHECK: __rust_alloc_zeroed(
+    // CHECK-NOT: __rust_alloc(
+    vec![[0, 0, 0]; n]
+}
+
+// CHECK-LABEL: @vec_zero_array_32
+#[no_mangle]
+pub fn vec_zero_array_32(n: usize) -> Vec<[i64; 32]> {
+    // CHECK-NOT: __rust_alloc(
+    // CHECK: __rust_alloc_zeroed(
+    // CHECK-NOT: __rust_alloc(
+    vec![[0_i64; 32]; n]
+}
index 531c37a3421198939bb94ed5a983cd24d1eae917..388d50c5cdc43627eae454d9abea881bf3d6c2a5 100644 (file)
@@ -14,7 +14,7 @@
 //
 // cdb-command:dx t,d
 // cdb-check:t,d              : [...] [Type: std::thread::Thread *]
-// cdb-check:    [...] inner            : {...} [Type: alloc::sync::Arc<std::thread::Inner>]
+// cdb-check:[...] inner [...][Type: core::pin::Pin<alloc::sync::Arc<std::thread::Inner> >]
 
 use std::thread;
 
diff --git a/src/test/debuginfo/unit-type.rs b/src/test/debuginfo/unit-type.rs
new file mode 100644 (file)
index 0000000..7aab41a
--- /dev/null
@@ -0,0 +1,71 @@
+// compile-flags:-g
+
+// We only test Rust-aware versions of GDB:
+// min-gdb-version: 8.2
+
+// === GDB TESTS ===================================================================================
+
+// gdb-command: run
+
+// gdb-command: print _ref
+// gdb-check: $1 = (*mut ()) 0x[...]
+
+// gdb-command: print _ptr
+// gdb-check: $2 = (*mut ()) 0x[...]
+
+// gdb-command: print _local
+// gdb-check: $3 = ()
+
+// gdb-command: print _field
+// gdb-check: $4 = unit_type::_TypeContainingUnitField {_a: 123, _unit: (), _b: 456}
+
+// Check that we can cast "void pointers" to their actual type in the debugger
+// gdb-command: print /x *(_ptr as *const u64)
+// gdb-check: $5 = 0x1122334455667788
+
+// === CDB TESTS ===================================================================================
+
+// cdb-command: g
+// cdb-check: Breakpoint 0 hit
+
+// cdb-command: dx _ref
+// cdb-check: _ref             : 0x[...] : () [Type: tuple$<> *]
+
+// cdb-command: dx _ptr
+// cdb-check: _ptr             : 0x[...] : () [Type: tuple$<> *]
+
+// cdb-command: dx _local
+// cdb-check: _local           : () [Type: tuple$<>]
+
+// cdb-command: dx _field,d
+// cdb-check: _field,d         [Type: unit_type::_TypeContainingUnitField]
+// cdb-check:     [+0x[...]] _a               : 123 [Type: unsigned int]
+// cdb-check:     [+0x[...]] _unit            : () [Type: tuple$<>]
+// cdb-check:     [+0x[...]] _b               : 456 [Type: unsigned __int64]
+
+// Check that we can cast "void pointers" to their actual type in the debugger
+// cdb-command: dx ((__int64 *)_ptr),x
+// cdb-check: ((__int64 *)_ptr),x : 0x[...] : 0x1122334455667788 [Type: __int64 *]
+// cdb-check:     0x1122334455667788 [Type: __int64]
+
+struct _TypeContainingUnitField {
+    _a: u32,
+    _unit: (),
+    _b: u64,
+}
+
+fn foo(_ref: &(), _ptr: *const ()) {
+    let _local = ();
+    let _field = _TypeContainingUnitField { _a: 123, _unit: (), _b: 456 };
+
+    zzz(); // #break
+}
+
+fn main() {
+    let pointee = 0x1122_3344_5566_7788i64;
+
+    foo(&(), &pointee as *const i64 as *const ());
+}
+
+#[inline(never)]
+fn zzz() {}
index ab9c740844b8fd3967b28fd69d8a3461fda9f2d0..6582cdc4a2c85e4ba16c11e3329022092a9af43a 100644 (file)
 
 // Change enum visibility -----------------------------------------------------
 #[cfg(any(cfail1,cfail4))]
-enum EnumVisibility { A }
+enum     EnumVisibility { A }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
 #[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes")]
 #[rustc_clean(cfg="cfail6")]
-pub enum EnumVisibility {
-    A
-}
+pub enum EnumVisibility { A }
 
 
 
index 22508e41bf83496ec0535b332a501ee6729ade27..5463b0dc87e4020ba43ee5c236d781b5e8af157d 100644 (file)
@@ -116,7 +116,7 @@ pub fn method_body_inlined() {
 // Change Method Privacy -------------------------------------------------------
 #[cfg(any(cfail1,cfail4))]
 impl Foo {
-    //------------------------------------------------------------------------------
+    //----------------------------------------------------
     //--------------------------
     //------------------------------------------------------------------------------
     //--------------------------
@@ -129,9 +129,9 @@ pub fn method_privacy() { }
 #[rustc_clean(cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 impl Foo {
-    #[rustc_clean(cfg="cfail2", except="associated_item,hir_owner,hir_owner_nodes")]
+    #[rustc_clean(cfg="cfail2", except="associated_item")]
     #[rustc_clean(cfg="cfail3")]
-    #[rustc_clean(cfg="cfail5", except="associated_item,hir_owner,hir_owner_nodes")]
+    #[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,associated_item")]
     #[rustc_clean(cfg="cfail6")]
     fn     method_privacy() { }
 }
index 2b2658b2f5f07b8f2107deb8535ab5c40fb24541..697be056761530e4312b751604fb17ee09d51c25 100644 (file)
 
 // Change static visibility
 #[cfg(any(cfail1,cfail4))]
-static STATIC_VISIBILITY: u8 = 0;
+static     STATIC_VISIBILITY: u8 = 0;
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
 #[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes")]
 #[rustc_clean(cfg="cfail6")]
index b5d8a3ab34103d0d6380ae91cb46e2136a70ef65..b4d558d259fe696b734fa402af305ede5fdb45e9 100644 (file)
@@ -84,12 +84,12 @@ struct TupleStructAddField(
 // Tuple Struct Field Visibility -----------------------------------------------
 
 #[cfg(any(cfail1,cfail4))]
-struct TupleStructFieldVisibility(char);
+struct TupleStructFieldVisibility(    char);
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail2", except="type_of")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail5")]
+#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,type_of")]
 #[rustc_clean(cfg="cfail6")]
 struct TupleStructFieldVisibility(pub char);
 
@@ -142,16 +142,14 @@ struct RecordStructAddField {
 // Record Struct Field Visibility ----------------------------------------------
 
 #[cfg(any(cfail1,cfail4))]
-struct RecordStructFieldVisibility { x: f32 }
+struct RecordStructFieldVisibility {     x: f32 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail2", except="type_of")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail5")]
+#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,type_of")]
 #[rustc_clean(cfg="cfail6")]
-struct RecordStructFieldVisibility {
-    pub x: f32
-}
+struct RecordStructFieldVisibility { pub x: f32 }
 
 
 // Add Lifetime Parameter ------------------------------------------------------
@@ -257,12 +255,12 @@ struct AddTypeParameterBoundWhereClause<T>(
 // Visibility ------------------------------------------------------------------
 
 #[cfg(any(cfail1,cfail4))]
-struct Visibility;
+struct     Visibility;
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
+#[rustc_clean(cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")]
+#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes")]
 #[rustc_clean(cfg="cfail6")]
 pub struct Visibility;
 
index 279449fce5e6feefc14393745407d15dcd34d794..717e9e8c8e1112bea8ad0679fc0d4c73e4b98c25 100644 (file)
@@ -31,9 +31,9 @@
 trait TraitVisibility { }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
+#[rustc_clean(cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")]
+#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes")]
 #[rustc_clean(cfg="cfail6")]
 pub trait TraitVisibility { }
 
index 0972d2d68a115f143b3d4660ebca56941e325c2d..7cc50a86e21e1d5ab813f4de454f456ca9403b93 100644 (file)
@@ -1,4 +1,4 @@
-// compile-flags: -C opt-level=0 -Z inline_mir=no
+// unit-test: InstCombine
 // ignore-wasm32 compiled with panic=abort by default
 
 // EMIT_MIR combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff
index 678e965cd67f268826bef48339f298e36283fd39..fdc016a95d58e68738edefe4e7dc7f82455d8b88 100644 (file)
       }
   
       bb0: {
+          StorageLive(_2);                 // scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
           _2 = &((*_1).0: T);              // scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
+          StorageLive(_3);                 // scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
           _3 = &((*_1).1: u64);            // scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
+          StorageLive(_4);                 // scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
           _4 = &((*_1).2: [f32; 3]);       // scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
+          StorageLive(_5);                 // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
+          StorageLive(_6);                 // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
+          StorageLive(_7);                 // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
 -         _7 = &(*_2);                     // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
 -         _6 = &(*_7);                     // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
 +         _7 = _2;                         // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
       }
   
       bb1: {
+          StorageDead(_6);                 // scope 1 at $DIR/combine_clone_of_primitives.rs:8:8: 8:9
+          StorageLive(_8);                 // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
+          StorageLive(_9);                 // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
+          StorageLive(_10);                // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
 -         _10 = &(*_3);                    // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
 -         _9 = &(*_10);                    // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
 -         _8 = <u64 as Clone>::clone(move _9) -> [return: bb2, unwind: bb4]; // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
       }
   
       bb2: {
+          StorageDead(_9);                 // scope 1 at $DIR/combine_clone_of_primitives.rs:9:10: 9:11
+          StorageLive(_11);                // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
+          StorageLive(_12);                // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
+          StorageLive(_13);                // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
 -         _13 = &(*_4);                    // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
 -         _12 = &(*_13);                   // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
 -         _11 = <[f32; 3] as Clone>::clone(move _12) -> [return: bb3, unwind: bb4]; // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
       }
   
       bb3: {
+          StorageDead(_12);                // scope 1 at $DIR/combine_clone_of_primitives.rs:10:15: 10:16
           Deinit(_0);                      // scope 1 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15
           (_0.0: T) = move _5;             // scope 1 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15
           (_0.1: u64) = move _8;           // scope 1 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15
           (_0.2: [f32; 3]) = move _11;     // scope 1 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15
+          StorageDead(_13);                // scope 1 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15
+          StorageDead(_11);                // scope 1 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15
+          StorageDead(_10);                // scope 1 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15
+          StorageDead(_8);                 // scope 1 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15
+          StorageDead(_7);                 // scope 1 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15
+          StorageDead(_5);                 // scope 1 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15
+          StorageDead(_4);                 // scope 0 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15
+          StorageDead(_3);                 // scope 0 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15
+          StorageDead(_2);                 // scope 0 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15
           return;                          // scope 0 at $DIR/combine_clone_of_primitives.rs:6:15: 6:15
       }
   
diff --git a/src/test/mir-opt/derefer_complex_case.main.Derefer.diff b/src/test/mir-opt/derefer_complex_case.main.Derefer.diff
new file mode 100644 (file)
index 0000000..f5eabf8
--- /dev/null
@@ -0,0 +1,111 @@
+- // MIR for `main` before Derefer
++ // MIR for `main` after Derefer
+  
+  fn main() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/derefer_complex_case.rs:3:11: 3:11
+      let mut _1: std::slice::Iter<i32>;   // in scope 0 at $DIR/derefer_complex_case.rs:4:17: 4:26
+      let mut _2: &[i32; 2];               // in scope 0 at $DIR/derefer_complex_case.rs:4:17: 4:26
+      let _3: [i32; 2];                    // in scope 0 at $DIR/derefer_complex_case.rs:4:18: 4:26
+      let mut _4: std::slice::Iter<i32>;   // in scope 0 at $DIR/derefer_complex_case.rs:4:17: 4:26
+      let mut _5: ();                      // in scope 0 at $DIR/derefer_complex_case.rs:3:1: 5:2
+      let _6: ();                          // in scope 0 at $DIR/derefer_complex_case.rs:4:17: 4:26
+      let mut _7: std::option::Option<&i32>; // in scope 0 at $DIR/derefer_complex_case.rs:4:17: 4:26
+      let mut _8: &mut std::slice::Iter<i32>; // in scope 0 at $DIR/derefer_complex_case.rs:4:17: 4:26
+      let mut _9: &mut std::slice::Iter<i32>; // in scope 0 at $DIR/derefer_complex_case.rs:4:17: 4:26
+      let mut _10: isize;                  // in scope 0 at $DIR/derefer_complex_case.rs:4:5: 4:40
+      let mut _11: !;                      // in scope 0 at $DIR/derefer_complex_case.rs:4:5: 4:40
+      let mut _13: i32;                    // in scope 0 at $DIR/derefer_complex_case.rs:4:34: 4:37
+      let mut _14: &[i32; 2];              // in scope 0 at $DIR/derefer_complex_case.rs:4:17: 4:26
++     let mut _15: &i32;                   // in scope 0 at $DIR/derefer_complex_case.rs:4:17: 4:26
+      scope 1 {
+          debug iter => _4;                // in scope 1 at $DIR/derefer_complex_case.rs:4:17: 4:26
+          let _12: i32;                    // in scope 1 at $DIR/derefer_complex_case.rs:4:10: 4:13
+          scope 2 {
+              debug foo => _12;            // in scope 2 at $DIR/derefer_complex_case.rs:4:10: 4:13
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/derefer_complex_case.rs:4:17: 4:26
+          StorageLive(_2);                 // scope 0 at $DIR/derefer_complex_case.rs:4:17: 4:26
+          _14 = const main::promoted[0];   // scope 0 at $DIR/derefer_complex_case.rs:4:17: 4:26
+                                           // mir::Constant
+                                           // + span: $DIR/derefer_complex_case.rs:4:17: 4:26
+                                           // + literal: Const { ty: &[i32; 2], val: Unevaluated(main, [], Some(promoted[0])) }
+          _2 = &(*_14);                    // scope 0 at $DIR/derefer_complex_case.rs:4:17: 4:26
+          _1 = <&[i32; 2] as IntoIterator>::into_iter(move _2) -> bb1; // scope 0 at $DIR/derefer_complex_case.rs:4:17: 4:26
+                                           // mir::Constant
+                                           // + span: $DIR/derefer_complex_case.rs:4:17: 4:26
+                                           // + literal: Const { ty: fn(&[i32; 2]) -> <&[i32; 2] as IntoIterator>::IntoIter {<&[i32; 2] as IntoIterator>::into_iter}, val: Value(Scalar(<ZST>)) }
+      }
+  
+      bb1: {
+          StorageDead(_2);                 // scope 0 at $DIR/derefer_complex_case.rs:4:25: 4:26
+          StorageLive(_4);                 // scope 0 at $DIR/derefer_complex_case.rs:4:17: 4:26
+          _4 = move _1;                    // scope 0 at $DIR/derefer_complex_case.rs:4:17: 4:26
+          goto -> bb2;                     // scope 1 at $DIR/derefer_complex_case.rs:4:5: 4:40
+      }
+  
+      bb2: {
+          StorageLive(_6);                 // scope 1 at $DIR/derefer_complex_case.rs:4:17: 4:26
+          StorageLive(_7);                 // scope 1 at $DIR/derefer_complex_case.rs:4:17: 4:26
+          StorageLive(_8);                 // scope 1 at $DIR/derefer_complex_case.rs:4:17: 4:26
+          StorageLive(_9);                 // scope 1 at $DIR/derefer_complex_case.rs:4:17: 4:26
+          _9 = &mut _4;                    // scope 1 at $DIR/derefer_complex_case.rs:4:17: 4:26
+          _8 = &mut (*_9);                 // scope 1 at $DIR/derefer_complex_case.rs:4:17: 4:26
+          _7 = <std::slice::Iter<i32> as Iterator>::next(move _8) -> bb3; // scope 1 at $DIR/derefer_complex_case.rs:4:17: 4:26
+                                           // mir::Constant
+                                           // + span: $DIR/derefer_complex_case.rs:4:17: 4:26
+                                           // + literal: Const { ty: for<'r> fn(&'r mut std::slice::Iter<i32>) -> Option<<std::slice::Iter<i32> as Iterator>::Item> {<std::slice::Iter<i32> as Iterator>::next}, val: Value(Scalar(<ZST>)) }
+      }
+  
+      bb3: {
+          StorageDead(_8);                 // scope 1 at $DIR/derefer_complex_case.rs:4:25: 4:26
+          _10 = discriminant(_7);          // scope 1 at $DIR/derefer_complex_case.rs:4:17: 4:26
+          switchInt(move _10) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 1 at $DIR/derefer_complex_case.rs:4:17: 4:26
+      }
+  
+      bb4: {
+          StorageLive(_12);                // scope 1 at $DIR/derefer_complex_case.rs:4:10: 4:13
+-         _12 = (*((_7 as Some).0: &i32)); // scope 1 at $DIR/derefer_complex_case.rs:4:10: 4:13
++         StorageLive(_15);                // scope 1 at $DIR/derefer_complex_case.rs:4:10: 4:13
++         _15 = move ((_7 as Some).0: &i32); // scope 1 at $DIR/derefer_complex_case.rs:4:10: 4:13
++         _12 = (*_15);                    // scope 1 at $DIR/derefer_complex_case.rs:4:10: 4:13
++         StorageDead(_15);                // scope 2 at $DIR/derefer_complex_case.rs:4:34: 4:37
+          StorageLive(_13);                // scope 2 at $DIR/derefer_complex_case.rs:4:34: 4:37
+          _13 = _12;                       // scope 2 at $DIR/derefer_complex_case.rs:4:34: 4:37
+          _6 = std::mem::drop::<i32>(move _13) -> bb7; // scope 2 at $DIR/derefer_complex_case.rs:4:29: 4:38
+                                           // mir::Constant
+                                           // + span: $DIR/derefer_complex_case.rs:4:29: 4:33
+                                           // + literal: Const { ty: fn(i32) {std::mem::drop::<i32>}, val: Value(Scalar(<ZST>)) }
+      }
+  
+      bb5: {
+          unreachable;                     // scope 1 at $DIR/derefer_complex_case.rs:4:17: 4:26
+      }
+  
+      bb6: {
+          _0 = const ();                   // scope 1 at $DIR/derefer_complex_case.rs:4:5: 4:40
+          StorageDead(_9);                 // scope 1 at $DIR/derefer_complex_case.rs:4:39: 4:40
+          StorageDead(_7);                 // scope 1 at $DIR/derefer_complex_case.rs:4:39: 4:40
+          StorageDead(_6);                 // scope 1 at $DIR/derefer_complex_case.rs:4:39: 4:40
+          StorageDead(_4);                 // scope 0 at $DIR/derefer_complex_case.rs:4:39: 4:40
+          StorageDead(_1);                 // scope 0 at $DIR/derefer_complex_case.rs:4:39: 4:40
+          return;                          // scope 0 at $DIR/derefer_complex_case.rs:5:2: 5:2
+      }
+  
+      bb7: {
+          StorageDead(_13);                // scope 2 at $DIR/derefer_complex_case.rs:4:37: 4:38
+          StorageDead(_12);                // scope 1 at $DIR/derefer_complex_case.rs:4:39: 4:40
+          StorageDead(_9);                 // scope 1 at $DIR/derefer_complex_case.rs:4:39: 4:40
+          StorageDead(_7);                 // scope 1 at $DIR/derefer_complex_case.rs:4:39: 4:40
+          StorageDead(_6);                 // scope 1 at $DIR/derefer_complex_case.rs:4:39: 4:40
+          _5 = const ();                   // scope 1 at $DIR/derefer_complex_case.rs:4:5: 4:40
+          goto -> bb2;                     // scope 1 at $DIR/derefer_complex_case.rs:4:5: 4:40
+      }
+  
+      bb8 (cleanup): {
+          resume;                          // scope 0 at $DIR/derefer_complex_case.rs:3:1: 5:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/derefer_complex_case.rs b/src/test/mir-opt/derefer_complex_case.rs
new file mode 100644 (file)
index 0000000..6abf49f
--- /dev/null
@@ -0,0 +1,5 @@
+// EMIT_MIR derefer_complex_case.main.Derefer.diff
+
+fn main() {
+    for &foo in &[42, 43] { drop(foo) }
+}
diff --git a/src/test/mir-opt/derefer_terminator_test.main.Derefer.diff b/src/test/mir-opt/derefer_terminator_test.main.Derefer.diff
new file mode 100644 (file)
index 0000000..8b91a65
--- /dev/null
@@ -0,0 +1,103 @@
+- // MIR for `main` before Derefer
++ // MIR for `main` after Derefer
+  
+  fn main() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/derefer_terminator_test.rs:2:11: 2:11
+      let _1: bool;                        // in scope 0 at $DIR/derefer_terminator_test.rs:3:9: 3:10
+      let _3: ();                          // in scope 0 at $DIR/derefer_terminator_test.rs:5:5: 8:6
+      let mut _4: &&&&bool;                // in scope 0 at $DIR/derefer_terminator_test.rs:5:15: 5:22
+      let _5: &&&bool;                     // in scope 0 at $DIR/derefer_terminator_test.rs:5:17: 5:21
+      let _6: &&bool;                      // in scope 0 at $DIR/derefer_terminator_test.rs:5:18: 5:21
+      let _7: &bool;                       // in scope 0 at $DIR/derefer_terminator_test.rs:5:19: 5:21
++     let mut _10: &&&bool;                // in scope 0 at $DIR/derefer_terminator_test.rs:5:15: 5:22
++     let mut _11: &&bool;                 // in scope 0 at $DIR/derefer_terminator_test.rs:5:15: 5:22
++     let mut _12: &bool;                  // in scope 0 at $DIR/derefer_terminator_test.rs:5:15: 5:22
+      scope 1 {
+          debug b => _1;                   // in scope 1 at $DIR/derefer_terminator_test.rs:3:9: 3:10
+          let _2: bool;                    // in scope 1 at $DIR/derefer_terminator_test.rs:4:9: 4:10
+          scope 2 {
+              debug d => _2;               // in scope 2 at $DIR/derefer_terminator_test.rs:4:9: 4:10
+              let _8: i32;                 // in scope 2 at $DIR/derefer_terminator_test.rs:6:22: 6:23
+              let _9: i32;                 // in scope 2 at $DIR/derefer_terminator_test.rs:9:9: 9:10
+              scope 3 {
+                  debug x => _8;           // in scope 3 at $DIR/derefer_terminator_test.rs:6:22: 6:23
+              }
+              scope 4 {
+                  debug y => _9;           // in scope 4 at $DIR/derefer_terminator_test.rs:9:9: 9:10
+              }
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/derefer_terminator_test.rs:3:9: 3:10
+          _1 = foo() -> bb1;               // scope 0 at $DIR/derefer_terminator_test.rs:3:13: 3:18
+                                           // mir::Constant
+                                           // + span: $DIR/derefer_terminator_test.rs:3:13: 3:16
+                                           // + literal: Const { ty: fn() -> bool {foo}, val: Value(Scalar(<ZST>)) }
+      }
+  
+      bb1: {
+          StorageLive(_2);                 // scope 1 at $DIR/derefer_terminator_test.rs:4:9: 4:10
+          _2 = foo() -> bb2;               // scope 1 at $DIR/derefer_terminator_test.rs:4:13: 4:18
+                                           // mir::Constant
+                                           // + span: $DIR/derefer_terminator_test.rs:4:13: 4:16
+                                           // + literal: Const { ty: fn() -> bool {foo}, val: Value(Scalar(<ZST>)) }
+      }
+  
+      bb2: {
+          StorageLive(_3);                 // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 8:6
+          StorageLive(_4);                 // scope 2 at $DIR/derefer_terminator_test.rs:5:15: 5:22
+          StorageLive(_5);                 // scope 2 at $DIR/derefer_terminator_test.rs:5:17: 5:21
+          StorageLive(_6);                 // scope 2 at $DIR/derefer_terminator_test.rs:5:18: 5:21
+          StorageLive(_7);                 // scope 2 at $DIR/derefer_terminator_test.rs:5:19: 5:21
+          _7 = &_1;                        // scope 2 at $DIR/derefer_terminator_test.rs:5:19: 5:21
+          _6 = &_7;                        // scope 2 at $DIR/derefer_terminator_test.rs:5:18: 5:21
+          _5 = &_6;                        // scope 2 at $DIR/derefer_terminator_test.rs:5:17: 5:21
+          _4 = &_5;                        // scope 2 at $DIR/derefer_terminator_test.rs:5:15: 5:22
+-         switchInt((*(*(*(*_4))))) -> [false: bb3, otherwise: bb4]; // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22
++         StorageLive(_10);                // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22
++         _10 = move (*_4);                // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22
++         StorageLive(_11);                // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22
++         _11 = move (*_10);               // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22
++         StorageDead(_10);                // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22
++         StorageLive(_12);                // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22
++         _12 = move (*_11);               // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22
++         StorageDead(_11);                // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22
++         switchInt((*_12)) -> [false: bb3, otherwise: bb4]; // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22
+      }
+  
+      bb3: {
++         StorageDead(_12);                // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22
+          _3 = const ();                   // scope 2 at $DIR/derefer_terminator_test.rs:7:18: 7:20
+          goto -> bb5;                     // scope 2 at $DIR/derefer_terminator_test.rs:7:18: 7:20
+      }
+  
+      bb4: {
++         StorageDead(_12);                // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22
+          StorageLive(_8);                 // scope 2 at $DIR/derefer_terminator_test.rs:6:22: 6:23
+          _8 = const 5_i32;                // scope 2 at $DIR/derefer_terminator_test.rs:6:26: 6:27
+          _3 = const ();                   // scope 2 at $DIR/derefer_terminator_test.rs:6:17: 6:29
+          StorageDead(_8);                 // scope 2 at $DIR/derefer_terminator_test.rs:6:28: 6:29
+          goto -> bb5;                     // scope 2 at $DIR/derefer_terminator_test.rs:6:28: 6:29
+      }
+  
+      bb5: {
+          StorageDead(_7);                 // scope 2 at $DIR/derefer_terminator_test.rs:8:5: 8:6
+          StorageDead(_6);                 // scope 2 at $DIR/derefer_terminator_test.rs:8:5: 8:6
+          StorageDead(_5);                 // scope 2 at $DIR/derefer_terminator_test.rs:8:5: 8:6
+          StorageDead(_4);                 // scope 2 at $DIR/derefer_terminator_test.rs:8:5: 8:6
+          StorageDead(_3);                 // scope 2 at $DIR/derefer_terminator_test.rs:8:5: 8:6
+          StorageLive(_9);                 // scope 2 at $DIR/derefer_terminator_test.rs:9:9: 9:10
+          _9 = const 42_i32;               // scope 2 at $DIR/derefer_terminator_test.rs:9:13: 9:15
+          _0 = const ();                   // scope 0 at $DIR/derefer_terminator_test.rs:2:11: 10:2
+          StorageDead(_9);                 // scope 2 at $DIR/derefer_terminator_test.rs:10:1: 10:2
+          StorageDead(_2);                 // scope 1 at $DIR/derefer_terminator_test.rs:10:1: 10:2
+          StorageDead(_1);                 // scope 0 at $DIR/derefer_terminator_test.rs:10:1: 10:2
+          return;                          // scope 0 at $DIR/derefer_terminator_test.rs:10:2: 10:2
+      }
+  
+      bb6 (cleanup): {
+          resume;                          // scope 0 at $DIR/derefer_terminator_test.rs:2:1: 10:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/derefer_terminator_test.rs b/src/test/mir-opt/derefer_terminator_test.rs
new file mode 100644 (file)
index 0000000..11f5b20
--- /dev/null
@@ -0,0 +1,14 @@
+// EMIT_MIR derefer_terminator_test.main.Derefer.diff
+fn main() {
+    let b = foo();
+    let d = foo();
+    match ****(&&&&b) {
+        true => {let x = 5;},
+        false => {}
+    }
+    let y = 42;
+}
+
+fn foo() -> bool {
+    true
+}
index d58e4eb838d1b34ac2edea296a2ea1cc6ebf9b22..84476aeed7a6ca3eb2a8105e1c635ce231008db9 100644 (file)
@@ -5,8 +5,8 @@
       let mut _0: ();                      // return place in scope 0 at $DIR/derefer_test.rs:2:11: 2:11
       let mut _1: (i32, i32);              // in scope 0 at $DIR/derefer_test.rs:3:9: 3:14
       let mut _3: &mut (i32, i32);         // in scope 0 at $DIR/derefer_test.rs:4:22: 4:28
-+     let mut _6: &mut (i32, i32);         // in scope 0 at $DIR/derefer_test.rs:5:13: 5:26
-+     let mut _7: &mut (i32, i32);         // in scope 0 at $DIR/derefer_test.rs:6:13: 6:26
++     let mut _6: &mut (i32, i32);         // in scope 0 at $DIR/derefer_test.rs:4:9: 4:14
++     let mut _7: &mut (i32, i32);         // in scope 0 at $DIR/derefer_test.rs:4:9: 4:14
       scope 1 {
           debug a => _1;                   // in scope 1 at $DIR/derefer_test.rs:3:9: 3:14
           let mut _2: (i32, &mut (i32, i32)); // in scope 1 at $DIR/derefer_test.rs:4:9: 4:14
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/derefer_test.rs:3:9: 3:14
-          Deinit(_1);                      // scope 0 at $DIR/derefer_test.rs:3:17: 3:24
-          (_1.0: i32) = const 42_i32;      // scope 0 at $DIR/derefer_test.rs:3:17: 3:24
-          (_1.1: i32) = const 43_i32;      // scope 0 at $DIR/derefer_test.rs:3:17: 3:24
+          _1 = (const 42_i32, const 43_i32); // scope 0 at $DIR/derefer_test.rs:3:17: 3:24
           StorageLive(_2);                 // scope 1 at $DIR/derefer_test.rs:4:9: 4:14
           StorageLive(_3);                 // scope 1 at $DIR/derefer_test.rs:4:22: 4:28
           _3 = &mut _1;                    // scope 1 at $DIR/derefer_test.rs:4:22: 4:28
-          Deinit(_2);                      // scope 1 at $DIR/derefer_test.rs:4:17: 4:29
-          (_2.0: i32) = const 99_i32;      // scope 1 at $DIR/derefer_test.rs:4:17: 4:29
-          (_2.1: &mut (i32, i32)) = move _3; // scope 1 at $DIR/derefer_test.rs:4:17: 4:29
+          _2 = (const 99_i32, move _3);    // scope 1 at $DIR/derefer_test.rs:4:17: 4:29
           StorageDead(_3);                 // scope 1 at $DIR/derefer_test.rs:4:28: 4:29
           StorageLive(_4);                 // scope 2 at $DIR/derefer_test.rs:5:9: 5:10
 -         _4 = &mut ((*(_2.1: &mut (i32, i32))).0: i32); // scope 2 at $DIR/derefer_test.rs:5:13: 5:26
           StorageDead(_2);                 // scope 1 at $DIR/derefer_test.rs:7:1: 7:2
           StorageDead(_1);                 // scope 0 at $DIR/derefer_test.rs:7:1: 7:2
           return;                          // scope 0 at $DIR/derefer_test.rs:7:2: 7:2
-+     }
-+ 
-+     bb1 (cleanup): {
-+         resume;                          // scope 0 at $DIR/derefer_test.rs:2:1: 7:2
+      }
+  
+      bb1 (cleanup): {
+          resume;                          // scope 0 at $DIR/derefer_test.rs:2:1: 7:2
       }
   }
   
index db24f71c75045fc7995c354a11bb1770f5e08e35..b8e5a0c328f4d490ad1d9beab2d43a01e5c74229 100644 (file)
@@ -7,12 +7,12 @@
       let mut _3: &mut (i32, i32);         // in scope 0 at $DIR/derefer_test_multiple.rs:4:22: 4:28
       let mut _5: &mut (i32, &mut (i32, i32)); // in scope 0 at $DIR/derefer_test_multiple.rs:5:22: 5:28
       let mut _7: &mut (i32, &mut (i32, &mut (i32, i32))); // in scope 0 at $DIR/derefer_test_multiple.rs:6:22: 6:28
-+     let mut _10: &mut (i32, &mut (i32, &mut (i32, i32))); // in scope 0 at $DIR/derefer_test_multiple.rs:7:13: 7:30
-+     let mut _11: &mut (i32, &mut (i32, i32)); // in scope 0 at $DIR/derefer_test_multiple.rs:7:13: 7:30
-+     let mut _12: &mut (i32, i32);        // in scope 0 at $DIR/derefer_test_multiple.rs:7:13: 7:30
-+     let mut _13: &mut (i32, &mut (i32, &mut (i32, i32))); // in scope 0 at $DIR/derefer_test_multiple.rs:8:13: 8:30
-+     let mut _14: &mut (i32, &mut (i32, i32)); // in scope 0 at $DIR/derefer_test_multiple.rs:8:13: 8:30
-+     let mut _15: &mut (i32, i32);        // in scope 0 at $DIR/derefer_test_multiple.rs:8:13: 8:30
++     let mut _10: &mut (i32, &mut (i32, &mut (i32, i32))); // in scope 0 at $DIR/derefer_test_multiple.rs:6:9: 6:14
++     let mut _11: &mut (i32, &mut (i32, i32)); // in scope 0 at $DIR/derefer_test_multiple.rs:6:9: 6:14
++     let mut _12: &mut (i32, i32);        // in scope 0 at $DIR/derefer_test_multiple.rs:6:9: 6:14
++     let mut _13: &mut (i32, &mut (i32, &mut (i32, i32))); // in scope 0 at $DIR/derefer_test_multiple.rs:6:9: 6:14
++     let mut _14: &mut (i32, &mut (i32, i32)); // in scope 0 at $DIR/derefer_test_multiple.rs:6:9: 6:14
++     let mut _15: &mut (i32, i32);        // in scope 0 at $DIR/derefer_test_multiple.rs:6:9: 6:14
       scope 1 {
           debug a => _1;                   // in scope 1 at $DIR/derefer_test_multiple.rs:3:9: 3:14
           let mut _2: (i32, &mut (i32, i32)); // in scope 1 at $DIR/derefer_test_multiple.rs:4:9: 4:14
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/derefer_test_multiple.rs:3:9: 3:14
-          Deinit(_1);                      // scope 0 at $DIR/derefer_test_multiple.rs:3:17: 3:25
-          (_1.0: i32) = const 42_i32;      // scope 0 at $DIR/derefer_test_multiple.rs:3:17: 3:25
-          (_1.1: i32) = const 43_i32;      // scope 0 at $DIR/derefer_test_multiple.rs:3:17: 3:25
+          _1 = (const 42_i32, const 43_i32); // scope 0 at $DIR/derefer_test_multiple.rs:3:17: 3:25
           StorageLive(_2);                 // scope 1 at $DIR/derefer_test_multiple.rs:4:9: 4:14
           StorageLive(_3);                 // scope 1 at $DIR/derefer_test_multiple.rs:4:22: 4:28
           _3 = &mut _1;                    // scope 1 at $DIR/derefer_test_multiple.rs:4:22: 4:28
-          Deinit(_2);                      // scope 1 at $DIR/derefer_test_multiple.rs:4:17: 4:29
-          (_2.0: i32) = const 99_i32;      // scope 1 at $DIR/derefer_test_multiple.rs:4:17: 4:29
-          (_2.1: &mut (i32, i32)) = move _3; // scope 1 at $DIR/derefer_test_multiple.rs:4:17: 4:29
+          _2 = (const 99_i32, move _3);    // scope 1 at $DIR/derefer_test_multiple.rs:4:17: 4:29
           StorageDead(_3);                 // scope 1 at $DIR/derefer_test_multiple.rs:4:28: 4:29
           StorageLive(_4);                 // scope 2 at $DIR/derefer_test_multiple.rs:5:9: 5:14
           StorageLive(_5);                 // scope 2 at $DIR/derefer_test_multiple.rs:5:22: 5:28
           _5 = &mut _2;                    // scope 2 at $DIR/derefer_test_multiple.rs:5:22: 5:28
-          Deinit(_4);                      // scope 2 at $DIR/derefer_test_multiple.rs:5:17: 5:29
-          (_4.0: i32) = const 11_i32;      // scope 2 at $DIR/derefer_test_multiple.rs:5:17: 5:29
-          (_4.1: &mut (i32, &mut (i32, i32))) = move _5; // scope 2 at $DIR/derefer_test_multiple.rs:5:17: 5:29
+          _4 = (const 11_i32, move _5);    // scope 2 at $DIR/derefer_test_multiple.rs:5:17: 5:29
           StorageDead(_5);                 // scope 2 at $DIR/derefer_test_multiple.rs:5:28: 5:29
           StorageLive(_6);                 // scope 3 at $DIR/derefer_test_multiple.rs:6:9: 6:14
           StorageLive(_7);                 // scope 3 at $DIR/derefer_test_multiple.rs:6:22: 6:28
           _7 = &mut _4;                    // scope 3 at $DIR/derefer_test_multiple.rs:6:22: 6:28
-          Deinit(_6);                      // scope 3 at $DIR/derefer_test_multiple.rs:6:17: 6:29
-          (_6.0: i32) = const 13_i32;      // scope 3 at $DIR/derefer_test_multiple.rs:6:17: 6:29
-          (_6.1: &mut (i32, &mut (i32, &mut (i32, i32)))) = move _7; // scope 3 at $DIR/derefer_test_multiple.rs:6:17: 6:29
+          _6 = (const 13_i32, move _7);    // scope 3 at $DIR/derefer_test_multiple.rs:6:17: 6:29
           StorageDead(_7);                 // scope 3 at $DIR/derefer_test_multiple.rs:6:28: 6:29
           StorageLive(_8);                 // scope 4 at $DIR/derefer_test_multiple.rs:7:9: 7:10
 -         _8 = &mut ((*((*((*(_6.1: &mut (i32, &mut (i32, &mut (i32, i32))))).1: &mut (i32, &mut (i32, i32)))).1: &mut (i32, i32))).1: i32); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30
 +         _10 = move (_6.1: &mut (i32, &mut (i32, &mut (i32, i32)))); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30
 +         StorageLive(_11);                // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30
 +         _11 = move ((*_10).1: &mut (i32, &mut (i32, i32))); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30
++         StorageDead(_10);                // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30
 +         StorageLive(_12);                // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30
 +         _12 = move ((*_11).1: &mut (i32, i32)); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30
++         StorageDead(_11);                // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30
 +         _8 = &mut ((*_12).1: i32);       // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30
-+         StorageDead(_10);                // scope 5 at $DIR/derefer_test_multiple.rs:8:9: 8:10
-+         StorageDead(_11);                // scope 5 at $DIR/derefer_test_multiple.rs:8:9: 8:10
 +         StorageDead(_12);                // scope 5 at $DIR/derefer_test_multiple.rs:8:9: 8:10
           StorageLive(_9);                 // scope 5 at $DIR/derefer_test_multiple.rs:8:9: 8:10
 -         _9 = &mut ((*((*((*(_6.1: &mut (i32, &mut (i32, &mut (i32, i32))))).1: &mut (i32, &mut (i32, i32)))).1: &mut (i32, i32))).1: i32); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30
 +         _13 = move (_6.1: &mut (i32, &mut (i32, &mut (i32, i32)))); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30
 +         StorageLive(_14);                // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30
 +         _14 = move ((*_13).1: &mut (i32, &mut (i32, i32))); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30
++         StorageDead(_13);                // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30
 +         StorageLive(_15);                // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30
 +         _15 = move ((*_14).1: &mut (i32, i32)); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30
++         StorageDead(_14);                // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30
 +         _9 = &mut ((*_15).1: i32);       // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30
-+         StorageDead(_13);                // scope 0 at $DIR/derefer_test_multiple.rs:2:12: 9:2
-+         StorageDead(_14);                // scope 0 at $DIR/derefer_test_multiple.rs:2:12: 9:2
 +         StorageDead(_15);                // scope 0 at $DIR/derefer_test_multiple.rs:2:12: 9:2
           _0 = const ();                   // scope 0 at $DIR/derefer_test_multiple.rs:2:12: 9:2
           StorageDead(_9);                 // scope 5 at $DIR/derefer_test_multiple.rs:9:1: 9:2
           StorageDead(_2);                 // scope 1 at $DIR/derefer_test_multiple.rs:9:1: 9:2
           StorageDead(_1);                 // scope 0 at $DIR/derefer_test_multiple.rs:9:1: 9:2
           return;                          // scope 0 at $DIR/derefer_test_multiple.rs:9:2: 9:2
-+     }
-+ 
-+     bb1 (cleanup): {
-+         resume;                          // scope 0 at $DIR/derefer_test_multiple.rs:2:1: 9:2
+      }
+  
+      bb1 (cleanup): {
+          resume;                          // scope 0 at $DIR/derefer_test_multiple.rs:2:1: 9:2
       }
   }
   
index 4f2b9696f8c821ccab2bfe4a5ff7deced7841d8f..1cdd97ab283bc813d3bde8e3d8b276f1e1b1c0bf 100644 (file)
@@ -32,7 +32,7 @@
           StorageDead(_5);                 // scope 0 at $DIR/early_otherwise_branch.rs:12:16: 12:17
           StorageDead(_4);                 // scope 0 at $DIR/early_otherwise_branch.rs:12:16: 12:17
           _8 = discriminant((_3.0: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch.rs:12:11: 12:17
--         switchInt(move _8) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb7]; // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17
+-         switchInt(move _8) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17
 +         StorageLive(_11);                // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17
 +         _11 = discriminant((_3.1: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17
 +         StorageLive(_12);                // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17
 +     bb4: {
           StorageDead(_3);                 // scope 0 at $DIR/early_otherwise_branch.rs:17:1: 17:2
           return;                          // scope 0 at $DIR/early_otherwise_branch.rs:17:2: 17:2
-      }
-  
--     bb7: {
--         unreachable;                     // scope 0 at $DIR/early_otherwise_branch.rs:15:14: 15:15
++     }
++ 
 +     bb5: {
 +         StorageDead(_12);                // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17
 +         switchInt(_8) -> [0_isize: bb3, 1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17
index e0ebcfeebfcc79622f24369c0dc9166911d8add3..7be9fbd0326f65fbbca5d0e26afa540d4e51ca58 100644 (file)
@@ -1,4 +1,4 @@
-// compile-flags: -Z mir-opt-level=4 -Z unsound-mir-opts
+// unit-test: EarlyOtherwiseBranch
 // EMIT_MIR early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff
 fn opt1(x: Option<u32>, y: Option<u32>) -> u32 {
     match (x, y) {
index 8527c01d756589ec0446deaee306eee29886eb3c..76055e1330fa7c88beec278069d74d0b5e99f3ad 100644 (file)
@@ -1,4 +1,4 @@
-// compile-flags: -Z mir-opt-level=4 -Z unsound-mir-opts
+// unit-test: EarlyOtherwiseBranch
 
 // EMIT_MIR early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff
 fn opt1(x: Option<u32>, y: Option<u32>, z: Option<u32>) -> u32 {
index 592388e69a913c98cfbe984afccd57085d99522e..67ce0c2aabb1c9841a2ffac1a406249658b723b7 100644 (file)
       let mut _31: f32;                    // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55
       let mut _32: !;                      // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:14: 26:28
       let mut _33: ();                     // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:25: 26:27
-+     let mut _34: isize;                  // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-+     let mut _35: bool;                   // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
+      let mut _34: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+      let mut _35: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+      let mut _36: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+      let mut _37: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+      let mut _38: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+      let mut _39: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+      let mut _40: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+      let mut _41: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+      let mut _42: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+      let mut _43: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+      let mut _44: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+      let mut _45: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+      let mut _46: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
       scope 1 {
 -         debug one => _12;                // in scope 1 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
 -         debug other => _13;              // in scope 1 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
           StorageDead(_6);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:23: 21:24
 -         StorageDead(_5);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:23: 21:24
 +         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:23: 21:24
-          _11 = discriminant((*(_4.0: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
--         switchInt(move _11) -> [0_isize: bb1, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb11]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-+         StorageLive(_34);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-+         _34 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-+         StorageLive(_35);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-+         _35 = Ne(_11, move _34);         // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-+         StorageDead(_34);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-+         switchInt(move _35) -> [false: bb7, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
+          StorageLive(_34);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+          _34 = move (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+          _11 = discriminant((*_34));      // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+          StorageDead(_34);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
+          switchInt(move _11) -> [0_isize: bb1, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
       }
   
       bb1: {
--         _7 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
--         switchInt(move _7) -> [0_isize: bb6, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
--     }
-- 
--     bb2: {
-+         StorageDead(_35);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:25: 26:27
+          StorageLive(_35);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+          _35 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+          _7 = discriminant((*_35));       // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+          StorageDead(_35);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
+          switchInt(move _7) -> [0_isize: bb6, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
+      }
+  
+      bb2: {
           StorageLive(_33);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:25: 26:27
--         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:25: 26:27
+          nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:25: 26:27
           Deinit(_0);                      // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:21: 26:28
--         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:21: 26:28
+          nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:21: 26:28
           discriminant(_0) = 1;            // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:21: 26:28
           StorageDead(_33);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:27: 26:28
 -         StorageDead(_3);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:6: 27:7
           return;                          // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:2: 28:2
       }
   
-+     bb2: {
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
-+         _15 = (((*(_4.0: &ViewportPercentageLength)) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
-+         _16 = (((*(_4.1: &ViewportPercentageLength)) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
-+         nop;                             // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:49
-+         nop;                             // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:41
-+         nop;                             // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:41
-+         nop;                             // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:44: 22:49
-+         nop;                             // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:44: 22:49
-+         ((((_0 as Ok).0: ViewportPercentageLength) as Vw).0: f32) = Add(move _15, move _16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:49
-+         nop;                             // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:48: 22:49
-+         nop;                             // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:48: 22:49
-+         Deinit(((_0 as Ok).0: ViewportPercentageLength)); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:35: 22:50
-+         nop;                             // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:35: 22:50
-+         discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 0; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:35: 22:50
-+         nop;                             // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
-+         goto -> bb6;                     // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
-+     }
-+ 
       bb3: {
--         _8 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
--         switchInt(move _8) -> [1_isize: bb7, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
-+         _20 = (((*(_4.0: &ViewportPercentageLength)) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
-+         _21 = (((*(_4.1: &ViewportPercentageLength)) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
-+         nop;                             // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49
-+         nop;                             // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41
-+         nop;                             // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41
-+         nop;                             // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49
-+         nop;                             // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49
-+         ((((_0 as Ok).0: ViewportPercentageLength) as Vh).0: f32) = Add(move _20, move _21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49
-+         nop;                             // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49
-+         nop;                             // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49
-+         Deinit(((_0 as Ok).0: ViewportPercentageLength)); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50
-+         nop;                             // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50
-+         discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 1; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50
-+         nop;                             // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
-+         goto -> bb6;                     // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
+          StorageLive(_36);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+          _36 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+          _8 = discriminant((*_36));       // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+          StorageDead(_36);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
+          switchInt(move _8) -> [1_isize: bb7, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
       }
   
       bb4: {
--         _9 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
--         switchInt(move _9) -> [2_isize: bb8, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
-+         _25 = (((*(_4.0: &ViewportPercentageLength)) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
-+         _26 = (((*(_4.1: &ViewportPercentageLength)) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
-+         nop;                             // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:55
-+         nop;                             // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:47
-+         nop;                             // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:47
-+         nop;                             // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:50: 24:55
-+         nop;                             // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:50: 24:55
-+         ((((_0 as Ok).0: ViewportPercentageLength) as Vmin).0: f32) = Add(move _25, move _26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:55
-+         nop;                             // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:54: 24:55
-+         nop;                             // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:54: 24:55
-+         Deinit(((_0 as Ok).0: ViewportPercentageLength)); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:39: 24:56
-+         nop;                             // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:39: 24:56
-+         discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 2; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:39: 24:56
-+         nop;                             // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
-+         goto -> bb6;                     // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
+          StorageLive(_37);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+          _37 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+          _9 = discriminant((*_37));       // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+          StorageDead(_37);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
+          switchInt(move _9) -> [2_isize: bb8, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
       }
   
       bb5: {
--         _10 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
--         switchInt(move _10) -> [3_isize: bb9, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
-+         _30 = (((*(_4.0: &ViewportPercentageLength)) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
-+         _31 = (((*(_4.1: &ViewportPercentageLength)) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
-+         nop;                             // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55
-+         nop;                             // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47
-+         nop;                             // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47
-+         nop;                             // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55
-+         nop;                             // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55
-+         ((((_0 as Ok).0: ViewportPercentageLength) as Vmax).0: f32) = Add(move _30, move _31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55
-+         nop;                             // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55
-+         nop;                             // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55
-+         Deinit(((_0 as Ok).0: ViewportPercentageLength)); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56
-+         nop;                             // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56
-+         discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 3; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56
-+         nop;                             // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
-+         goto -> bb6;                     // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
+          StorageLive(_38);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+          _38 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+          _10 = discriminant((*_38));      // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+          StorageDead(_38);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
+          switchInt(move _10) -> [3_isize: bb9, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
       }
   
       bb6: {
 -         StorageLive(_12);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
--         _12 = (((*(_4.0: &ViewportPercentageLength)) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
++         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
+          StorageLive(_39);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
+          _39 = move (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
+-         _12 = (((*_39) as Vw).0: f32);   // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
++         _15 = (((*_39) as Vw).0: f32);   // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
+          StorageDead(_39);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
 -         StorageLive(_13);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
--         _13 = (((*(_4.1: &ViewportPercentageLength)) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
++         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
+          StorageLive(_40);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
+          _40 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
+-         _13 = (((*_40) as Vw).0: f32);   // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
++         _16 = (((*_40) as Vw).0: f32);   // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
+          StorageDead(_40);                // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:49
 -         StorageLive(_14);                // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:49
 -         StorageLive(_15);                // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:41
 -         _15 = _12;                       // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:41
 -         StorageDead(_14);                // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
 -         StorageDead(_13);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
 -         StorageDead(_12);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
--         goto -> bb10;                    // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
--     }
-- 
--     bb7: {
++         nop;                             // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:49
++         nop;                             // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:41
++         nop;                             // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:41
++         nop;                             // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:44: 22:49
++         nop;                             // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:44: 22:49
++         ((((_0 as Ok).0: ViewportPercentageLength) as Vw).0: f32) = Add(move _15, move _16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:49
++         nop;                             // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:48: 22:49
++         nop;                             // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:48: 22:49
++         Deinit(((_0 as Ok).0: ViewportPercentageLength)); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:35: 22:50
++         nop;                             // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:35: 22:50
++         discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 0; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:35: 22:50
++         nop;                             // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
++         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
++         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
+          goto -> bb10;                    // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
+      }
+  
+      bb7: {
 -         StorageLive(_17);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
--         _17 = (((*(_4.0: &ViewportPercentageLength)) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
++         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
+          StorageLive(_41);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
+          _41 = move (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
+-         _17 = (((*_41) as Vh).0: f32);   // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
++         _20 = (((*_41) as Vh).0: f32);   // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
+          StorageDead(_41);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
 -         StorageLive(_18);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
--         _18 = (((*(_4.1: &ViewportPercentageLength)) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
++         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
+          StorageLive(_42);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
+          _42 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
+-         _18 = (((*_42) as Vh).0: f32);   // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
++         _21 = (((*_42) as Vh).0: f32);   // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
+          StorageDead(_42);                // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49
 -         StorageLive(_19);                // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49
 -         StorageLive(_20);                // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41
 -         _20 = _17;                       // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41
 -         StorageDead(_19);                // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
 -         StorageDead(_18);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
 -         StorageDead(_17);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
--         goto -> bb10;                    // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
--     }
-- 
--     bb8: {
++         nop;                             // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49
++         nop;                             // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41
++         nop;                             // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41
++         nop;                             // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49
++         nop;                             // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49
++         ((((_0 as Ok).0: ViewportPercentageLength) as Vh).0: f32) = Add(move _20, move _21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49
++         nop;                             // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49
++         nop;                             // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49
++         Deinit(((_0 as Ok).0: ViewportPercentageLength)); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50
++         nop;                             // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50
++         discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 1; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50
++         nop;                             // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
++         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
++         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
+          goto -> bb10;                    // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
+      }
+  
+      bb8: {
 -         StorageLive(_22);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
--         _22 = (((*(_4.0: &ViewportPercentageLength)) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
++         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
+          StorageLive(_43);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
+          _43 = move (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
+-         _22 = (((*_43) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
++         _25 = (((*_43) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
+          StorageDead(_43);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
 -         StorageLive(_23);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
--         _23 = (((*(_4.1: &ViewportPercentageLength)) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
++         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
+          StorageLive(_44);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
+          _44 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
+-         _23 = (((*_44) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
++         _26 = (((*_44) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
+          StorageDead(_44);                // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:55
 -         StorageLive(_24);                // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:55
 -         StorageLive(_25);                // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:47
 -         _25 = _22;                       // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:47
 -         StorageDead(_24);                // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
 -         StorageDead(_23);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
 -         StorageDead(_22);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
--         goto -> bb10;                    // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
--     }
-- 
--     bb9: {
++         nop;                             // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:55
++         nop;                             // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:47
++         nop;                             // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:47
++         nop;                             // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:50: 24:55
++         nop;                             // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:50: 24:55
++         ((((_0 as Ok).0: ViewportPercentageLength) as Vmin).0: f32) = Add(move _25, move _26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:55
++         nop;                             // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:54: 24:55
++         nop;                             // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:54: 24:55
++         Deinit(((_0 as Ok).0: ViewportPercentageLength)); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:39: 24:56
++         nop;                             // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:39: 24:56
++         discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 2; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:39: 24:56
++         nop;                             // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
++         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
++         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
+          goto -> bb10;                    // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
+      }
+  
+      bb9: {
 -         StorageLive(_27);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
--         _27 = (((*(_4.0: &ViewportPercentageLength)) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
++         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
+          StorageLive(_45);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
+          _45 = move (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
+-         _27 = (((*_45) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
++         _30 = (((*_45) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
+          StorageDead(_45);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
 -         StorageLive(_28);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
--         _28 = (((*(_4.1: &ViewportPercentageLength)) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
++         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
+          StorageLive(_46);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
+          _46 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
+-         _28 = (((*_46) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
++         _31 = (((*_46) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
+          StorageDead(_46);                // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55
 -         StorageLive(_29);                // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55
 -         StorageLive(_30);                // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47
 -         _30 = _27;                       // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47
 -         StorageDead(_29);                // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
 -         StorageDead(_28);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
 -         StorageDead(_27);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
--         goto -> bb10;                    // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
--     }
-- 
--     bb10: {
++         nop;                             // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55
++         nop;                             // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47
++         nop;                             // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47
++         nop;                             // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55
++         nop;                             // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55
++         ((((_0 as Ok).0: ViewportPercentageLength) as Vmax).0: f32) = Add(move _30, move _31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55
++         nop;                             // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55
++         nop;                             // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55
++         Deinit(((_0 as Ok).0: ViewportPercentageLength)); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56
++         nop;                             // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56
++         discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 3; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56
++         nop;                             // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
++         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
++         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
+          goto -> bb10;                    // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
+      }
+  
+      bb10: {
           Deinit(_0);                      // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:5: 27:7
 -         ((_0 as Ok).0: ViewportPercentageLength) = move _3; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:5: 27:7
 +         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:5: 27:7
 +         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:1: 28:2
           return;                          // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:2: 28:2
       }
-  
--     bb11: {
--         unreachable;                     // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:2: 28:2
-+     bb7: {
-+         StorageDead(_35);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-+         switchInt(_11) -> [0_isize: bb2, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-      }
   }
   
index 4cd34ba38ba96cc3661faa308f57932ce325165f..c2b00f915a4eba65d6e1450500b81bc090acecf2 100644 (file)
       let mut _31: f32;                    // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55
       let mut _32: !;                      // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:14: 26:28
       let mut _33: ();                     // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:25: 26:27
-+     let mut _34: isize;                  // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-+     let mut _35: bool;                   // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
+      let mut _34: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+      let mut _35: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+      let mut _36: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+      let mut _37: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+      let mut _38: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+      let mut _39: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+      let mut _40: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+      let mut _41: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+      let mut _42: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+      let mut _43: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+      let mut _44: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+      let mut _45: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+      let mut _46: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
       scope 1 {
           debug one => _12;                // in scope 1 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
           debug other => _13;              // in scope 1 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
           (_4.1: &ViewportPercentageLength) = move _6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
           StorageDead(_6);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:23: 21:24
           StorageDead(_5);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:23: 21:24
-          _11 = discriminant((*(_4.0: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
--         switchInt(move _11) -> [0_isize: bb1, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb11]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-+         StorageLive(_34);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-+         _34 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-+         StorageLive(_35);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-+         _35 = Ne(_11, move _34);         // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-+         StorageDead(_34);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-+         switchInt(move _35) -> [false: bb7, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
+          StorageLive(_34);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+          _34 = move (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+          _11 = discriminant((*_34));      // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+          StorageDead(_34);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
+          switchInt(move _11) -> [0_isize: bb1, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
       }
   
       bb1: {
--         _7 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
--         switchInt(move _7) -> [0_isize: bb6, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
--     }
-- 
--     bb2: {
-+         StorageDead(_35);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:25: 26:27
+          StorageLive(_35);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+          _35 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+          _7 = discriminant((*_35));       // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+          StorageDead(_35);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
+          switchInt(move _7) -> [0_isize: bb6, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
+      }
+  
+      bb2: {
           StorageLive(_33);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:25: 26:27
--         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:25: 26:27
+          nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:25: 26:27
           Deinit(_0);                      // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:21: 26:28
--         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:21: 26:28
+          nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:21: 26:28
           discriminant(_0) = 1;            // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:21: 26:28
           StorageDead(_33);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:27: 26:28
           StorageDead(_3);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:6: 27:7
           return;                          // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:2: 28:2
       }
   
--     bb3: {
--         _8 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
--         switchInt(move _8) -> [1_isize: bb7, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
--     }
-- 
--     bb4: {
--         _9 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
--         switchInt(move _9) -> [2_isize: bb8, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
--     }
-- 
--     bb5: {
--         _10 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
--         switchInt(move _10) -> [3_isize: bb9, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
--     }
-- 
--     bb6: {
-+     bb2: {
+      bb3: {
+          StorageLive(_36);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+          _36 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+          _8 = discriminant((*_36));       // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+          StorageDead(_36);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
+          switchInt(move _8) -> [1_isize: bb7, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
+      }
+  
+      bb4: {
+          StorageLive(_37);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+          _37 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+          _9 = discriminant((*_37));       // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+          StorageDead(_37);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
+          switchInt(move _9) -> [2_isize: bb8, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
+      }
+  
+      bb5: {
+          StorageLive(_38);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+          _38 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+          _10 = discriminant((*_38));      // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+          StorageDead(_38);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
+          switchInt(move _10) -> [3_isize: bb9, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
+      }
+  
+      bb6: {
           StorageLive(_12);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
-          _12 = (((*(_4.0: &ViewportPercentageLength)) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
+          StorageLive(_39);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
+          _39 = move (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
+          _12 = (((*_39) as Vw).0: f32);   // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
+          StorageDead(_39);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
           StorageLive(_13);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
-          _13 = (((*(_4.1: &ViewportPercentageLength)) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
+          StorageLive(_40);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
+          _40 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
+          _13 = (((*_40) as Vw).0: f32);   // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
+          StorageDead(_40);                // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:49
           StorageLive(_14);                // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:49
           StorageLive(_15);                // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:41
           _15 = _12;                       // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:41
           StorageDead(_14);                // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
           StorageDead(_13);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
           StorageDead(_12);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
--         goto -> bb10;                    // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
-+         goto -> bb6;                     // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
+          goto -> bb10;                    // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
       }
   
--     bb7: {
-+     bb3: {
+      bb7: {
           StorageLive(_17);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
-          _17 = (((*(_4.0: &ViewportPercentageLength)) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
+          StorageLive(_41);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
+          _41 = move (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
+          _17 = (((*_41) as Vh).0: f32);   // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
+          StorageDead(_41);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
           StorageLive(_18);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
-          _18 = (((*(_4.1: &ViewportPercentageLength)) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
+          StorageLive(_42);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
+          _42 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
+          _18 = (((*_42) as Vh).0: f32);   // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
+          StorageDead(_42);                // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49
           StorageLive(_19);                // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49
           StorageLive(_20);                // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41
           _20 = _17;                       // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41
           StorageDead(_19);                // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
           StorageDead(_18);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
           StorageDead(_17);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
--         goto -> bb10;                    // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
-+         goto -> bb6;                     // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
+          goto -> bb10;                    // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
       }
   
--     bb8: {
-+     bb4: {
+      bb8: {
           StorageLive(_22);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
-          _22 = (((*(_4.0: &ViewportPercentageLength)) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
+          StorageLive(_43);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
+          _43 = move (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
+          _22 = (((*_43) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
+          StorageDead(_43);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
           StorageLive(_23);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
-          _23 = (((*(_4.1: &ViewportPercentageLength)) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
+          StorageLive(_44);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
+          _44 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
+          _23 = (((*_44) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
+          StorageDead(_44);                // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:55
           StorageLive(_24);                // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:55
           StorageLive(_25);                // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:47
           _25 = _22;                       // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:47
           StorageDead(_24);                // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
           StorageDead(_23);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
           StorageDead(_22);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
--         goto -> bb10;                    // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
-+         goto -> bb6;                     // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
+          goto -> bb10;                    // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
       }
   
--     bb9: {
-+     bb5: {
+      bb9: {
           StorageLive(_27);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
-          _27 = (((*(_4.0: &ViewportPercentageLength)) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
+          StorageLive(_45);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
+          _45 = move (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
+          _27 = (((*_45) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
+          StorageDead(_45);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
           StorageLive(_28);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
-          _28 = (((*(_4.1: &ViewportPercentageLength)) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
+          StorageLive(_46);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
+          _46 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
+          _28 = (((*_46) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
+          StorageDead(_46);                // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55
           StorageLive(_29);                // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55
           StorageLive(_30);                // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47
           _30 = _27;                       // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47
           StorageDead(_29);                // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
           StorageDead(_28);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
           StorageDead(_27);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
--         goto -> bb10;                    // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
-+         goto -> bb6;                     // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
+          goto -> bb10;                    // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
       }
   
--     bb10: {
-+     bb6: {
+      bb10: {
           Deinit(_0);                      // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:5: 27:7
           ((_0 as Ok).0: ViewportPercentageLength) = move _3; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:5: 27:7
           discriminant(_0) = 0;            // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:5: 27:7
           StorageDead(_4);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:1: 28:2
           return;                          // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:2: 28:2
       }
-  
--     bb11: {
--         unreachable;                     // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:2: 28:2
-+     bb7: {
-+         StorageDead(_35);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-+         switchInt(_11) -> [0_isize: bb2, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-      }
   }
   
index 6adc5194aec75963419fd915aab8a3e133f4f454..848f2feb32125aaa99da7ee1a30f33510b615068 100644 (file)
           StorageDead(_5);                 // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:16: 8:17
           StorageDead(_4);                 // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:16: 8:17
           _8 = discriminant((_3.0: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:11: 8:17
-          switchInt(move _8) -> [0_isize: bb1, otherwise: bb3]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:5: 8:17
+          switchInt(move _8) -> [0_isize: bb1, 1_isize: bb4, otherwise: bb3]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:5: 8:17
       }
   
       bb1: {
           _6 = discriminant((_3.1: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:11: 8:17
-          switchInt(move _6) -> [0_isize: bb2, otherwise: bb6]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:5: 8:17
+          switchInt(move _6) -> [0_isize: bb2, 1_isize: bb7, otherwise: bb3]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:5: 8:17
       }
   
       bb2: {
           _0 = const 3_u32;                // scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:25: 12:26
-          goto -> bb7;                     // scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:25: 12:26
+          goto -> bb8;                     // scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:25: 12:26
       }
   
       bb3: {
-          _7 = discriminant((_3.1: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:11: 8:17
-          switchInt(move _7) -> [0_isize: bb5, otherwise: bb4]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:5: 8:17
+          unreachable;                     // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:11: 8:17
       }
   
       bb4: {
+          _7 = discriminant((_3.1: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:11: 8:17
+          switchInt(move _7) -> [0_isize: bb6, 1_isize: bb5, otherwise: bb3]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:5: 8:17
+      }
+  
+      bb5: {
           StorageLive(_9);                 // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:15: 9:16
           _9 = (((_3.0: std::option::Option<u32>) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:15: 9:16
           StorageLive(_10);                // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:24: 9:25
           _0 = const 0_u32;                // scope 1 at $DIR/early_otherwise_branch_noopt.rs:9:31: 9:32
           StorageDead(_10);                // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:31: 9:32
           StorageDead(_9);                 // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:31: 9:32
-          goto -> bb7;                     // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:31: 9:32
+          goto -> bb8;                     // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:31: 9:32
       }
   
-      bb5: {
+      bb6: {
           StorageLive(_11);                // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:15: 10:16
           _11 = (((_3.0: std::option::Option<u32>) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:15: 10:16
           _0 = const 1_u32;                // scope 2 at $DIR/early_otherwise_branch_noopt.rs:10:28: 10:29
           StorageDead(_11);                // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:28: 10:29
-          goto -> bb7;                     // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:28: 10:29
+          goto -> bb8;                     // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:28: 10:29
       }
   
-      bb6: {
+      bb7: {
           StorageLive(_12);                // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:21: 11:22
           _12 = (((_3.1: std::option::Option<u32>) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:21: 11:22
           _0 = const 2_u32;                // scope 3 at $DIR/early_otherwise_branch_noopt.rs:11:28: 11:29
           StorageDead(_12);                // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:28: 11:29
-          goto -> bb7;                     // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:28: 11:29
+          goto -> bb8;                     // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:28: 11:29
       }
   
-      bb7: {
+      bb8: {
           StorageDead(_3);                 // scope 0 at $DIR/early_otherwise_branch_noopt.rs:14:1: 14:2
           return;                          // scope 0 at $DIR/early_otherwise_branch_noopt.rs:14:2: 14:2
       }
index 1f8c59df35fff019ad64595fbbc5f13c7976a0ff..ef766bbd4a651b6ff664af1f1f6a915c1774a350 100644 (file)
@@ -1,4 +1,4 @@
-// compile-flags: -Z mir-opt-level=4 -Zunsound-mir-opts
+// unit-test: EarlyOtherwiseBranch
 
 // must not optimize as it does not follow the pattern of
 // left and right hand side being the same variant
index a272266066246ce21169db924e061d480a578125..7d42c772f160ae04a72b2f18b427fc5204f2d8d9 100644 (file)
@@ -19,7 +19,7 @@
   
       bb1: {
           _0 = const 0_i32;                // scope 0 at $DIR/early_otherwise_branch_soundness.rs:25:14: 25:15
-          return;                          // scope 0 at $DIR/early_otherwise_branch_soundness.rs:25:14: 25:15
+          goto -> bb5;                     // scope 0 at $DIR/early_otherwise_branch_soundness.rs:25:14: 25:15
       }
   
       bb2: {
@@ -29,7 +29,7 @@
   
       bb3: {
           _0 = const 0_i32;                // scope 0 at $DIR/early_otherwise_branch_soundness.rs:23:18: 23:19
-          return;                          // scope 0 at $DIR/early_otherwise_branch_soundness.rs:23:18: 23:19
+          goto -> bb5;                     // scope 0 at $DIR/early_otherwise_branch_soundness.rs:23:18: 23:19
       }
   
       bb4: {
           _5 = (((*_2) as Some).0: i32);   // scope 0 at $DIR/early_otherwise_branch_soundness.rs:22:18: 22:19
           _0 = _5;                         // scope 1 at $DIR/early_otherwise_branch_soundness.rs:22:24: 22:25
           StorageDead(_5);                 // scope 0 at $DIR/early_otherwise_branch_soundness.rs:22:24: 22:25
-          return;                          // scope 0 at $DIR/early_otherwise_branch_soundness.rs:22:24: 22:25
+          goto -> bb5;                     // scope 0 at $DIR/early_otherwise_branch_soundness.rs:22:24: 22:25
+      }
+  
+      bb5: {
+          return;                          // scope 0 at $DIR/early_otherwise_branch_soundness.rs:27:2: 27:2
       }
   }
   
index 56b7c9a2db47815e93b688c19054e01a1eb35e42..1efaba044ecf1bca44392f70ed61fef63ae84a88 100644 (file)
@@ -6,6 +6,7 @@
       let mut _0: u32;                     // return place in scope 0 at $DIR/early_otherwise_branch_soundness.rs:12:26: 12:29
       let mut _2: isize;                   // in scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:20: 13:30
       let mut _3: isize;                   // in scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31
+      let mut _4: &E;                      // in scope 0 at $DIR/early_otherwise_branch_soundness.rs:12:16: 12:17
   
       bb0: {
           _3 = discriminant((*_1));        // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31
       }
   
       bb1: {
-          _2 = discriminant((*(((*_1) as Some).0: &E))); // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31
+          StorageLive(_4);                 // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31
+          _4 = move (((*_1) as Some).0: &E); // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31
+          _2 = discriminant((*_4));        // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31
+          StorageDead(_4);                 // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31
           switchInt(move _2) -> [1_isize: bb2, otherwise: bb3]; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31
       }
   
       bb2: {
           _0 = const 1_u32;                // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:38: 13:39
-          return;                          // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:5: 13:52
+          goto -> bb4;                     // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:5: 13:52
       }
   
       bb3: {
           _0 = const 2_u32;                // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:49: 13:50
-          return;                          // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:5: 13:52
+          goto -> bb4;                     // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:5: 13:52
+      }
+  
+      bb4: {
+          return;                          // scope 0 at $DIR/early_otherwise_branch_soundness.rs:14:2: 14:2
       }
   }
   
index d2513213d796f7591efe2a5fadc7774df2aa9dab..cd458923245348dcfd013b31b74c96487146c6f4 100644 (file)
@@ -1,4 +1,4 @@
-// compile-flags: -Z mir-opt-level=4 -Zunsound-mir-opts
+// unit-test: EarlyOtherwiseBranch
 
 // Tests various cases that the `early_otherwise_branch` opt should *not* optimize
 
index b34389a0ab5271b5347a9c045808964499256289..398311e6bb8e2b9249f495287ea1ee858b7aed39 100644 (file)
@@ -1,4 +1,4 @@
-// compile-flags: -O
+// unit-test: SimplifyComparisonIntegral
 // EMIT_MIR if_condition_int.opt_u32.SimplifyComparisonIntegral.diff
 // EMIT_MIR if_condition_int.opt_negative.SimplifyComparisonIntegral.diff
 // EMIT_MIR if_condition_int.opt_char.SimplifyComparisonIntegral.diff
index 337f0871843ea150ae37496421ab5824f8fe6152..75e37092ff3c3177cd46aa067b23aaea90ce27cd 100644 (file)
@@ -19,6 +19,8 @@ fn foo(_1: T, _2: i32) -> (i32, T) {
             debug t => (*((*_6).1: &T)); // in scope 2 at $DIR/inline-closure-captures.rs:10:17: 10:18
             let mut _10: i32;            // in scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20
             let mut _11: T;              // in scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23
+            let mut _12: &i32;           // in scope 2 at $DIR/inline-closure-captures.rs:11:13: 11:24
+            let mut _13: &T;             // in scope 2 at $DIR/inline-closure-captures.rs:11:13: 11:24
         }
     }
 
@@ -43,9 +45,15 @@ fn foo(_1: T, _2: i32) -> (i32, T) {
         StorageLive(_9);                 // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9
         _9 = move (_7.0: i32);           // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9
         StorageLive(_10);                // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20
-        _10 = (*((*_6).0: &i32));        // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20
+        StorageLive(_12);                // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20
+        _12 = move ((*_6).0: &i32);      // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20
+        _10 = (*_12);                    // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20
+        StorageDead(_12);                // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23
         StorageLive(_11);                // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23
-        _11 = (*((*_6).1: &T));          // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23
+        StorageLive(_13);                // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23
+        _13 = move ((*_6).1: &T);        // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23
+        _11 = (*_13);                    // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23
+        StorageDead(_13);                // scope 2 at $DIR/inline-closure-captures.rs:11:18: 11:24
         Deinit(_0);                      // scope 2 at $DIR/inline-closure-captures.rs:11:18: 11:24
         (_0.0: i32) = move _10;          // scope 2 at $DIR/inline-closure-captures.rs:11:18: 11:24
         (_0.1: T) = move _11;            // scope 2 at $DIR/inline-closure-captures.rs:11:18: 11:24
index 2e03467018693b54934618980b7162ee836d23f4..d6c1c92cd9177a273a7b11cbefd73ffe7c1c41e9 100644 (file)
@@ -64,9 +64,5 @@
           StorageDead(_3);                 // scope 0 at $DIR/lower_array_len.rs:11:5: 11:6
           return;                          // scope 0 at $DIR/lower_array_len.rs:12:2: 12:2
       }
-  
-      bb6 (cleanup): {
-          resume;                          // scope 0 at $DIR/lower_array_len.rs:6:1: 12:2
-      }
   }
   
index 6aa77a9ed6013481c93f9ca643db528c1652599f..11fc20aa693c71c18ffdefdf6fc62e68cac6d5d8 100644 (file)
@@ -77,9 +77,5 @@
           StorageDead(_3);                 // scope 0 at $DIR/lower_array_len.rs:24:5: 24:6
           return;                          // scope 0 at $DIR/lower_array_len.rs:25:2: 25:2
       }
-  
-      bb7 (cleanup): {
-          resume;                          // scope 0 at $DIR/lower_array_len.rs:17:1: 25:2
-      }
   }
   
index b41582477c692a2d67176fba8e45e51ef93ead19..892fdda818ebd1694eeec93f89235b3f50c1bd4b 100644 (file)
@@ -26,9 +26,5 @@
           StorageDead(_2);                 // scope 0 at $DIR/lower_array_len.rs:31:13: 31:14
           return;                          // scope 0 at $DIR/lower_array_len.rs:32:2: 32:2
       }
-  
-      bb2 (cleanup): {
-          resume;                          // scope 0 at $DIR/lower_array_len.rs:30:1: 32:2
-      }
   }
   
index 92ec7a3633e9462b7b85afd35e0d43d3abc20e05..201fffbf0d45a5752960262c671d39009d88f8b5 100644 (file)
@@ -26,9 +26,5 @@
           StorageDead(_2);                 // scope 0 at $DIR/lower_array_len.rs:38:13: 38:14
           return;                          // scope 0 at $DIR/lower_array_len.rs:39:2: 39:2
       }
-  
-      bb2 (cleanup): {
-          resume;                          // scope 0 at $DIR/lower_array_len.rs:37:1: 39:2
-      }
   }
   
index 2210ad54e8d3d02975cb6108fb94baea1d87e594..13241d882f21087cbf63a9d2ec1b8ea4e2935bfc 100644 (file)
@@ -59,9 +59,5 @@
           StorageDead(_3);                 // scope 0 at $DIR/lower_slice_len.rs:9:5: 9:6
           return;                          // scope 0 at $DIR/lower_slice_len.rs:10:2: 10:2
       }
-  
-      bb6 (cleanup): {
-          resume;                          // scope 0 at $DIR/lower_slice_len.rs:4:1: 10:2
-      }
   }
   
index f2438e69749905d71f917c13cc180718b495148f..12955aed1fbbe242b22061e33e0df6f5731cd49d 100644 (file)
@@ -1,4 +1,4 @@
-// compile-flags: -Z mir-opt-level=3
+// unit-test: LowerSliceLenCalls
 
 // EMIT_MIR lower_slice_len.bound.LowerSliceLenCalls.diff
 pub fn bound(index: usize, slice: &[u8]) -> u8 {
index ab46d7b94c72c09872aec2d17d961ae5f1cc4d97..5786ae62127054cbd56a2e507ba8b9da07befd86 100644 (file)
@@ -1,4 +1,4 @@
-// compile-flags: -Zmir-opt-level=1
+// unit-test: RenameReturnPlace
 
 // EMIT_MIR nrvo_simple.nrvo.RenameReturnPlace.diff
 fn nrvo(init: fn(&mut [u8; 1024])) -> [u8; 1024] {
index 868eeb6367e33badc2a89a89bcdfa9321b49c054..7e843b65e88fc77375c808f25ad8ac05a84fb7db 100644 (file)
@@ -9,7 +9,7 @@
       bb0: {
           _2 = discriminant(_1);           // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:22:11: 22:12
 -         switchInt(move _2) -> [1_isize: bb3, 2_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:22:5: 22:12
-+         switchInt(move _2) -> [1_isize: bb3, 2_isize: bb2, otherwise: bb6]; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:22:5: 22:12
++         switchInt(move _2) -> [1_isize: bb3, 2_isize: bb2, otherwise: bb5]; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:22:5: 22:12
       }
   
       bb1: {
   
       bb4: {
           return;                          // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:27:2: 27:2
-      }
-  
-      bb5 (cleanup): {
-          resume;                          // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:21:1: 27:2
 +     }
 + 
-+     bb6: {
++     bb5: {
 +         unreachable;                     // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:25:14: 25:15
       }
   }
index 33c1458dc0c17bdb3cca1226e860e5287956eb7b..5da011d427a2caefb6ce0318854fc6327ed14f7e 100644 (file)
@@ -30,9 +30,5 @@
       bb4: {
           return;                          // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:18:2: 18:2
       }
-  
-      bb5 (cleanup): {
-          resume;                          // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:12:1: 18:2
-      }
   }
   
index 380844f8861f6286ef28f4185f82dee94c14e6d0..08312bde20f51e00eae57c4941705a906efec44e 100644 (file)
           _0 = const ();                   // scope 0 at $DIR/unreachable.rs:19:6: 19:6
           StorageDead(_1);                 // scope 0 at $DIR/unreachable.rs:20:1: 20:2
           return;                          // scope 0 at $DIR/unreachable.rs:20:2: 20:2
--     }
-- 
--     bb7 (cleanup): {
--         resume;                          // scope 0 at $DIR/unreachable.rs:8:1: 20:2
       }
   }
   
index e26990b1def8946a3c7305f2fd9d7c61c01a7336..e5867ccfc5cb6c13d5771cf6f65a93126122cbae 100644 (file)
           StorageDead(_1);                 // scope 0 at $DIR/unreachable_diverging.rs:20:1: 20:2
           StorageDead(_2);                 // scope 0 at $DIR/unreachable_diverging.rs:20:1: 20:2
           return;                          // scope 0 at $DIR/unreachable_diverging.rs:20:2: 20:2
--     }
-- 
--     bb7 (cleanup): {
--         resume;                          // scope 0 at $DIR/unreachable_diverging.rs:12:1: 20:2
       }
   }
   
index 0c96fb593e659311008e39f56ca578e136808795..3af37955f238079de77ae656b08b2694d33ba5ba 100644 (file)
@@ -9,5 +9,5 @@ extern crate std;
 // pp-exact:dollar-crate.pp
 
 fn main() {
-    ::std::io::_print(::core::fmt::Arguments::new_v1(&["rust\n"], &[]));
+    { ::std::io::_print(::core::fmt::Arguments::new_v1(&["rust\n"], &[])); };
 }
index 9b10fd86c4778d8ee4f744d6566c667d6c5cea63..a59a3002c7f68508c28bdfda5ff2e2ffc5e1b7f8 100644 (file)
@@ -6,4 +6,4 @@ extern crate std;
 // pretty-mode:hir
 // pp-exact:hir-pretty-loop.pp
 
-pub fn foo() { loop { break; } }
+fn foo() { loop { break; } }
index ea74a267be81e1cd03831aeaf6b75c8c2ff54a42..752c36a0fbc5a58759f1fa0d0e564990c783f301 100644 (file)
@@ -8,9 +8,9 @@ extern crate std;
 
 // #4264 fixed-length vector types
 
-pub fn foo(_: [i32; (3 as usize)]) ({ } as ())
+fn foo(_: [i32; (3 as usize)]) ({ } as ())
 
-pub fn bar() ({
+fn bar() ({
         const FOO: usize = ((5 as usize) - (4 as usize) as usize);
         let _: [(); (FOO as usize)] = ([(() as ())] as [(); 1]);
 
@@ -41,14 +41,14 @@ pub fn bar() ({
                 (res as String)
             } as String);
     } as ())
-pub type Foo = [i32; (3 as usize)];
-pub struct Bar {
-    pub x: [i32; (3 as usize)],
+type Foo = [i32; (3 as usize)];
+struct Bar {
+    x: [i32; (3 as usize)],
 }
-pub struct TupleBar([i32; (4 as usize)]);
-pub enum Baz { BazVariant([i32; (5 as usize)]), }
-pub fn id<T>(x: T) -> T ({ (x as T) } as T)
-pub fn use_id() ({
+struct TupleBar([i32; (4 as usize)]);
+enum Baz { BazVariant([i32; (5 as usize)]), }
+fn id<T>(x: T) -> T ({ (x as T) } as T)
+fn use_id() ({
         let _ =
             ((id::<[i32; (3 as usize)]> as
                     fn([i32; 3]) -> [i32; 3] {id::<[i32; 3]>})(([(1 as i32),
diff --git a/src/test/pretty/yeet-expr.rs b/src/test/pretty/yeet-expr.rs
new file mode 100644 (file)
index 0000000..c899f11
--- /dev/null
@@ -0,0 +1,12 @@
+// pp-exact
+#![feature(yeet_expr)]
+
+fn yeet_no_expr() -> Option<String> { do yeet }
+
+fn yeet_no_expr_with_semicolon() -> Option<String> { do yeet; }
+
+fn yeet_with_expr() -> Result<String, i32> { do yeet 1 + 2 }
+
+fn yeet_with_expr_with_semicolon() -> Result<String, i32> { do yeet 1 + 2; }
+
+fn main() {}
index 8bf9c97fddad4679ad7cec5436641d19e8001daf..e463099a5ee4795186d28aab4710755993fabb4e 100644 (file)
   116|      1|
   117|      1|    let
   118|      1|        _unused_closure
-  119|      1|    =
-  120|      1|        |
+  119|       |    =
+  120|       |        |
   121|       |            mut countdown
   122|       |        |
   123|      0|    {
   169|       |    ;
   170|       |
   171|      1|    let short_used_not_covered_closure_line_break_no_block_embedded_branch =
-  172|      1|        | _unused_arg: u8 |
+  172|       |        | _unused_arg: u8 |
   173|      0|            println!(
   174|      0|                "not called: {}",
   175|      0|                if is_true { "check" } else { "me" }
   187|       |    ;
   188|       |
   189|      1|    let short_used_covered_closure_line_break_no_block_embedded_branch =
-  190|       |        | _unused_arg: u8 |
+  190|      1|        | _unused_arg: u8 |
   191|      1|            println!(
   192|      1|                "not called: {}",
   193|      1|                if is_true { "check" } else { "me" }
index 998d1f328596c8a16cc5d6e4677542d4d06e4f41..3dda6f190e448ae6c513d0f31e27e4e94a574673 100644 (file)
@@ -25,6 +25,12 @@ fn main() {
         let mut contents = Vec::new();
         File::open(path).unwrap().read_to_end(&mut contents).unwrap();
 
+        // This file is produced during linking in a temporary directory.
+        let arg = if arg.ends_with("/symbols.o") || arg.ends_with("\\symbols.o") {
+            "symbols.o"
+        } else {
+            &*arg
+        };
         out.push_str(&format!("{}: {}\n", arg, hash(&contents)));
     }
 
index dc55c947d89a2fef1017bee007cc63dbb2735e6a..4bb35f33ad3e92e82bb2530c284d24aed4325f0b 100644 (file)
@@ -54,9 +54,12 @@ all:
        # Check that a Rust dylib does not export generics if -Zshare-generics=no
        [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -v __imp_ | grep -c public_generic_function_from_rlib)" -eq "0" ]
 
+# FIXME(nbdd0121): This is broken in MinGW, see https://github.com/rust-lang/rust/pull/95604#issuecomment-1101564032
+ifndef IS_WINDOWS
        # Check that an executable does not export any dynamic symbols
        [ "$$($(NM) $(TMPDIR)/$(EXE_NAME) | grep -v __imp_ | grep -c public_c_function_from_rlib)" -eq "0" ]
        [ "$$($(NM) $(TMPDIR)/$(EXE_NAME) | grep -v __imp_ | grep -c public_rust_function_from_exe)" -eq "0" ]
+endif
 
 
        # Check the combined case, where we generate a cdylib and an rlib in the same
@@ -91,6 +94,8 @@ all:
        [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -v __imp_ | grep -c public_rust_function_from_rlib)" -eq "1" ]
        [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -v __imp_ | grep -c public_generic_function_from_rlib)" -eq "1" ]
 
+ifndef IS_WINDOWS
        # Check that an executable does not export any dynamic symbols
        [ "$$($(NM) $(TMPDIR)/$(EXE_NAME) | grep -v __imp_ | grep -c public_c_function_from_rlib)" -eq "0" ]
        [ "$$($(NM) $(TMPDIR)/$(EXE_NAME) | grep -v __imp_ | grep -c public_rust_function_from_exe)" -eq "0" ]
+endif
index 4e8936905c440a3fbd0b3f6f6163121c19543698..f02bccc4b2da50039c9fa6d912622b93e1af575e 100644 (file)
@@ -23,10 +23,6 @@ fn foo() -> i32 {
         _0 = move (_1.0: i32);           // scope 0 at main.rs:5:5: 5:10
         return;                          // scope 0 at main.rs:6:2: 6:2
     }
-
-    bb2 (cleanup): {
-        resume;                          // scope 0 at main.rs:4:1: 6:2
-    }
 }
 
 fn main() -> () {
index d89b526d4303fddb93b2c9a08112dbb4c5e742fc..9f46883beaaccd86223a1c1694d5a33899718bc6 100644 (file)
@@ -14,7 +14,7 @@ invocation-only:
        [ -e $(INVOCATION_ONLY)/x/index.html ]
        [ -e $(INVOCATION_ONLY)/theme-xxx.css ] # generated from z.css
        ! [ -e $(INVOCATION_ONLY)/storage-xxx.js ]
-       ! [ -e $(INVOCATION_ONLY)/SourceSerif4-It.ttf.woff ]
+       ! [ -e $(INVOCATION_ONLY)/SourceSerif4-It.ttf.woff2 ]
 
        # FIXME: this probably shouldn't have a suffix
        [ -e $(INVOCATION_ONLY)/y-xxx.css ]
@@ -24,7 +24,7 @@ invocation-only:
 toolchain-only:
        $(RUSTDOC) -Z unstable-options --emit=toolchain-shared-resources --output $(TOOLCHAIN_ONLY) --resource-suffix=-xxx --extend-css z.css x.rs
        [ -e $(TOOLCHAIN_ONLY)/storage-xxx.js ]
-       ! [ -e $(TOOLCHAIN_ONLY)/SourceSerif4-It.ttf.woff ]
+       ! [ -e $(TOOLCHAIN_ONLY)/SourceSerif4-It.ttf.woff2 ]
        ! [ -e $(TOOLCHAIN_ONLY)/search-index-xxx.js ]
        ! [ -e $(TOOLCHAIN_ONLY)/x/index.html ]
        ! [ -e $(TOOLCHAIN_ONLY)/theme.css ]
@@ -35,7 +35,7 @@ toolchain-only:
 all-shared:
        $(RUSTDOC) -Z unstable-options --emit=toolchain-shared-resources,unversioned-shared-resources --output $(ALL_SHARED) --resource-suffix=-xxx --extend-css z.css x.rs
        [ -e $(ALL_SHARED)/storage-xxx.js ]
-       [ -e $(ALL_SHARED)/SourceSerif4-It.ttf.woff ]
+       [ -e $(ALL_SHARED)/SourceSerif4-It.ttf.woff2 ]
        ! [ -e $(ALL_SHARED)/search-index-xxx.js ]
        ! [ -e $(ALL_SHARED)/settings.html ]
        ! [ -e $(ALL_SHARED)/x ]
diff --git a/src/test/run-make/issue-47384/Makefile b/src/test/run-make/issue-47384/Makefile
new file mode 100644 (file)
index 0000000..f10365f
--- /dev/null
@@ -0,0 +1,12 @@
+-include ../../run-make-fulldeps/tools.mk
+
+# only-linux
+# ignore-cross-compile
+
+all: main.rs
+       $(RUSTC) --crate-type lib lib.rs
+       $(RUSTC) --crate-type cdylib -Clink-args="-Tlinker.ld" main.rs
+       # Ensure `#[used]` and `KEEP`-ed section is there
+       objdump -s -j".static" $(TMPDIR)/libmain.so
+       # Ensure `#[no_mangle]` symbol is there
+       nm $(TMPDIR)/libmain.so | $(CGREP) bar
diff --git a/src/test/run-make/issue-47384/lib.rs b/src/test/run-make/issue-47384/lib.rs
new file mode 100644 (file)
index 0000000..99508bc
--- /dev/null
@@ -0,0 +1,12 @@
+mod foo {
+    #[link_section = ".rodata.STATIC"]
+    #[used]
+    static STATIC: [u32; 10] = [1; 10];
+}
+
+mod bar {
+    #[no_mangle]
+    extern "C" fn bar() -> i32 {
+        0
+    }
+}
diff --git a/src/test/run-make/issue-47384/linker.ld b/src/test/run-make/issue-47384/linker.ld
new file mode 100644 (file)
index 0000000..2e70aca
--- /dev/null
@@ -0,0 +1,7 @@
+SECTIONS
+{
+    .static : ALIGN(4)
+    {
+        KEEP(*(.rodata.STATIC));
+    }
+}
diff --git a/src/test/run-make/issue-47384/main.rs b/src/test/run-make/issue-47384/main.rs
new file mode 100644 (file)
index 0000000..0257263
--- /dev/null
@@ -0,0 +1 @@
+extern crate lib;
diff --git a/src/test/run-make/issue-96498/Makefile b/src/test/run-make/issue-96498/Makefile
new file mode 100644 (file)
index 0000000..eae6400
--- /dev/null
@@ -0,0 +1,8 @@
+# only-windows
+# needs-rust-lld
+
+-include ../../run-make-fulldeps/tools.mk
+
+# Ensure that LLD can link
+all:
+       $(RUSTC) -C linker=rust-lld foo.rs
diff --git a/src/test/run-make/issue-96498/foo.rs b/src/test/run-make/issue-96498/foo.rs
new file mode 100644 (file)
index 0000000..93ac364
--- /dev/null
@@ -0,0 +1,4 @@
+#![crate_type = "cdylib"]
+
+#[no_mangle]
+extern "C" fn foo() {}
index 6e305e81eeec04b6ff7861c6a90b44d86bc25cff..8713bf65c8432a2d5dbaa343a8c2eff1b790df19 100644 (file)
@@ -4,17 +4,20 @@ goto: file://|DOC_PATH|/test_docs/index.html
 // First, we check that the search results are hidden when the Escape key is pressed.
 write: (".search-input", "test")
 wait-for: "#search h1" // The search element is empty before the first search 
-assert-attribute: ("#search", {"class": "content"})
+// Check that the currently displayed element is search.
+wait-for: "#alternative-display #search"
 assert-attribute: ("#main-content", {"class": "content hidden"})
 assert-document-property: ({"URL": "index.html?search=test"}, ENDS_WITH)
 press-key: "Escape"
-assert-attribute: ("#search", {"class": "content hidden"})
+// Checks that search is no longer in the displayed content.
+wait-for: "#not-displayed #search"
+assert-false: "#alternative-display #search"
 assert-attribute: ("#main-content", {"class": "content"})
 assert-document-property: ({"URL": "index.html"}, [ENDS_WITH])
 
 // Check that focusing the search input brings back the search results
 focus: ".search-input"
-assert-attribute: ("#search", {"class": "content"})
+wait-for: "#alternative-display #search"
 assert-attribute: ("#main-content", {"class": "content hidden"})
 assert-document-property: ({"URL": "index.html?search=test"}, ENDS_WITH)
 
@@ -24,8 +27,8 @@ click: "#help-button"
 assert-document-property: ({"URL": "index.html?search=test"}, [ENDS_WITH])
 assert-attribute: ("#help", {"class": ""})
 press-key: "Escape"
+wait-for: "#alternative-display #search"
 assert-attribute: ("#help", {"class": "hidden"})
-assert-attribute: ("#search", {"class": "content"})
 assert-attribute: ("#main-content", {"class": "content hidden"})
 assert-document-property: ({"URL": "index.html?search=test"}, [ENDS_WITH])
 
@@ -37,5 +40,6 @@ assert-false: ".search-input:focus"
 assert: "#results a:focus"
 press-key: "Escape"
 assert-attribute: ("#help", {"class": "hidden"})
-assert-attribute: ("#search", {"class": "content hidden"})
+wait-for: "#not-displayed #search"
+assert-false: "#alternative-display #search"
 assert-attribute: ("#main-content", {"class": "content"})
diff --git a/src/test/rustdoc-gui/settings.goml b/src/test/rustdoc-gui/settings.goml
new file mode 100644 (file)
index 0000000..6c4611b
--- /dev/null
@@ -0,0 +1,67 @@
+// This test ensures that the settings menu display is working as expected.
+goto: file://|DOC_PATH|/test_docs/index.html
+// First, we check that the settings page doesn't exist.
+assert-false: "#settings"
+// We now click on the settings button.
+click: "#settings-menu"
+wait-for: "#settings"
+assert: "#main-content.hidden"
+assert-css: ("#settings", {"display": "block"})
+// Let's close it by clicking on the same button.
+click: "#settings-menu"
+assert-false: "#alternative-display #settings"
+assert: "#not-displayed #settings"
+assert: "#main-content:not(.hidden)"
+
+// Let's open and then close it again with the "close settings" button.
+click: "#settings-menu"
+wait-for: "#alternative-display #settings"
+assert: "#main-content.hidden"
+click: "#back"
+wait-for: "#not-displayed #settings"
+assert: "#main-content:not(.hidden)"
+
+// Let's check that pressing "ESCAPE" is closing it.
+click: "#settings-menu"
+wait-for: "#alternative-display #settings"
+press-key: "Escape"
+wait-for: "#not-displayed #settings"
+assert: "#main-content:not(.hidden)"
+
+// Let's click on it when the search results are displayed.
+focus: ".search-input"
+write: "test"
+wait-for: "#alternative-display #search"
+click: "#settings-menu"
+wait-for: "#alternative-display #settings"
+assert: "#not-displayed #search"
+assert: "#main-content.hidden"
+
+// Now let's check the content of the settings menu.
+local-storage: {"rustdoc-theme": "dark", "rustdoc-use-system-theme": "false"}
+reload:
+click: "#settings-menu"
+wait-for: "#settings"
+
+// We check that the "Use system theme" is disabled.
+assert-property: ("#use-system-theme", {"checked": "false"})
+assert: "//*[@class='setting-line']/*[text()='Use system theme']"
+// Meaning that only the "theme" menu is showing up.
+assert: ".setting-line:not(.hidden) #theme"
+assert: ".setting-line.hidden #preferred-dark-theme"
+assert: ".setting-line.hidden #preferred-light-theme"
+
+// We check that the correct theme is selected.
+assert-property: ("#theme .choices #theme-dark", {"checked": "true"})
+
+// We now switch the display.
+click: "#use-system-theme"
+// Wait for the hidden element to show up.
+wait-for: ".setting-line:not(.hidden) #preferred-dark-theme"
+assert: ".setting-line:not(.hidden) #preferred-light-theme"
+// Check that the theme picking is hidden.
+assert: ".setting-line.hidden #theme"
+
+// We check their text as well.
+assert-text: ("#preferred-dark-theme .setting-name", "Preferred dark theme")
+assert-text: ("#preferred-light-theme .setting-name", "Preferred light theme")
index 333391ba27970505c7141a8cbf31e491511c5e7e..9706511ea19c398fda3051fc9651f0f53a27c1e0 100644 (file)
@@ -9,6 +9,7 @@ click: "#theme-choices > button:last-child"
 wait-for-css: ("body", { "background-color": "rgb(255, 255, 255)" })
 
 goto: file://|DOC_PATH|/settings.html
+wait-for: "#settings"
 click: "#theme-light"
 wait-for-css: ("body", { "background-color": "rgb(255, 255, 255)" })
 assert-local-storage: { "rustdoc-theme": "light" }
index 3b66c85d8dad283e5c1d2fe94b7ac8417449b65c..f576ced1c62086d85a69c8416902845435fa32a3 100644 (file)
@@ -1,15 +1,19 @@
 // Ensures that the theme is working when going back in history.
 goto: file://|DOC_PATH|/test_docs/index.html
 // Set the theme to dark.
-local-storage: {"rustdoc-theme": "dark", "rustdoc-preferred-dark-theme": "dark", "rustdoc-use-system-theme": "false"}
+local-storage: {
+    "rustdoc-theme": "dark",
+    "rustdoc-preferred-dark-theme": "dark",
+    "rustdoc-use-system-theme": "false",
+}
 // We reload the page so the local storage settings are being used.
 reload:
 assert-css: ("body", { "background-color": "rgb(53, 53, 53)" })
 assert-local-storage: { "rustdoc-theme": "dark" }
 
 // Now we go to the settings page.
-click: "#settings-menu"
-wait-for: ".settings"
+goto: file://|DOC_PATH|/settings.html
+wait-for: "#settings"
 // We change the theme to "light".
 click: "#theme-light"
 wait-for-css: ("body", { "background-color": "rgb(255, 255, 255)" })
@@ -18,7 +22,7 @@ assert-local-storage: { "rustdoc-theme": "light" }
 // We go back in history.
 history-go-back:
 // Confirm that we're not on the settings page.
-assert-false: ".settings"
+assert-false: "#settings"
 // Check that the current theme is still "light".
 assert-css: ("body", { "background-color": "rgb(255, 255, 255)" })
 assert-local-storage: { "rustdoc-theme": "light" }
index 779ab867c12b1afc7adcf34a5418d2638bee889a..dc42031e05f2f21f2522fe94e1a6fbade387fec8 100644 (file)
@@ -35,6 +35,8 @@ const QUERY = [
     "a,:",
     "  a<>  :",
     "mod : :",
+    "a!a",
+    "a!!",
 ];
 
 const PARSED = [
@@ -362,4 +364,22 @@ const PARSED = [
         userQuery: "mod : :",
         error: 'Unexpected `:`',
     },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "a!a",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "a!a",
+        error: '`!` can only be at the end of an ident',
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "a!!",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "a!!",
+        error: 'Cannot have more than one `!` in an ident',
+    },
 ];
diff --git a/src/test/rustdoc-js-std/parser-ident.js b/src/test/rustdoc-js-std/parser-ident.js
new file mode 100644 (file)
index 0000000..4b5ab01
--- /dev/null
@@ -0,0 +1,93 @@
+const QUERY = [
+    "R<!>",
+    "!",
+    "a!",
+    "a!::b",
+    "a!::b!",
+];
+
+const PARSED = [
+    {
+        elems: [{
+            name: "r",
+            fullPath: ["r"],
+            pathWithoutLast: [],
+            pathLast: "r",
+            generics: [
+                {
+                    name: "!",
+                    fullPath: ["!"],
+                    pathWithoutLast: [],
+                    pathLast: "!",
+                    generics: [],
+                },
+            ],
+        }],
+        foundElems: 1,
+        original: "R<!>",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "r<!>",
+        error: null,
+    },
+    {
+        elems: [{
+            name: "!",
+            fullPath: ["!"],
+            pathWithoutLast: [],
+            pathLast: "!",
+            generics: [],
+        }],
+        foundElems: 1,
+        original: "!",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "!",
+        error: null,
+    },
+    {
+        elems: [{
+            name: "a!",
+            fullPath: ["a!"],
+            pathWithoutLast: [],
+            pathLast: "a!",
+            generics: [],
+        }],
+        foundElems: 1,
+        original: "a!",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "a!",
+        error: null,
+    },
+    {
+        elems: [{
+            name: "a!::b",
+            fullPath: ["a!", "b"],
+            pathWithoutLast: ["a!"],
+            pathLast: "b",
+            generics: [],
+        }],
+        foundElems: 1,
+        original: "a!::b",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "a!::b",
+        error: null,
+    },
+    {
+        elems: [{
+            name: "a!::b!",
+            fullPath: ["a!", "b!"],
+            pathWithoutLast: ["a!"],
+            pathLast: "b!",
+            generics: [],
+        }],
+        foundElems: 1,
+        original: "a!::b!",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "a!::b!",
+        error: null,
+    },
+];
index b45466aa940a46938e7d52305676f6f73cebdab3..6fce17dcabdd815085239bae4348a83cb8ef26db 100644 (file)
@@ -1,4 +1,10 @@
-const QUERY = ['-> F<P>', '-> P', '->,a', 'aaaaa->a'];
+const QUERY = [
+    "-> F<P>",
+    "-> P",
+    "->,a",
+    "aaaaa->a",
+    "-> !",
+];
 
 const PARSED = [
     {
@@ -75,4 +81,19 @@ const PARSED = [
         userQuery: "aaaaa->a",
         error: null,
     },
+    {
+        elems: [],
+        foundElems: 1,
+        original: "-> !",
+        returned: [{
+            name: "!",
+            fullPath: ["!"],
+            pathWithoutLast: [],
+            pathLast: "!",
+            generics: [],
+        }],
+        typeFilter: -1,
+        userQuery: "-> !",
+        error: null,
+    },
 ];
diff --git a/src/test/rustdoc-ui/intra-doc/macro-rules-error.rs b/src/test/rustdoc-ui/intra-doc/macro-rules-error.rs
new file mode 100644 (file)
index 0000000..84d63c2
--- /dev/null
@@ -0,0 +1,27 @@
+// `macro_rules` scopes are respected during doc link resolution.
+
+// compile-flags: --document-private-items
+
+#![deny(rustdoc::broken_intra_doc_links)]
+
+mod no_escape {
+    macro_rules! before_but_limited_to_module {
+        () => {};
+    }
+}
+
+/// [before_but_limited_to_module] FIXME: This error should be reported
+// ERROR unresolved link to `before_but_limited_to_module`
+/// [after] FIXME: This error should be reported
+// ERROR unresolved link to `after`
+/// [str] FIXME: This error shouldn not be reported
+//~^ ERROR `str` is both a builtin type and a macro
+fn check() {}
+
+macro_rules! after {
+    () => {};
+}
+
+macro_rules! str {
+    () => {};
+}
diff --git a/src/test/rustdoc-ui/intra-doc/macro-rules-error.stderr b/src/test/rustdoc-ui/intra-doc/macro-rules-error.stderr
new file mode 100644 (file)
index 0000000..4b984f4
--- /dev/null
@@ -0,0 +1,22 @@
+error: `str` is both a builtin type and a macro
+  --> $DIR/macro-rules-error.rs:17:6
+   |
+LL | /// [str] FIXME: This error shouldn not be reported
+   |      ^^^ ambiguous link
+   |
+note: the lint level is defined here
+  --> $DIR/macro-rules-error.rs:5:9
+   |
+LL | #![deny(rustdoc::broken_intra_doc_links)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: to link to the builtin type, prefix with `prim@`
+   |
+LL | /// [prim@str] FIXME: This error shouldn not be reported
+   |      +++++
+help: to link to the macro, add an exclamation mark
+   |
+LL | /// [str!] FIXME: This error shouldn not be reported
+   |         +
+
+error: aborting due to previous error
+
index a14e4bdf1d706195de9551a46c704051349072e8..3aeb370ef6dc5084d244b2dad575b6d8c8b9ed86 100644 (file)
@@ -7,3 +7,18 @@ macro_rules! foo {
 
 /// [foo!]
 pub fn baz() {}
+
+#[macro_use]
+mod macros {
+    macro_rules! escaping {
+        () => {};
+    }
+}
+
+pub mod inner {
+    /// [foo!]
+    /// [escaping]
+    pub fn baz() {
+        foo!();
+    }
+}
index d0372d4945f3a4598043fea06c2565c2f5ae8373..a19e452b459e19c85d84fb048b34a3b03cac84fc 100644 (file)
@@ -1,7 +1,6 @@
 Available passes for running rustdoc:
 check_doc_test_visibility - run various visibility-related lints on doctests
         strip-hidden - strips all `#[doc(hidden)]` items from the output
-   unindent-comments - removes excess indentation on comments in order for markdown to like it
        strip-private - strips all private items from a crate which cannot be seen externally, implies strip-priv-imports
   strip-priv-imports - strips all private import statements (`use`, `extern crate`) from a crate
    propagate-doc-cfg - propagates `#[doc(cfg(...))]` to child items
@@ -14,7 +13,6 @@ check-invalid-html-tags - detects invalid HTML tags in doc comments
 
 Default passes for rustdoc:
  collect-trait-impls
-   unindent-comments
 check_doc_test_visibility
         strip-hidden  (when not --document-hidden-items)
        strip-private  (when not --document-private-items)
diff --git a/src/test/rustdoc/deref-slice-core.rs b/src/test/rustdoc/deref-slice-core.rs
new file mode 100644 (file)
index 0000000..cccf273
--- /dev/null
@@ -0,0 +1,22 @@
+// https://github.com/rust-lang/rust/issues/95325
+//
+// Show methods reachable from Deref of primitive.
+#![no_std]
+
+use core::ops::Deref;
+
+// @has 'deref_slice_core/struct.MyArray.html'
+// @has '-' '//*[@id="deref-methods-%5BT%5D"]' 'Methods from Deref<Target = [T]>'
+// @has '-' '//*[@class="impl-items"]//*[@id="method.len"]' 'pub fn len(&self)'
+
+pub struct MyArray<T> {
+    array: [T; 10],
+}
+
+impl<T> Deref for MyArray<T> {
+    type Target = [T];
+
+    fn deref(&self) -> &Self::Target {
+        &self.array
+    }
+}
diff --git a/src/test/rustdoc/issue-95873.rs b/src/test/rustdoc/issue-95873.rs
new file mode 100644 (file)
index 0000000..ff33fb6
--- /dev/null
@@ -0,0 +1,2 @@
+// @has issue_95873/index.html "//*[@class='item-left import-item']" "pub use ::std as x;"
+pub use ::std as x;
diff --git a/src/test/rustdoc/issue-96381.rs b/src/test/rustdoc/issue-96381.rs
new file mode 100644 (file)
index 0000000..f0f123f
--- /dev/null
@@ -0,0 +1,16 @@
+// should-fail
+
+#![allow(unused)]
+
+trait Foo<T>: Sized {
+    fn bar(i: i32, t: T, s: &Self) -> (T, i32);
+}
+
+impl Foo<usize> for () {
+    fn bar(i: _, t: _, s: _) -> _ {
+        //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
+        (1, 2)
+    }
+}
+
+fn main() {}
index c7ef5ad70a114002fdad17f7e7c47c83d083aaa3..064472f5785a1f80823eca178058754472deaf48 100644 (file)
@@ -5,10 +5,11 @@
 // ignore-cross-compile
 
 use std::env;
+use std::ffi::OsStr;
 use std::fs;
+use std::path::PathBuf;
 use std::process;
 use std::str;
-use std::path::PathBuf;
 
 fn main() {
     // If we're the child, make sure we were invoked correctly
@@ -18,8 +19,8 @@ fn main() {
         // checking that it ends_with the executable name. This
         // is needed because of Windows, which has a different behavior.
         // See #15149 for more info.
-        return assert!(args[0].ends_with(&format!("mytest{}",
-                                                  env::consts::EXE_SUFFIX)));
+        let my_path = env::current_exe().unwrap();
+        return assert_eq!(my_path.file_stem(), Some(OsStr::new("mytest")));
     }
 
     test();
@@ -28,14 +29,13 @@ fn main() {
 fn test() {
     // If we're the parent, copy our own binary to a new directory.
     let my_path = env::current_exe().unwrap();
-    let my_dir  = my_path.parent().unwrap();
+    let my_dir = my_path.parent().unwrap();
 
     let child_dir = PathBuf::from(env::var_os("RUST_TEST_TMPDIR").unwrap());
     let child_dir = child_dir.join("issue-15140-child");
     fs::create_dir_all(&child_dir).unwrap();
 
-    let child_path = child_dir.join(&format!("mytest{}",
-                                             env::consts::EXE_SUFFIX));
+    let child_path = child_dir.join(&format!("mytest{}", env::consts::EXE_SUFFIX));
     fs::copy(&my_path, &child_path).unwrap();
 
     // Append the new directory to our own PATH.
@@ -45,12 +45,13 @@ fn test() {
         env::join_paths(paths).unwrap()
     };
 
-    let child_output = process::Command::new("mytest").env("PATH", &path)
-                                                      .arg("child")
-                                                      .output().unwrap();
+    let child_output =
+        process::Command::new("mytest").env("PATH", &path).arg("child").output().unwrap();
 
-    assert!(child_output.status.success(),
-            "child assertion failed\n child stdout:\n {}\n child stderr:\n {}",
-            str::from_utf8(&child_output.stdout).unwrap(),
-            str::from_utf8(&child_output.stderr).unwrap());
+    assert!(
+        child_output.status.success(),
+        "child assertion failed\n child stdout:\n {}\n child stderr:\n {}",
+        str::from_utf8(&child_output.stdout).unwrap(),
+        str::from_utf8(&child_output.stderr).unwrap()
+    );
 }
diff --git a/src/test/ui-fulldeps/session-derive-errors.rs b/src/test/ui-fulldeps/session-derive-errors.rs
deleted file mode 100644 (file)
index adec548..0000000
+++ /dev/null
@@ -1,428 +0,0 @@
-// check-fail
-// Tests error conditions for specifying diagnostics using #[derive(SessionDiagnostic)]
-
-// The proc_macro2 crate handles spans differently when on beta/stable release rather than nightly,
-// changing the output of this test. Since SessionDiagnostic is strictly internal to the compiler
-// the test is just ignored on stable and beta:
-// ignore-beta
-// ignore-stable
-
-#![feature(rustc_private)]
-#![crate_type = "lib"]
-
-extern crate rustc_span;
-use rustc_span::symbol::Ident;
-use rustc_span::Span;
-
-extern crate rustc_macros;
-use rustc_macros::SessionDiagnostic;
-
-extern crate rustc_middle;
-use rustc_middle::ty::Ty;
-
-extern crate rustc_errors;
-use rustc_errors::Applicability;
-
-extern crate rustc_session;
-
-#[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "hello-world")]
-struct Hello {}
-
-#[derive(SessionDiagnostic)]
-#[warning(code = "E0123", slug = "hello-world")]
-struct HelloWarn {}
-
-#[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
-//~^ ERROR `#[derive(SessionDiagnostic)]` can only be used on structs
-enum SessionDiagnosticOnEnum {
-    Foo,
-    Bar,
-}
-
-#[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
-#[error = "E0123"]
-//~^ ERROR `#[error = ...]` is not a valid `SessionDiagnostic` struct attribute
-struct WrongStructAttrStyle {}
-
-#[derive(SessionDiagnostic)]
-#[nonsense(code = "E0123", slug = "foo")]
-//~^ ERROR `#[nonsense(...)]` is not a valid `SessionDiagnostic` struct attribute
-//~^^ ERROR diagnostic kind not specified
-//~^^^ ERROR cannot find attribute `nonsense` in this scope
-struct InvalidStructAttr {}
-
-#[derive(SessionDiagnostic)]
-#[error("E0123")]
-//~^ ERROR `#[error("...")]` is not a valid `SessionDiagnostic` struct attribute
-//~^^ ERROR `slug` not specified
-struct InvalidLitNestedAttr {}
-
-#[derive(SessionDiagnostic)]
-#[error(nonsense, code = "E0123", slug = "foo")]
-//~^ ERROR `#[error(nonsense)]` is not a valid `SessionDiagnostic` struct attribute
-struct InvalidNestedStructAttr {}
-
-#[derive(SessionDiagnostic)]
-#[error(nonsense("foo"), code = "E0123", slug = "foo")]
-//~^ ERROR `#[error(nonsense(...))]` is not a valid `SessionDiagnostic` struct attribute
-struct InvalidNestedStructAttr1 {}
-
-#[derive(SessionDiagnostic)]
-#[error(nonsense = "...", code = "E0123", slug = "foo")]
-//~^ ERROR `#[error(nonsense = ...)]` is not a valid `SessionDiagnostic` struct attribute
-struct InvalidNestedStructAttr2 {}
-
-#[derive(SessionDiagnostic)]
-#[error(nonsense = 4, code = "E0123", slug = "foo")]
-//~^ ERROR `#[error(nonsense = ...)]` is not a valid `SessionDiagnostic` struct attribute
-struct InvalidNestedStructAttr3 {}
-
-#[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
-struct WrongPlaceField {
-    #[suggestion = "bar"]
-    //~^ ERROR `#[suggestion = ...]` is not a valid `SessionDiagnostic` field attribute
-    sp: Span,
-}
-
-#[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
-#[error(code = "E0456", slug = "bar")] //~ ERROR `error` specified multiple times
-struct ErrorSpecifiedTwice {}
-
-#[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
-#[warning(code = "E0293", slug = "bar")]
-//~^ ERROR `warning` specified when `error` was already specified
-struct WarnSpecifiedAfterError {}
-
-#[derive(SessionDiagnostic)]
-#[error(code = "E0456", code = "E0457", slug = "bar")] //~ ERROR `code` specified multiple times
-struct CodeSpecifiedTwice {}
-
-#[derive(SessionDiagnostic)]
-#[error(code = "E0456", slug = "foo", slug = "bar")] //~ ERROR `slug` specified multiple times
-struct SlugSpecifiedTwice {}
-
-#[derive(SessionDiagnostic)]
-struct KindNotProvided {} //~ ERROR diagnostic kind not specified
-
-#[derive(SessionDiagnostic)]
-#[error(code = "E0456")] //~ ERROR `slug` not specified
-struct SlugNotProvided {}
-
-#[derive(SessionDiagnostic)]
-#[error(slug = "foo")]
-struct CodeNotProvided {}
-
-#[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
-struct MessageWrongType {
-    #[primary_span]
-    //~^ ERROR `#[primary_span]` attribute can only be applied to fields of type `Span`
-    foo: String,
-}
-
-#[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
-struct InvalidPathFieldAttr {
-    #[nonsense]
-    //~^ ERROR `#[nonsense]` is not a valid `SessionDiagnostic` field attribute
-    //~^^ ERROR cannot find attribute `nonsense` in this scope
-    foo: String,
-}
-
-#[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
-struct ErrorWithField {
-    name: String,
-    #[label = "bar"]
-    span: Span,
-}
-
-#[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
-struct ErrorWithMessageAppliedToField {
-    #[label = "bar"]
-    //~^ ERROR the `#[label = ...]` attribute can only be applied to fields of type `Span`
-    name: String,
-}
-
-#[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
-struct ErrorWithNonexistentField {
-    #[suggestion(message = "bar", code = "{name}")]
-    //~^ ERROR `name` doesn't refer to a field on this type
-    suggestion: (Span, Applicability),
-}
-
-#[derive(SessionDiagnostic)]
-//~^ ERROR invalid format string: expected `'}'`
-#[error(code = "E0123", slug = "foo")]
-struct ErrorMissingClosingBrace {
-    #[suggestion(message = "bar", code = "{name")]
-    suggestion: (Span, Applicability),
-    name: String,
-    val: usize,
-}
-
-#[derive(SessionDiagnostic)]
-//~^ ERROR invalid format string: unmatched `}`
-#[error(code = "E0123", slug = "foo")]
-struct ErrorMissingOpeningBrace {
-    #[suggestion(message = "bar", code = "name}")]
-    suggestion: (Span, Applicability),
-    name: String,
-    val: usize,
-}
-
-#[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
-struct LabelOnSpan {
-    #[label = "bar"]
-    sp: Span,
-}
-
-#[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
-struct LabelOnNonSpan {
-    #[label = "bar"]
-    //~^ ERROR the `#[label = ...]` attribute can only be applied to fields of type `Span`
-    id: u32,
-}
-
-#[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
-struct Suggest {
-    #[suggestion(message = "bar", code = "This is the suggested code")]
-    #[suggestion_short(message = "qux", code = "This is the suggested code")]
-    #[suggestion_hidden(message = "foobar", code = "This is the suggested code")]
-    #[suggestion_verbose(message = "fooqux", code = "This is the suggested code")]
-    suggestion: (Span, Applicability),
-}
-
-#[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
-struct SuggestWithoutCode {
-    #[suggestion(message = "bar")]
-    suggestion: (Span, Applicability),
-}
-
-#[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
-struct SuggestWithBadKey {
-    #[suggestion(nonsense = "bar")]
-    //~^ ERROR `#[suggestion(nonsense = ...)]` is not a valid `SessionDiagnostic` field attribute
-    suggestion: (Span, Applicability),
-}
-
-#[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
-struct SuggestWithShorthandMsg {
-    #[suggestion(msg = "bar")]
-    //~^ ERROR `#[suggestion(msg = ...)]` is not a valid `SessionDiagnostic` field attribute
-    suggestion: (Span, Applicability),
-}
-
-#[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
-struct SuggestWithoutMsg {
-    #[suggestion(code = "bar")]
-    suggestion: (Span, Applicability),
-}
-
-#[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
-struct SuggestWithTypesSwapped {
-    #[suggestion(message = "bar", code = "This is suggested code")]
-    suggestion: (Applicability, Span),
-}
-
-#[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
-struct SuggestWithWrongTypeApplicabilityOnly {
-    #[suggestion(message = "bar", code = "This is suggested code")]
-    //~^ ERROR wrong field type for suggestion
-    suggestion: Applicability,
-}
-
-#[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
-struct SuggestWithSpanOnly {
-    #[suggestion(message = "bar", code = "This is suggested code")]
-    suggestion: Span,
-}
-
-#[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
-struct SuggestWithDuplicateSpanAndApplicability {
-    #[suggestion(message = "bar", code = "This is suggested code")]
-    //~^ ERROR type of field annotated with `#[suggestion(...)]` contains more than one `Span`
-    suggestion: (Span, Span, Applicability),
-}
-
-#[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
-struct SuggestWithDuplicateApplicabilityAndSpan {
-    #[suggestion(message = "bar", code = "This is suggested code")]
-    //~^ ERROR type of field annotated with `#[suggestion(...)]` contains more than one
-    suggestion: (Applicability, Applicability, Span),
-}
-
-#[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
-struct WrongKindOfAnnotation {
-    #[label("bar")]
-    //~^ ERROR `#[label(...)]` is not a valid `SessionDiagnostic` field attribute
-    z: Span,
-}
-
-#[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
-struct OptionsInErrors {
-    #[label = "bar"]
-    label: Option<Span>,
-    #[suggestion(message = "bar")]
-    opt_sugg: Option<(Span, Applicability)>,
-}
-
-#[derive(SessionDiagnostic)]
-#[error(code = "E0456", slug = "foo")]
-struct MoveOutOfBorrowError<'tcx> {
-    name: Ident,
-    ty: Ty<'tcx>,
-    #[primary_span]
-    #[label = "bar"]
-    span: Span,
-    #[label = "qux"]
-    other_span: Span,
-    #[suggestion(message = "bar", code = "{name}.clone()")]
-    opt_sugg: Option<(Span, Applicability)>,
-}
-
-#[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
-struct ErrorWithLifetime<'a> {
-    #[label = "bar"]
-    span: Span,
-    name: &'a str,
-}
-
-#[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
-struct ErrorWithDefaultLabelAttr<'a> {
-    #[label]
-    span: Span,
-    name: &'a str,
-}
-
-#[derive(SessionDiagnostic)]
-//~^ ERROR no method named `into_diagnostic_arg` found for struct `Hello` in the current scope
-#[error(code = "E0123", slug = "foo")]
-struct ArgFieldWithoutSkip {
-    #[primary_span]
-    span: Span,
-    other: Hello,
-}
-
-#[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
-struct ArgFieldWithSkip {
-    #[primary_span]
-    span: Span,
-    // `Hello` does not implement `IntoDiagnosticArg` so this would result in an error if
-    // not for `#[skip_arg]`.
-    #[skip_arg]
-    other: Hello,
-}
-
-#[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
-struct ErrorWithSpannedNote {
-    #[note]
-    span: Span,
-}
-
-#[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
-struct ErrorWithSpannedNoteCustom {
-    #[note = "bar"]
-    span: Span,
-}
-
-#[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
-#[note]
-struct ErrorWithNote {
-    val: String,
-}
-
-#[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
-#[note = "bar"]
-struct ErrorWithNoteCustom {
-    val: String,
-}
-
-#[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
-struct ErrorWithSpannedHelp {
-    #[help]
-    span: Span,
-}
-
-#[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
-struct ErrorWithSpannedHelpCustom {
-    #[help = "bar"]
-    span: Span,
-}
-
-#[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
-#[help]
-struct ErrorWithHelp {
-    val: String,
-}
-
-#[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
-#[help = "bar"]
-struct ErrorWithHelpCustom {
-    val: String,
-}
-
-#[derive(SessionDiagnostic)]
-#[help]
-//~^ ERROR `#[help]` must come after `#[error(..)]` or `#[warn(..)]`
-#[error(code = "E0123", slug = "foo")]
-struct ErrorWithHelpWrongOrder {
-    val: String,
-}
-
-#[derive(SessionDiagnostic)]
-#[help = "bar"]
-//~^ ERROR `#[help = ...]` must come after `#[error(..)]` or `#[warn(..)]`
-#[error(code = "E0123", slug = "foo")]
-struct ErrorWithHelpCustomWrongOrder {
-    val: String,
-}
-
-#[derive(SessionDiagnostic)]
-#[note]
-//~^ ERROR `#[note]` must come after `#[error(..)]` or `#[warn(..)]`
-#[error(code = "E0123", slug = "foo")]
-struct ErrorWithNoteWrongOrder {
-    val: String,
-}
-
-#[derive(SessionDiagnostic)]
-#[note = "bar"]
-//~^ ERROR `#[note = ...]` must come after `#[error(..)]` or `#[warn(..)]`
-#[error(code = "E0123", slug = "foo")]
-struct ErrorWithNoteCustomWrongOrder {
-    val: String,
-}
diff --git a/src/test/ui-fulldeps/session-derive-errors.stderr b/src/test/ui-fulldeps/session-derive-errors.stderr
deleted file mode 100644 (file)
index a528ae1..0000000
+++ /dev/null
@@ -1,293 +0,0 @@
-error: `#[derive(SessionDiagnostic)]` can only be used on structs
-  --> $DIR/session-derive-errors.rs:37:1
-   |
-LL | / #[error(code = "E0123", slug = "foo")]
-LL | |
-LL | | enum SessionDiagnosticOnEnum {
-LL | |     Foo,
-LL | |     Bar,
-LL | | }
-   | |_^
-
-error: `#[error = ...]` is not a valid `SessionDiagnostic` struct attribute
-  --> $DIR/session-derive-errors.rs:46:1
-   |
-LL | #[error = "E0123"]
-   | ^^^^^^^^^^^^^^^^^^
-
-error: `#[nonsense(...)]` is not a valid `SessionDiagnostic` struct attribute
-  --> $DIR/session-derive-errors.rs:51:1
-   |
-LL | #[nonsense(code = "E0123", slug = "foo")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: diagnostic kind not specified
-  --> $DIR/session-derive-errors.rs:51:1
-   |
-LL | / #[nonsense(code = "E0123", slug = "foo")]
-LL | |
-LL | |
-LL | |
-LL | | struct InvalidStructAttr {}
-   | |___________________________^
-   |
-   = help: use the `#[error(...)]` attribute to create an error
-
-error: `#[error("...")]` is not a valid `SessionDiagnostic` struct attribute
-  --> $DIR/session-derive-errors.rs:58:9
-   |
-LL | #[error("E0123")]
-   |         ^^^^^^^
-
-error: `slug` not specified
-  --> $DIR/session-derive-errors.rs:58:1
-   |
-LL | / #[error("E0123")]
-LL | |
-LL | |
-LL | | struct InvalidLitNestedAttr {}
-   | |______________________________^
-   |
-   = help: use the `#[error(slug = "...")]` attribute to set this diagnostic's slug
-
-error: `#[error(nonsense)]` is not a valid `SessionDiagnostic` struct attribute
-  --> $DIR/session-derive-errors.rs:64:9
-   |
-LL | #[error(nonsense, code = "E0123", slug = "foo")]
-   |         ^^^^^^^^
-
-error: `#[error(nonsense(...))]` is not a valid `SessionDiagnostic` struct attribute
-  --> $DIR/session-derive-errors.rs:69:9
-   |
-LL | #[error(nonsense("foo"), code = "E0123", slug = "foo")]
-   |         ^^^^^^^^^^^^^^^
-
-error: `#[error(nonsense = ...)]` is not a valid `SessionDiagnostic` struct attribute
-  --> $DIR/session-derive-errors.rs:74:9
-   |
-LL | #[error(nonsense = "...", code = "E0123", slug = "foo")]
-   |         ^^^^^^^^^^^^^^^^
-
-error: `#[error(nonsense = ...)]` is not a valid `SessionDiagnostic` struct attribute
-  --> $DIR/session-derive-errors.rs:79:9
-   |
-LL | #[error(nonsense = 4, code = "E0123", slug = "foo")]
-   |         ^^^^^^^^^^^^
-   |
-   = help: value must be a string
-
-error: `#[suggestion = ...]` is not a valid `SessionDiagnostic` field attribute
-  --> $DIR/session-derive-errors.rs:86:5
-   |
-LL |     #[suggestion = "bar"]
-   |     ^^^^^^^^^^^^^^^^^^^^^
-
-error: `error` specified multiple times
-  --> $DIR/session-derive-errors.rs:93:1
-   |
-LL | #[error(code = "E0456", slug = "bar")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: previously specified here
-  --> $DIR/session-derive-errors.rs:92:1
-   |
-LL | #[error(code = "E0123", slug = "foo")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: `warning` specified when `error` was already specified
-  --> $DIR/session-derive-errors.rs:98:1
-   |
-LL | #[warning(code = "E0293", slug = "bar")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: previously specified here
-  --> $DIR/session-derive-errors.rs:97:1
-   |
-LL | #[error(code = "E0123", slug = "foo")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: `code` specified multiple times
-  --> $DIR/session-derive-errors.rs:103:32
-   |
-LL | #[error(code = "E0456", code = "E0457", slug = "bar")]
-   |                                ^^^^^^^
-   |
-note: previously specified here
-  --> $DIR/session-derive-errors.rs:103:16
-   |
-LL | #[error(code = "E0456", code = "E0457", slug = "bar")]
-   |                ^^^^^^^
-
-error: `slug` specified multiple times
-  --> $DIR/session-derive-errors.rs:107:46
-   |
-LL | #[error(code = "E0456", slug = "foo", slug = "bar")]
-   |                                              ^^^^^
-   |
-note: previously specified here
-  --> $DIR/session-derive-errors.rs:107:32
-   |
-LL | #[error(code = "E0456", slug = "foo", slug = "bar")]
-   |                                ^^^^^
-
-error: diagnostic kind not specified
-  --> $DIR/session-derive-errors.rs:111:1
-   |
-LL | struct KindNotProvided {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: use the `#[error(...)]` attribute to create an error
-
-error: `slug` not specified
-  --> $DIR/session-derive-errors.rs:114:1
-   |
-LL | / #[error(code = "E0456")]
-LL | | struct SlugNotProvided {}
-   | |_________________________^
-   |
-   = help: use the `#[error(slug = "...")]` attribute to set this diagnostic's slug
-
-error: the `#[primary_span]` attribute can only be applied to fields of type `Span`
-  --> $DIR/session-derive-errors.rs:124:5
-   |
-LL |     #[primary_span]
-   |     ^^^^^^^^^^^^^^^
-
-error: `#[nonsense]` is not a valid `SessionDiagnostic` field attribute
-  --> $DIR/session-derive-errors.rs:132:5
-   |
-LL |     #[nonsense]
-   |     ^^^^^^^^^^^
-
-error: the `#[label = ...]` attribute can only be applied to fields of type `Span`
-  --> $DIR/session-derive-errors.rs:149:5
-   |
-LL |     #[label = "bar"]
-   |     ^^^^^^^^^^^^^^^^
-
-error: `name` doesn't refer to a field on this type
-  --> $DIR/session-derive-errors.rs:157:42
-   |
-LL |     #[suggestion(message = "bar", code = "{name}")]
-   |                                          ^^^^^^^^
-
-error: invalid format string: expected `'}'` but string was terminated
-  --> $DIR/session-derive-errors.rs:162:16
-   |
-LL | #[derive(SessionDiagnostic)]
-   |           -    ^ expected `'}'` in format string
-   |           |
-   |           because of this opening brace
-   |
-   = note: if you intended to print `{`, you can escape it using `{{`
-   = note: this error originates in the derive macro `SessionDiagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: invalid format string: unmatched `}` found
-  --> $DIR/session-derive-errors.rs:172:15
-   |
-LL | #[derive(SessionDiagnostic)]
-   |               ^ unmatched `}` in format string
-   |
-   = note: if you intended to print `}`, you can escape it using `}}`
-   = note: this error originates in the derive macro `SessionDiagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: the `#[label = ...]` attribute can only be applied to fields of type `Span`
-  --> $DIR/session-derive-errors.rs:192:5
-   |
-LL |     #[label = "bar"]
-   |     ^^^^^^^^^^^^^^^^
-
-error: `#[suggestion(nonsense = ...)]` is not a valid `SessionDiagnostic` field attribute
-  --> $DIR/session-derive-errors.rs:217:18
-   |
-LL |     #[suggestion(nonsense = "bar")]
-   |                  ^^^^^^^^^^^^^^^^
-
-error: `#[suggestion(msg = ...)]` is not a valid `SessionDiagnostic` field attribute
-  --> $DIR/session-derive-errors.rs:225:18
-   |
-LL |     #[suggestion(msg = "bar")]
-   |                  ^^^^^^^^^^^
-
-error: wrong field type for suggestion
-  --> $DIR/session-derive-errors.rs:247:5
-   |
-LL | /     #[suggestion(message = "bar", code = "This is suggested code")]
-LL | |
-LL | |     suggestion: Applicability,
-   | |_____________________________^
-   |
-   = help: `#[suggestion(...)]` should be applied to fields of type `Span` or `(Span, Applicability)`
-
-error: type of field annotated with `#[suggestion(...)]` contains more than one `Span`
-  --> $DIR/session-derive-errors.rs:262:5
-   |
-LL | /     #[suggestion(message = "bar", code = "This is suggested code")]
-LL | |
-LL | |     suggestion: (Span, Span, Applicability),
-   | |___________________________________________^
-
-error: type of field annotated with `#[suggestion(...)]` contains more than one Applicability
-  --> $DIR/session-derive-errors.rs:270:5
-   |
-LL | /     #[suggestion(message = "bar", code = "This is suggested code")]
-LL | |
-LL | |     suggestion: (Applicability, Applicability, Span),
-   | |____________________________________________________^
-
-error: `#[label(...)]` is not a valid `SessionDiagnostic` field attribute
-  --> $DIR/session-derive-errors.rs:278:5
-   |
-LL |     #[label("bar")]
-   |     ^^^^^^^^^^^^^^^
-
-error: `#[help]` must come after `#[error(..)]` or `#[warn(..)]`
-  --> $DIR/session-derive-errors.rs:399:1
-   |
-LL | #[help]
-   | ^^^^^^^
-
-error: `#[help = ...]` must come after `#[error(..)]` or `#[warn(..)]`
-  --> $DIR/session-derive-errors.rs:407:1
-   |
-LL | #[help = "bar"]
-   | ^^^^^^^^^^^^^^^
-
-error: `#[note]` must come after `#[error(..)]` or `#[warn(..)]`
-  --> $DIR/session-derive-errors.rs:415:1
-   |
-LL | #[note]
-   | ^^^^^^^
-
-error: `#[note = ...]` must come after `#[error(..)]` or `#[warn(..)]`
-  --> $DIR/session-derive-errors.rs:423:1
-   |
-LL | #[note = "bar"]
-   | ^^^^^^^^^^^^^^^
-
-error: cannot find attribute `nonsense` in this scope
-  --> $DIR/session-derive-errors.rs:51:3
-   |
-LL | #[nonsense(code = "E0123", slug = "foo")]
-   |   ^^^^^^^^
-
-error: cannot find attribute `nonsense` in this scope
-  --> $DIR/session-derive-errors.rs:132:7
-   |
-LL |     #[nonsense]
-   |       ^^^^^^^^
-
-error[E0599]: no method named `into_diagnostic_arg` found for struct `Hello` in the current scope
-  --> $DIR/session-derive-errors.rs:322:10
-   |
-LL | struct Hello {}
-   | ------------ method `into_diagnostic_arg` not found for this
-...
-LL | #[derive(SessionDiagnostic)]
-   |          ^^^^^^^^^^^^^^^^^ method not found in `Hello`
-   |
-   = note: this error originates in the derive macro `SessionDiagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to 37 previous errors
-
-For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs
new file mode 100644 (file)
index 0000000..efbf78a
--- /dev/null
@@ -0,0 +1,476 @@
+// check-fail
+// Tests error conditions for specifying diagnostics using #[derive(SessionDiagnostic)]
+
+// The proc_macro2 crate handles spans differently when on beta/stable release rather than nightly,
+// changing the output of this test. Since SessionDiagnostic is strictly internal to the compiler
+// the test is just ignored on stable and beta:
+// ignore-beta
+// ignore-stable
+
+#![feature(rustc_private)]
+#![crate_type = "lib"]
+
+extern crate rustc_span;
+use rustc_span::symbol::Ident;
+use rustc_span::Span;
+
+extern crate rustc_macros;
+use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic};
+
+extern crate rustc_middle;
+use rustc_middle::ty::Ty;
+
+extern crate rustc_errors;
+use rustc_errors::Applicability;
+
+extern crate rustc_session;
+
+#[derive(SessionDiagnostic)]
+#[error(code = "E0123", slug = "hello-world")]
+struct Hello {}
+
+#[derive(SessionDiagnostic)]
+#[warning(code = "E0123", slug = "hello-world")]
+struct HelloWarn {}
+
+#[derive(SessionDiagnostic)]
+#[error(code = "E0123", slug = "foo")]
+//~^ ERROR `#[derive(SessionDiagnostic)]` can only be used on structs
+enum SessionDiagnosticOnEnum {
+    Foo,
+    Bar,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(code = "E0123", slug = "foo")]
+#[error = "E0123"]
+//~^ ERROR `#[error = ...]` is not a valid attribute
+struct WrongStructAttrStyle {}
+
+#[derive(SessionDiagnostic)]
+#[nonsense(code = "E0123", slug = "foo")]
+//~^ ERROR `#[nonsense(...)]` is not a valid attribute
+//~^^ ERROR diagnostic kind not specified
+//~^^^ ERROR cannot find attribute `nonsense` in this scope
+struct InvalidStructAttr {}
+
+#[derive(SessionDiagnostic)]
+#[error("E0123")]
+//~^ ERROR `#[error("...")]` is not a valid attribute
+//~^^ ERROR `slug` not specified
+struct InvalidLitNestedAttr {}
+
+#[derive(SessionDiagnostic)]
+#[error(nonsense, code = "E0123", slug = "foo")]
+//~^ ERROR `#[error(nonsense)]` is not a valid attribute
+struct InvalidNestedStructAttr {}
+
+#[derive(SessionDiagnostic)]
+#[error(nonsense("foo"), code = "E0123", slug = "foo")]
+//~^ ERROR `#[error(nonsense(...))]` is not a valid attribute
+struct InvalidNestedStructAttr1 {}
+
+#[derive(SessionDiagnostic)]
+#[error(nonsense = "...", code = "E0123", slug = "foo")]
+//~^ ERROR `#[error(nonsense = ...)]` is not a valid attribute
+struct InvalidNestedStructAttr2 {}
+
+#[derive(SessionDiagnostic)]
+#[error(nonsense = 4, code = "E0123", slug = "foo")]
+//~^ ERROR `#[error(nonsense = ...)]` is not a valid attribute
+struct InvalidNestedStructAttr3 {}
+
+#[derive(SessionDiagnostic)]
+#[error(code = "E0123", slug = "foo")]
+struct WrongPlaceField {
+    #[suggestion = "bar"]
+    //~^ ERROR `#[suggestion = ...]` is not a valid attribute
+    sp: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(code = "E0123", slug = "foo")]
+#[error(code = "E0456", slug = "bar")]
+//~^ ERROR specified multiple times
+//~^^ ERROR specified multiple times
+//~^^^ ERROR specified multiple times
+struct ErrorSpecifiedTwice {}
+
+#[derive(SessionDiagnostic)]
+#[error(code = "E0123", slug = "foo")]
+#[warning(code = "E0293", slug = "bar")]
+//~^ ERROR specified multiple times
+//~^^ ERROR specified multiple times
+//~^^^ ERROR specified multiple times
+struct WarnSpecifiedAfterError {}
+
+#[derive(SessionDiagnostic)]
+#[error(code = "E0456", code = "E0457", slug = "bar")]
+//~^ ERROR specified multiple times
+struct CodeSpecifiedTwice {}
+
+#[derive(SessionDiagnostic)]
+#[error(code = "E0456", slug = "foo", slug = "bar")]
+//~^ ERROR specified multiple times
+struct SlugSpecifiedTwice {}
+
+#[derive(SessionDiagnostic)]
+struct KindNotProvided {} //~ ERROR diagnostic kind not specified
+
+#[derive(SessionDiagnostic)]
+#[error(code = "E0456")] //~ ERROR `slug` not specified
+struct SlugNotProvided {}
+
+#[derive(SessionDiagnostic)]
+#[error(slug = "foo")]
+struct CodeNotProvided {}
+
+#[derive(SessionDiagnostic)]
+#[error(code = "E0123", slug = "foo")]
+struct MessageWrongType {
+    #[primary_span]
+    //~^ ERROR `#[primary_span]` attribute can only be applied to fields of type `Span`
+    foo: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(code = "E0123", slug = "foo")]
+struct InvalidPathFieldAttr {
+    #[nonsense]
+    //~^ ERROR `#[nonsense]` is not a valid attribute
+    //~^^ ERROR cannot find attribute `nonsense` in this scope
+    foo: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(code = "E0123", slug = "foo")]
+struct ErrorWithField {
+    name: String,
+    #[label = "bar"]
+    span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(code = "E0123", slug = "foo")]
+struct ErrorWithMessageAppliedToField {
+    #[label = "bar"]
+    //~^ ERROR the `#[label = ...]` attribute can only be applied to fields of type `Span`
+    name: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(code = "E0123", slug = "foo")]
+struct ErrorWithNonexistentField {
+    #[suggestion(message = "bar", code = "{name}")]
+    //~^ ERROR `name` doesn't refer to a field on this type
+    suggestion: (Span, Applicability),
+}
+
+#[derive(SessionDiagnostic)]
+//~^ ERROR invalid format string: expected `'}'`
+#[error(code = "E0123", slug = "foo")]
+struct ErrorMissingClosingBrace {
+    #[suggestion(message = "bar", code = "{name")]
+    suggestion: (Span, Applicability),
+    name: String,
+    val: usize,
+}
+
+#[derive(SessionDiagnostic)]
+//~^ ERROR invalid format string: unmatched `}`
+#[error(code = "E0123", slug = "foo")]
+struct ErrorMissingOpeningBrace {
+    #[suggestion(message = "bar", code = "name}")]
+    suggestion: (Span, Applicability),
+    name: String,
+    val: usize,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(code = "E0123", slug = "foo")]
+struct LabelOnSpan {
+    #[label = "bar"]
+    sp: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(code = "E0123", slug = "foo")]
+struct LabelOnNonSpan {
+    #[label = "bar"]
+    //~^ ERROR the `#[label = ...]` attribute can only be applied to fields of type `Span`
+    id: u32,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(code = "E0123", slug = "foo")]
+struct Suggest {
+    #[suggestion(message = "bar", code = "This is the suggested code")]
+    #[suggestion_short(message = "qux", code = "This is the suggested code")]
+    #[suggestion_hidden(message = "foobar", code = "This is the suggested code")]
+    #[suggestion_verbose(message = "fooqux", code = "This is the suggested code")]
+    suggestion: (Span, Applicability),
+}
+
+#[derive(SessionDiagnostic)]
+#[error(code = "E0123", slug = "foo")]
+struct SuggestWithoutCode {
+    #[suggestion(message = "bar")]
+    suggestion: (Span, Applicability),
+}
+
+#[derive(SessionDiagnostic)]
+#[error(code = "E0123", slug = "foo")]
+struct SuggestWithBadKey {
+    #[suggestion(nonsense = "bar")]
+    //~^ ERROR `#[suggestion(nonsense = ...)]` is not a valid attribute
+    suggestion: (Span, Applicability),
+}
+
+#[derive(SessionDiagnostic)]
+#[error(code = "E0123", slug = "foo")]
+struct SuggestWithShorthandMsg {
+    #[suggestion(msg = "bar")]
+    //~^ ERROR `#[suggestion(msg = ...)]` is not a valid attribute
+    suggestion: (Span, Applicability),
+}
+
+#[derive(SessionDiagnostic)]
+#[error(code = "E0123", slug = "foo")]
+struct SuggestWithoutMsg {
+    #[suggestion(code = "bar")]
+    suggestion: (Span, Applicability),
+}
+
+#[derive(SessionDiagnostic)]
+#[error(code = "E0123", slug = "foo")]
+struct SuggestWithTypesSwapped {
+    #[suggestion(message = "bar", code = "This is suggested code")]
+    suggestion: (Applicability, Span),
+}
+
+#[derive(SessionDiagnostic)]
+#[error(code = "E0123", slug = "foo")]
+struct SuggestWithWrongTypeApplicabilityOnly {
+    #[suggestion(message = "bar", code = "This is suggested code")]
+    //~^ ERROR wrong field type for suggestion
+    suggestion: Applicability,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(code = "E0123", slug = "foo")]
+struct SuggestWithSpanOnly {
+    #[suggestion(message = "bar", code = "This is suggested code")]
+    suggestion: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(code = "E0123", slug = "foo")]
+struct SuggestWithDuplicateSpanAndApplicability {
+    #[suggestion(message = "bar", code = "This is suggested code")]
+    //~^ ERROR type of field annotated with `#[suggestion(...)]` contains more than one `Span`
+    suggestion: (Span, Span, Applicability),
+}
+
+#[derive(SessionDiagnostic)]
+#[error(code = "E0123", slug = "foo")]
+struct SuggestWithDuplicateApplicabilityAndSpan {
+    #[suggestion(message = "bar", code = "This is suggested code")]
+    //~^ ERROR type of field annotated with `#[suggestion(...)]` contains more than one
+    suggestion: (Applicability, Applicability, Span),
+}
+
+#[derive(SessionDiagnostic)]
+#[error(code = "E0123", slug = "foo")]
+struct WrongKindOfAnnotation {
+    #[label("bar")]
+    //~^ ERROR `#[label(...)]` is not a valid attribute
+    z: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(code = "E0123", slug = "foo")]
+struct OptionsInErrors {
+    #[label = "bar"]
+    label: Option<Span>,
+    #[suggestion(message = "bar")]
+    opt_sugg: Option<(Span, Applicability)>,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(code = "E0456", slug = "foo")]
+struct MoveOutOfBorrowError<'tcx> {
+    name: Ident,
+    ty: Ty<'tcx>,
+    #[primary_span]
+    #[label = "bar"]
+    span: Span,
+    #[label = "qux"]
+    other_span: Span,
+    #[suggestion(message = "bar", code = "{name}.clone()")]
+    opt_sugg: Option<(Span, Applicability)>,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(code = "E0123", slug = "foo")]
+struct ErrorWithLifetime<'a> {
+    #[label = "bar"]
+    span: Span,
+    name: &'a str,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(code = "E0123", slug = "foo")]
+struct ErrorWithDefaultLabelAttr<'a> {
+    #[label]
+    span: Span,
+    name: &'a str,
+}
+
+#[derive(SessionDiagnostic)]
+//~^ ERROR no method named `into_diagnostic_arg` found for struct `Hello` in the current scope
+#[error(code = "E0123", slug = "foo")]
+struct ArgFieldWithoutSkip {
+    #[primary_span]
+    span: Span,
+    other: Hello,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(code = "E0123", slug = "foo")]
+struct ArgFieldWithSkip {
+    #[primary_span]
+    span: Span,
+    // `Hello` does not implement `IntoDiagnosticArg` so this would result in an error if
+    // not for `#[skip_arg]`.
+    #[skip_arg]
+    other: Hello,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(code = "E0123", slug = "foo")]
+struct ErrorWithSpannedNote {
+    #[note]
+    span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(code = "E0123", slug = "foo")]
+struct ErrorWithSpannedNoteCustom {
+    #[note = "bar"]
+    span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(code = "E0123", slug = "foo")]
+#[note]
+struct ErrorWithNote {
+    val: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(code = "E0123", slug = "foo")]
+#[note = "bar"]
+struct ErrorWithNoteCustom {
+    val: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(code = "E0123", slug = "foo")]
+struct ErrorWithSpannedHelp {
+    #[help]
+    span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(code = "E0123", slug = "foo")]
+struct ErrorWithSpannedHelpCustom {
+    #[help = "bar"]
+    span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(code = "E0123", slug = "foo")]
+#[help]
+struct ErrorWithHelp {
+    val: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(code = "E0123", slug = "foo")]
+#[help = "bar"]
+struct ErrorWithHelpCustom {
+    val: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[help]
+//~^ ERROR `#[help]` must come after `#[error(..)]` or `#[warn(..)]`
+#[error(code = "E0123", slug = "foo")]
+struct ErrorWithHelpWrongOrder {
+    val: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[help = "bar"]
+//~^ ERROR `#[help = ...]` must come after `#[error(..)]` or `#[warn(..)]`
+#[error(code = "E0123", slug = "foo")]
+struct ErrorWithHelpCustomWrongOrder {
+    val: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[note]
+//~^ ERROR `#[note]` must come after `#[error(..)]` or `#[warn(..)]`
+#[error(code = "E0123", slug = "foo")]
+struct ErrorWithNoteWrongOrder {
+    val: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[note = "bar"]
+//~^ ERROR `#[note = ...]` must come after `#[error(..)]` or `#[warn(..)]`
+#[error(code = "E0123", slug = "foo")]
+struct ErrorWithNoteCustomWrongOrder {
+    val: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(code = "E0123", slug = "foo")]
+struct ApplicabilityInBoth {
+    #[suggestion(message = "bar", code = "...", applicability = "maybe-incorrect")]
+    //~^ ERROR applicability cannot be set in both the field and attribute
+    suggestion: (Span, Applicability),
+}
+
+#[derive(SessionDiagnostic)]
+#[error(code = "E0123", slug = "foo")]
+struct InvalidApplicability {
+    #[suggestion(message = "bar", code = "...", applicability = "batman")]
+    //~^ ERROR invalid applicability
+    suggestion: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(code = "E0123", slug = "foo")]
+struct ValidApplicability {
+    #[suggestion(message = "bar", code = "...", applicability = "maybe-incorrect")]
+    suggestion: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(code = "E0123", slug = "foo")]
+struct NoApplicability {
+    #[suggestion(message = "bar", code = "...")]
+    suggestion: Span,
+}
+
+#[derive(SessionSubdiagnostic)]
+#[note(slug = "note")]
+struct Note;
+
+#[derive(SessionDiagnostic)]
+#[error(slug = "subdiagnostic")]
+struct Subdiagnostic {
+    #[subdiagnostic]
+    note: Note,
+}
diff --git a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
new file mode 100644 (file)
index 0000000..b1738b6
--- /dev/null
@@ -0,0 +1,365 @@
+error: `#[derive(SessionDiagnostic)]` can only be used on structs
+  --> $DIR/diagnostic-derive.rs:37:1
+   |
+LL | / #[error(code = "E0123", slug = "foo")]
+LL | |
+LL | | enum SessionDiagnosticOnEnum {
+LL | |     Foo,
+LL | |     Bar,
+LL | | }
+   | |_^
+
+error: `#[error = ...]` is not a valid attribute
+  --> $DIR/diagnostic-derive.rs:46:1
+   |
+LL | #[error = "E0123"]
+   | ^^^^^^^^^^^^^^^^^^
+
+error: `#[nonsense(...)]` is not a valid attribute
+  --> $DIR/diagnostic-derive.rs:51:1
+   |
+LL | #[nonsense(code = "E0123", slug = "foo")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: only `error` and `warning` are valid attributes
+
+error: diagnostic kind not specified
+  --> $DIR/diagnostic-derive.rs:51:1
+   |
+LL | / #[nonsense(code = "E0123", slug = "foo")]
+LL | |
+LL | |
+LL | |
+LL | | struct InvalidStructAttr {}
+   | |___________________________^
+   |
+   = help: use the `#[error(...)]` attribute to create an error
+
+error: `#[error("...")]` is not a valid attribute
+  --> $DIR/diagnostic-derive.rs:58:9
+   |
+LL | #[error("E0123")]
+   |         ^^^^^^^
+
+error: `slug` not specified
+  --> $DIR/diagnostic-derive.rs:58:1
+   |
+LL | / #[error("E0123")]
+LL | |
+LL | |
+LL | | struct InvalidLitNestedAttr {}
+   | |______________________________^
+   |
+   = help: use the `#[error(slug = "...")]` attribute to set this diagnostic's slug
+
+error: `#[error(nonsense)]` is not a valid attribute
+  --> $DIR/diagnostic-derive.rs:64:9
+   |
+LL | #[error(nonsense, code = "E0123", slug = "foo")]
+   |         ^^^^^^^^
+
+error: `#[error(nonsense(...))]` is not a valid attribute
+  --> $DIR/diagnostic-derive.rs:69:9
+   |
+LL | #[error(nonsense("foo"), code = "E0123", slug = "foo")]
+   |         ^^^^^^^^^^^^^^^
+
+error: `#[error(nonsense = ...)]` is not a valid attribute
+  --> $DIR/diagnostic-derive.rs:74:9
+   |
+LL | #[error(nonsense = "...", code = "E0123", slug = "foo")]
+   |         ^^^^^^^^^^^^^^^^
+   |
+   = help: only `slug` and `code` are valid nested attributes
+
+error: `#[error(nonsense = ...)]` is not a valid attribute
+  --> $DIR/diagnostic-derive.rs:79:9
+   |
+LL | #[error(nonsense = 4, code = "E0123", slug = "foo")]
+   |         ^^^^^^^^^^^^
+
+error: `#[suggestion = ...]` is not a valid attribute
+  --> $DIR/diagnostic-derive.rs:86:5
+   |
+LL |     #[suggestion = "bar"]
+   |     ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: only `label`, `note` and `help` are valid field attributes
+
+error: specified multiple times
+  --> $DIR/diagnostic-derive.rs:93:1
+   |
+LL | #[error(code = "E0456", slug = "bar")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: previously specified here
+  --> $DIR/diagnostic-derive.rs:92:1
+   |
+LL | #[error(code = "E0123", slug = "foo")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: specified multiple times
+  --> $DIR/diagnostic-derive.rs:93:16
+   |
+LL | #[error(code = "E0456", slug = "bar")]
+   |                ^^^^^^^
+   |
+note: previously specified here
+  --> $DIR/diagnostic-derive.rs:92:16
+   |
+LL | #[error(code = "E0123", slug = "foo")]
+   |                ^^^^^^^
+
+error: specified multiple times
+  --> $DIR/diagnostic-derive.rs:93:32
+   |
+LL | #[error(code = "E0456", slug = "bar")]
+   |                                ^^^^^
+   |
+note: previously specified here
+  --> $DIR/diagnostic-derive.rs:92:32
+   |
+LL | #[error(code = "E0123", slug = "foo")]
+   |                                ^^^^^
+
+error: specified multiple times
+  --> $DIR/diagnostic-derive.rs:101:1
+   |
+LL | #[warning(code = "E0293", slug = "bar")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: previously specified here
+  --> $DIR/diagnostic-derive.rs:100:1
+   |
+LL | #[error(code = "E0123", slug = "foo")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: specified multiple times
+  --> $DIR/diagnostic-derive.rs:101:18
+   |
+LL | #[warning(code = "E0293", slug = "bar")]
+   |                  ^^^^^^^
+   |
+note: previously specified here
+  --> $DIR/diagnostic-derive.rs:100:16
+   |
+LL | #[error(code = "E0123", slug = "foo")]
+   |                ^^^^^^^
+
+error: specified multiple times
+  --> $DIR/diagnostic-derive.rs:101:34
+   |
+LL | #[warning(code = "E0293", slug = "bar")]
+   |                                  ^^^^^
+   |
+note: previously specified here
+  --> $DIR/diagnostic-derive.rs:100:32
+   |
+LL | #[error(code = "E0123", slug = "foo")]
+   |                                ^^^^^
+
+error: specified multiple times
+  --> $DIR/diagnostic-derive.rs:108:32
+   |
+LL | #[error(code = "E0456", code = "E0457", slug = "bar")]
+   |                                ^^^^^^^
+   |
+note: previously specified here
+  --> $DIR/diagnostic-derive.rs:108:16
+   |
+LL | #[error(code = "E0456", code = "E0457", slug = "bar")]
+   |                ^^^^^^^
+
+error: specified multiple times
+  --> $DIR/diagnostic-derive.rs:113:46
+   |
+LL | #[error(code = "E0456", slug = "foo", slug = "bar")]
+   |                                              ^^^^^
+   |
+note: previously specified here
+  --> $DIR/diagnostic-derive.rs:113:32
+   |
+LL | #[error(code = "E0456", slug = "foo", slug = "bar")]
+   |                                ^^^^^
+
+error: diagnostic kind not specified
+  --> $DIR/diagnostic-derive.rs:118:1
+   |
+LL | struct KindNotProvided {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: use the `#[error(...)]` attribute to create an error
+
+error: `slug` not specified
+  --> $DIR/diagnostic-derive.rs:121:1
+   |
+LL | / #[error(code = "E0456")]
+LL | | struct SlugNotProvided {}
+   | |_________________________^
+   |
+   = help: use the `#[error(slug = "...")]` attribute to set this diagnostic's slug
+
+error: the `#[primary_span]` attribute can only be applied to fields of type `Span`
+  --> $DIR/diagnostic-derive.rs:131:5
+   |
+LL |     #[primary_span]
+   |     ^^^^^^^^^^^^^^^
+
+error: `#[nonsense]` is not a valid attribute
+  --> $DIR/diagnostic-derive.rs:139:5
+   |
+LL |     #[nonsense]
+   |     ^^^^^^^^^^^
+   |
+   = help: only `skip_arg`, `primary_span`, `label`, `note`, `help` and `subdiagnostic` are valid field attributes
+
+error: the `#[label = ...]` attribute can only be applied to fields of type `Span`
+  --> $DIR/diagnostic-derive.rs:156:5
+   |
+LL |     #[label = "bar"]
+   |     ^^^^^^^^^^^^^^^^
+
+error: `name` doesn't refer to a field on this type
+  --> $DIR/diagnostic-derive.rs:164:42
+   |
+LL |     #[suggestion(message = "bar", code = "{name}")]
+   |                                          ^^^^^^^^
+
+error: invalid format string: expected `'}'` but string was terminated
+  --> $DIR/diagnostic-derive.rs:169:16
+   |
+LL | #[derive(SessionDiagnostic)]
+   |           -    ^ expected `'}'` in format string
+   |           |
+   |           because of this opening brace
+   |
+   = note: if you intended to print `{`, you can escape it using `{{`
+   = note: this error originates in the derive macro `SessionDiagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: invalid format string: unmatched `}` found
+  --> $DIR/diagnostic-derive.rs:179:15
+   |
+LL | #[derive(SessionDiagnostic)]
+   |               ^ unmatched `}` in format string
+   |
+   = note: if you intended to print `}`, you can escape it using `}}`
+   = note: this error originates in the derive macro `SessionDiagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: the `#[label = ...]` attribute can only be applied to fields of type `Span`
+  --> $DIR/diagnostic-derive.rs:199:5
+   |
+LL |     #[label = "bar"]
+   |     ^^^^^^^^^^^^^^^^
+
+error: `#[suggestion(nonsense = ...)]` is not a valid attribute
+  --> $DIR/diagnostic-derive.rs:224:18
+   |
+LL |     #[suggestion(nonsense = "bar")]
+   |                  ^^^^^^^^^^^^^^^^
+   |
+   = help: only `message`, `code` and `applicability` are valid field attributes
+
+error: `#[suggestion(msg = ...)]` is not a valid attribute
+  --> $DIR/diagnostic-derive.rs:232:18
+   |
+LL |     #[suggestion(msg = "bar")]
+   |                  ^^^^^^^^^^^
+   |
+   = help: only `message`, `code` and `applicability` are valid field attributes
+
+error: wrong field type for suggestion
+  --> $DIR/diagnostic-derive.rs:254:5
+   |
+LL | /     #[suggestion(message = "bar", code = "This is suggested code")]
+LL | |
+LL | |     suggestion: Applicability,
+   | |_____________________________^
+   |
+   = help: `#[suggestion(...)]` should be applied to fields of type `Span` or `(Span, Applicability)`
+
+error: type of field annotated with `#[suggestion(...)]` contains more than one `Span`
+  --> $DIR/diagnostic-derive.rs:269:5
+   |
+LL | /     #[suggestion(message = "bar", code = "This is suggested code")]
+LL | |
+LL | |     suggestion: (Span, Span, Applicability),
+   | |___________________________________________^
+
+error: type of field annotated with `#[suggestion(...)]` contains more than one Applicability
+  --> $DIR/diagnostic-derive.rs:277:5
+   |
+LL | /     #[suggestion(message = "bar", code = "This is suggested code")]
+LL | |
+LL | |     suggestion: (Applicability, Applicability, Span),
+   | |____________________________________________________^
+
+error: `#[label(...)]` is not a valid attribute
+  --> $DIR/diagnostic-derive.rs:285:5
+   |
+LL |     #[label("bar")]
+   |     ^^^^^^^^^^^^^^^
+   |
+   = help: only `suggestion{,_short,_hidden,_verbose}` are valid field attributes
+
+error: `#[help]` must come after `#[error(..)]` or `#[warn(..)]`
+  --> $DIR/diagnostic-derive.rs:406:1
+   |
+LL | #[help]
+   | ^^^^^^^
+
+error: `#[help = ...]` must come after `#[error(..)]` or `#[warn(..)]`
+  --> $DIR/diagnostic-derive.rs:414:1
+   |
+LL | #[help = "bar"]
+   | ^^^^^^^^^^^^^^^
+
+error: `#[note]` must come after `#[error(..)]` or `#[warn(..)]`
+  --> $DIR/diagnostic-derive.rs:422:1
+   |
+LL | #[note]
+   | ^^^^^^^
+
+error: `#[note = ...]` must come after `#[error(..)]` or `#[warn(..)]`
+  --> $DIR/diagnostic-derive.rs:430:1
+   |
+LL | #[note = "bar"]
+   | ^^^^^^^^^^^^^^^
+
+error: applicability cannot be set in both the field and attribute
+  --> $DIR/diagnostic-derive.rs:440:49
+   |
+LL |     #[suggestion(message = "bar", code = "...", applicability = "maybe-incorrect")]
+   |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: invalid applicability
+  --> $DIR/diagnostic-derive.rs:448:49
+   |
+LL |     #[suggestion(message = "bar", code = "...", applicability = "batman")]
+   |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: cannot find attribute `nonsense` in this scope
+  --> $DIR/diagnostic-derive.rs:51:3
+   |
+LL | #[nonsense(code = "E0123", slug = "foo")]
+   |   ^^^^^^^^
+
+error: cannot find attribute `nonsense` in this scope
+  --> $DIR/diagnostic-derive.rs:139:7
+   |
+LL |     #[nonsense]
+   |       ^^^^^^^^
+
+error[E0599]: no method named `into_diagnostic_arg` found for struct `Hello` in the current scope
+  --> $DIR/diagnostic-derive.rs:329:10
+   |
+LL | struct Hello {}
+   | ------------ method `into_diagnostic_arg` not found for this
+...
+LL | #[derive(SessionDiagnostic)]
+   |          ^^^^^^^^^^^^^^^^^ method not found in `Hello`
+   |
+   = note: this error originates in the derive macro `SessionDiagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 43 previous errors
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs
new file mode 100644 (file)
index 0000000..bb406c3
--- /dev/null
@@ -0,0 +1,501 @@
+// check-fail
+// Tests error conditions for specifying subdiagnostics using #[derive(SessionSubdiagnostic)]
+
+// The proc_macro2 crate handles spans differently when on beta/stable release rather than nightly,
+// changing the output of this test. Since SessionSubdiagnostic is strictly internal to the compiler
+// the test is just ignored on stable and beta:
+// ignore-beta
+// ignore-stable
+
+#![feature(rustc_private)]
+#![crate_type = "lib"]
+
+extern crate rustc_errors;
+extern crate rustc_session;
+extern crate rustc_span;
+extern crate rustc_macros;
+
+use rustc_errors::Applicability;
+use rustc_span::Span;
+use rustc_macros::SessionSubdiagnostic;
+
+#[derive(SessionSubdiagnostic)]
+#[label(slug = "label-a")]
+struct A {
+    #[primary_span]
+    span: Span,
+    var: String,
+}
+
+#[derive(SessionSubdiagnostic)]
+enum B {
+    #[label(slug = "label-b-a")]
+    A {
+        #[primary_span]
+        span: Span,
+        var: String,
+    },
+    #[label(slug = "label-b-b")]
+    B {
+        #[primary_span]
+        span: Span,
+        var: String,
+    }
+}
+
+#[derive(SessionSubdiagnostic)]
+#[label(slug = "label-c")]
+//~^ ERROR label without `#[primary_span]` field
+struct C {
+    var: String,
+}
+
+#[derive(SessionSubdiagnostic)]
+#[label]
+//~^ ERROR `#[label]` is not a valid attribute
+struct D {
+    #[primary_span]
+    span: Span,
+    var: String,
+}
+
+#[derive(SessionSubdiagnostic)]
+#[foo]
+//~^ ERROR `#[foo]` is not a valid attribute
+//~^^ ERROR cannot find attribute `foo` in this scope
+struct E {
+    #[primary_span]
+    span: Span,
+    var: String,
+}
+
+#[derive(SessionSubdiagnostic)]
+#[label = "..."]
+//~^ ERROR `#[label = ...]` is not a valid attribute
+struct F {
+    #[primary_span]
+    span: Span,
+    var: String,
+}
+
+#[derive(SessionSubdiagnostic)]
+#[label(bug = "...")]
+//~^ ERROR `#[label(bug = ...)]` is not a valid attribute
+struct G {
+    #[primary_span]
+    span: Span,
+    var: String,
+}
+
+#[derive(SessionSubdiagnostic)]
+#[label("...")]
+//~^ ERROR `#[label("...")]` is not a valid attribute
+struct H {
+    #[primary_span]
+    span: Span,
+    var: String,
+}
+
+#[derive(SessionSubdiagnostic)]
+#[label(slug = 4)]
+//~^ ERROR `#[label(slug = ...)]` is not a valid attribute
+struct J {
+    #[primary_span]
+    span: Span,
+    var: String,
+}
+
+#[derive(SessionSubdiagnostic)]
+#[label(slug("..."))]
+//~^ ERROR `#[label(slug(...))]` is not a valid attribute
+struct K {
+    #[primary_span]
+    span: Span,
+    var: String,
+}
+
+#[derive(SessionSubdiagnostic)]
+#[label(slug)]
+//~^ ERROR `#[label(slug)]` is not a valid attribute
+struct L {
+    #[primary_span]
+    span: Span,
+    var: String,
+}
+
+#[derive(SessionSubdiagnostic)]
+#[label()]
+//~^ ERROR `slug` must be set in a `#[label(...)]` attribute
+struct M {
+    #[primary_span]
+    span: Span,
+    var: String,
+}
+
+#[derive(SessionSubdiagnostic)]
+#[label(code = "...")]
+//~^ ERROR `code` is not a valid nested attribute of a `label` attribute
+struct N {
+    #[primary_span]
+    span: Span,
+    var: String,
+}
+
+#[derive(SessionSubdiagnostic)]
+#[foo]
+//~^ ERROR cannot find attribute `foo` in this scope
+//~^^ ERROR unsupported type attribute for subdiagnostic enum
+enum O {
+    #[label(slug = "...")]
+    A {
+        #[primary_span]
+        span: Span,
+        var: String,
+    }
+}
+
+#[derive(SessionSubdiagnostic)]
+enum P {
+    #[bar]
+//~^ ERROR `#[bar]` is not a valid attribute
+//~^^ ERROR cannot find attribute `bar` in this scope
+    A {
+        #[primary_span]
+        span: Span,
+        var: String,
+    }
+}
+
+#[derive(SessionSubdiagnostic)]
+enum Q {
+    #[bar = "..."]
+//~^ ERROR `#[bar = ...]` is not a valid attribute
+//~^^ ERROR cannot find attribute `bar` in this scope
+    A {
+        #[primary_span]
+        span: Span,
+        var: String,
+    }
+}
+
+#[derive(SessionSubdiagnostic)]
+enum R {
+    #[bar = 4]
+//~^ ERROR `#[bar = ...]` is not a valid attribute
+//~^^ ERROR cannot find attribute `bar` in this scope
+    A {
+        #[primary_span]
+        span: Span,
+        var: String,
+    }
+}
+
+#[derive(SessionSubdiagnostic)]
+enum S {
+    #[bar("...")]
+//~^ ERROR `#[bar("...")]` is not a valid attribute
+//~^^ ERROR cannot find attribute `bar` in this scope
+    A {
+        #[primary_span]
+        span: Span,
+        var: String,
+    }
+}
+
+#[derive(SessionSubdiagnostic)]
+enum T {
+    #[label(code = "...")]
+//~^ ERROR `code` is not a valid nested attribute of a `label`
+    A {
+        #[primary_span]
+        span: Span,
+        var: String,
+    }
+}
+
+#[derive(SessionSubdiagnostic)]
+enum U {
+    #[label(slug = "label-u")]
+    A {
+        #[primary_span]
+        span: Span,
+        var: String,
+    },
+    B {
+//~^ ERROR subdiagnostic kind not specified
+        #[primary_span]
+        span: Span,
+        var: String,
+    }
+}
+
+#[derive(SessionSubdiagnostic)]
+#[label(slug = "...")]
+//~^ ERROR label without `#[primary_span]` field
+struct V {
+    #[primary_span]
+    //~^ ERROR the `#[primary_span]` attribute can only be applied to fields of type `Span`
+    span: String,
+}
+
+#[derive(SessionSubdiagnostic)]
+#[label(slug = "...")]
+struct W {
+    #[primary_span]
+    span: Span,
+    #[applicability]
+    //~^ ERROR `#[applicability]` is only valid on suggestions
+    applicability: Applicability,
+}
+
+#[derive(SessionSubdiagnostic)]
+#[label(slug = "...")]
+struct X {
+    #[primary_span]
+    span: Span,
+    #[bar]
+    //~^ ERROR `#[bar]` is not a valid attribute
+    //~^^ ERROR cannot find attribute `bar` in this scope
+    bar: String,
+}
+
+#[derive(SessionSubdiagnostic)]
+#[label(slug = "...")]
+struct Y {
+    #[primary_span]
+    span: Span,
+    #[bar = "..."]
+    //~^ ERROR `#[bar = ...]` is not a valid attribute
+    //~^^ ERROR cannot find attribute `bar` in this scope
+    bar: String,
+}
+
+#[derive(SessionSubdiagnostic)]
+#[label(slug = "...")]
+struct Z {
+    #[primary_span]
+    span: Span,
+    #[bar("...")]
+    //~^ ERROR `#[bar(...)]` is not a valid attribute
+    //~^^ ERROR cannot find attribute `bar` in this scope
+    bar: String,
+}
+
+#[derive(SessionSubdiagnostic)]
+#[label(slug = "label-aa")]
+struct AA {
+    #[primary_span]
+    span: Span,
+    #[skip_arg]
+    z: Z
+}
+
+#[derive(SessionSubdiagnostic)]
+union AB {
+//~^ ERROR unexpected unsupported untagged union
+    span: u32,
+    b: u64
+}
+
+#[derive(SessionSubdiagnostic)]
+#[label(slug = "label-ac-1")]
+//~^ NOTE previously specified here
+//~^^ NOTE previously specified here
+#[label(slug = "label-ac-2")]
+//~^ ERROR specified multiple times
+//~^^ ERROR specified multiple times
+struct AC {
+    #[primary_span]
+    span: Span,
+}
+
+#[derive(SessionSubdiagnostic)]
+#[label(slug = "label-ad-1", slug = "label-ad-2")]
+//~^ ERROR specified multiple times
+//~^^ NOTE previously specified here
+struct AD {
+    #[primary_span]
+    span: Span,
+}
+
+#[derive(SessionSubdiagnostic)]
+#[label(slug = "label-ad-1")]
+struct AE {
+    #[primary_span]
+//~^ NOTE previously specified here
+    span_a: Span,
+    #[primary_span]
+//~^ ERROR specified multiple times
+    span_b: Span,
+}
+
+#[derive(SessionSubdiagnostic)]
+struct AF {
+//~^ ERROR subdiagnostic kind not specified
+    #[primary_span]
+    span: Span,
+}
+
+#[derive(SessionSubdiagnostic)]
+#[suggestion(slug = "suggestion-af", code = "...")]
+struct AG {
+    #[primary_span]
+    span: Span,
+    #[applicability]
+    applicability: Applicability,
+    var: String,
+}
+
+#[derive(SessionSubdiagnostic)]
+enum AH {
+    #[suggestion(slug = "suggestion-ag-a", code = "...")]
+    A {
+        #[primary_span]
+        span: Span,
+        #[applicability]
+        applicability: Applicability,
+        var: String,
+    },
+    #[suggestion(slug = "suggestion-ag-b", code = "...")]
+    B {
+        #[primary_span]
+        span: Span,
+        #[applicability]
+        applicability: Applicability,
+        var: String,
+    }
+}
+
+#[derive(SessionSubdiagnostic)]
+#[suggestion(slug = "...", code = "...", code = "...")]
+//~^ ERROR specified multiple times
+//~^^ NOTE previously specified here
+struct AI {
+    #[primary_span]
+    span: Span,
+    #[applicability]
+    applicability: Applicability,
+}
+
+#[derive(SessionSubdiagnostic)]
+#[suggestion(slug = "...", code = "...")]
+struct AJ {
+    #[primary_span]
+    span: Span,
+    #[applicability]
+//~^ NOTE previously specified here
+    applicability_a: Applicability,
+    #[applicability]
+//~^ ERROR specified multiple times
+    applicability_b: Applicability,
+}
+
+#[derive(SessionSubdiagnostic)]
+#[suggestion(slug = "...", code = "...")]
+//~^ ERROR suggestion without `applicability`
+struct AK {
+    #[primary_span]
+    span: Span,
+    #[applicability]
+//~^ ERROR the `#[applicability]` attribute can only be applied to fields of type `Applicability`
+    applicability: Span,
+}
+
+#[derive(SessionSubdiagnostic)]
+#[suggestion(slug = "...", code = "...")]
+//~^ ERROR suggestion without `applicability`
+struct AL {
+    #[primary_span]
+    span: Span,
+}
+
+#[derive(SessionSubdiagnostic)]
+#[suggestion(slug = "...")]
+//~^ ERROR suggestion without `code = "..."`
+struct AM {
+    #[primary_span]
+    span: Span,
+    #[applicability]
+    applicability: Applicability,
+}
+
+#[derive(SessionSubdiagnostic)]
+#[suggestion(slug = "...", code ="...", applicability = "foo")]
+//~^ ERROR invalid applicability
+struct AN {
+    #[primary_span]
+    span: Span,
+}
+
+#[derive(SessionSubdiagnostic)]
+#[help(slug = "label-am")]
+struct AO {
+    var: String
+}
+
+#[derive(SessionSubdiagnostic)]
+#[note(slug = "label-an")]
+struct AP;
+
+#[derive(SessionSubdiagnostic)]
+#[suggestion(slug = "...", code = "...")]
+//~^ ERROR suggestion without `applicability`
+//~^^ ERROR suggestion without `#[primary_span]` field
+struct AQ {
+    var: String,
+}
+
+#[derive(SessionSubdiagnostic)]
+#[suggestion(slug = "...", code ="...", applicability = "machine-applicable")]
+struct AR {
+    #[primary_span]
+    span: Span,
+}
+
+#[derive(SessionSubdiagnostic)]
+#[label]
+//~^ ERROR unsupported type attribute for subdiagnostic enum
+enum AS {
+    #[label(slug = "...")]
+    A {
+        #[primary_span]
+        span: Span,
+        var: String,
+    }
+}
+
+#[derive(SessionSubdiagnostic)]
+#[suggestion(slug = "...", code ="{var}", applicability = "machine-applicable")]
+struct AT {
+    #[primary_span]
+    span: Span,
+    var: String,
+}
+
+#[derive(SessionSubdiagnostic)]
+#[suggestion(slug = "...", code ="{var}", applicability = "machine-applicable")]
+//~^ ERROR `var` doesn't refer to a field on this type
+struct AU {
+    #[primary_span]
+    span: Span,
+}
+
+#[derive(SessionSubdiagnostic)]
+enum AV {
+    #[suggestion(slug = "...", code ="{var}", applicability = "machine-applicable")]
+    A {
+        #[primary_span]
+        span: Span,
+        var: String,
+    }
+}
+
+#[derive(SessionSubdiagnostic)]
+enum AW {
+    #[suggestion(slug = "...", code ="{var}", applicability = "machine-applicable")]
+//~^ ERROR `var` doesn't refer to a field on this type
+    A {
+        #[primary_span]
+        span: Span,
+    }
+}
diff --git a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr
new file mode 100644 (file)
index 0000000..4984cc4
--- /dev/null
@@ -0,0 +1,389 @@
+error: label without `#[primary_span]` field
+  --> $DIR/subdiagnostic-derive.rs:47:1
+   |
+LL | / #[label(slug = "label-c")]
+LL | |
+LL | | struct C {
+LL | |     var: String,
+LL | | }
+   | |_^
+
+error: `#[label]` is not a valid attribute
+  --> $DIR/subdiagnostic-derive.rs:54:1
+   |
+LL | #[label]
+   | ^^^^^^^^
+
+error: `#[foo]` is not a valid attribute
+  --> $DIR/subdiagnostic-derive.rs:63:1
+   |
+LL | #[foo]
+   | ^^^^^^
+
+error: `#[label = ...]` is not a valid attribute
+  --> $DIR/subdiagnostic-derive.rs:73:1
+   |
+LL | #[label = "..."]
+   | ^^^^^^^^^^^^^^^^
+
+error: `#[label(bug = ...)]` is not a valid attribute
+  --> $DIR/subdiagnostic-derive.rs:82:9
+   |
+LL | #[label(bug = "...")]
+   |         ^^^^^^^^^^^
+   |
+   = help: only `code`, `slug` and `applicability` are valid nested attributes
+
+error: `#[label("...")]` is not a valid attribute
+  --> $DIR/subdiagnostic-derive.rs:91:9
+   |
+LL | #[label("...")]
+   |         ^^^^^
+
+error: `#[label(slug = ...)]` is not a valid attribute
+  --> $DIR/subdiagnostic-derive.rs:100:9
+   |
+LL | #[label(slug = 4)]
+   |         ^^^^^^^^
+
+error: `#[label(slug(...))]` is not a valid attribute
+  --> $DIR/subdiagnostic-derive.rs:109:9
+   |
+LL | #[label(slug("..."))]
+   |         ^^^^^^^^^^^
+
+error: `#[label(slug)]` is not a valid attribute
+  --> $DIR/subdiagnostic-derive.rs:118:9
+   |
+LL | #[label(slug)]
+   |         ^^^^
+
+error: `slug` must be set in a `#[label(...)]` attribute
+  --> $DIR/subdiagnostic-derive.rs:127:1
+   |
+LL | #[label()]
+   | ^^^^^^^^^^
+
+error: `code` is not a valid nested attribute of a `label` attribute
+  --> $DIR/subdiagnostic-derive.rs:136:1
+   |
+LL | #[label(code = "...")]
+   | ^^^^^^^^^^^^^^^^^^^^^^
+
+error: unsupported type attribute for subdiagnostic enum
+  --> $DIR/subdiagnostic-derive.rs:145:1
+   |
+LL | #[foo]
+   | ^^^^^^
+
+error: `#[bar]` is not a valid attribute
+  --> $DIR/subdiagnostic-derive.rs:159:5
+   |
+LL |     #[bar]
+   |     ^^^^^^
+
+error: `#[bar = ...]` is not a valid attribute
+  --> $DIR/subdiagnostic-derive.rs:171:5
+   |
+LL |     #[bar = "..."]
+   |     ^^^^^^^^^^^^^^
+
+error: `#[bar = ...]` is not a valid attribute
+  --> $DIR/subdiagnostic-derive.rs:183:5
+   |
+LL |     #[bar = 4]
+   |     ^^^^^^^^^^
+
+error: `#[bar("...")]` is not a valid attribute
+  --> $DIR/subdiagnostic-derive.rs:195:11
+   |
+LL |     #[bar("...")]
+   |           ^^^^^
+
+error: `code` is not a valid nested attribute of a `label` attribute
+  --> $DIR/subdiagnostic-derive.rs:207:5
+   |
+LL |     #[label(code = "...")]
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+
+error: subdiagnostic kind not specified
+  --> $DIR/subdiagnostic-derive.rs:224:5
+   |
+LL |     B {
+   |     ^
+
+error: the `#[primary_span]` attribute can only be applied to fields of type `Span`
+  --> $DIR/subdiagnostic-derive.rs:236:5
+   |
+LL |     #[primary_span]
+   |     ^^^^^^^^^^^^^^^
+
+error: label without `#[primary_span]` field
+  --> $DIR/subdiagnostic-derive.rs:233:1
+   |
+LL | / #[label(slug = "...")]
+LL | |
+LL | | struct V {
+LL | |     #[primary_span]
+LL | |
+LL | |     span: String,
+LL | | }
+   | |_^
+
+error: `#[applicability]` is only valid on suggestions
+  --> $DIR/subdiagnostic-derive.rs:246:5
+   |
+LL |     #[applicability]
+   |     ^^^^^^^^^^^^^^^^
+
+error: `#[bar]` is not a valid attribute
+  --> $DIR/subdiagnostic-derive.rs:256:5
+   |
+LL |     #[bar]
+   |     ^^^^^^
+   |
+   = help: only `primary_span`, `applicability` and `skip_arg` are valid field attributes
+
+error: `#[bar = ...]` is not a valid attribute
+  --> $DIR/subdiagnostic-derive.rs:267:5
+   |
+LL |     #[bar = "..."]
+   |     ^^^^^^^^^^^^^^
+
+error: `#[bar(...)]` is not a valid attribute
+  --> $DIR/subdiagnostic-derive.rs:278:5
+   |
+LL |     #[bar("...")]
+   |     ^^^^^^^^^^^^^
+
+error: unexpected unsupported untagged union
+  --> $DIR/subdiagnostic-derive.rs:294:1
+   |
+LL | / union AB {
+LL | |
+LL | |     span: u32,
+LL | |     b: u64
+LL | | }
+   | |_^
+
+error: specified multiple times
+  --> $DIR/subdiagnostic-derive.rs:304:9
+   |
+LL | #[label(slug = "label-ac-2")]
+   |         ^^^^^^^^^^^^^^^^^^^
+   |
+note: previously specified here
+  --> $DIR/subdiagnostic-derive.rs:301:9
+   |
+LL | #[label(slug = "label-ac-1")]
+   |         ^^^^^^^^^^^^^^^^^^^
+
+error: specified multiple times
+  --> $DIR/subdiagnostic-derive.rs:304:1
+   |
+LL | #[label(slug = "label-ac-2")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: previously specified here
+  --> $DIR/subdiagnostic-derive.rs:301:1
+   |
+LL | #[label(slug = "label-ac-1")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: specified multiple times
+  --> $DIR/subdiagnostic-derive.rs:313:30
+   |
+LL | #[label(slug = "label-ad-1", slug = "label-ad-2")]
+   |                              ^^^^^^^^^^^^^^^^^^^
+   |
+note: previously specified here
+  --> $DIR/subdiagnostic-derive.rs:313:9
+   |
+LL | #[label(slug = "label-ad-1", slug = "label-ad-2")]
+   |         ^^^^^^^^^^^^^^^^^^^
+
+error: specified multiple times
+  --> $DIR/subdiagnostic-derive.rs:327:5
+   |
+LL |     #[primary_span]
+   |     ^^^^^^^^^^^^^^^
+   |
+note: previously specified here
+  --> $DIR/subdiagnostic-derive.rs:324:5
+   |
+LL |     #[primary_span]
+   |     ^^^^^^^^^^^^^^^
+
+error: subdiagnostic kind not specified
+  --> $DIR/subdiagnostic-derive.rs:333:8
+   |
+LL | struct AF {
+   |        ^^
+
+error: specified multiple times
+  --> $DIR/subdiagnostic-derive.rs:370:42
+   |
+LL | #[suggestion(slug = "...", code = "...", code = "...")]
+   |                                          ^^^^^^^^^^^^
+   |
+note: previously specified here
+  --> $DIR/subdiagnostic-derive.rs:370:28
+   |
+LL | #[suggestion(slug = "...", code = "...", code = "...")]
+   |                            ^^^^^^^^^^^^
+
+error: specified multiple times
+  --> $DIR/subdiagnostic-derive.rs:388:5
+   |
+LL |     #[applicability]
+   |     ^^^^^^^^^^^^^^^^
+   |
+note: previously specified here
+  --> $DIR/subdiagnostic-derive.rs:385:5
+   |
+LL |     #[applicability]
+   |     ^^^^^^^^^^^^^^^^
+
+error: the `#[applicability]` attribute can only be applied to fields of type `Applicability`
+  --> $DIR/subdiagnostic-derive.rs:399:5
+   |
+LL |     #[applicability]
+   |     ^^^^^^^^^^^^^^^^
+
+error: suggestion without `applicability`
+  --> $DIR/subdiagnostic-derive.rs:394:1
+   |
+LL | / #[suggestion(slug = "...", code = "...")]
+LL | |
+LL | | struct AK {
+LL | |     #[primary_span]
+...  |
+LL | |     applicability: Span,
+LL | | }
+   | |_^
+
+error: suggestion without `applicability`
+  --> $DIR/subdiagnostic-derive.rs:405:1
+   |
+LL | / #[suggestion(slug = "...", code = "...")]
+LL | |
+LL | | struct AL {
+LL | |     #[primary_span]
+LL | |     span: Span,
+LL | | }
+   | |_^
+
+error: suggestion without `code = "..."`
+  --> $DIR/subdiagnostic-derive.rs:413:1
+   |
+LL | / #[suggestion(slug = "...")]
+LL | |
+LL | | struct AM {
+LL | |     #[primary_span]
+...  |
+LL | |     applicability: Applicability,
+LL | | }
+   | |_^
+
+error: invalid applicability
+  --> $DIR/subdiagnostic-derive.rs:423:41
+   |
+LL | #[suggestion(slug = "...", code ="...", applicability = "foo")]
+   |                                         ^^^^^^^^^^^^^^^^^^^^^
+
+error: suggestion without `applicability`
+  --> $DIR/subdiagnostic-derive.rs:441:1
+   |
+LL | / #[suggestion(slug = "...", code = "...")]
+LL | |
+LL | |
+LL | | struct AQ {
+LL | |     var: String,
+LL | | }
+   | |_^
+
+error: suggestion without `#[primary_span]` field
+  --> $DIR/subdiagnostic-derive.rs:441:1
+   |
+LL | / #[suggestion(slug = "...", code = "...")]
+LL | |
+LL | |
+LL | | struct AQ {
+LL | |     var: String,
+LL | | }
+   | |_^
+
+error: unsupported type attribute for subdiagnostic enum
+  --> $DIR/subdiagnostic-derive.rs:456:1
+   |
+LL | #[label]
+   | ^^^^^^^^
+
+error: `var` doesn't refer to a field on this type
+  --> $DIR/subdiagnostic-derive.rs:476:34
+   |
+LL | #[suggestion(slug = "...", code ="{var}", applicability = "machine-applicable")]
+   |                                  ^^^^^^^
+
+error: `var` doesn't refer to a field on this type
+  --> $DIR/subdiagnostic-derive.rs:495:38
+   |
+LL |     #[suggestion(slug = "...", code ="{var}", applicability = "machine-applicable")]
+   |                                      ^^^^^^^
+
+error: cannot find attribute `foo` in this scope
+  --> $DIR/subdiagnostic-derive.rs:63:3
+   |
+LL | #[foo]
+   |   ^^^
+
+error: cannot find attribute `foo` in this scope
+  --> $DIR/subdiagnostic-derive.rs:145:3
+   |
+LL | #[foo]
+   |   ^^^
+
+error: cannot find attribute `bar` in this scope
+  --> $DIR/subdiagnostic-derive.rs:159:7
+   |
+LL |     #[bar]
+   |       ^^^
+
+error: cannot find attribute `bar` in this scope
+  --> $DIR/subdiagnostic-derive.rs:171:7
+   |
+LL |     #[bar = "..."]
+   |       ^^^
+
+error: cannot find attribute `bar` in this scope
+  --> $DIR/subdiagnostic-derive.rs:183:7
+   |
+LL |     #[bar = 4]
+   |       ^^^
+
+error: cannot find attribute `bar` in this scope
+  --> $DIR/subdiagnostic-derive.rs:195:7
+   |
+LL |     #[bar("...")]
+   |       ^^^
+
+error: cannot find attribute `bar` in this scope
+  --> $DIR/subdiagnostic-derive.rs:256:7
+   |
+LL |     #[bar]
+   |       ^^^
+
+error: cannot find attribute `bar` in this scope
+  --> $DIR/subdiagnostic-derive.rs:267:7
+   |
+LL |     #[bar = "..."]
+   |       ^^^
+
+error: cannot find attribute `bar` in this scope
+  --> $DIR/subdiagnostic-derive.rs:278:7
+   |
+LL |     #[bar("...")]
+   |       ^^^
+
+error: aborting due to 51 previous errors
+
diff --git a/src/test/ui/argument-suggestions/issue-96638.rs b/src/test/ui/argument-suggestions/issue-96638.rs
new file mode 100644 (file)
index 0000000..9c6e81a
--- /dev/null
@@ -0,0 +1,9 @@
+fn f(_: usize, _: &usize, _: usize) {}
+
+fn arg<T>() -> T { todo!() }
+
+fn main() {
+    let x = arg(); // `x` must be inferred
+    // The reference on `&x` is important to reproduce the ICE
+    f(&x, ""); //~ ERROR this function takes 3 arguments but 2 arguments were supplied
+}
diff --git a/src/test/ui/argument-suggestions/issue-96638.stderr b/src/test/ui/argument-suggestions/issue-96638.stderr
new file mode 100644 (file)
index 0000000..35190e2
--- /dev/null
@@ -0,0 +1,19 @@
+error[E0061]: this function takes 3 arguments but 2 arguments were supplied
+  --> $DIR/issue-96638.rs:8:5
+   |
+LL |     f(&x, "");
+   |     ^ -- an argument of type `usize` is missing
+   |
+note: function defined here
+  --> $DIR/issue-96638.rs:1:4
+   |
+LL | fn f(_: usize, _: &usize, _: usize) {}
+   |    ^ --------  ---------  --------
+help: provide the argument
+   |
+LL |     f({usize}, &x, {usize});
+   |     ~~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0061`.
index eba1a8e2278b7d20b11c95c26f2f57c896395891..724bdcd920ab46c12f71adfdbfa347b53fd76939 100644 (file)
@@ -1,22 +1,22 @@
 error[E0277]: the trait bound `Header<'_>: Copy` is not satisfied
-  --> $DIR/repeat_empty_ok.rs:8:19
+  --> $DIR/repeat_empty_ok.rs:8:20
    |
 LL |     let headers = [Header{value: &[]}; 128];
-   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Header<'_>`
+   |                    ^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Header<'_>`
    |
-   = note: the `Copy` trait is required because the repeated element will be copied
+   = note: the `Copy` trait is required because this value will be copied for each element of the array
 help: consider annotating `Header<'_>` with `#[derive(Copy)]`
    |
 LL | #[derive(Copy)]
    |
 
 error[E0277]: the trait bound `Header<'_>: Copy` is not satisfied
-  --> $DIR/repeat_empty_ok.rs:13:19
+  --> $DIR/repeat_empty_ok.rs:13:20
    |
 LL |     let headers = [Header{value: &[0]}; 128];
-   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Header<'_>`
+   |                    ^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Header<'_>`
    |
-   = note: the `Copy` trait is required because the repeated element will be copied
+   = note: the `Copy` trait is required because this value will be copied for each element of the array
 help: consider annotating `Header<'_>` with `#[derive(Copy)]`
    |
 LL | #[derive(Copy)]
index ef0443034ec43117eaa604d484381e19d61bad08..1de1ddbe3a4d0f3813197cd9187dca471aeb4b16 100644 (file)
@@ -24,7 +24,6 @@ fn bar() -> impl Bar {
 
 fn baz() -> impl Bar<Item = i32> {
     //~^ ERROR type mismatch resolving `<impl Bar as Foo>::Item == i32`
-    //~| ERROR type mismatch resolving `<impl Bar as Foo>::Item == i32`
     bar()
 }
 
index b7c49570ca40c737ca316b979457bb7423b35444..bd8c8a4414c4db27144ce67e722e79a54b55b0ee 100644 (file)
@@ -16,29 +16,6 @@ help: consider constraining the associated type `<impl Bar as Foo>::Item` to `i3
 LL | fn bar() -> impl Bar<Item = i32> {
    |                     ++++++++++++
 
-error[E0271]: type mismatch resolving `<impl Bar as Foo>::Item == i32`
-  --> $DIR/impl-trait-return-missing-constraint.rs:25:34
-   |
-LL |   fn bar() -> impl Bar {
-   |               -------- the expected opaque type
-...
-LL |   fn baz() -> impl Bar<Item = i32> {
-   |  __________________________________^
-LL | |
-LL | |
-LL | |     bar()
-LL | | }
-   | |_^ expected associated type, found `i32`
-   |
-   = note: expected associated type `<impl Bar as Foo>::Item`
-                         found type `i32`
-   = help: consider constraining the associated type `<impl Bar as Foo>::Item` to `i32` or calling a method that returns `<impl Bar as Foo>::Item`
-   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
-help: consider constraining the associated type `<impl Bar as Foo>::Item` to `i32`
-   |
-LL | fn bar() -> impl Bar<Item = i32> {
-   |                     ++++++++++++
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0271`.
diff --git a/src/test/ui/associated-types/issue-19081.rs b/src/test/ui/associated-types/issue-19081.rs
new file mode 100644 (file)
index 0000000..fbfe4c6
--- /dev/null
@@ -0,0 +1,14 @@
+// check-pass
+pub trait Hasher {
+    type State;
+
+    fn hash<T: Hash<
+        <Self as Hasher>::State
+    >>(&self, value: &T) -> u64;
+}
+
+pub trait Hash<S> {
+    fn hash(&self, state: &mut S);
+}
+
+fn main() {}
diff --git a/src/test/ui/associated-types/issue-25339.rs b/src/test/ui/associated-types/issue-25339.rs
new file mode 100644 (file)
index 0000000..6f8ec70
--- /dev/null
@@ -0,0 +1,31 @@
+// run-pass
+#![allow(dead_code)]
+#![allow(unused_variables)]
+#![feature(associated_type_defaults)]
+
+use std::marker::PhantomData;
+
+pub trait Routing<I> {
+    type Output;
+    fn resolve(&self, input: I);
+}
+
+pub trait ToRouting {
+    type Input;
+    type Routing : ?Sized = dyn Routing<Self::Input, Output=()>;
+    fn to_routing(self) -> Self::Routing;
+}
+
+pub struct Mount<I, R: Routing<I>> {
+    action: R,
+    _marker: PhantomData<I>
+}
+
+impl<I, R: Routing<I>> Mount<I, R> {
+    pub fn create<T: ToRouting<Routing=R>>(mount: &str, input: T) {
+        input.to_routing();
+    }
+}
+
+fn main() {
+}
diff --git a/src/test/ui/associated-types/issue-55846.rs b/src/test/ui/associated-types/issue-55846.rs
new file mode 100644 (file)
index 0000000..bd76675
--- /dev/null
@@ -0,0 +1,39 @@
+// run-pass
+
+// Regression test for #55846, which once caused an ICE.
+
+use std::marker::PhantomData;
+
+struct Foo;
+
+struct Bar<A> {
+    a: PhantomData<A>,
+}
+
+impl Fooifier for Foo {
+    type Assoc = Foo;
+}
+
+trait Fooifier {
+    type Assoc;
+}
+
+trait Barifier<H> {
+    fn barify();
+}
+
+impl<H> Barifier<H> for Bar<H> {
+    fn barify() {
+        println!("All correct!");
+    }
+}
+
+impl Bar<<Foo as Fooifier>::Assoc> {
+    fn this_shouldnt_crash() {
+        <Self as Barifier<<Foo as Fooifier>::Assoc>>::barify();
+    }
+}
+
+fn main() {
+    Bar::<Foo>::this_shouldnt_crash();
+}
index d22413beecbcf4e6516262a71a320ec7322d7129..2114fb59ba3a629048cea13bead38b92a544a017 100644 (file)
@@ -7,7 +7,7 @@ LL |     S::f();
    = note: consult the function's documentation for information on how to avoid undefined behavior
 
 error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
-  --> $DIR/async-unsafe-fn-call-in-safe.rs:15:5
+  --> $DIR/async-unsafe-fn-call-in-safe.rs:17:5
    |
 LL |     f();
    |     ^^^ call to unsafe function
@@ -15,7 +15,7 @@ LL |     f();
    = note: consult the function's documentation for information on how to avoid undefined behavior
 
 error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
-  --> $DIR/async-unsafe-fn-call-in-safe.rs:19:5
+  --> $DIR/async-unsafe-fn-call-in-safe.rs:23:5
    |
 LL |     S::f();
    |     ^^^^^^ call to unsafe function
@@ -23,7 +23,7 @@ LL |     S::f();
    = note: consult the function's documentation for information on how to avoid undefined behavior
 
 error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
-  --> $DIR/async-unsafe-fn-call-in-safe.rs:20:5
+  --> $DIR/async-unsafe-fn-call-in-safe.rs:24:5
    |
 LL |     f();
    |     ^^^ call to unsafe function
index fc37822cb7b6c018f3dd59e5eb0ee91cce2cec4d..c941dc27aa307dcf2f9d4b9c1e31fd483bf83d2f 100644 (file)
@@ -11,8 +11,12 @@ impl S {
 async unsafe fn f() {}
 
 async fn g() {
-    S::f(); //~ ERROR call to unsafe function is unsafe
-    f(); //~ ERROR call to unsafe function is unsafe
+    S::f();
+    //[mir]~^ ERROR call to unsafe function is unsafe
+    //[thir]~^^ ERROR call to unsafe function `S::f` is unsafe
+    f();
+    //[mir]~^ ERROR call to unsafe function is unsafe
+    //[thir]~^^ ERROR call to unsafe function `f` is unsafe
 }
 
 fn main() {
index 21ba45d7f1e15fbebaa8d44b89c58f5c5dbdc684..68d97d3fd7d5fd178bd33564686378920e0f821d 100644 (file)
@@ -1,4 +1,4 @@
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+error[E0133]: call to unsafe function `S::f` is unsafe and requires unsafe function or block
   --> $DIR/async-unsafe-fn-call-in-safe.rs:14:5
    |
 LL |     S::f();
@@ -6,8 +6,8 @@ LL |     S::f();
    |
    = note: consult the function's documentation for information on how to avoid undefined behavior
 
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
-  --> $DIR/async-unsafe-fn-call-in-safe.rs:15:5
+error[E0133]: call to unsafe function `f` is unsafe and requires unsafe function or block
+  --> $DIR/async-unsafe-fn-call-in-safe.rs:17:5
    |
 LL |     f();
    |     ^^^ call to unsafe function
index ad0a359224147b949a660602a24b807d6c3b6e17..5bbc20359c64a09f3c1fd762dbc50a0369bc077d 100644 (file)
@@ -14,10 +14,10 @@ note: captured value is not `Send` because `&` references cannot be sent unless
 LL |                     let x = x;
    |                             ^ has type `&T` which is not `Send`, because `T` is not `Sync`
    = note: required for the cast to the object type `dyn Future<Output = ()> + Send`
-help: consider further restricting type parameter `T`
+help: consider further restricting this bound
    |
-LL |         where 'me:'async_trait, T: std::marker::Sync {
-   |                               ++++++++++++++++++++++
+LL |     fn bar<'me, 'async_trait, T: Send + std::marker::Sync>(x: &'me T)
+   |                                       +++++++++++++++++++
 
 error: aborting due to previous error
 
index ae13b90c3cfc0bd33f7cd806337cb38e48eaf16f..a51dc88a4eded368247b823ca0be53a5537ee326 100644 (file)
@@ -7,7 +7,7 @@ LL | pub async const fn x() {}
    |     |     expected one of `extern`, `fn`, or `unsafe`
    |     help: `const` must come before `async`: `const async`
    |
-   = note: keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`
+   = note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`
 
 error: aborting due to previous error
 
index 0c362052501ed1ec8f61607876779a8bc03a8d31..f23d17d6bfa5795e8ad5b5afc4a2846bf2be875e 100644 (file)
@@ -12,7 +12,7 @@ LL |     unsafe async fn g() {}
 LL | }
    | - the item list ends here
    |
-   = note: keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`
+   = note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`
 
 error: expected one of `extern` or `fn`, found keyword `async`
   --> $DIR/no-unsafe-async.rs:11:8
@@ -23,7 +23,7 @@ LL | unsafe async fn f() {}
    | |      expected one of `extern` or `fn`
    | help: `async` must come before `unsafe`: `async unsafe`
    |
-   = note: keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`
+   = note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/binop/issue-3820.rs b/src/test/ui/binop/issue-3820.rs
new file mode 100644 (file)
index 0000000..b987a90
--- /dev/null
@@ -0,0 +1,15 @@
+struct Thing {
+    x: isize
+}
+
+impl Thing {
+    fn mul(&self, c: &isize) -> Thing {
+        Thing {x: self.x * *c}
+    }
+}
+
+fn main() {
+    let u = Thing {x: 2};
+    let _v = u.mul(&3); // This is ok
+    let w = u * 3; //~ ERROR cannot multiply `Thing` by `{integer}`
+}
diff --git a/src/test/ui/binop/issue-3820.stderr b/src/test/ui/binop/issue-3820.stderr
new file mode 100644 (file)
index 0000000..d5c24e1
--- /dev/null
@@ -0,0 +1,28 @@
+error[E0369]: cannot multiply `Thing` by `{integer}`
+  --> $DIR/issue-3820.rs:14:15
+   |
+LL |     let w = u * 3;
+   |             - ^ - {integer}
+   |             |
+   |             Thing
+   |
+note: an implementation of `Mul<_>` might be missing for `Thing`
+  --> $DIR/issue-3820.rs:1:1
+   |
+LL | struct Thing {
+   | ^^^^^^^^^^^^ must implement `Mul<_>`
+note: the following trait must be implemented
+  --> $SRC_DIR/core/src/ops/arith.rs:LL:COL
+   |
+LL | / pub trait Mul<Rhs = Self> {
+LL | |     /// The resulting type after applying the `*` operator.
+LL | |     #[stable(feature = "rust1", since = "1.0.0")]
+LL | |     type Output;
+...  |
+LL | |     fn mul(self, rhs: Rhs) -> Self::Output;
+LL | | }
+   | |_^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0369`.
diff --git a/src/test/ui/binop/issue-93927.rs b/src/test/ui/binop/issue-93927.rs
new file mode 100644 (file)
index 0000000..de27c97
--- /dev/null
@@ -0,0 +1,20 @@
+// Regression test for #93927: suggested trait bound for T should be Eq, not PartialEq
+struct MyType<T>(T);
+
+impl<T> PartialEq for MyType<T>
+where
+    T: Eq,
+{
+    fn eq(&self, other: &Self) -> bool {
+        true
+    }
+}
+
+fn cond<T: PartialEq>(val: MyType<T>) -> bool {
+    val == val
+    //~^ ERROR binary operation `==` cannot be applied to type `MyType<T>`
+}
+
+fn main() {
+    cond(MyType(0));
+}
diff --git a/src/test/ui/binop/issue-93927.stderr b/src/test/ui/binop/issue-93927.stderr
new file mode 100644 (file)
index 0000000..75558b5
--- /dev/null
@@ -0,0 +1,16 @@
+error[E0369]: binary operation `==` cannot be applied to type `MyType<T>`
+  --> $DIR/issue-93927.rs:14:9
+   |
+LL |     val == val
+   |     --- ^^ --- MyType<T>
+   |     |
+   |     MyType<T>
+   |
+help: consider further restricting this bound
+   |
+LL | fn cond<T: PartialEq + std::cmp::Eq>(val: MyType<T>) -> bool {
+   |                      ++++++++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0369`.
index 2dac4a22ae7136983347e6a7efe0e4fa44805900..b1e59e9d5de362a70b3ef16d636045279732f5f2 100644 (file)
@@ -2,9 +2,12 @@ error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/builtin-superkinds-self-type.rs:10:16
    |
 LL | impl <T: Sync> Foo for T { }
-   |       --       ^^^ ...so that the type `T` will meet its required lifetime bounds
-   |       |
-   |       help: consider adding an explicit lifetime bound...: `T: 'static +`
+   |                ^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | impl <T: Sync + 'static> Foo for T { }
+   |               +++++++++
 
 error: aborting due to previous error
 
index a60100ddaeaeb1b40e282202cbc8b03e212a0b26..8c516e8900c27b27ed4285899b29c87caaea8cbb 100644 (file)
@@ -1,4 +1,4 @@
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+error[E0133]: call to unsafe function `Pin::<P>::new_unchecked` is unsafe and requires unsafe function or block
   --> $DIR/coerce-unsafe-closure-to-unsafe-fn-ptr.rs:5:31
    |
 LL |     let _: unsafe fn() = || { ::std::pin::Pin::new_unchecked(&0_u8); };
diff --git a/src/test/ui/codegen/issue-16602-1.rs b/src/test/ui/codegen/issue-16602-1.rs
new file mode 100644 (file)
index 0000000..dd64ee7
--- /dev/null
@@ -0,0 +1,6 @@
+// run-pass
+fn main() {
+    let mut t = [1; 2];
+    t = [t[1] * 2, t[0] * 2];
+    assert_eq!(&t[..], &[2, 2]);
+}
diff --git a/src/test/ui/codegen/issue-16602-2.rs b/src/test/ui/codegen/issue-16602-2.rs
new file mode 100644 (file)
index 0000000..6364630
--- /dev/null
@@ -0,0 +1,12 @@
+// run-pass
+struct A {
+    pub x: u32,
+    pub y: u32,
+}
+
+fn main() {
+    let mut a = A { x: 1, y: 1 };
+    a = A { x: a.y * 2, y: a.x * 2 };
+    assert_eq!(a.x, 2);
+    assert_eq!(a.y, 2);
+}
diff --git a/src/test/ui/codegen/issue-16602-3.rs b/src/test/ui/codegen/issue-16602-3.rs
new file mode 100644 (file)
index 0000000..dbfeef0
--- /dev/null
@@ -0,0 +1,27 @@
+// run-pass
+#![allow(unused_variables)]
+#![allow(unused_assignments)]
+#[derive(Debug)]
+enum Foo {
+    Bar(u32, u32),
+    Baz(&'static u32, &'static u32)
+}
+
+static NUM: u32 = 100;
+
+fn main () {
+    let mut b = Foo::Baz(&NUM, &NUM);
+    b = Foo::Bar(f(&b), g(&b));
+}
+
+static FNUM: u32 = 1;
+
+fn f (b: &Foo) -> u32 {
+    FNUM
+}
+
+static GNUM: u32 = 2;
+
+fn g (b: &Foo) -> u32 {
+    GNUM
+}
diff --git a/src/test/ui/coercion/coerce-issue-49593-box-never-windows.nofallback.stderr b/src/test/ui/coercion/coerce-issue-49593-box-never-windows.nofallback.stderr
new file mode 100644 (file)
index 0000000..ab9cc70
--- /dev/null
@@ -0,0 +1,39 @@
+error[E0277]: the trait bound `(): std::error::Error` is not satisfied
+  --> $DIR/coerce-issue-49593-box-never-windows.rs:18:53
+   |
+LL |     /* *mut $0 is coerced to Box<dyn Error> here */ Box::<_ /* ! */>::new(x)
+   |                                                     ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()`
+   |
+   = help: the following other types implement trait `std::error::Error`:
+             !
+             &'a T
+             AccessError
+             AddrParseError
+             Arc<T>
+             BorrowError
+             BorrowMutError
+             Box<T>
+           and 45 others
+   = note: required for the cast to the object type `dyn std::error::Error`
+
+error[E0277]: the trait bound `(): std::error::Error` is not satisfied
+  --> $DIR/coerce-issue-49593-box-never-windows.rs:23:49
+   |
+LL |     /* *mut $0 is coerced to *mut Error here */ raw_ptr_box::<_ /* ! */>(x)
+   |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()`
+   |
+   = help: the following other types implement trait `std::error::Error`:
+             !
+             &'a T
+             AccessError
+             AddrParseError
+             Arc<T>
+             BorrowError
+             BorrowMutError
+             Box<T>
+           and 45 others
+   = note: required for the cast to the object type `(dyn std::error::Error + 'static)`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/coercion/coerce-issue-49593-box-never-windows.rs b/src/test/ui/coercion/coerce-issue-49593-box-never-windows.rs
new file mode 100644 (file)
index 0000000..95d3935
--- /dev/null
@@ -0,0 +1,58 @@
+// revisions: nofallback fallback
+// only-windows - the number of `Error` impls is platform-dependent
+//[fallback] check-pass
+//[nofallback] check-fail
+
+#![feature(never_type)]
+#![cfg_attr(fallback, feature(never_type_fallback))]
+#![allow(unreachable_code)]
+
+use std::error::Error;
+use std::mem;
+
+fn raw_ptr_box<T>(t: T) -> *mut T {
+    panic!()
+}
+
+fn foo(x: !) -> Box<dyn Error> {
+    /* *mut $0 is coerced to Box<dyn Error> here */ Box::<_ /* ! */>::new(x)
+    //[nofallback]~^ ERROR trait bound `(): std::error::Error` is not satisfied
+}
+
+fn foo_raw_ptr(x: !) -> *mut dyn Error {
+    /* *mut $0 is coerced to *mut Error here */ raw_ptr_box::<_ /* ! */>(x)
+    //[nofallback]~^ ERROR trait bound `(): std::error::Error` is not satisfied
+}
+
+fn no_coercion(d: *mut dyn Error) -> *mut dyn Error {
+    /* an unsize coercion won't compile here, and it is indeed not used
+       because there is nothing requiring the _ to be Sized */
+    d as *mut _
+}
+
+trait Xyz {}
+struct S;
+struct T;
+impl Xyz for S {}
+impl Xyz for T {}
+
+fn foo_no_never() {
+    let mut x /* : Option<S> */ = None;
+    let mut first_iter = false;
+    loop {
+        if !first_iter {
+            let y: Box<dyn Xyz>
+                = /* Box<$0> is coerced to Box<Xyz> here */ Box::new(x.unwrap());
+        }
+
+        x = Some(S);
+        first_iter = true;
+    }
+
+    let mut y : Option<S> = None;
+    // assert types are equal
+    mem::swap(&mut x, &mut y);
+}
+
+fn main() {
+}
index 1b1ce67cb0c1fd20e716ef156775cfea4f3b95c7..1daa91f025a8925827efe68655f3792b1c06c805 100644 (file)
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `(): std::error::Error` is not satisfied
-  --> $DIR/coerce-issue-49593-box-never.rs:17:53
+  --> $DIR/coerce-issue-49593-box-never.rs:18:53
    |
 LL |     /* *mut $0 is coerced to Box<dyn Error> here */ Box::<_ /* ! */>::new(x)
    |                                                     ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()`
@@ -17,7 +17,7 @@ LL |     /* *mut $0 is coerced to Box<dyn Error> here */ Box::<_ /* ! */>::new(x
    = note: required for the cast to the object type `dyn std::error::Error`
 
 error[E0277]: the trait bound `(): std::error::Error` is not satisfied
-  --> $DIR/coerce-issue-49593-box-never.rs:22:49
+  --> $DIR/coerce-issue-49593-box-never.rs:23:49
    |
 LL |     /* *mut $0 is coerced to *mut Error here */ raw_ptr_box::<_ /* ! */>(x)
    |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()`
index 7a4324bd5adcedd124b9473e4e742cb1ea3fd4e8..16efb65acb2b68de082c8e4a838a5dbb2948378f 100644 (file)
@@ -1,4 +1,5 @@
 // revisions: nofallback fallback
+// ignore-windows - the number of `Error` impls is platform-dependent
 //[fallback] check-pass
 //[nofallback] check-fail
 
index 0cf2a406da443d6c97799f3d10304249e9c8461e..fe4b5b410789572e32aaae7e0a003c16eb51df1e 100644 (file)
@@ -1,4 +1,4 @@
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for types defined outside of the crate
   --> $DIR/coherence-cow.rs:18:1
    |
 LL | impl<T> Remote for Pair<T,Cover<T>> { }
index b523db4da23eaf0b2ac534ed57e57d7bcd08e3a6..da4ede3251ed83729fcfddde25d482c2b91df15b 100644 (file)
@@ -1,4 +1,4 @@
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for types defined outside of the crate
   --> $DIR/coherence-cow.rs:22:1
    |
 LL | impl<T> Remote for Pair<Cover<T>,T> { }
index bd635fc2e8c29353b8b4bf2673f97d932b821e73..d1a20c0ca101b99e1f597e1957438ba5c72edc8c 100644 (file)
@@ -1,4 +1,4 @@
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for types defined outside of the crate
   --> $DIR/coherence-cow.rs:26:1
    |
 LL | impl<T,U> Remote for Pair<Cover<T>,U> { }
index a7d6968a2967cc272de8e7fcb712ca75b96c8574..b3ca354c633aade9e89e5bfa9d21eba1407121a2 100644 (file)
@@ -1,4 +1,4 @@
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for primitive types
   --> $DIR/coherence-impls-copy.rs:5:1
    |
 LL | impl Copy for i32 {}
index 52d2cc88cbe7f2668ad6484b3c829d0053d95668..01f166a21f7683aee5f4d7678f0ec5d598eb30dd 100644 (file)
@@ -1,4 +1,4 @@
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for primitive types
   --> $DIR/coherence-orphan.rs:10:1
    |
 LL | impl TheTrait<usize> for isize { }
@@ -10,7 +10,7 @@ LL | impl TheTrait<usize> for isize { }
    |
    = note: define and implement a trait or new type instead
 
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for types defined outside of the crate
   --> $DIR/coherence-orphan.rs:17:1
    |
 LL | impl !Send for Vec<isize> { }
index c1a02681c1343f0b79f96e10c930a962303e2959..15c92dfeb07d73d26bc9ab2b6961c5fa5d2a2e07 100644 (file)
@@ -1,4 +1,4 @@
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for types defined outside of the crate
   --> $DIR/coherence-overlapping-pairs.rs:8:1
    |
 LL | impl<T> Remote for lib::Pair<T,Foo> { }
index b18bf44dbdf2894894a55dfe5760c4527c77843c..03d787123812874dd36776e8534131e79af04800 100644 (file)
@@ -1,4 +1,4 @@
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for primitive types
   --> $DIR/coherence-pair-covered-uncovered-1.rs:12:1
    |
 LL | impl<T, U> Remote1<Pair<T, Local<U>>> for i32 { }
index 34fdf64ea109f8551b60e55f58bad11aeb319488..73dfe2f572ae3e205c55d8b85d6566401f23b3ac 100644 (file)
@@ -1,4 +1,4 @@
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for types defined outside of the crate
   --> $DIR/coherence-pair-covered-uncovered.rs:8:1
    |
 LL | impl<T,U> Remote for Pair<T,Local<U>> { }
index 567b6a6c17fda1e2faba5aef0bfc58a9f023e9e4..95fdf172ec255404e54378bd1dcb6837b7c8d48d 100644 (file)
@@ -1,4 +1,4 @@
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for types defined outside of the crate
   --> $DIR/coherence-vec-local-2.rs:11:1
    |
 LL | impl<T> Remote for Vec<Local<T>> { }
index 38464f12a21d041c8010013052a2916cf60f92c7..4835e771abd3bf807d77609c75e175ba9097063c 100644 (file)
@@ -1,4 +1,4 @@
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for types defined outside of the crate
   --> $DIR/coherence-vec-local.rs:11:1
    |
 LL | impl Remote for Vec<Local> { }
index 8c310b318a7af47761cd07084361c68c4cf77095..afc6fc45d0e03f890f5e9c5c020c2fd68f9c7bb4 100644 (file)
@@ -1,4 +1,4 @@
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for types defined outside of the crate
   --> $DIR/coherence_local_err_struct.rs:14:1
    |
 LL | impl lib::MyCopy for lib::MyStruct<MyType> { }
index fe7c9b93f5401245b540b1f3efad88c3c819aaf9..93f7a6fdc25d34eb43be6bb0832b416fd415e6da 100644 (file)
@@ -1,4 +1,4 @@
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for primitive types
   --> $DIR/impl-foreign-for-foreign.rs:10:1
    |
 LL | impl Remote for i32 {
index bdf19cf00a7cee35b564d99e8ed538f2b0863ea5..e24537bce229a5f4942b6306a06c48efb599c9ef 100644 (file)
@@ -1,4 +1,4 @@
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for primitive types
   --> $DIR/impl-foreign-for-foreign[foreign].rs:10:1
    |
 LL | impl Remote1<Rc<i32>> for i32 {
@@ -10,7 +10,7 @@ LL | impl Remote1<Rc<i32>> for i32 {
    |
    = note: define and implement a trait or new type instead
 
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for primitive types
   --> $DIR/impl-foreign-for-foreign[foreign].rs:14:1
    |
 LL | impl Remote1<Rc<Local>> for f64 {
@@ -22,7 +22,7 @@ LL | impl Remote1<Rc<Local>> for f64 {
    |
    = note: define and implement a trait or new type instead
 
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for primitive types
   --> $DIR/impl-foreign-for-foreign[foreign].rs:18:1
    |
 LL | impl<T> Remote1<Rc<T>> for f32 {
index 20dc955ffe42b9f4cac442ef8ae0fad3826032b9..55ea4409e6f362f9b7037308b3298b9f61359d16 100644 (file)
@@ -1,4 +1,4 @@
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for types defined outside of the crate
   --> $DIR/impl-foreign-for-fundamental[foreign].rs:10:1
    |
 LL | impl Remote for Box<i32> {
@@ -10,7 +10,7 @@ LL | impl Remote for Box<i32> {
    |
    = note: define and implement a trait or new type instead
 
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for types defined outside of the crate
   --> $DIR/impl-foreign-for-fundamental[foreign].rs:14:1
    |
 LL | impl<T> Remote for Box<Rc<T>> {
index 5552d825793715a819cd74ff5edd60da5062f692..65b3aa394a85f756e942841fa000c0d0822c0f6e 100644 (file)
@@ -1,4 +1,4 @@
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for primitive types
   --> $DIR/impl-foreign[foreign]-for-foreign.rs:10:1
    |
 LL | impl Remote1<u32> for f64 {
index c1e2fdaf5e302e4f0da96d9a609d906ee6d7c59a..8e77c13e1116aef74a36dcd8f9fe2542d5bc2277 100644 (file)
@@ -1,4 +1,4 @@
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for primitive types
   --> $DIR/impl-foreign[fundemental[foreign]]-for-foreign.rs:11:1
    |
 LL | impl Remote1<Box<String>> for i32 {
@@ -11,7 +11,7 @@ LL | impl Remote1<Box<String>> for i32 {
    |
    = note: define and implement a trait or new type instead
 
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for primitive types
   --> $DIR/impl-foreign[fundemental[foreign]]-for-foreign.rs:15:1
    |
 LL | impl Remote1<Box<Rc<i32>>> for f64 {
@@ -24,7 +24,7 @@ LL | impl Remote1<Box<Rc<i32>>> for f64 {
    |
    = note: define and implement a trait or new type instead
 
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for primitive types
   --> $DIR/impl-foreign[fundemental[foreign]]-for-foreign.rs:19:1
    |
 LL | impl<T> Remote1<Box<Rc<T>>> for f32 {
index 7f8ec83b24a8b9d39798d4204e8df52c2b2ca79c..92346c29198cede287a0edafea079342fd0578cb 100644 (file)
@@ -1,4 +1,4 @@
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for types defined outside of the crate
   --> $DIR/impl[t]-foreign-for-foreign[t].rs:11:1
    |
 LL | impl Remote for Rc<Local> {
@@ -9,7 +9,7 @@ LL | impl Remote for Rc<Local> {
    |
    = note: define and implement a trait or new type instead
 
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for types defined outside of the crate
   --> $DIR/impl[t]-foreign-for-foreign[t].rs:16:1
    |
 LL | impl<T> Remote for Arc<T> {
index b8488d83998e87ebcf45716ca7d3f27e945e8eaa..b7f795eadb760d9162c2c60cb8cb46a2c008855c 100644 (file)
@@ -2,7 +2,6 @@
 
 fn will_ice(something: &u32) -> impl Iterator<Item = &u32> {
     //~^ ERROR `()` is not an iterator
-    //~| ERROR `()` is not an iterator
 }
 
 fn main() {}
index 2348f2f52978f159c15e1eb22db188853aa65153..63a4df242f85f9897247a8b24d4101dd16eaeb35 100644 (file)
@@ -6,18 +6,6 @@ LL | fn will_ice(something: &u32) -> impl Iterator<Item = &u32> {
    |
    = help: the trait `Iterator` is not implemented for `()`
 
-error[E0277]: `()` is not an iterator
-  --> $DIR/conservative_impl_trait.rs:3:60
-   |
-LL |   fn will_ice(something: &u32) -> impl Iterator<Item = &u32> {
-   |  ____________________________________________________________^
-LL | |
-LL | |
-LL | | }
-   | |_^ `()` is not an iterator
-   |
-   = help: the trait `Iterator` is not implemented for `()`
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0277`.
index ac693426fbd983d6d295f4663e9f6ad890450938..88d9ed46e1ad3a8251b2924881bf1d089be35778 100644 (file)
@@ -16,53 +16,8 @@ LL |     let _: [u8; bar::<N>()];
    = help: const parameters may only be used as standalone arguments, i.e. `N`
    = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions
 
-error: generic parameters may not be used in const operations
-  --> $DIR/const-arg-in-const-arg.rs:24:23
-   |
-LL |     let _ = [0; bar::<N>()];
-   |                       ^ cannot perform const operation using `N`
-   |
-   = help: const parameters may only be used as standalone arguments, i.e. `N`
-   = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions
-
-error: generic parameters may not be used in const operations
-  --> $DIR/const-arg-in-const-arg.rs:29:24
-   |
-LL |     let _: Foo<{ foo::<T>() }>;
-   |                        ^ cannot perform const operation using `T`
-   |
-   = note: type parameters may not be used in const expressions
-   = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions
-
-error: generic parameters may not be used in const operations
-  --> $DIR/const-arg-in-const-arg.rs:30:24
-   |
-LL |     let _: Foo<{ bar::<N>() }>;
-   |                        ^ cannot perform const operation using `N`
-   |
-   = help: const parameters may only be used as standalone arguments, i.e. `N`
-   = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions
-
-error: generic parameters may not be used in const operations
-  --> $DIR/const-arg-in-const-arg.rs:35:27
-   |
-LL |     let _ = Foo::<{ foo::<T>() }>;
-   |                           ^ cannot perform const operation using `T`
-   |
-   = note: type parameters may not be used in const expressions
-   = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions
-
-error: generic parameters may not be used in const operations
-  --> $DIR/const-arg-in-const-arg.rs:36:27
-   |
-LL |     let _ = Foo::<{ bar::<N>() }>;
-   |                           ^ cannot perform const operation using `N`
-   |
-   = help: const parameters may only be used as standalone arguments, i.e. `N`
-   = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions
-
 error[E0658]: a non-static lifetime is not allowed in a `const`
-  --> $DIR/const-arg-in-const-arg.rs:15:23
+  --> $DIR/const-arg-in-const-arg.rs:16:23
    |
 LL |     let _: [u8; faz::<'a>(&())];
    |                       ^^
@@ -71,7 +26,7 @@ LL |     let _: [u8; faz::<'a>(&())];
    = help: add `#![feature(generic_const_exprs)]` to the crate attributes to enable
 
 error[E0658]: a non-static lifetime is not allowed in a `const`
-  --> $DIR/const-arg-in-const-arg.rs:16:23
+  --> $DIR/const-arg-in-const-arg.rs:18:23
    |
 LL |     let _: [u8; baz::<'a>(&())];
    |                       ^^
@@ -80,7 +35,7 @@ LL |     let _: [u8; baz::<'a>(&())];
    = help: add `#![feature(generic_const_exprs)]` to the crate attributes to enable
 
 error[E0658]: a non-static lifetime is not allowed in a `const`
-  --> $DIR/const-arg-in-const-arg.rs:17:23
+  --> $DIR/const-arg-in-const-arg.rs:19:23
    |
 LL |     let _: [u8; faz::<'b>(&())];
    |                       ^^
@@ -89,7 +44,7 @@ LL |     let _: [u8; faz::<'b>(&())];
    = help: add `#![feature(generic_const_exprs)]` to the crate attributes to enable
 
 error[E0658]: a non-static lifetime is not allowed in a `const`
-  --> $DIR/const-arg-in-const-arg.rs:18:23
+  --> $DIR/const-arg-in-const-arg.rs:21:23
    |
 LL |     let _: [u8; baz::<'b>(&())];
    |                       ^^
@@ -97,8 +52,17 @@ LL |     let _: [u8; baz::<'b>(&())];
    = note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information
    = help: add `#![feature(generic_const_exprs)]` to the crate attributes to enable
 
+error: generic parameters may not be used in const operations
+  --> $DIR/const-arg-in-const-arg.rs:24:23
+   |
+LL |     let _ = [0; bar::<N>()];
+   |                       ^ cannot perform const operation using `N`
+   |
+   = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions
+
 error[E0658]: a non-static lifetime is not allowed in a `const`
-  --> $DIR/const-arg-in-const-arg.rs:25:23
+  --> $DIR/const-arg-in-const-arg.rs:26:23
    |
 LL |     let _ = [0; faz::<'a>(&())];
    |                       ^^
@@ -107,7 +71,7 @@ LL |     let _ = [0; faz::<'a>(&())];
    = help: add `#![feature(generic_const_exprs)]` to the crate attributes to enable
 
 error[E0658]: a non-static lifetime is not allowed in a `const`
-  --> $DIR/const-arg-in-const-arg.rs:26:23
+  --> $DIR/const-arg-in-const-arg.rs:28:23
    |
 LL |     let _ = [0; baz::<'a>(&())];
    |                       ^^
@@ -116,7 +80,7 @@ LL |     let _ = [0; baz::<'a>(&())];
    = help: add `#![feature(generic_const_exprs)]` to the crate attributes to enable
 
 error[E0658]: a non-static lifetime is not allowed in a `const`
-  --> $DIR/const-arg-in-const-arg.rs:27:23
+  --> $DIR/const-arg-in-const-arg.rs:29:23
    |
 LL |     let _ = [0; faz::<'b>(&())];
    |                       ^^
@@ -125,7 +89,7 @@ LL |     let _ = [0; faz::<'b>(&())];
    = help: add `#![feature(generic_const_exprs)]` to the crate attributes to enable
 
 error[E0658]: a non-static lifetime is not allowed in a `const`
-  --> $DIR/const-arg-in-const-arg.rs:28:23
+  --> $DIR/const-arg-in-const-arg.rs:31:23
    |
 LL |     let _ = [0; baz::<'b>(&())];
    |                       ^^
@@ -133,8 +97,26 @@ LL |     let _ = [0; baz::<'b>(&())];
    = note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information
    = help: add `#![feature(generic_const_exprs)]` to the crate attributes to enable
 
+error: generic parameters may not be used in const operations
+  --> $DIR/const-arg-in-const-arg.rs:32:24
+   |
+LL |     let _: Foo<{ foo::<T>() }>;
+   |                        ^ cannot perform const operation using `T`
+   |
+   = note: type parameters may not be used in const expressions
+   = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions
+
+error: generic parameters may not be used in const operations
+  --> $DIR/const-arg-in-const-arg.rs:33:24
+   |
+LL |     let _: Foo<{ bar::<N>() }>;
+   |                        ^ cannot perform const operation using `N`
+   |
+   = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions
+
 error[E0658]: a non-static lifetime is not allowed in a `const`
-  --> $DIR/const-arg-in-const-arg.rs:31:24
+  --> $DIR/const-arg-in-const-arg.rs:35:24
    |
 LL |     let _: Foo<{ faz::<'a>(&()) }>;
    |                        ^^
@@ -143,7 +125,7 @@ LL |     let _: Foo<{ faz::<'a>(&()) }>;
    = help: add `#![feature(generic_const_exprs)]` to the crate attributes to enable
 
 error[E0658]: a non-static lifetime is not allowed in a `const`
-  --> $DIR/const-arg-in-const-arg.rs:32:24
+  --> $DIR/const-arg-in-const-arg.rs:37:24
    |
 LL |     let _: Foo<{ baz::<'a>(&()) }>;
    |                        ^^
@@ -152,7 +134,7 @@ LL |     let _: Foo<{ baz::<'a>(&()) }>;
    = help: add `#![feature(generic_const_exprs)]` to the crate attributes to enable
 
 error[E0658]: a non-static lifetime is not allowed in a `const`
-  --> $DIR/const-arg-in-const-arg.rs:33:24
+  --> $DIR/const-arg-in-const-arg.rs:38:24
    |
 LL |     let _: Foo<{ faz::<'b>(&()) }>;
    |                        ^^
@@ -161,7 +143,7 @@ LL |     let _: Foo<{ faz::<'b>(&()) }>;
    = help: add `#![feature(generic_const_exprs)]` to the crate attributes to enable
 
 error[E0658]: a non-static lifetime is not allowed in a `const`
-  --> $DIR/const-arg-in-const-arg.rs:34:24
+  --> $DIR/const-arg-in-const-arg.rs:40:24
    |
 LL |     let _: Foo<{ baz::<'b>(&()) }>;
    |                        ^^
@@ -169,8 +151,26 @@ LL |     let _: Foo<{ baz::<'b>(&()) }>;
    = note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information
    = help: add `#![feature(generic_const_exprs)]` to the crate attributes to enable
 
+error: generic parameters may not be used in const operations
+  --> $DIR/const-arg-in-const-arg.rs:41:27
+   |
+LL |     let _ = Foo::<{ foo::<T>() }>;
+   |                           ^ cannot perform const operation using `T`
+   |
+   = note: type parameters may not be used in const expressions
+   = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions
+
+error: generic parameters may not be used in const operations
+  --> $DIR/const-arg-in-const-arg.rs:42:27
+   |
+LL |     let _ = Foo::<{ bar::<N>() }>;
+   |                           ^ cannot perform const operation using `N`
+   |
+   = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions
+
 error[E0658]: a non-static lifetime is not allowed in a `const`
-  --> $DIR/const-arg-in-const-arg.rs:37:27
+  --> $DIR/const-arg-in-const-arg.rs:44:27
    |
 LL |     let _ = Foo::<{ faz::<'a>(&()) }>;
    |                           ^^
@@ -179,7 +179,7 @@ LL |     let _ = Foo::<{ faz::<'a>(&()) }>;
    = help: add `#![feature(generic_const_exprs)]` to the crate attributes to enable
 
 error[E0658]: a non-static lifetime is not allowed in a `const`
-  --> $DIR/const-arg-in-const-arg.rs:38:27
+  --> $DIR/const-arg-in-const-arg.rs:46:27
    |
 LL |     let _ = Foo::<{ baz::<'a>(&()) }>;
    |                           ^^
@@ -188,7 +188,7 @@ LL |     let _ = Foo::<{ baz::<'a>(&()) }>;
    = help: add `#![feature(generic_const_exprs)]` to the crate attributes to enable
 
 error[E0658]: a non-static lifetime is not allowed in a `const`
-  --> $DIR/const-arg-in-const-arg.rs:39:27
+  --> $DIR/const-arg-in-const-arg.rs:47:27
    |
 LL |     let _ = Foo::<{ faz::<'b>(&()) }>;
    |                           ^^
@@ -197,7 +197,7 @@ LL |     let _ = Foo::<{ faz::<'b>(&()) }>;
    = help: add `#![feature(generic_const_exprs)]` to the crate attributes to enable
 
 error[E0658]: a non-static lifetime is not allowed in a `const`
-  --> $DIR/const-arg-in-const-arg.rs:40:27
+  --> $DIR/const-arg-in-const-arg.rs:49:27
    |
 LL |     let _ = Foo::<{ baz::<'b>(&()) }>;
    |                           ^^
@@ -205,6 +205,155 @@ LL |     let _ = Foo::<{ baz::<'b>(&()) }>;
    = note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information
    = help: add `#![feature(generic_const_exprs)]` to the crate attributes to enable
 
-error: aborting due to 23 previous errors
+error[E0747]: unresolved item provided when a constant was expected
+  --> $DIR/const-arg-in-const-arg.rs:14:23
+   |
+LL |     let _: [u8; bar::<N>()];
+   |                       ^
+   |
+help: if this generic argument was intended as a const parameter, surround it with braces
+   |
+LL |     let _: [u8; bar::<{ N }>()];
+   |                       +   +
+
+error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+  --> $DIR/const-arg-in-const-arg.rs:16:23
+   |
+LL |     let _: [u8; faz::<'a>(&())];
+   |                       ^^
+   |
+note: the late bound lifetime parameter is introduced here
+  --> $DIR/const-arg-in-const-arg.rs:8:14
+   |
+LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
+   |              ^^
+
+error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+  --> $DIR/const-arg-in-const-arg.rs:19:23
+   |
+LL |     let _: [u8; faz::<'b>(&())];
+   |                       ^^
+   |
+note: the late bound lifetime parameter is introduced here
+  --> $DIR/const-arg-in-const-arg.rs:8:14
+   |
+LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
+   |              ^^
+
+error[E0747]: unresolved item provided when a constant was expected
+  --> $DIR/const-arg-in-const-arg.rs:24:23
+   |
+LL |     let _ = [0; bar::<N>()];
+   |                       ^
+   |
+help: if this generic argument was intended as a const parameter, surround it with braces
+   |
+LL |     let _ = [0; bar::<{ N }>()];
+   |                       +   +
+
+error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+  --> $DIR/const-arg-in-const-arg.rs:26:23
+   |
+LL |     let _ = [0; faz::<'a>(&())];
+   |                       ^^
+   |
+note: the late bound lifetime parameter is introduced here
+  --> $DIR/const-arg-in-const-arg.rs:8:14
+   |
+LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
+   |              ^^
+
+error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+  --> $DIR/const-arg-in-const-arg.rs:29:23
+   |
+LL |     let _ = [0; faz::<'b>(&())];
+   |                       ^^
+   |
+note: the late bound lifetime parameter is introduced here
+  --> $DIR/const-arg-in-const-arg.rs:8:14
+   |
+LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
+   |              ^^
+
+error[E0747]: unresolved item provided when a constant was expected
+  --> $DIR/const-arg-in-const-arg.rs:33:24
+   |
+LL |     let _: Foo<{ bar::<N>() }>;
+   |                        ^
+   |
+help: if this generic argument was intended as a const parameter, surround it with braces
+   |
+LL |     let _: Foo<{ bar::<{ N }>() }>;
+   |                        +   +
+
+error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+  --> $DIR/const-arg-in-const-arg.rs:35:24
+   |
+LL |     let _: Foo<{ faz::<'a>(&()) }>;
+   |                        ^^
+   |
+note: the late bound lifetime parameter is introduced here
+  --> $DIR/const-arg-in-const-arg.rs:8:14
+   |
+LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
+   |              ^^
+
+error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+  --> $DIR/const-arg-in-const-arg.rs:38:24
+   |
+LL |     let _: Foo<{ faz::<'b>(&()) }>;
+   |                        ^^
+   |
+note: the late bound lifetime parameter is introduced here
+  --> $DIR/const-arg-in-const-arg.rs:8:14
+   |
+LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
+   |              ^^
+
+error: constant expression depends on a generic parameter
+  --> $DIR/const-arg-in-const-arg.rs:23:17
+   |
+LL |     let _ = [0; foo::<T>()];
+   |                 ^^^^^^^^^^
+   |
+   = note: this may fail depending on what value the parameter takes
+
+error[E0747]: unresolved item provided when a constant was expected
+  --> $DIR/const-arg-in-const-arg.rs:42:27
+   |
+LL |     let _ = Foo::<{ bar::<N>() }>;
+   |                           ^
+   |
+help: if this generic argument was intended as a const parameter, surround it with braces
+   |
+LL |     let _ = Foo::<{ bar::<{ N }>() }>;
+   |                           +   +
+
+error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+  --> $DIR/const-arg-in-const-arg.rs:44:27
+   |
+LL |     let _ = Foo::<{ faz::<'a>(&()) }>;
+   |                           ^^
+   |
+note: the late bound lifetime parameter is introduced here
+  --> $DIR/const-arg-in-const-arg.rs:8:14
+   |
+LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
+   |              ^^
+
+error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+  --> $DIR/const-arg-in-const-arg.rs:47:27
+   |
+LL |     let _ = Foo::<{ faz::<'b>(&()) }>;
+   |                           ^^
+   |
+note: the late bound lifetime parameter is introduced here
+  --> $DIR/const-arg-in-const-arg.rs:8:14
+   |
+LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
+   |              ^^
+
+error: aborting due to 36 previous errors
 
-For more information about this error, try `rustc --explain E0658`.
+Some errors have detailed explanations: E0658, E0747.
+For more information about an error, try `rustc --explain E0658`.
index 39f0b23733029b580728ba1d80db2cb89fdc51a5..b9daadb547493fcebb7c55d7d0011b5646102eb8 100644 (file)
@@ -12,31 +12,40 @@ const fn baz<'a>(_: &'a ()) -> usize where &'a (): Sized { 13 }
 fn test<'a, 'b, T, const N: usize>() where &'b (): Sized {
     let _: [u8; foo::<T>()]; //~ ERROR generic parameters may not
     let _: [u8; bar::<N>()]; //~ ERROR generic parameters may not
+                             //~^ ERROR unresolved item provided when a constant was expected
     let _: [u8; faz::<'a>(&())]; //~ ERROR a non-static lifetime
+                                 //~^ ERROR cannot specify lifetime arguments
     let _: [u8; baz::<'a>(&())]; //~ ERROR a non-static lifetime
     let _: [u8; faz::<'b>(&())]; //~ ERROR a non-static lifetime
+                                 //~^ ERROR cannot specify lifetime arguments
     let _: [u8; baz::<'b>(&())]; //~ ERROR a non-static lifetime
 
-    // NOTE: This can be a future compat warning instead of an error,
-    // so we stop compilation before emitting this error in this test.
-    let _ = [0; foo::<T>()];
-
+    let _ = [0; foo::<T>()]; //~ ERROR constant expression depends on a generic parameter
     let _ = [0; bar::<N>()]; //~ ERROR generic parameters may not
+                             //~^ ERROR unresolved item provided when a constant was expected
     let _ = [0; faz::<'a>(&())]; //~ ERROR a non-static lifetime
+                                 //~^ ERROR cannot specify lifetime arguments
     let _ = [0; baz::<'a>(&())]; //~ ERROR a non-static lifetime
     let _ = [0; faz::<'b>(&())]; //~ ERROR a non-static lifetime
+                                 //~^ ERROR cannot specify lifetime arguments
     let _ = [0; baz::<'b>(&())]; //~ ERROR a non-static lifetime
     let _: Foo<{ foo::<T>() }>; //~ ERROR generic parameters may not
     let _: Foo<{ bar::<N>() }>; //~ ERROR generic parameters may not
+                                //~^ ERROR unresolved item provided when a constant was expected
     let _: Foo<{ faz::<'a>(&()) }>; //~ ERROR a non-static lifetime
+                                    //~^ ERROR cannot specify lifetime arguments
     let _: Foo<{ baz::<'a>(&()) }>; //~ ERROR a non-static lifetime
     let _: Foo<{ faz::<'b>(&()) }>; //~ ERROR a non-static lifetime
+                                    //~^ ERROR cannot specify lifetime arguments
     let _: Foo<{ baz::<'b>(&()) }>; //~ ERROR a non-static lifetime
     let _ = Foo::<{ foo::<T>() }>; //~ ERROR generic parameters may not
     let _ = Foo::<{ bar::<N>() }>; //~ ERROR generic parameters may not
+                                   //~^ ERROR unresolved item provided when a constant was expected
     let _ = Foo::<{ faz::<'a>(&()) }>; //~ ERROR a non-static lifetime
+                                       //~^ ERROR cannot specify lifetime arguments
     let _ = Foo::<{ baz::<'a>(&()) }>; //~ ERROR a non-static lifetime
     let _ = Foo::<{ faz::<'b>(&()) }>; //~ ERROR a non-static lifetime
+                                       //~^ ERROR cannot specify lifetime arguments
     let _ = Foo::<{ baz::<'b>(&()) }>; //~ ERROR a non-static lifetime
 }
 
index 24031aa1e61f365537dd7cfbaadb45492436797e..308c121a94111ad86386d09611be0325e5fede06 100644 (file)
@@ -5,7 +5,6 @@ impl<const N: u32> Trait for Uwu<N> {}
 
 fn rawr() -> impl Trait {
     //~^ error: the trait bound `Uwu<10_u32, 12_u32>: Trait` is not satisfied
-    //~| error: the trait bound `Uwu<10_u32, 12_u32>: Trait` is not satisfied
     Uwu::<10, 12>
 }
 
@@ -17,13 +16,11 @@ impl Traitor<1, 2> for u64 {}
 
 fn uwu<const N: u8>() -> impl Traitor<N> {
     //~^ error: the trait bound `u32: Traitor<N, N>` is not satisfied
-    //~| error: the trait bound `u32: Traitor<N, N>` is not satisfied
     1_u32
 }
 
 fn owo() -> impl Traitor {
     //~^ error: the trait bound `u64: Traitor<1_u8, 1_u8>` is not satisfied
-    //~| error: the trait bound `u64: Traitor<1_u8, 1_u8>` is not satisfied
     1_u64
 }
 
index 48c61c22e7a32d51b4e49aa331379356d718a611..8031da28ca1ffb82e6815dc4626ee14af38d606d 100644 (file)
@@ -6,21 +6,8 @@ LL | fn rawr() -> impl Trait {
    |
    = help: the trait `Trait` is implemented for `Uwu<N>`
 
-error[E0277]: the trait bound `Uwu<10_u32, 12_u32>: Trait` is not satisfied
-  --> $DIR/rp_impl_trait_fail.rs:6:25
-   |
-LL |   fn rawr() -> impl Trait {
-   |  _________________________^
-LL | |
-LL | |
-LL | |     Uwu::<10, 12>
-LL | | }
-   | |_^ the trait `Trait` is not implemented for `Uwu<10_u32, 12_u32>`
-   |
-   = help: the trait `Trait` is implemented for `Uwu<N>`
-
 error[E0277]: the trait bound `u32: Traitor<N, N>` is not satisfied
-  --> $DIR/rp_impl_trait_fail.rs:18:26
+  --> $DIR/rp_impl_trait_fail.rs:17:26
    |
 LL | fn uwu<const N: u8>() -> impl Traitor<N> {
    |                          ^^^^^^^^^^^^^^^ the trait `Traitor<N, N>` is not implemented for `u32`
@@ -29,23 +16,8 @@ LL | fn uwu<const N: u8>() -> impl Traitor<N> {
              <u32 as Traitor<N, 2_u8>>
              <u64 as Traitor<1_u8, 2_u8>>
 
-error[E0277]: the trait bound `u32: Traitor<N, N>` is not satisfied
-  --> $DIR/rp_impl_trait_fail.rs:18:42
-   |
-LL |   fn uwu<const N: u8>() -> impl Traitor<N> {
-   |  __________________________________________^
-LL | |
-LL | |
-LL | |     1_u32
-LL | | }
-   | |_^ the trait `Traitor<N, N>` is not implemented for `u32`
-   |
-   = help: the following other types implement trait `Traitor<N, M>`:
-             <u32 as Traitor<N, 2_u8>>
-             <u64 as Traitor<1_u8, 2_u8>>
-
 error[E0277]: the trait bound `u64: Traitor<1_u8, 1_u8>` is not satisfied
-  --> $DIR/rp_impl_trait_fail.rs:24:13
+  --> $DIR/rp_impl_trait_fail.rs:22:13
    |
 LL | fn owo() -> impl Traitor {
    |             ^^^^^^^^^^^^ the trait `Traitor<1_u8, 1_u8>` is not implemented for `u64`
@@ -54,21 +26,6 @@ LL | fn owo() -> impl Traitor {
              <u32 as Traitor<N, 2_u8>>
              <u64 as Traitor<1_u8, 2_u8>>
 
-error[E0277]: the trait bound `u64: Traitor<1_u8, 1_u8>` is not satisfied
-  --> $DIR/rp_impl_trait_fail.rs:24:26
-   |
-LL |   fn owo() -> impl Traitor {
-   |  __________________________^
-LL | |
-LL | |
-LL | |     1_u64
-LL | | }
-   | |_^ the trait `Traitor<1_u8, 1_u8>` is not implemented for `u64`
-   |
-   = help: the following other types implement trait `Traitor<N, M>`:
-             <u32 as Traitor<N, 2_u8>>
-             <u64 as Traitor<1_u8, 2_u8>>
-
-error: aborting due to 6 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
index 179643a7552939e147460bfb7b3e9eda75fadbe4..43a5df117fdc740fbcf9fb9f84e9e2f10b6c56d9 100644 (file)
@@ -6,6 +6,15 @@ LL | struct Bug<'a, const S: &'a str>(PhantomData<&'a ()>);
    |
    = note: for more information, see issue #74052 <https://github.com/rust-lang/rust/issues/74052>
 
-error: aborting due to previous error
+error: `&'static str` is forbidden as the type of a const generic parameter
+  --> $DIR/issue-56445-1.rs:9:25
+   |
+LL | struct Bug<'a, const S: &'a str>(PhantomData<&'a ()>);
+   |                         ^^^^^^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+   = help: more complex types are supported with `#![feature(adt_const_params)]`
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0771`.
index aeef778991f067f7d6727dce3028f825f622bea0..13eb2ea9f69d508ae164189ecf09b0d4380322fe 100644 (file)
@@ -8,5 +8,6 @@
 
 struct Bug<'a, const S: &'a str>(PhantomData<&'a ()>);
 //~^ ERROR: use of non-static lifetime `'a` in const generic
+//[min]~| ERROR: `&'static str` is forbidden as the type of a const generic parameter
 
 impl Bug<'_, ""> {}
index 48aaaf5e5440a03779ddb736477ac0db37a0ffd9..5bb35669623671649c292794a1fbe8dccc3a7fd2 100644 (file)
@@ -1,10 +1,10 @@
 error[E0277]: the trait bound `T: Copy` is not satisfied
-  --> $DIR/issue-61336-2.rs:6:5
+  --> $DIR/issue-61336-2.rs:6:6
    |
 LL |     [x; { N }]
-   |     ^^^^^^^^^^ the trait `Copy` is not implemented for `T`
+   |      ^ the trait `Copy` is not implemented for `T`
    |
-   = note: the `Copy` trait is required because the repeated element will be copied
+   = note: the `Copy` trait is required because this value will be copied for each element of the array
 help: consider restricting type parameter `T`
    |
 LL | fn g<T: std::marker::Copy, const N: usize>(x: T) -> [T; N] {
index 665a1a677a1abdefac955d588fbfdb5326a17175..8d9e545b4568975d28182a4f48050adf4c79e1fc 100644 (file)
@@ -1,10 +1,10 @@
 error[E0277]: the trait bound `T: Copy` is not satisfied
-  --> $DIR/issue-61336.rs:6:5
+  --> $DIR/issue-61336.rs:6:6
    |
 LL |     [x; N]
-   |     ^^^^^^ the trait `Copy` is not implemented for `T`
+   |      ^ the trait `Copy` is not implemented for `T`
    |
-   = note: the `Copy` trait is required because the repeated element will be copied
+   = note: the `Copy` trait is required because this value will be copied for each element of the array
 help: consider restricting type parameter `T`
    |
 LL | fn g<T: std::marker::Copy, const N: usize>(x: T) -> [T; N] {
index 19217843759c1a31cea0ea2f1bd3f821a8d5c7df..18b4dc714ded0b036f1c73211eceeee0c7f1abc2 100644 (file)
@@ -12,5 +12,5 @@ const fn copy() -> u32 {
 fn main() {
     let _: [u32; 2] = [copy(); 2];
     let _: [Option<Bar>; 2] = [no_copy(); 2];
-    //~^ ERROR the trait bound `Option<Bar>: Copy` is not satisfied
+    //~^ ERROR the trait bound `Bar: Copy` is not satisfied
 }
index 52a1669e330027e56e722269184fef8e5f0f8ee9..5306fed225118c0434cc9347cb6d1025d48080cd 100644 (file)
@@ -1,13 +1,17 @@
-error[E0277]: the trait bound `Option<Bar>: Copy` is not satisfied
-  --> $DIR/fn-call-in-non-const.rs:14:31
+error[E0277]: the trait bound `Bar: Copy` is not satisfied
+  --> $DIR/fn-call-in-non-const.rs:14:32
    |
 LL |     let _: [Option<Bar>; 2] = [no_copy(); 2];
-   |                               ^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Option<Bar>`
+   |                                ^^^^^^^^^ the trait `Copy` is not implemented for `Bar`
    |
-   = help: the trait `Copy` is implemented for `Option<T>`
-   = note: the `Copy` trait is required because the repeated element will be copied
+   = note: required because of the requirements on the impl of `Copy` for `Option<Bar>`
+   = note: the `Copy` trait is required because this value will be copied for each element of the array
    = help: consider creating a new `const` item and initializing it with the result of the function call to be used in the repeat position, like `const VAL: Type = const_fn();` and `let x = [VAL; 42];`
    = help: create an inline `const` block, see RFC #2920 <https://github.com/rust-lang/rfcs/pull/2920> for more information
+help: consider annotating `Bar` with `#[derive(Copy)]`
+   |
+LL | #[derive(Copy)]
+   |
 
 error: aborting due to previous error
 
index bb12139a7bae93f4ffaf8eadeeae27beb6adb45b..d5a17249cc9dd378bff63436fa2d92e59f41e4e5 100644 (file)
@@ -11,13 +11,13 @@ mod non_constants {
     fn no_impl_copy_empty_value_multiple_elements() {
         let x = None;
         let arr: [Option<Bar>; 2] = [x; 2];
-        //~^ ERROR the trait bound `Option<Bar>: Copy` is not satisfied [E0277]
+        //~^ ERROR the trait bound `Bar: Copy` is not satisfied [E0277]
     }
 
     fn no_impl_copy_value_multiple_elements() {
         let x = Some(Bar);
         let arr: [Option<Bar>; 2] = [x; 2];
-        //~^ ERROR the trait bound `Option<Bar>: Copy` is not satisfied [E0277]
+        //~^ ERROR the trait bound `Bar: Copy` is not satisfied [E0277]
     }
 }
 
index 318fec60290ee974aec2ec7e45f755c76706e42e..2e7ff5cb8b32c6da2b879432e3285499e25ed394 100644 (file)
@@ -1,20 +1,28 @@
-error[E0277]: the trait bound `Option<Bar>: Copy` is not satisfied
-  --> $DIR/migrate-fail.rs:13:37
+error[E0277]: the trait bound `Bar: Copy` is not satisfied
+  --> $DIR/migrate-fail.rs:13:38
    |
 LL |         let arr: [Option<Bar>; 2] = [x; 2];
-   |                                     ^^^^^^ the trait `Copy` is not implemented for `Option<Bar>`
+   |                                      ^ the trait `Copy` is not implemented for `Bar`
+   |
+   = note: required because of the requirements on the impl of `Copy` for `Option<Bar>`
+   = note: the `Copy` trait is required because this value will be copied for each element of the array
+help: consider annotating `Bar` with `#[derive(Copy)]`
+   |
+LL | #[derive(Copy)]
    |
-   = help: the trait `Copy` is implemented for `Option<T>`
-   = note: the `Copy` trait is required because the repeated element will be copied
 
-error[E0277]: the trait bound `Option<Bar>: Copy` is not satisfied
-  --> $DIR/migrate-fail.rs:19:37
+error[E0277]: the trait bound `Bar: Copy` is not satisfied
+  --> $DIR/migrate-fail.rs:19:38
    |
 LL |         let arr: [Option<Bar>; 2] = [x; 2];
-   |                                     ^^^^^^ the trait `Copy` is not implemented for `Option<Bar>`
+   |                                      ^ the trait `Copy` is not implemented for `Bar`
+   |
+   = note: required because of the requirements on the impl of `Copy` for `Option<Bar>`
+   = note: the `Copy` trait is required because this value will be copied for each element of the array
+help: consider annotating `Bar` with `#[derive(Copy)]`
+   |
+LL | #[derive(Copy)]
    |
-   = help: the trait `Copy` is implemented for `Option<T>`
-   = note: the `Copy` trait is required because the repeated element will be copied
 
 error: aborting due to 2 previous errors
 
index 871387c1fd0cf9ffce619f87568c7395decf1bc1..9d4aef39e54016d7a99627a0f280ad03cf925094 100644 (file)
@@ -10,13 +10,13 @@ mod non_constants {
     fn no_impl_copy_empty_value_multiple_elements() {
         let x = None;
         let arr: [Option<Bar>; 2] = [x; 2];
-        //~^ ERROR the trait bound `Option<Bar>: Copy` is not satisfied [E0277]
+        //~^ ERROR the trait bound `Bar: Copy` is not satisfied [E0277]
     }
 
     fn no_impl_copy_value_multiple_elements() {
         let x = Some(Bar);
         let arr: [Option<Bar>; 2] = [x; 2];
-        //~^ ERROR the trait bound `Option<Bar>: Copy` is not satisfied [E0277]
+        //~^ ERROR the trait bound `Bar: Copy` is not satisfied [E0277]
     }
 }
 
index 5a34361aa83b68193e129314be994fa88966a639..c0d273b5a9a2a14ce9c94c23dce6d12951c2a34e 100644 (file)
@@ -1,20 +1,28 @@
-error[E0277]: the trait bound `Option<Bar>: Copy` is not satisfied
-  --> $DIR/nll-fail.rs:12:37
+error[E0277]: the trait bound `Bar: Copy` is not satisfied
+  --> $DIR/nll-fail.rs:12:38
    |
 LL |         let arr: [Option<Bar>; 2] = [x; 2];
-   |                                     ^^^^^^ the trait `Copy` is not implemented for `Option<Bar>`
+   |                                      ^ the trait `Copy` is not implemented for `Bar`
+   |
+   = note: required because of the requirements on the impl of `Copy` for `Option<Bar>`
+   = note: the `Copy` trait is required because this value will be copied for each element of the array
+help: consider annotating `Bar` with `#[derive(Copy)]`
+   |
+LL | #[derive(Copy)]
    |
-   = help: the trait `Copy` is implemented for `Option<T>`
-   = note: the `Copy` trait is required because the repeated element will be copied
 
-error[E0277]: the trait bound `Option<Bar>: Copy` is not satisfied
-  --> $DIR/nll-fail.rs:18:37
+error[E0277]: the trait bound `Bar: Copy` is not satisfied
+  --> $DIR/nll-fail.rs:18:38
    |
 LL |         let arr: [Option<Bar>; 2] = [x; 2];
-   |                                     ^^^^^^ the trait `Copy` is not implemented for `Option<Bar>`
+   |                                      ^ the trait `Copy` is not implemented for `Bar`
+   |
+   = note: required because of the requirements on the impl of `Copy` for `Option<Bar>`
+   = note: the `Copy` trait is required because this value will be copied for each element of the array
+help: consider annotating `Bar` with `#[derive(Copy)]`
+   |
+LL | #[derive(Copy)]
    |
-   = help: the trait `Copy` is implemented for `Option<T>`
-   = note: the `Copy` trait is required because the repeated element will be copied
 
 error: aborting due to 2 previous errors
 
index 5a614cbdd15619c3867ffe6251da3b1339a2df1b..49d1e9b9434202e9d8871345f64d27889abf1395 100644 (file)
@@ -3,5 +3,5 @@
 
 fn main() {
     [Foo(String::new()); 4];
-    //~^ ERROR the trait bound `Foo<String>: Copy` is not satisfied [E0277]
+    //~^ ERROR the trait bound `String: Copy` is not satisfied [E0277]
 }
index 6979ff36176cdfec5a544055609cc3afdb77dc8b..ece200ad10b5b4bcbde24dd0e2220b463dc66719 100644 (file)
@@ -1,11 +1,18 @@
-error[E0277]: the trait bound `Foo<String>: Copy` is not satisfied
-  --> $DIR/trait-error.rs:5:5
+error[E0277]: the trait bound `String: Copy` is not satisfied
+  --> $DIR/trait-error.rs:5:6
    |
 LL |     [Foo(String::new()); 4];
-   |     ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Foo<String>`
+   |      ^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String`
    |
-   = help: the trait `Copy` is implemented for `Foo<T>`
-   = note: the `Copy` trait is required because the repeated element will be copied
+note: required because of the requirements on the impl of `Copy` for `Foo<String>`
+  --> $DIR/trait-error.rs:1:10
+   |
+LL | #[derive(Copy, Clone)]
+   |          ^^^^
+   = note: the `Copy` trait is required because this value will be copied for each element of the array
+   = help: consider creating a new `const` item and initializing it with the result of the function call to be used in the repeat position, like `const VAL: Type = const_fn();` and `let x = [VAL; 42];`
+   = help: create an inline `const` block, see RFC #2920 <https://github.com/rust-lang/rfcs/pull/2920> for more information
+   = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to previous error
 
index d34ac773da25e039c9c1b2a08704646d89ccd22a..298f0a4a446dd5b31ce5517b85db144a8330b9cb 100644 (file)
@@ -16,6 +16,12 @@ error[E0080]: evaluation of `foo::<()>` failed
 LL |     &<A<T> as Foo<T>>::BAR
    |      ^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors
 
+note: the above error was encountered while instantiating `fn foo::<()>`
+  --> $DIR/issue-50814-2.rs:31:22
+   |
+LL |     println!("{:x}", foo::<()>() as *const usize as usize);
+   |                      ^^^^^^^^^^^
+
 error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
index dd8d6bf839a04e26cc83e1372be38588f1e70269..87bea28e76325d594b55ac51398095f5c23669fb 100644 (file)
@@ -16,6 +16,12 @@ error[E0080]: evaluation of `foo::<i32>` failed
 LL |     &Sum::<U8,U8>::MAX
    |      ^^^^^^^^^^^^^^^^^ referenced constant has errors
 
+note: the above error was encountered while instantiating `fn foo::<i32>`
+  --> $DIR/issue-50814.rs:26:5
+   |
+LL |     foo(0);
+   |     ^^^^^^
+
 error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
index bbb8511a65410ca89b838f36a7d1871415867cf8..65ab1b02b3587d3cbbae56c1946f5e07c4db2f4e 100644 (file)
@@ -7,14 +7,17 @@ LL |     unsafe { std::mem::transmute(()) }
    |              transmuting to uninhabited type
    |              inside `foo` at $DIR/validate_uninhabited_zsts.rs:4:14
 ...
-LL | const FOO: [Empty; 3] = [foo(); 3];
-   |                          ----- inside `FOO` at $DIR/validate_uninhabited_zsts.rs:13:26
+LL | const FOO: [empty::Empty; 3] = [foo(); 3];
+   |                                 ----- inside `FOO` at $DIR/validate_uninhabited_zsts.rs:20:33
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/validate_uninhabited_zsts.rs:16:35
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/validate_uninhabited_zsts.rs:23:1
+   |
+LL | const BAR: [empty::Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at [0].0: encountered a value of uninhabited type empty::Void
    |
-LL | const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
-   |                                   ^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 0, align: 1) {}
 
 warning: the type `!` does not permit zero-initialization
   --> $DIR/validate_uninhabited_zsts.rs:4:14
@@ -28,16 +31,20 @@ LL |     unsafe { std::mem::transmute(()) }
    = note: `#[warn(invalid_value)]` on by default
    = note: the `!` type has no valid value
 
-warning: the type `Empty` does not permit zero-initialization
-  --> $DIR/validate_uninhabited_zsts.rs:16:35
+warning: the type `empty::Empty` does not permit zero-initialization
+  --> $DIR/validate_uninhabited_zsts.rs:23:42
+   |
+LL | const BAR: [empty::Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
+   |                                          ^^^^^^^^^^^^^^^^^^^^^^^
+   |                                          |
+   |                                          this code causes undefined behavior when executed
+   |                                          help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
    |
-LL | const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
-   |                                   ^^^^^^^^^^^^^^^^^^^^^^^
-   |                                   |
-   |                                   this code causes undefined behavior when executed
-   |                                   help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
+note: enums with no variants have no valid value (in this struct field)
+  --> $DIR/validate_uninhabited_zsts.rs:16:22
    |
-   = note: enums with no variants have no valid value
+LL |     pub struct Empty(Void);
+   |                      ^^^^
 
 error: aborting due to 2 previous errors; 2 warnings emitted
 
index bbb8511a65410ca89b838f36a7d1871415867cf8..65ab1b02b3587d3cbbae56c1946f5e07c4db2f4e 100644 (file)
@@ -7,14 +7,17 @@ LL |     unsafe { std::mem::transmute(()) }
    |              transmuting to uninhabited type
    |              inside `foo` at $DIR/validate_uninhabited_zsts.rs:4:14
 ...
-LL | const FOO: [Empty; 3] = [foo(); 3];
-   |                          ----- inside `FOO` at $DIR/validate_uninhabited_zsts.rs:13:26
+LL | const FOO: [empty::Empty; 3] = [foo(); 3];
+   |                                 ----- inside `FOO` at $DIR/validate_uninhabited_zsts.rs:20:33
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/validate_uninhabited_zsts.rs:16:35
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/validate_uninhabited_zsts.rs:23:1
+   |
+LL | const BAR: [empty::Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at [0].0: encountered a value of uninhabited type empty::Void
    |
-LL | const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
-   |                                   ^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 0, align: 1) {}
 
 warning: the type `!` does not permit zero-initialization
   --> $DIR/validate_uninhabited_zsts.rs:4:14
@@ -28,16 +31,20 @@ LL |     unsafe { std::mem::transmute(()) }
    = note: `#[warn(invalid_value)]` on by default
    = note: the `!` type has no valid value
 
-warning: the type `Empty` does not permit zero-initialization
-  --> $DIR/validate_uninhabited_zsts.rs:16:35
+warning: the type `empty::Empty` does not permit zero-initialization
+  --> $DIR/validate_uninhabited_zsts.rs:23:42
+   |
+LL | const BAR: [empty::Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
+   |                                          ^^^^^^^^^^^^^^^^^^^^^^^
+   |                                          |
+   |                                          this code causes undefined behavior when executed
+   |                                          help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
    |
-LL | const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
-   |                                   ^^^^^^^^^^^^^^^^^^^^^^^
-   |                                   |
-   |                                   this code causes undefined behavior when executed
-   |                                   help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
+note: enums with no variants have no valid value (in this struct field)
+  --> $DIR/validate_uninhabited_zsts.rs:16:22
    |
-   = note: enums with no variants have no valid value
+LL |     pub struct Empty(Void);
+   |                      ^^^^
 
 error: aborting due to 2 previous errors; 2 warnings emitted
 
index 990d5a308238ffda3a8baf0ee06805d156a7f43a..96f3312758292e34b8e9cf9a5e9f206de18c8e1e 100644 (file)
@@ -6,16 +6,23 @@ const fn foo() -> ! {
     //~| WARN the type `!` does not permit zero-initialization [invalid_value]
 }
 
-#[derive(Clone, Copy)]
-enum Empty { }
+// Type defined in a submodule, so that it is not "visibly"
+// uninhabited (which would change interpreter behavior).
+pub mod empty {
+    #[derive(Clone, Copy)]
+    enum Void {}
+
+    #[derive(Clone, Copy)]
+    pub struct Empty(Void);
+}
 
 #[warn(const_err)]
-const FOO: [Empty; 3] = [foo(); 3];
+const FOO: [empty::Empty; 3] = [foo(); 3];
 
 #[warn(const_err)]
-const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
-//~^ ERROR evaluation of constant value failed
-//~| WARN the type `Empty` does not permit zero-initialization
+const BAR: [empty::Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
+//~^ ERROR it is undefined behavior to use this value
+//~| WARN the type `empty::Empty` does not permit zero-initialization
 
 fn main() {
     FOO;
index 33014a1500cf7061793586bf57f37ac5db885ea3..4cd0fd2eaf76d035a9225cb8f6728f17bac3d437 100644 (file)
@@ -7,7 +7,7 @@ LL |     let a: [u8; foo()];
    = note: consult the function's documentation for information on how to avoid undefined behavior
 
 error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
-  --> $DIR/const-extern-fn-requires-unsafe.rs:11:5
+  --> $DIR/const-extern-fn-requires-unsafe.rs:12:5
    |
 LL |     foo();
    |     ^^^^^ call to unsafe function
index 031e67a1e3c3f18dcf7f199406a6e977f966ca69..afe645ae8815c69be70f111f3c91b5f9034cbc27 100644 (file)
@@ -7,7 +7,8 @@
 
 fn main() {
     let a: [u8; foo()];
-    //~^ ERROR call to unsafe function is unsafe and requires unsafe function or block
+    //[mir]~^ call to unsafe function is unsafe and requires unsafe function or block
+    //[thir]~^^ call to unsafe function `foo` is unsafe and requires unsafe function or block
     foo();
     //[mir]~^ ERROR call to unsafe function is unsafe and requires unsafe function or block
 }
index c6077da768baca3007784029d9389ae9881516f0..b313f06539ff7f5153e15c00956c7dbc96f08fb7 100644 (file)
@@ -1,4 +1,4 @@
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+error[E0133]: call to unsafe function `foo` is unsafe and requires unsafe function or block
   --> $DIR/const-extern-fn-requires-unsafe.rs:9:17
    |
 LL |     let a: [u8; foo()];
index c857ad6df2de24cec2e01771bdf1553f92789817..310db2174aafa34627b53fea6852346e56af4301 100644 (file)
@@ -37,22 +37,6 @@ fn f32() {
     const_assert!(f32::from_bits(0x44a72000), 1337.0);
     const_assert!(f32::from_ne_bytes(0x44a72000u32.to_ne_bytes()), 1337.0);
     const_assert!(f32::from_bits(0xc1640000), -14.25);
-
-    // Check that NaNs roundtrip their bits regardless of signalingness
-    // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits
-    const MASKED_NAN1: u32 = f32::NAN.to_bits() ^ 0x002A_AAAA;
-    const MASKED_NAN2: u32 = f32::NAN.to_bits() ^ 0x0055_5555;
-
-    const_assert!(f32::from_bits(MASKED_NAN1).is_nan());
-    const_assert!(f32::from_bits(MASKED_NAN1).is_nan());
-
-    // LLVM does not guarantee that loads and stores of NaNs preserve their exact bit pattern.
-    // In practice, this seems to only cause a problem on x86, since the most widely used calling
-    // convention mandates that floating point values are returned on the x87 FPU stack. See #73328.
-    if !cfg!(target_arch = "x86") {
-        const_assert!(f32::from_bits(MASKED_NAN1).to_bits(), MASKED_NAN1);
-        const_assert!(f32::from_bits(MASKED_NAN2).to_bits(), MASKED_NAN2);
-    }
 }
 
 fn f64() {
@@ -70,20 +54,6 @@ fn f64() {
     const_assert!(f64::from_bits(0x4094e40000000000), 1337.0);
     const_assert!(f64::from_ne_bytes(0x4094e40000000000u64.to_ne_bytes()), 1337.0);
     const_assert!(f64::from_bits(0xc02c800000000000), -14.25);
-
-    // Check that NaNs roundtrip their bits regardless of signalingness
-    // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits
-    const MASKED_NAN1: u64 = f64::NAN.to_bits() ^ 0x000A_AAAA_AAAA_AAAA;
-    const MASKED_NAN2: u64 = f64::NAN.to_bits() ^ 0x0005_5555_5555_5555;
-
-    const_assert!(f64::from_bits(MASKED_NAN1).is_nan());
-    const_assert!(f64::from_bits(MASKED_NAN1).is_nan());
-
-    // See comment above.
-    if !cfg!(target_arch = "x86") {
-        const_assert!(f64::from_bits(MASKED_NAN1).to_bits(), MASKED_NAN1);
-        const_assert!(f64::from_bits(MASKED_NAN2).to_bits(), MASKED_NAN2);
-    }
 }
 
 fn main() {
diff --git a/src/test/ui/consts/const-float-bits-reject-conv.rs b/src/test/ui/consts/const-float-bits-reject-conv.rs
new file mode 100644 (file)
index 0000000..122f5b9
--- /dev/null
@@ -0,0 +1,62 @@
+// compile-flags: -Zmir-opt-level=0
+#![feature(const_float_bits_conv)]
+#![feature(const_float_classify)]
+
+// Don't promote
+const fn nop<T>(x: T) -> T { x }
+
+macro_rules! const_assert {
+    ($a:expr) => {
+        {
+            const _: () = assert!($a);
+            assert!(nop($a));
+        }
+    };
+    ($a:expr, $b:expr) => {
+        {
+            const _: () = assert!($a == $b);
+            assert_eq!(nop($a), nop($b));
+        }
+    };
+}
+
+fn f32() {
+    // Check that NaNs roundtrip their bits regardless of signalingness
+    // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits
+    // ...actually, let's just check that these break. :D
+    const MASKED_NAN1: u32 = f32::NAN.to_bits() ^ 0x002A_AAAA;
+    const MASKED_NAN2: u32 = f32::NAN.to_bits() ^ 0x0055_5555;
+
+    const_assert!(f32::from_bits(MASKED_NAN1).is_nan());
+    const_assert!(f32::from_bits(MASKED_NAN1).is_nan());
+
+    // LLVM does not guarantee that loads and stores of NaNs preserve their exact bit pattern.
+    // In practice, this seems to only cause a problem on x86, since the most widely used calling
+    // convention mandates that floating point values are returned on the x87 FPU stack. See #73328.
+    if !cfg!(target_arch = "x86") {
+        const_assert!(f32::from_bits(MASKED_NAN1).to_bits(), MASKED_NAN1);
+        const_assert!(f32::from_bits(MASKED_NAN2).to_bits(), MASKED_NAN2);
+    }
+}
+
+fn f64() {
+    // Check that NaNs roundtrip their bits regardless of signalingness
+    // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits
+    // ...actually, let's just check that these break. :D
+    const MASKED_NAN1: u64 = f64::NAN.to_bits() ^ 0x000A_AAAA_AAAA_AAAA;
+    const MASKED_NAN2: u64 = f64::NAN.to_bits() ^ 0x0005_5555_5555_5555;
+
+    const_assert!(f64::from_bits(MASKED_NAN1).is_nan());
+    const_assert!(f64::from_bits(MASKED_NAN1).is_nan());
+
+    // See comment above.
+    if !cfg!(target_arch = "x86") {
+        const_assert!(f64::from_bits(MASKED_NAN1).to_bits(), MASKED_NAN1);
+        const_assert!(f64::from_bits(MASKED_NAN2).to_bits(), MASKED_NAN2);
+    }
+}
+
+fn main() {
+    f32();
+    f64();
+}
diff --git a/src/test/ui/consts/const-float-bits-reject-conv.stderr b/src/test/ui/consts/const-float-bits-reject-conv.stderr
new file mode 100644 (file)
index 0000000..b39e881
--- /dev/null
@@ -0,0 +1,119 @@
+error[E0080]: evaluation of constant value failed
+  --> $SRC_DIR/core/src/num/f32.rs:LL:COL
+   |
+LL |                     panic!("const-eval error: cannot use f32::to_bits on a NaN")
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                     |
+   |                     the evaluated program panicked at 'const-eval error: cannot use f32::to_bits on a NaN', $SRC_DIR/core/src/num/f32.rs:LL:COL
+   |                     inside `core::f32::<impl f32>::to_bits::ct_f32_to_u32` at $SRC_DIR/core/src/panic.rs:LL:COL
+...
+LL |         unsafe { intrinsics::const_eval_select((self,), ct_f32_to_u32, rt_f32_to_u32) }
+   |                  -------------------------------------------------------------------- inside `core::f32::<impl f32>::to_bits` at $SRC_DIR/core/src/num/f32.rs:LL:COL
+   |
+  ::: $SRC_DIR/core/src/ops/function.rs:LL:COL
+   |
+LL |     extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
+   |     ------------------------------------------------------------------ inside `<fn(f32) -> u32 {core::f32::<impl f32>::to_bits::ct_f32_to_u32} as FnOnce<(f32,)>>::call_once - shim(fn(f32) -> u32 {core::f32::<impl f32>::to_bits::ct_f32_to_u32})` at $SRC_DIR/core/src/ops/function.rs:LL:COL
+   |
+  ::: $SRC_DIR/core/src/intrinsics.rs:LL:COL
+   |
+LL |     called_in_const.call_once(arg)
+   |     ------------------------------ inside `const_eval_select::<(f32,), fn(f32) -> u32 {core::f32::<impl f32>::to_bits::ct_f32_to_u32}, [closure@core::f32::<impl f32>::to_bits::{closure#0}], u32>` at $SRC_DIR/core/src/intrinsics.rs:LL:COL
+   |
+  ::: $DIR/const-float-bits-reject-conv.rs:27:30
+   |
+LL |     const MASKED_NAN1: u32 = f32::NAN.to_bits() ^ 0x002A_AAAA;
+   |                              ------------------ inside `f32::MASKED_NAN1` at $DIR/const-float-bits-reject-conv.rs:27:30
+   |
+   = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0080]: evaluation of constant value failed
+  --> $SRC_DIR/core/src/num/f32.rs:LL:COL
+   |
+LL |                     panic!("const-eval error: cannot use f32::to_bits on a NaN")
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                     |
+   |                     the evaluated program panicked at 'const-eval error: cannot use f32::to_bits on a NaN', $SRC_DIR/core/src/num/f32.rs:LL:COL
+   |                     inside `core::f32::<impl f32>::to_bits::ct_f32_to_u32` at $SRC_DIR/core/src/panic.rs:LL:COL
+...
+LL |         unsafe { intrinsics::const_eval_select((self,), ct_f32_to_u32, rt_f32_to_u32) }
+   |                  -------------------------------------------------------------------- inside `core::f32::<impl f32>::to_bits` at $SRC_DIR/core/src/num/f32.rs:LL:COL
+   |
+  ::: $SRC_DIR/core/src/ops/function.rs:LL:COL
+   |
+LL |     extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
+   |     ------------------------------------------------------------------ inside `<fn(f32) -> u32 {core::f32::<impl f32>::to_bits::ct_f32_to_u32} as FnOnce<(f32,)>>::call_once - shim(fn(f32) -> u32 {core::f32::<impl f32>::to_bits::ct_f32_to_u32})` at $SRC_DIR/core/src/ops/function.rs:LL:COL
+   |
+  ::: $SRC_DIR/core/src/intrinsics.rs:LL:COL
+   |
+LL |     called_in_const.call_once(arg)
+   |     ------------------------------ inside `const_eval_select::<(f32,), fn(f32) -> u32 {core::f32::<impl f32>::to_bits::ct_f32_to_u32}, [closure@core::f32::<impl f32>::to_bits::{closure#0}], u32>` at $SRC_DIR/core/src/intrinsics.rs:LL:COL
+   |
+  ::: $DIR/const-float-bits-reject-conv.rs:28:30
+   |
+LL |     const MASKED_NAN2: u32 = f32::NAN.to_bits() ^ 0x0055_5555;
+   |                              ------------------ inside `f32::MASKED_NAN2` at $DIR/const-float-bits-reject-conv.rs:28:30
+   |
+   = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0080]: evaluation of constant value failed
+  --> $SRC_DIR/core/src/num/f64.rs:LL:COL
+   |
+LL |                     panic!("const-eval error: cannot use f64::to_bits on a NaN")
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                     |
+   |                     the evaluated program panicked at 'const-eval error: cannot use f64::to_bits on a NaN', $SRC_DIR/core/src/num/f64.rs:LL:COL
+   |                     inside `core::f64::<impl f64>::to_bits::ct_f64_to_u64` at $SRC_DIR/core/src/panic.rs:LL:COL
+...
+LL |         unsafe { intrinsics::const_eval_select((self,), ct_f64_to_u64, rt_f64_to_u64) }
+   |                  -------------------------------------------------------------------- inside `core::f64::<impl f64>::to_bits` at $SRC_DIR/core/src/num/f64.rs:LL:COL
+   |
+  ::: $SRC_DIR/core/src/ops/function.rs:LL:COL
+   |
+LL |     extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
+   |     ------------------------------------------------------------------ inside `<fn(f64) -> u64 {core::f64::<impl f64>::to_bits::ct_f64_to_u64} as FnOnce<(f64,)>>::call_once - shim(fn(f64) -> u64 {core::f64::<impl f64>::to_bits::ct_f64_to_u64})` at $SRC_DIR/core/src/ops/function.rs:LL:COL
+   |
+  ::: $SRC_DIR/core/src/intrinsics.rs:LL:COL
+   |
+LL |     called_in_const.call_once(arg)
+   |     ------------------------------ inside `const_eval_select::<(f64,), fn(f64) -> u64 {core::f64::<impl f64>::to_bits::ct_f64_to_u64}, [closure@core::f64::<impl f64>::to_bits::{closure#0}], u64>` at $SRC_DIR/core/src/intrinsics.rs:LL:COL
+   |
+  ::: $DIR/const-float-bits-reject-conv.rs:46:30
+   |
+LL |     const MASKED_NAN1: u64 = f64::NAN.to_bits() ^ 0x000A_AAAA_AAAA_AAAA;
+   |                              ------------------ inside `f64::MASKED_NAN1` at $DIR/const-float-bits-reject-conv.rs:46:30
+   |
+   = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0080]: evaluation of constant value failed
+  --> $SRC_DIR/core/src/num/f64.rs:LL:COL
+   |
+LL |                     panic!("const-eval error: cannot use f64::to_bits on a NaN")
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                     |
+   |                     the evaluated program panicked at 'const-eval error: cannot use f64::to_bits on a NaN', $SRC_DIR/core/src/num/f64.rs:LL:COL
+   |                     inside `core::f64::<impl f64>::to_bits::ct_f64_to_u64` at $SRC_DIR/core/src/panic.rs:LL:COL
+...
+LL |         unsafe { intrinsics::const_eval_select((self,), ct_f64_to_u64, rt_f64_to_u64) }
+   |                  -------------------------------------------------------------------- inside `core::f64::<impl f64>::to_bits` at $SRC_DIR/core/src/num/f64.rs:LL:COL
+   |
+  ::: $SRC_DIR/core/src/ops/function.rs:LL:COL
+   |
+LL |     extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
+   |     ------------------------------------------------------------------ inside `<fn(f64) -> u64 {core::f64::<impl f64>::to_bits::ct_f64_to_u64} as FnOnce<(f64,)>>::call_once - shim(fn(f64) -> u64 {core::f64::<impl f64>::to_bits::ct_f64_to_u64})` at $SRC_DIR/core/src/ops/function.rs:LL:COL
+   |
+  ::: $SRC_DIR/core/src/intrinsics.rs:LL:COL
+   |
+LL |     called_in_const.call_once(arg)
+   |     ------------------------------ inside `const_eval_select::<(f64,), fn(f64) -> u64 {core::f64::<impl f64>::to_bits::ct_f64_to_u64}, [closure@core::f64::<impl f64>::to_bits::{closure#0}], u64>` at $SRC_DIR/core/src/intrinsics.rs:LL:COL
+   |
+  ::: $DIR/const-float-bits-reject-conv.rs:47:30
+   |
+LL |     const MASKED_NAN2: u64 = f64::NAN.to_bits() ^ 0x0005_5555_5555_5555;
+   |                              ------------------ inside `f64::MASKED_NAN2` at $DIR/const-float-bits-reject-conv.rs:47:30
+   |
+   = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
index 4d53cfc35e1c4ab88db8e8b0bca1e545a23c99b2..e36324f0b3eea2680367b8780d7413fde536266e 100644 (file)
@@ -22,8 +22,8 @@ LL |     for i in 0..x {
 note: impl defined here, but it is not `const`
   --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
    |
-LL | impl<I: Iterator> IntoIterator for I {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | impl<I: ~const Iterator> const IntoIterator for I {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 
 error[E0658]: mutable references are not allowed in constant functions
index f02cb4f1ff193f21149f5098df0f061cd103397b..9eb7524b5044b3acb1779e3977c7e2e768877f88 100644 (file)
@@ -1,10 +1,10 @@
 error[E0277]: the trait bound `String: Copy` is not satisfied
-  --> $DIR/const-fn-in-vec.rs:4:32
+  --> $DIR/const-fn-in-vec.rs:4:33
    |
 LL |     let strings: [String; 5] = [String::new(); 5];
-   |                                ^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String`
+   |                                 ^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String`
    |
-   = note: the `Copy` trait is required because the repeated element will be copied
+   = note: the `Copy` trait is required because this value will be copied for each element of the array
    = help: consider creating a new `const` item and initializing it with the result of the function call to be used in the repeat position, like `const VAL: Type = const_fn();` and `let x = [VAL; 42];`
    = help: create an inline `const` block, see RFC #2920 <https://github.com/rust-lang/rfcs/pull/2920> for more information
 
index b0dc43eb8e8508f0d23cb136faa64e168408afb2..f2e1c8a4991a31c5f265db040cf518b6b0695c74 100644 (file)
@@ -7,8 +7,8 @@ LL |     for _ in 0..5 {}
 note: impl defined here, but it is not `const`
   --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
    |
-LL | impl<I: Iterator> IntoIterator for I {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | impl<I: ~const Iterator> const IntoIterator for I {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
 
 error[E0015]: cannot call non-const fn `<std::ops::Range<i32> as Iterator>::next` in constants
diff --git a/src/test/ui/consts/issue-19244.rs b/src/test/ui/consts/issue-19244.rs
new file mode 100644 (file)
index 0000000..44d9748
--- /dev/null
@@ -0,0 +1,34 @@
+// run-pass
+
+struct MyStruct { field: usize }
+struct Nested { nested: MyStruct }
+struct Mix2 { nested: ((usize,),) }
+
+const STRUCT: MyStruct = MyStruct { field: 42 };
+const TUP: (usize,) = (43,);
+const NESTED_S: Nested = Nested { nested: MyStruct { field: 5 } };
+const NESTED_T: ((usize,),) = ((4,),);
+const MIX_1: ((Nested,),) = ((Nested { nested: MyStruct { field: 3 } },),);
+const MIX_2: Mix2 = Mix2 { nested: ((2,),) };
+const INSTANT_1: usize = (MyStruct { field: 1 }).field;
+const INSTANT_2: usize = (0,).0;
+
+fn main() {
+    let a = [0; STRUCT.field];
+    let b = [0; TUP.0];
+    let c = [0; NESTED_S.nested.field];
+    let d = [0; (NESTED_T.0).0];
+    let e = [0; (MIX_1.0).0.nested.field];
+    let f = [0; (MIX_2.nested.0).0];
+    let g = [0; INSTANT_1];
+    let h = [0; INSTANT_2];
+
+    assert_eq!(a.len(), 42);
+    assert_eq!(b.len(), 43);
+    assert_eq!(c.len(), 5);
+    assert_eq!(d.len(), 4);
+    assert_eq!(e.len(), 3);
+    assert_eq!(f.len(), 2);
+    assert_eq!(g.len(), 1);
+    assert_eq!(h.len(), 0);
+}
diff --git a/src/test/ui/did_you_mean/replace-impl-infer-ty-from-trait.fixed b/src/test/ui/did_you_mean/replace-impl-infer-ty-from-trait.fixed
new file mode 100644 (file)
index 0000000..4963790
--- /dev/null
@@ -0,0 +1,15 @@
+// run-rustfix
+#![allow(unused)]
+
+trait Foo<T>: Sized {
+    fn bar(i: i32, t: T, s: &Self) -> (T, i32);
+}
+
+impl Foo<usize> for () {
+    fn bar(i: i32, t: usize, s: &()) -> (usize, i32) {
+        //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
+        (1, 2)
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/did_you_mean/replace-impl-infer-ty-from-trait.rs b/src/test/ui/did_you_mean/replace-impl-infer-ty-from-trait.rs
new file mode 100644 (file)
index 0000000..ddf39c9
--- /dev/null
@@ -0,0 +1,15 @@
+// run-rustfix
+#![allow(unused)]
+
+trait Foo<T>: Sized {
+    fn bar(i: i32, t: T, s: &Self) -> (T, i32);
+}
+
+impl Foo<usize> for () {
+    fn bar(i: _, t: _, s: _) -> _ {
+        //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
+        (1, 2)
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/did_you_mean/replace-impl-infer-ty-from-trait.stderr b/src/test/ui/did_you_mean/replace-impl-infer-ty-from-trait.stderr
new file mode 100644 (file)
index 0000000..730836a
--- /dev/null
@@ -0,0 +1,18 @@
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
+  --> $DIR/replace-impl-infer-ty-from-trait.rs:9:15
+   |
+LL |     fn bar(i: _, t: _, s: _) -> _ {
+   |               ^     ^     ^     ^ not allowed in type signatures
+   |               |     |     |
+   |               |     |     not allowed in type signatures
+   |               |     not allowed in type signatures
+   |               not allowed in type signatures
+   |
+help: try replacing `_` with the types in the corresponding trait method signature
+   |
+LL |     fn bar(i: i32, t: usize, s: &()) -> (usize, i32) {
+   |               ~~~     ~~~~~     ~~~     ~~~~~~~~~~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0121`.
index cdbafff2a202bbc70e098609b28cb58660aea48a..76d9f5cc0e52a3f8cfdf2b29fd983bd08f8ed4bf 100644 (file)
@@ -1,4 +1,4 @@
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for primitive types
   --> $DIR/E0117.rs:1:1
    |
 LL | impl Drop for u32 {}
index b11d5e2c2fc729092954da02bf092c3edde49202..f1d7aba2aa3b68a01a296aaf12b78fb742dde4dd 100644 (file)
@@ -1,4 +1,4 @@
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+error[E0133]: call to unsafe function `f` is unsafe and requires unsafe function or block
   --> $DIR/E0133.rs:7:5
    |
 LL |     f();
index 7dcfe96b35c9a04b4a5600bcae3a93717bf76b7a..e2bab486064f0fa8c38a9f5a4ff4cd5ce28eb6b9 100644 (file)
@@ -14,7 +14,6 @@ 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: use the fully qualified path for the potential candidate: `<Impl as Into<u32>>::into(foo_impl)`
    |
 note: multiple `impl`s satisfying `Impl: Into<_>` found
   --> $DIR/E0283.rs:17:1
@@ -24,6 +23,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
+   |
+LL |     let bar = <Impl as Into<u32>>::into(foo_impl) * 1u32;
+   |               ++++++++++++++++++++++++++        ~
 
 error: aborting due to 2 previous errors
 
index 5a16d5845a60e57561c49d7bbf106b98dee43dfd..3ab727f5f69dacfc9e3ab2ca60901c91a64edb6f 100644 (file)
@@ -1,3 +1,11 @@
+error[E0771]: use of non-static lifetime `'a` in const generic
+  --> $DIR/E0771.rs:4:41
+   |
+LL | fn function_with_str<'a, const STRING: &'a str>() {}
+   |                                         ^^
+   |
+   = note: for more information, see issue #74052 <https://github.com/rust-lang/rust/issues/74052>
+
 warning: the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/E0771.rs:1:12
    |
@@ -7,14 +15,6 @@ LL | #![feature(adt_const_params)]
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #95174 <https://github.com/rust-lang/rust/issues/95174> for more information
 
-error[E0771]: use of non-static lifetime `'a` in const generic
-  --> $DIR/E0771.rs:4:41
-   |
-LL | fn function_with_str<'a, const STRING: &'a str>() {}
-   |                                         ^^
-   |
-   = note: for more information, see issue #74052 <https://github.com/rust-lang/rust/issues/74052>
-
 error: aborting due to previous error; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0771`.
diff --git a/src/test/ui/extern-flag/no-nounused.rs b/src/test/ui/extern-flag/no-nounused.rs
new file mode 100644 (file)
index 0000000..5ec7559
--- /dev/null
@@ -0,0 +1,6 @@
+// aux-crate:somedep=somedep.rs
+// compile-flags: -Zunstable-options -Dunused-crate-dependencies
+// edition:2018
+
+fn main() { //~ ERROR external crate `somedep` unused in `no_nounused`
+}
diff --git a/src/test/ui/extern-flag/no-nounused.stderr b/src/test/ui/extern-flag/no-nounused.stderr
new file mode 100644 (file)
index 0000000..6446c53
--- /dev/null
@@ -0,0 +1,10 @@
+error: external crate `somedep` unused in `no_nounused`: remove the dependency or add `use somedep as _;`
+  --> $DIR/no-nounused.rs:5:1
+   |
+LL | fn main() {
+   | ^
+   |
+   = note: requested on the command line with `-D unused-crate-dependencies`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/extern-flag/nounused.rs b/src/test/ui/extern-flag/nounused.rs
new file mode 100644 (file)
index 0000000..2513986
--- /dev/null
@@ -0,0 +1,7 @@
+// check-pass
+// aux-crate:nounused:somedep=somedep.rs
+// compile-flags: -Zunstable-options -Dunused-crate-dependencies
+// edition:2018
+
+fn main() {
+}
diff --git a/src/test/ui/extern/extern-type-diag-not-similar.rs b/src/test/ui/extern/extern-type-diag-not-similar.rs
new file mode 100644 (file)
index 0000000..39d00a6
--- /dev/null
@@ -0,0 +1,22 @@
+// We previously mentioned other extern types in the error message here.
+//
+// Two extern types shouldn't really be considered similar just
+// because they are both extern types.
+
+#![feature(extern_types)]
+extern {
+    type ShouldNotBeMentioned;
+}
+
+extern {
+    type Foo;
+}
+
+unsafe impl Send for ShouldNotBeMentioned {}
+
+fn assert_send<T: Send + ?Sized>() {}
+
+fn main() {
+    assert_send::<Foo>()
+    //~^ ERROR `Foo` cannot be sent between threads safely
+}
diff --git a/src/test/ui/extern/extern-type-diag-not-similar.stderr b/src/test/ui/extern/extern-type-diag-not-similar.stderr
new file mode 100644 (file)
index 0000000..75836f7
--- /dev/null
@@ -0,0 +1,16 @@
+error[E0277]: `Foo` cannot be sent between threads safely
+  --> $DIR/extern-type-diag-not-similar.rs:20:19
+   |
+LL |     assert_send::<Foo>()
+   |                   ^^^ `Foo` cannot be sent between threads safely
+   |
+   = help: the trait `Send` is not implemented for `Foo`
+note: required by a bound in `assert_send`
+  --> $DIR/extern-type-diag-not-similar.rs:17:19
+   |
+LL | fn assert_send<T: Send + ?Sized>() {}
+   |                   ^^^^ required by this bound in `assert_send`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
index 2bccec458944130b655b71983e0f8f84a51f3ade..7ffebab415334ea26629d5a57b452a7a4b02be29 100644 (file)
@@ -1,8 +1,6 @@
 error[E0310]: the parameter type `U` may not live long enough
   --> $DIR/feature-gate-infer_static_outlives_requirements.rs:5:10
    |
-LL | struct Foo<U> {
-   |            - help: consider adding an explicit lifetime bound...: `U: 'static`
 LL |     bar: Bar<U>
    |          ^^^^^^ ...so that the type `U` will meet its required lifetime bounds...
    |
@@ -11,6 +9,10 @@ note: ...that is required by this bound
    |
 LL | struct Bar<T: 'static> {
    |               ^^^^^^^
+help: consider adding an explicit lifetime bound...
+   |
+LL | struct Foo<U: 'static> {
+   |             +++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/feature-gates/feature-gate-yeet_expr-in-cfg.rs b/src/test/ui/feature-gates/feature-gate-yeet_expr-in-cfg.rs
new file mode 100644 (file)
index 0000000..a33bd34
--- /dev/null
@@ -0,0 +1,19 @@
+// compile-flags: --edition 2021
+
+pub fn demo() -> Option<i32> {
+    #[cfg(nope)]
+    {
+        do yeet //~ ERROR `do yeet` expression is experimental
+    }
+
+    Some(1)
+}
+
+#[cfg(nope)]
+pub fn alternative() -> Result<(), String> {
+    do yeet "hello"; //~ ERROR `do yeet` expression is experimental
+}
+
+fn main() {
+    demo();
+}
diff --git a/src/test/ui/feature-gates/feature-gate-yeet_expr-in-cfg.stderr b/src/test/ui/feature-gates/feature-gate-yeet_expr-in-cfg.stderr
new file mode 100644 (file)
index 0000000..f90c379
--- /dev/null
@@ -0,0 +1,21 @@
+error[E0658]: `do yeet` expression is experimental
+  --> $DIR/feature-gate-yeet_expr-in-cfg.rs:6:9
+   |
+LL |         do yeet
+   |         ^^^^^^^
+   |
+   = note: see issue #96373 <https://github.com/rust-lang/rust/issues/96373> for more information
+   = help: add `#![feature(yeet_expr)]` to the crate attributes to enable
+
+error[E0658]: `do yeet` expression is experimental
+  --> $DIR/feature-gate-yeet_expr-in-cfg.rs:14:5
+   |
+LL |     do yeet "hello";
+   |     ^^^^^^^^^^^^^^^
+   |
+   = note: see issue #96373 <https://github.com/rust-lang/rust/issues/96373> for more information
+   = help: add `#![feature(yeet_expr)]` to the crate attributes to enable
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/feature-gate-yeet_expr.rs b/src/test/ui/feature-gates/feature-gate-yeet_expr.rs
new file mode 100644 (file)
index 0000000..978a84c
--- /dev/null
@@ -0,0 +1,9 @@
+// compile-flags: --edition 2018
+
+pub fn demo() -> Option<i32> {
+    do yeet //~ ERROR `do yeet` expression is experimental
+}
+
+pub fn main() -> Result<(), String> {
+    do yeet "hello"; //~ ERROR `do yeet` expression is experimental
+}
diff --git a/src/test/ui/feature-gates/feature-gate-yeet_expr.stderr b/src/test/ui/feature-gates/feature-gate-yeet_expr.stderr
new file mode 100644 (file)
index 0000000..8d1b923
--- /dev/null
@@ -0,0 +1,21 @@
+error[E0658]: `do yeet` expression is experimental
+  --> $DIR/feature-gate-yeet_expr.rs:4:5
+   |
+LL |     do yeet
+   |     ^^^^^^^
+   |
+   = note: see issue #96373 <https://github.com/rust-lang/rust/issues/96373> for more information
+   = help: add `#![feature(yeet_expr)]` to the crate attributes to enable
+
+error[E0658]: `do yeet` expression is experimental
+  --> $DIR/feature-gate-yeet_expr.rs:8:5
+   |
+LL |     do yeet "hello";
+   |     ^^^^^^^^^^^^^^^
+   |
+   = note: see issue #96373 <https://github.com/rust-lang/rust/issues/96373> for more information
+   = help: add `#![feature(yeet_expr)]` to the crate attributes to enable
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/fn/keyword-order.rs b/src/test/ui/fn/keyword-order.rs
new file mode 100644 (file)
index 0000000..8a21db6
--- /dev/null
@@ -0,0 +1,6 @@
+// edition:2018
+
+default pub const async unsafe extern fn err() {} //~ ERROR `default` is not followed by an item
+//~^ ERROR expected item, found keyword `pub`
+
+pub default const async unsafe extern fn ok() {}
diff --git a/src/test/ui/fn/keyword-order.stderr b/src/test/ui/fn/keyword-order.stderr
new file mode 100644 (file)
index 0000000..d3b140c
--- /dev/null
@@ -0,0 +1,16 @@
+error: `default` is not followed by an item
+  --> $DIR/keyword-order.rs:3:1
+   |
+LL | default pub const async unsafe extern fn err() {}
+   | ^^^^^^^ the `default` qualifier
+   |
+   = note: only `fn`, `const`, `type`, or `impl` items may be prefixed by `default`
+
+error: expected item, found keyword `pub`
+  --> $DIR/keyword-order.rs:3:9
+   |
+LL | default pub const async unsafe extern fn err() {}
+   |         ^^^ expected item
+
+error: aborting due to 2 previous errors
+
index de3de286fc93ae6bc80343f56d1e737af46b4116..67302ea1bcddb04c35d98c4277038552f1b383f6 100644 (file)
@@ -9,5 +9,6 @@ mod test {
 
 fn main() {
     test::free();
-    //~^ ERROR call to unsafe function is unsafe
+    //[mir]~^ ERROR call to unsafe function is unsafe
+    //[thir]~^^ ERROR call to unsafe function `test::free` is unsafe
 }
index d3cf5d84fdd98be1457cf37de3bc8e034b48e678..00ba0f7a6a3e07ccec84d86c46611e0976c2e848 100644 (file)
@@ -1,4 +1,4 @@
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+error[E0133]: call to unsafe function `test::free` is unsafe and requires unsafe function or block
   --> $DIR/foreign-unsafe-fn-called.rs:11:5
    |
 LL |     test::free();
index f8a81af786f7ef8f61a0d25eadfaacaa388876f3..3d2bcb8ad3550922d568c46c90673cf16ef72f8f 100644 (file)
@@ -3,14 +3,14 @@ fn main() {
     let arc = std::sync::Arc::new(oops);
     //~^ ERROR cannot find value `oops` in this scope
     //~| NOTE not found
-    // The error "note: `arc` is a function, perhaps you wish to call it" MUST NOT appear.
+    // The error "note: this is a function, perhaps you wish to call it" MUST NOT appear.
     arc.blablabla();
     //~^ ERROR no method named `blablabla`
     //~| NOTE method not found
     let arc2 = std::sync::Arc::new(|| 1);
-    // The error "note: `arc2` is a function, perhaps you wish to call it" SHOULD appear
+    // The error "note: this is a function, perhaps you wish to call it" SHOULD appear
     arc2.blablabla();
     //~^ ERROR no method named `blablabla`
     //~| NOTE method not found
-    //~| NOTE `arc2` is a function, perhaps you wish to call it
+    //~| NOTE this is a function, perhaps you wish to call it
 }
index 4d6b3282ad9e925abe89d4b59ceaadcb1721a216..3e42cb1fb6ec02d6f160894aa0a551501101ba28 100644 (file)
@@ -14,9 +14,9 @@ error[E0599]: no method named `blablabla` found for struct `Arc<[closure@$DIR/fn
   --> $DIR/fn-help-with-err.rs:12:10
    |
 LL |     arc2.blablabla();
-   |          ^^^^^^^^^ method not found in `Arc<[closure@$DIR/fn-help-with-err.rs:10:36: 10:40]>`
-   |
-   = note: `arc2` is a function, perhaps you wish to call it
+   |     ---- ^^^^^^^^^ method not found in `Arc<[closure@$DIR/fn-help-with-err.rs:10:36: 10:40]>`
+   |     |
+   |     this is a function, perhaps you wish to call it
 
 error: aborting due to 3 previous errors
 
index f27956e45950a04b6c919b207282a782a6175b25..caa452060b19830047e08cdb3eeb997403258f98 100644 (file)
@@ -7,13 +7,10 @@
 
 fn foo(bar: bool) -> impl Generator<(bool,)> {
     //~^ ERROR: type mismatch in generator arguments [E0631]
-    //~| ERROR: type mismatch in generator arguments [E0631]
-    //~| NOTE: expected signature of `fn((bool,)) -> _`
     //~| NOTE: expected signature of `fn((bool,)) -> _`
     //~| NOTE: in this expansion of desugaring of `impl Trait`
     |bar| {
         //~^ NOTE: found signature of `fn(bool) -> _`
-        //~| NOTE: found signature of `fn(bool) -> _`
         if bar {
             yield bar;
         }
index 25357411ce1897cadea4a9333f1438aef4f91509..5bd8ad129fef908d874662b5f04500e772afe288 100644 (file)
@@ -7,22 +7,6 @@ LL | fn foo(bar: bool) -> impl Generator<(bool,)> {
 LL |     |bar| {
    |     ----- found signature of `fn(bool) -> _`
 
-error[E0631]: type mismatch in generator arguments
-  --> $DIR/issue-88653.rs:8:46
-   |
-LL |   fn foo(bar: bool) -> impl Generator<(bool,)> {
-   |  ______________________________________________^
-LL | |
-LL | |
-LL | |
-...  |
-LL | |     |bar| {
-   | |     ----- found signature of `fn(bool) -> _`
-...  |
-LL | |     }
-LL | | }
-   | |_^ expected signature of `fn((bool,)) -> _`
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0631`.
index 77b830783c32a03242b7351ab24fcb20a74d197b..8d1ce6c7a437c424e05a052805cc2f09a8dfe1b6 100644 (file)
@@ -4,7 +4,6 @@
 
 fn foo() -> impl Generator<Return = i32> {
     //~^ ERROR type mismatch
-    //~| ERROR type mismatch
     || {
         if false {
             return Ok(6);
index 6369e7ec4c784fb3248b4e47e1524bfbebe5459f..f05faedf21b827dd18c3fcc46b5fdcb6712a8531 100644 (file)
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/type-mismatch-signature-deduction.rs:15:9
+  --> $DIR/type-mismatch-signature-deduction.rs:14:9
    |
 LL |         5
    |         ^ expected enum `Result`, found integer
@@ -7,12 +7,12 @@ LL |         5
    = note: expected type `Result<{integer}, _>`
               found type `{integer}`
 note: return type inferred to be `Result<{integer}, _>` here
-  --> $DIR/type-mismatch-signature-deduction.rs:10:20
+  --> $DIR/type-mismatch-signature-deduction.rs:9:20
    |
 LL |             return Ok(6);
    |                    ^^^^^
 
-error[E0271]: type mismatch resolving `<[generator@$DIR/type-mismatch-signature-deduction.rs:8:5: 16:6] as Generator>::Return == i32`
+error[E0271]: type mismatch resolving `<[generator@$DIR/type-mismatch-signature-deduction.rs:7:5: 15:6] as Generator>::Return == i32`
   --> $DIR/type-mismatch-signature-deduction.rs:5:13
    |
 LL | fn foo() -> impl Generator<Return = i32> {
@@ -21,23 +21,7 @@ LL | fn foo() -> impl Generator<Return = i32> {
    = note: expected enum `Result<{integer}, _>`
               found type `i32`
 
-error[E0271]: type mismatch resolving `<[generator@$DIR/type-mismatch-signature-deduction.rs:8:5: 16:6] as Generator>::Return == i32`
-  --> $DIR/type-mismatch-signature-deduction.rs:5:42
-   |
-LL |   fn foo() -> impl Generator<Return = i32> {
-   |  __________________________________________^
-LL | |
-LL | |
-LL | |     || {
-...  |
-LL | |     }
-LL | | }
-   | |_^ expected enum `Result`, found `i32`
-   |
-   = note: expected enum `Result<{integer}, _>`
-              found type `i32`
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 Some errors have detailed explanations: E0271, E0308.
 For more information about an error, try `rustc --explain E0271`.
index 448d7ec2873955bb67aaf6b7da37d509c59e3b01..1c3d166a1af11a0c0d2258559aafe785f50f2bf5 100644 (file)
@@ -46,6 +46,7 @@ pub fn from<Doc>(document: &'d Doc) -> Lexer<'d, Cursor>
 
 fn create_doc() -> impl Document<Cursor<'_> = DocCursorImpl<'_>> {
     //~^ ERROR: missing lifetime specifier
+    //~| ERROR: missing lifetime specifier
     DocumentImpl {}
 }
 
index c5f59a24057d24747704ea38c570f0d2950ecd87..08efc82c88658ed7e3129a19b39dcd3a16bf5578 100644 (file)
@@ -10,6 +10,18 @@ help: consider using the `'static` lifetime
 LL | fn create_doc() -> impl Document<Cursor<'static> = DocCursorImpl<'_>> {
    |                                         ~~~~~~~
 
-error: aborting due to previous error
+error[E0106]: missing lifetime specifier
+  --> $DIR/issue-70304.rs:47:61
+   |
+LL | fn create_doc() -> impl Document<Cursor<'_> = DocCursorImpl<'_>> {
+   |                                                             ^^ expected named lifetime parameter
+   |
+   = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
+help: consider using the `'static` lifetime
+   |
+LL | fn create_doc() -> impl Document<Cursor<'_> = DocCursorImpl<'static>> {
+   |                                                             ~~~~~~~
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0106`.
index 2f29cd5d9e900176a6fa820e796b44a66e6db1e1..a13dc043dc52bc57163e45ce321e5fd9d8663cf9 100644 (file)
@@ -1,10 +1,7 @@
 error[E0311]: the parameter type `T` may not live long enough
   --> $DIR/issue-86483.rs:5:1
    |
-LL |   pub trait IceIce<T>
-   |   ^                - help: consider adding an explicit lifetime bound...: `T: 'a`
-   |  _|
-   | |
+LL | / pub trait IceIce<T>
 LL | | where
 LL | |     for<'a> T: 'a,
 LL | | {
@@ -19,13 +16,14 @@ note: ...that is required by this bound
    |
 LL |     for<'a> T: 'a,
    |                ^^
+help: consider adding an explicit lifetime bound...
+   |
+LL |     for<'a> T: 'a + 'a,
+   |                   ++++
 
 error[E0311]: the parameter type `T` may not live long enough
   --> $DIR/issue-86483.rs:9:5
    |
-LL | pub trait IceIce<T>
-   |                  - help: consider adding an explicit lifetime bound...: `T: 'a`
-...
 LL |     type Ice<'v>: IntoIterator<Item = &'v T>;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds...
    |
@@ -34,6 +32,10 @@ note: ...that is required by this bound
    |
 LL |     for<'a> T: 'a,
    |                ^^
+help: consider adding an explicit lifetime bound...
+   |
+LL |     for<'a> T: 'a + 'a,
+   |                   ++++
 
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/issue-86483.rs:9:32
index a27d811023834aaf7ce4388c00ec371c55e89f35..b424d9a2fdb0c593beb015117848beb2b7e732cf 100644 (file)
@@ -1,10 +1,13 @@
 error[E0311]: the parameter type `T` may not live long enough
   --> $DIR/issue-91139.rs:27:12
    |
-LL | fn foo<T>() {
-   |        - help: consider adding an explicit lifetime bound...: `T: 'a`
 LL |     let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn foo<T: 'a>() {
+   |         ++++
 
 error: aborting due to previous error
 
index 72ade5774d749898fba7524c13e2a95cbcf6c42f..c74161cd3e059fb3c642069e410269e845d6e76d 100644 (file)
@@ -2,17 +2,23 @@ error[E0311]: the parameter type `C` may not live long enough
   --> $DIR/issue-92096.rs:20:33
    |
 LL | fn call_connect<C>(c: &'_ C) -> impl '_ + Future + Send
-   |                 -               ^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `C` will meet its required lifetime bounds
-   |                 |
-   |                 help: consider adding an explicit lifetime bound...: `C: 'a`
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `C` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL |     C: Client + Send + Sync + 'a,
+   |                             ++++
 
 error[E0311]: the parameter type `C` may not live long enough
   --> $DIR/issue-92096.rs:20:33
    |
 LL | fn call_connect<C>(c: &'_ C) -> impl '_ + Future + Send
-   |                 -               ^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `C` will meet its required lifetime bounds
-   |                 |
-   |                 help: consider adding an explicit lifetime bound...: `C: 'a`
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `C` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL |     C: Client + Send + Sync + 'a,
+   |                             ++++
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/generic-associated-types/issue-95305.rs b/src/test/ui/generic-associated-types/issue-95305.rs
new file mode 100644 (file)
index 0000000..9ead347
--- /dev/null
@@ -0,0 +1,17 @@
+// It's not yet clear how '_ and GATs should interact.
+// Forbid it for now but proper support might be added
+// at some point in the future.
+
+#![feature(generic_associated_types)]
+
+trait Foo {
+    type Item<'a>;
+}
+
+fn foo(x: &impl Foo<Item<'_> = u32>) { }
+                       //~^ ERROR missing lifetime specifier
+
+fn bar(x: &impl for<'a> Foo<Item<'a> = &'_ u32>) { }
+                                      //~^ ERROR missing lifetime specifier
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/issue-95305.stderr b/src/test/ui/generic-associated-types/issue-95305.stderr
new file mode 100644 (file)
index 0000000..2b48378
--- /dev/null
@@ -0,0 +1,25 @@
+error[E0106]: missing lifetime specifier
+  --> $DIR/issue-95305.rs:11:26
+   |
+LL | fn foo(x: &impl Foo<Item<'_> = u32>) { }
+   |                          ^^ expected named lifetime parameter
+   |
+help: consider introducing a named lifetime parameter
+   |
+LL | fn foo<'a>(x: &impl Foo<Item<'a> = u32>) { }
+   |       ++++                   ~~
+
+error[E0106]: missing lifetime specifier
+  --> $DIR/issue-95305.rs:14:41
+   |
+LL | fn bar(x: &impl for<'a> Foo<Item<'a> = &'_ u32>) { }
+   |                                         ^^ expected named lifetime parameter
+   |
+help: consider using the `'a` lifetime
+   |
+LL | fn bar(x: &impl for<'a> Foo<Item<'a> = &'a u32>) { }
+   |                                         ~~
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0106`.
diff --git a/src/test/ui/generic-associated-types/missing-bounds.fixed b/src/test/ui/generic-associated-types/missing-bounds.fixed
deleted file mode 100644 (file)
index 0e23412..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-// run-rustfix
-
-use std::ops::Add;
-
-struct A<B>(B);
-
-impl<B> Add for A<B> where B: Add + Add<Output = B> {
-    type Output = Self;
-
-    fn add(self, rhs: Self) -> Self {
-        A(self.0 + rhs.0) //~ ERROR mismatched types
-    }
-}
-
-struct C<B>(B);
-
-impl<B: Add + Add<Output = B>> Add for C<B> {
-    type Output = Self;
-
-    fn add(self, rhs: Self) -> Self {
-        Self(self.0 + rhs.0) //~ ERROR mismatched types
-    }
-}
-
-struct D<B>(B);
-
-impl<B: std::ops::Add<Output = B>> Add for D<B> {
-    type Output = Self;
-
-    fn add(self, rhs: Self) -> Self {
-        Self(self.0 + rhs.0) //~ ERROR cannot add `B` to `B`
-    }
-}
-
-struct E<B>(B);
-
-impl<B: Add> Add for E<B> where B: Add<Output = B>, B: Add<Output = B> {
-    //~^ ERROR equality constraints are not yet supported in `where` clauses
-    type Output = Self;
-
-    fn add(self, rhs: Self) -> Self {
-        Self(self.0 + rhs.0) //~ ERROR mismatched types
-    }
-}
-
-fn main() {}
index ffafff5e9f586d2543061aaaa616eec501040f8a..b3661ba3744eec99eb11d3495e79f9b6bd25325e 100644 (file)
@@ -1,5 +1,3 @@
-// run-rustfix
-
 use std::ops::Add;
 
 struct A<B>(B);
index 240be93cf961708801d1b7af36267ba964f68485..5323ee172267f20ae4c56d2137247b4f9dbd003c 100644 (file)
@@ -1,5 +1,5 @@
 error: equality constraints are not yet supported in `where` clauses
-  --> $DIR/missing-bounds.rs:37:33
+  --> $DIR/missing-bounds.rs:35:33
    |
 LL | impl<B: Add> Add for E<B> where <B as Add>::Output = B {
    |                                 ^^^^^^^^^^^^^^^^^^^^^^ not supported
@@ -11,7 +11,7 @@ LL | impl<B: Add> Add for E<B> where B: Add<Output = B> {
    |                                 ~~~~~~~~~~~~~~~~~~
 
 error[E0308]: mismatched types
-  --> $DIR/missing-bounds.rs:11:11
+  --> $DIR/missing-bounds.rs:9:11
    |
 LL | impl<B> Add for A<B> where B: Add {
    |      - this type parameter
@@ -24,7 +24,7 @@ LL |         A(self.0 + rhs.0)
    = note: expected type parameter `B`
              found associated type `<B as Add>::Output`
 note: tuple struct defined here
-  --> $DIR/missing-bounds.rs:5:8
+  --> $DIR/missing-bounds.rs:3:8
    |
 LL | struct A<B>(B);
    |        ^
@@ -34,7 +34,7 @@ LL | impl<B> Add for A<B> where B: Add + Add<Output = B> {
    |                                   +++++++++++++++++
 
 error[E0308]: mismatched types
-  --> $DIR/missing-bounds.rs:21:14
+  --> $DIR/missing-bounds.rs:19:14
    |
 LL | impl<B: Add> Add for C<B> {
    |      - this type parameter
@@ -47,7 +47,7 @@ LL |         Self(self.0 + rhs.0)
    = note: expected type parameter `B`
              found associated type `<B as Add>::Output`
 note: tuple struct defined here
-  --> $DIR/missing-bounds.rs:15:8
+  --> $DIR/missing-bounds.rs:13:8
    |
 LL | struct C<B>(B);
    |        ^
@@ -57,7 +57,7 @@ LL | impl<B: Add + Add<Output = B>> Add for C<B> {
    |             +++++++++++++++++
 
 error[E0369]: cannot add `B` to `B`
-  --> $DIR/missing-bounds.rs:31:21
+  --> $DIR/missing-bounds.rs:29:21
    |
 LL |         Self(self.0 + rhs.0)
    |              ------ ^ ----- B
@@ -66,11 +66,11 @@ LL |         Self(self.0 + rhs.0)
    |
 help: consider restricting type parameter `B`
    |
-LL | impl<B: std::ops::Add<Output = B>> Add for D<B> {
-   |       +++++++++++++++++++++++++++
+LL | impl<B: std::ops::Add> Add for D<B> {
+   |       +++++++++++++++
 
 error[E0308]: mismatched types
-  --> $DIR/missing-bounds.rs:42:14
+  --> $DIR/missing-bounds.rs:40:14
    |
 LL | impl<B: Add> Add for E<B> where <B as Add>::Output = B {
    |      - this type parameter
@@ -83,14 +83,14 @@ LL |         Self(self.0 + rhs.0)
    = note: expected type parameter `B`
              found associated type `<B as Add>::Output`
 note: tuple struct defined here
-  --> $DIR/missing-bounds.rs:35:8
+  --> $DIR/missing-bounds.rs:33:8
    |
 LL | struct E<B>(B);
    |        ^
-help: consider further restricting type parameter `B`
+help: consider further restricting this bound
    |
-LL | impl<B: Add> Add for E<B> where <B as Add>::Output = B, B: Add<Output = B> {
-   |                                                       ++++++++++++++++++++
+LL | impl<B: Add + Add<Output = B>> Add for E<B> where <B as Add>::Output = B {
+   |             +++++++++++++++++
 
 error: aborting due to 5 previous errors
 
index 4f0a023ee39c3f25495dfe9cd626cf530f0748c2..ae52010cc50a294b62579322bd234f31e2ed67ad 100644 (file)
@@ -2,7 +2,7 @@ warning: unnecessary lifetime parameter `'a`
   --> $DIR/unsatified-item-lifetime-bound.rs:4:12
    |
 LL |     type Y<'a: 'static>;
-   |            ^^^^^^^^^^^
+   |            ^^
    |
    = help: you can use the `'static` lifetime directly, in place of `'a`
 
diff --git a/src/test/ui/generics/issue-80512-param-reordering-with-defaults.rs b/src/test/ui/generics/issue-80512-param-reordering-with-defaults.rs
new file mode 100644 (file)
index 0000000..fe3e4fb
--- /dev/null
@@ -0,0 +1,4 @@
+#![crate_type = "lib"]
+
+struct S<T = (), 'a>(&'a T);
+//~^ ERROR lifetime parameters must be declared prior to type parameters
diff --git a/src/test/ui/generics/issue-80512-param-reordering-with-defaults.stderr b/src/test/ui/generics/issue-80512-param-reordering-with-defaults.stderr
new file mode 100644 (file)
index 0000000..119b1a0
--- /dev/null
@@ -0,0 +1,8 @@
+error: lifetime parameters must be declared prior to type parameters
+  --> $DIR/issue-80512-param-reordering-with-defaults.rs:3:18
+   |
+LL | struct S<T = (), 'a>(&'a T);
+   |         ---------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, T = ()>`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/generics/post_monomorphization_error_backtrace.rs b/src/test/ui/generics/post_monomorphization_error_backtrace.rs
new file mode 100644 (file)
index 0000000..1fd9b6b
--- /dev/null
@@ -0,0 +1,33 @@
+// build-fail
+
+fn assert_zst<T>() {
+    struct F<T>(T);
+    impl<T> F<T> {
+        const V: () = assert!(std::mem::size_of::<T>() == 0);
+        //~^ ERROR: evaluation of `assert_zst::F::<u32>::V` failed [E0080]
+        //~| NOTE: in this expansion of assert!
+        //~| NOTE: the evaluated program panicked
+        //~| ERROR: evaluation of `assert_zst::F::<i32>::V` failed [E0080]
+        //~| NOTE: in this expansion of assert!
+        //~| NOTE: the evaluated program panicked
+    }
+    let _ = F::<T>::V;
+}
+
+fn foo<U>() {
+    assert_zst::<U>()
+    //~^ NOTE: the above error was encountered while instantiating `fn assert_zst::<u32>`
+    //~| NOTE: the above error was encountered while instantiating `fn assert_zst::<i32>`
+}
+
+
+fn bar<V>() {
+    foo::<V>()
+}
+
+fn main() {
+    bar::<()>();
+    bar::<u32>();
+    bar::<u32>();
+    bar::<i32>();
+}
diff --git a/src/test/ui/generics/post_monomorphization_error_backtrace.stderr b/src/test/ui/generics/post_monomorphization_error_backtrace.stderr
new file mode 100644 (file)
index 0000000..0d707d8
--- /dev/null
@@ -0,0 +1,31 @@
+error[E0080]: evaluation of `assert_zst::F::<u32>::V` failed
+  --> $DIR/post_monomorphization_error_backtrace.rs:6:23
+   |
+LL |         const V: () = assert!(std::mem::size_of::<T>() == 0);
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'assertion failed: std::mem::size_of::<T>() == 0', $DIR/post_monomorphization_error_backtrace.rs:6:23
+   |
+   = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: the above error was encountered while instantiating `fn assert_zst::<u32>`
+  --> $DIR/post_monomorphization_error_backtrace.rs:18:5
+   |
+LL |     assert_zst::<U>()
+   |     ^^^^^^^^^^^^^^^^^
+
+error[E0080]: evaluation of `assert_zst::F::<i32>::V` failed
+  --> $DIR/post_monomorphization_error_backtrace.rs:6:23
+   |
+LL |         const V: () = assert!(std::mem::size_of::<T>() == 0);
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'assertion failed: std::mem::size_of::<T>() == 0', $DIR/post_monomorphization_error_backtrace.rs:6:23
+   |
+   = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: the above error was encountered while instantiating `fn assert_zst::<i32>`
+  --> $DIR/post_monomorphization_error_backtrace.rs:18:5
+   |
+LL |     assert_zst::<U>()
+   |     ^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
index 7ffe2f4cd7e1ce2c354f7349fdfa3b118cb1e8ca..7157b186fc8ad591967e48e829b074c9ebe3ec3b 100644 (file)
@@ -18,6 +18,10 @@ note: the following trait bounds were not satisfied:
    |
 LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
    |         ---------     -                          ^^^^^^ unsatisfied trait bound introduced here
+help: one of the expressions' fields has a method of the same name
+   |
+LL |     let filter = map.stream.filterx(|x: &_| true);
+   |                      +++++++
 
 error[E0599]: the method `countx` exists for struct `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>`, but its trait bounds were not satisfied
   --> $DIR/issue-30786.rs:140:24
@@ -39,6 +43,10 @@ note: the following trait bounds were not satisfied:
    |
 LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
    |         ---------     -                          ^^^^^^ unsatisfied trait bound introduced here
+help: one of the expressions' fields has a method of the same name
+   |
+LL |     let count = filter.stream.countx();
+   |                        +++++++
 
 error: aborting due to 2 previous errors
 
index 7ffe2f4cd7e1ce2c354f7349fdfa3b118cb1e8ca..7157b186fc8ad591967e48e829b074c9ebe3ec3b 100644 (file)
@@ -18,6 +18,10 @@ note: the following trait bounds were not satisfied:
    |
 LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
    |         ---------     -                          ^^^^^^ unsatisfied trait bound introduced here
+help: one of the expressions' fields has a method of the same name
+   |
+LL |     let filter = map.stream.filterx(|x: &_| true);
+   |                      +++++++
 
 error[E0599]: the method `countx` exists for struct `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>`, but its trait bounds were not satisfied
   --> $DIR/issue-30786.rs:140:24
@@ -39,6 +43,10 @@ note: the following trait bounds were not satisfied:
    |
 LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
    |         ---------     -                          ^^^^^^ unsatisfied trait bound introduced here
+help: one of the expressions' fields has a method of the same name
+   |
+LL |     let count = filter.stream.countx();
+   |                        +++++++
 
 error: aborting due to 2 previous errors
 
index 9f962fa9bbaf51fc1a54f738dd4f076ac8e15834..3329592478d6fa9d884f6f10f3c13941d36cba56 100644 (file)
@@ -24,7 +24,6 @@ trait Trait {
     /// `T::Assoc` can't be normalized any further here.
     fn foo_fail<T: Trait>() -> impl FooLike<Output = T::Assoc> {
         //~^ ERROR: type mismatch
-        //~| ERROR: type mismatch
         Foo(())
     }
 }
@@ -42,7 +41,6 @@ trait Trait<'a> {
     fn foo2_fail<'a, T: Trait<'a>>() -> impl FooLike<Output = T::Assoc> {
         //~^ ERROR `impl Trait` return type cannot contain a projection or `Self` that references lifetimes from a parent scope
         //~| ERROR: type mismatch
-        //~| ERROR: type mismatch
         Foo(())
     }
 }
index 0344f416eb7ff6859445f995cef66631a39e6bce..eac7e6b315ec4a71cf4e863b5c47ee8d6a44f428 100644 (file)
@@ -16,37 +16,14 @@ help: consider constraining the associated type `<T as impl_trait::Trait>::Assoc
 LL |     fn foo_fail<T: Trait<Assoc = ()>>() -> impl FooLike<Output = T::Assoc> {
    |                         ++++++++++++
 
-error[E0271]: type mismatch resolving `<Foo<()> as FooLike>::Output == <T as impl_trait::Trait>::Assoc`
-  --> $DIR/bound-normalization-fail.rs:25:64
-   |
-LL |       fn foo_fail<T: Trait>() -> impl FooLike<Output = T::Assoc> {
-   |  ________________________________________________________________^
-LL | |
-LL | |
-LL | |         Foo(())
-LL | |     }
-   | |_____^ type mismatch resolving `<Foo<()> as FooLike>::Output == <T as impl_trait::Trait>::Assoc`
-   |
-note: expected this to be `()`
-  --> $DIR/bound-normalization-fail.rs:14:19
-   |
-LL |     type Output = T;
-   |                   ^
-   = note:    expected unit type `()`
-           found associated type `<T as impl_trait::Trait>::Assoc`
-help: consider constraining the associated type `<T as impl_trait::Trait>::Assoc` to `()`
-   |
-LL |     fn foo_fail<T: Trait<Assoc = ()>>() -> impl FooLike<Output = T::Assoc> {
-   |                         ++++++++++++
-
 error[E0760]: `impl Trait` return type cannot contain a projection or `Self` that references lifetimes from a parent scope
-  --> $DIR/bound-normalization-fail.rs:42:41
+  --> $DIR/bound-normalization-fail.rs:41:41
    |
 LL |     fn foo2_fail<'a, T: Trait<'a>>() -> impl FooLike<Output = T::Assoc> {
    |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0271]: type mismatch resolving `<Foo<()> as FooLike>::Output == <T as lifetimes::Trait<'static>>::Assoc`
-  --> $DIR/bound-normalization-fail.rs:42:41
+  --> $DIR/bound-normalization-fail.rs:41:41
    |
 LL |     fn foo2_fail<'a, T: Trait<'a>>() -> impl FooLike<Output = T::Assoc> {
    |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type mismatch resolving `<Foo<()> as FooLike>::Output == <T as lifetimes::Trait<'static>>::Assoc`
@@ -63,31 +40,7 @@ help: consider constraining the associated type `<T as lifetimes::Trait<'static>
 LL |     fn foo2_fail<'a, T: Trait<'a, Assoc = ()>>() -> impl FooLike<Output = T::Assoc> {
    |                                 ++++++++++++
 
-error[E0271]: type mismatch resolving `<Foo<()> as FooLike>::Output == <T as lifetimes::Trait<'static>>::Assoc`
-  --> $DIR/bound-normalization-fail.rs:42:73
-   |
-LL |       fn foo2_fail<'a, T: Trait<'a>>() -> impl FooLike<Output = T::Assoc> {
-   |  _________________________________________________________________________^
-LL | |
-LL | |
-LL | |
-LL | |         Foo(())
-LL | |     }
-   | |_____^ type mismatch resolving `<Foo<()> as FooLike>::Output == <T as lifetimes::Trait<'static>>::Assoc`
-   |
-note: expected this to be `()`
-  --> $DIR/bound-normalization-fail.rs:14:19
-   |
-LL |     type Output = T;
-   |                   ^
-   = note:    expected unit type `()`
-           found associated type `<T as lifetimes::Trait<'static>>::Assoc`
-help: consider constraining the associated type `<T as lifetimes::Trait<'static>>::Assoc` to `()`
-   |
-LL |     fn foo2_fail<'a, T: Trait<'a, Assoc = ()>>() -> impl FooLike<Output = T::Assoc> {
-   |                                 ++++++++++++
-
-error: aborting due to 5 previous errors
+error: aborting due to 3 previous errors
 
 Some errors have detailed explanations: E0271, E0760.
 For more information about an error, try `rustc --explain E0271`.
index c27b5ca9f6689856be63574890ccd9e99352f72c..a7428f9bf129fa859e344d4c7960d618ff6f0c4e 100644 (file)
@@ -29,17 +29,17 @@ fn baa(b: bool) -> impl std::fmt::Debug {
 }
 
 fn muh() -> Result<(), impl std::fmt::Debug> {
-    Err("whoops")?; //~ ERROR `?` couldn't convert the error to `impl Debug`
+    Err("whoops")?; //~^ ERROR type annotations needed
     Ok(())
 }
 
 fn muh2() -> Result<(), impl std::fmt::Debug> {
-    return Err(From::from("foo")); //~ ERROR the trait bound `impl Debug: From<&str>` is not satisfied
+    return Err(From::from("foo")); //~^ ERROR type annotations needed
     Ok(())
 }
 
 fn muh3() -> Result<(), impl std::fmt::Debug> {
-    Err(From::from("foo")) //~ ERROR the trait bound `impl Debug: From<&str>` is not satisfied
+    Err(From::from("foo")) //~^ ERROR type annotations needed
 }
 
 fn main() {}
index d458c7be783d59ae1ec5b8a0fdf35daf8090d6ef..5209d7a5743498831e20266c9cd4ae8d14164504 100644 (file)
@@ -1,27 +1,21 @@
-error[E0277]: `?` couldn't convert the error to `impl Debug`
-  --> $DIR/cross-return-site-inference.rs:32:18
+error[E0282]: type annotations needed
+  --> $DIR/cross-return-site-inference.rs:31:24
    |
 LL | fn muh() -> Result<(), impl std::fmt::Debug> {
-   |             -------------------------------- expected `impl Debug` because of this
-LL |     Err("whoops")?;
-   |                  ^ the trait `From<&str>` is not implemented for `impl Debug`
-   |
-   = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
-   = help: the trait `FromResidual<Result<Infallible, E>>` is implemented for `Result<T, F>`
-   = note: required because of the requirements on the impl of `FromResidual<Result<Infallible, &str>>` for `Result<(), impl Debug>`
+   |                        ^^^^^^^^^^^^^^^^^^^^ cannot infer type
 
-error[E0277]: the trait bound `impl Debug: From<&str>` is not satisfied
-  --> $DIR/cross-return-site-inference.rs:37:16
+error[E0282]: type annotations needed
+  --> $DIR/cross-return-site-inference.rs:36:25
    |
-LL |     return Err(From::from("foo"));
-   |                ^^^^^^^^^^ the trait `From<&str>` is not implemented for `impl Debug`
+LL | fn muh2() -> Result<(), impl std::fmt::Debug> {
+   |                         ^^^^^^^^^^^^^^^^^^^^ cannot infer type
 
-error[E0277]: the trait bound `impl Debug: From<&str>` is not satisfied
-  --> $DIR/cross-return-site-inference.rs:42:9
+error[E0282]: type annotations needed
+  --> $DIR/cross-return-site-inference.rs:41:25
    |
-LL |     Err(From::from("foo"))
-   |         ^^^^^^^^^^ the trait `From<&str>` is not implemented for `impl Debug`
+LL | fn muh3() -> Result<(), impl std::fmt::Debug> {
+   |                         ^^^^^^^^^^^^^^^^^^^^ cannot infer type
 
 error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0282`.
index 51247f1d7b07a85ab3b42d339dc88c27e22072af..3e48aef553b16c8f9b987ebcd00fd23f95a56611 100644 (file)
@@ -2,7 +2,7 @@ warning: unnecessary lifetime parameter `'a`
   --> $DIR/equal-hidden-lifetimes.rs:7:25
    |
 LL | fn equal_regions_static<'a: 'static>(x: &'a i32) -> impl Sized {
-   |                         ^^^^^^^^^^^
+   |                         ^^
    |
    = help: you can use the `'static` lifetime directly, in place of `'a`
 
diff --git a/src/test/ui/impl-trait/fallback_inference.rs b/src/test/ui/impl-trait/fallback_inference.rs
new file mode 100644 (file)
index 0000000..001f9ee
--- /dev/null
@@ -0,0 +1,7 @@
+use std::marker::PhantomData;
+
+fn weird() -> PhantomData<impl Sized> {
+    PhantomData //~^ ERROR type annotations needed
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/fallback_inference.stderr b/src/test/ui/impl-trait/fallback_inference.stderr
new file mode 100644 (file)
index 0000000..b637ca6
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0282]: type annotations needed
+  --> $DIR/fallback_inference.rs:3:27
+   |
+LL | fn weird() -> PhantomData<impl Sized> {
+   |                           ^^^^^^^^^^ cannot infer type
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
index cf2c8b7e415408faac524e65a15070252072d169..be9c643b2d881c88d188cca56a8a784f499b5dae 100644 (file)
@@ -5,7 +5,7 @@ pub struct Lint {}
 impl Lint {}
 
 pub fn gather_all() -> impl Iterator<Item = Lint> {
-    //~^ ERROR `()` is not an iterator
+    //~^ ERROR type annotations needed
     lint_files().flat_map(|f| gather_from_file(&f))
 }
 
index 4a990286d966d2c0ad009200b3ce9dbcc496dff8..fc7200c75c2260d2a419bdff3ca13a7189677193 100644 (file)
@@ -10,15 +10,13 @@ error[E0433]: failed to resolve: use of undeclared crate or module `foo`
 LL | fn lint_files() -> impl Iterator<Item = foo::MissingItem> {
    |                                         ^^^ use of undeclared crate or module `foo`
 
-error[E0277]: `()` is not an iterator
+error[E0282]: type annotations needed
   --> $DIR/issue-72911.rs:7:24
    |
 LL | pub fn gather_all() -> impl Iterator<Item = Lint> {
-   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^ `()` is not an iterator
-   |
-   = help: the trait `Iterator` is not implemented for `()`
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type
 
 error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0277, E0433.
-For more information about an error, try `rustc --explain E0277`.
+Some errors have detailed explanations: E0282, E0433.
+For more information about an error, try `rustc --explain E0282`.
index 74e2f99cd33f9b300f2aa960147e26b89f5e19b1..4c0490c721bc4110f703b85077cf68b06fc1fea1 100644 (file)
@@ -1,12 +1,8 @@
 error: implementation of `FnOnce` is not general enough
-  --> $DIR/issue-67830.rs:21:66
+  --> $DIR/issue-67830.rs:21:14
    |
-LL |   fn test() -> impl for<'a> MyFn<&'a A, Output=impl Iterator + 'a> {
-   |  __________________________________________________________________^
-LL | |
-LL | |     Wrap(|a| Some(a).into_iter())
-LL | | }
-   | |_^ implementation of `FnOnce` is not general enough
+LL | fn test() -> impl for<'a> MyFn<&'a A, Output=impl Iterator + 'a> {
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
    |
    = note: closure with signature `fn(&'2 A) -> std::option::IntoIter<&A>` must implement `FnOnce<(&'1 A,)>`, for any lifetime `'1`...
    = note: ...but it actually implements `FnOnce<(&'2 A,)>`, for some specific lifetime `'2`
index e8cef42f208ca78ac1418d3940a9861929f839dd..19edeaffc496f1398c00058941b60d4bbf26ab5d 100644 (file)
@@ -27,16 +27,16 @@ struct Context {
 
 fn execute_transaction_fut<'f, F, O>(
     f: F,
-) -> impl FnOnce(&mut dyn Transaction) -> TransactionFuture<O>
+) -> impl FnOnce(&mut dyn Transaction) -> TransactionFuture<'_, O>
 where
-    F: FnOnce(&mut dyn Transaction) -> TransactionFuture<O> + 'f
+    F: FnOnce(&mut dyn Transaction) -> TransactionFuture<'_, O> + 'f
 {
     f
 }
 
 impl Context {
     async fn do_transaction<O>(
-        &self, f: impl FnOnce(&mut dyn Transaction) -> TransactionFuture<O>
+        &self, f: impl FnOnce(&mut dyn Transaction) -> TransactionFuture<'_, O>
     ) -> TransactionResult<O>
     {
         let mut conn = Connection {};
index 9cf8ff76c87f8301f0f8f140b89276b6ad898d88..66cffa9e36c0ddcea71577acfe208186ba921fe5 100644 (file)
@@ -24,10 +24,14 @@ LL | fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send
 LL |     x
    |     ^ returning this value requires that `'b` must outlive `'static`
    |
-help: to allow this `impl Trait` to capture borrowed data with lifetime `'b`, add `'b` as a bound
+help: to declare that the `impl Trait` captures data from argument `x`, you can add an explicit `'b` lifetime bound
    |
 LL | fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> + 'b {
    |                                                                                  ++++
+help: to declare that the `impl Trait` captures data from argument `x`, you can add an explicit `'b` lifetime bound
+   |
+LL | fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a + 'b> {
+   |                                                                                 ++++
 
 error: implementation of `Hrtb` is not general enough
   --> $DIR/issue-88236-2.rs:20:5
index 45fadcab3f2e15ca61c5292446699bba9b793260..9574b880f7d11c179a10cef6be1d984157f08f1d 100644 (file)
@@ -8,15 +8,12 @@ LL | fn make_weird_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Sen
    = note: ...but `Hrtb<'1>` is actually implemented for the type `&'1 ()`, for some specific lifetime `'1`
 
 error: implementation of `Hrtb` is not general enough
-  --> $DIR/issue-88236-2.rs:19:82
+  --> $DIR/issue-88236-2.rs:19:36
    |
-LL |   fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> {
-   |  __________________________________________________________________________________^
-LL | |     x
-LL | | }
-   | |_^ implementation of `Hrtb` is not general enough
+LL | fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> {
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Hrtb` is not general enough
    |
-   = note: `&()` must implement `Hrtb<'0>`, for any lifetime `'0`...
+   = note: `Hrtb<'1>` would have to be implemented for the type `&()`, for any lifetime `'1`...
    = note: ...but `Hrtb<'_>` is actually implemented for the type `&()`
 
 error: aborting due to 2 previous errors
diff --git a/src/test/ui/impl-trait/issues/issue-92305.rs b/src/test/ui/impl-trait/issues/issue-92305.rs
new file mode 100644 (file)
index 0000000..1518c11
--- /dev/null
@@ -0,0 +1,15 @@
+// edition:2021
+
+use std::iter;
+
+fn f<T>(data: &[T]) -> impl Iterator<Item = Vec> {
+    //~^ ERROR: missing generics for struct `Vec` [E0107]
+    iter::empty() //~ ERROR: type annotations needed [E0282]
+}
+
+fn g<T>(data: &[T], target: T) -> impl Iterator<Item = Vec<T>> {
+    //~^ ERROR: type annotations needed [E0282]
+    f(data).filter(|x| x == target)
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/issues/issue-92305.stderr b/src/test/ui/impl-trait/issues/issue-92305.stderr
new file mode 100644 (file)
index 0000000..c4fc492
--- /dev/null
@@ -0,0 +1,32 @@
+error[E0107]: missing generics for struct `Vec`
+  --> $DIR/issue-92305.rs:5:45
+   |
+LL | fn f<T>(data: &[T]) -> impl Iterator<Item = Vec> {
+   |                                             ^^^ expected at least 1 generic argument
+   |
+note: struct defined here, with at least 1 generic parameter: `T`
+  --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
+   |
+LL | pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global> {
+   |            ^^^ -
+help: add missing generic argument
+   |
+LL | fn f<T>(data: &[T]) -> impl Iterator<Item = Vec<T>> {
+   |                                             ~~~~~~
+
+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`
+
+error[E0282]: type annotations needed
+  --> $DIR/issue-92305.rs:10:35
+   |
+LL | fn g<T>(data: &[T], target: T) -> impl Iterator<Item = Vec<T>> {
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0107, E0282.
+For more information about an error, try `rustc --explain E0107`.
index 9589b69491e251c19138f26223031e35b32eb66c..db737a9c544c0497320ab6f868c07aba42b00112 100644 (file)
@@ -32,7 +32,14 @@ LL | fn elided2(x: &i32) -> impl Copy + 'static { x }
    |               |
    |               let's call the lifetime of this reference `'1`
    |
-   = help: consider replacing `'1` with `'static`
+help: consider changing the `impl Trait`'s explicit `'static` bound to the lifetime of argument `x`
+   |
+LL | fn elided2(x: &i32) -> impl Copy + '_ { x }
+   |                                    ~~
+help: alternatively, add an explicit `'static` bound to this reference
+   |
+LL | fn elided2(x: &'static i32) -> impl Copy + 'static { x }
+   |               ~~~~~~~~~~~~
 
 error: lifetime may not live long enough
   --> $DIR/must_outlive_least_region_or_bound.rs:11:55
@@ -40,7 +47,14 @@ error: lifetime may not live long enough
 LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x }
    |              -- lifetime `'a` defined here            ^ returning this value requires that `'a` must outlive `'static`
    |
-   = help: consider replacing `'a` with `'static`
+help: consider changing the `impl Trait`'s explicit `'static` bound to the lifetime of argument `x`
+   |
+LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'a { x }
+   |                                             ~~
+help: alternatively, add an explicit `'static` bound to this reference
+   |
+LL | fn explicit2<'a>(x: &'static i32) -> impl Copy + 'static { x }
+   |                     ~~~~~~~~~~~~
 
 error[E0621]: explicit lifetime required in the type of `x`
   --> $DIR/must_outlive_least_region_or_bound.rs:13:41
@@ -57,6 +71,15 @@ LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) }
    |               -                                       ^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static`
    |               |
    |               let's call the lifetime of this reference `'1`
+   |
+help: to declare that the trait object captures data from argument `x`, you can add an explicit `'_` lifetime bound
+   |
+LL | fn elided5(x: &i32) -> (Box<dyn Debug + '_>, impl Debug) { (Box::new(x), x) }
+   |                                       ++++
+help: to declare that the `impl Trait` captures data from argument `x`, you can add an explicit `'_` lifetime bound
+   |
+LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug + '_) { (Box::new(x), x) }
+   |                                                    ++++
 
 error: lifetime may not live long enough
   --> $DIR/must_outlive_least_region_or_bound.rs:29:69
@@ -64,7 +87,14 @@ error: lifetime may not live long enough
 LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
    |               -- lifetime `'a` defined here                         ^ returning this value requires that `'a` must outlive `'static`
    |
-   = help: consider replacing `'a` with `'static`
+help: consider changing the `impl Trait`'s explicit `'static` bound to the lifetime of argument `x`
+   |
+LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'a { x }
+   |                                                           ~~
+help: alternatively, add an explicit `'static` bound to this reference
+   |
+LL | fn with_bound<'a>(x: &'static i32) -> impl LifetimeTrait<'a> + 'static { x }
+   |                      ~~~~~~~~~~~~
 
 error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
   --> $DIR/must_outlive_least_region_or_bound.rs:34:5
@@ -80,12 +110,15 @@ LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32
    |                                                                              ++++
 
 error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/must_outlive_least_region_or_bound.rs:41:5
+  --> $DIR/must_outlive_least_region_or_bound.rs:40:5
    |
 LL |     x
-   |     ^
+   |     ^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
    |
-   = help: consider adding an explicit lifetime bound `T: 'static`...
+LL | fn ty_param_wont_outlive_static<T:Debug + 'static>(x: T) -> impl Debug + 'static {
+   |                                         +++++++++
 
 error: aborting due to 9 previous errors
 
index baa42da64468d51e991df9dff9b649f339e35e17..60e4672f1b7ff7eb71587b3039c9996434594103 100644 (file)
@@ -37,7 +37,6 @@ fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) {
 
 fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static {
     //~^ ERROR the parameter type `T` may not live long enough
-    //~| ERROR the parameter type `T` may not live long enough
     x
 }
 
index 1272adb35e98c3fb1e7d927a7166e29cdd6f15dc..dade2b91fe0b6cfcb55cf71f03d9f59e83c1e79e 100644 (file)
@@ -128,22 +128,12 @@ error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/must_outlive_least_region_or_bound.rs:38:51
    |
 LL | fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static {
-   |                                 --                ^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
-   |                                 |
-   |                                 help: consider adding an explicit lifetime bound...: `T: 'static +`
-
-error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/must_outlive_least_region_or_bound.rs:38:72
-   |
-LL |   fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static {
-   |  _________________________________--_____________________________________^
-   | |                                 |
-   | |                                 help: consider adding an explicit lifetime bound...: `T: 'static +`
-LL | |
-LL | |
-LL | |     x
-LL | | }
-   | |_^ ...so that the type `T` will meet its required lifetime bounds
+   |                                                   ^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn ty_param_wont_outlive_static<T:Debug + 'static>(x: T) -> impl Debug + 'static {
+   |                                         +++++++++
 
 error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
   --> $DIR/must_outlive_least_region_or_bound.rs:16:50
@@ -231,7 +221,7 @@ help: alternatively, add an explicit `'static` bound to this reference
 LL | fn explicit4<'a>(x: &'static i32) -> Box<dyn Debug + 'static> { Box::new(x) }
    |                     ~~~~~~~~~~~~
 
-error: aborting due to 14 previous errors
+error: aborting due to 13 previous errors
 
 Some errors have detailed explanations: E0310, E0621, E0700, E0759.
 For more information about an error, try `rustc --explain E0310`.
index f2217f699fbbdc6a7951e092bb52bb6dcb137e70..a2a49c5535d3dd5df9ba63cae37bdac14bbcd052 100644 (file)
@@ -24,7 +24,6 @@ impl<R: Duh, F: FnMut() -> R> Trait for F {
 // type does not implement `Duh`, even if its hidden type does. So we error out.
 fn foo() -> impl Trait<Assoc = Sendable> {
     //~^ ERROR `Sendable: Duh` is not satisfied
-    //~| ERROR `Sendable: Duh` is not satisfied
     || 42
 }
 
index 81a75e39c9177a29145510d863a40a3ef86c64d9..359fb909e5418e9271192872ee5b5732f2fa4c10 100644 (file)
@@ -5,30 +5,12 @@ LL | fn foo() -> impl Trait<Assoc = Sendable> {
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Duh` is not implemented for `Sendable`
    |
    = help: the trait `Duh` is implemented for `i32`
-note: required because of the requirements on the impl of `Trait` for `[closure@$DIR/nested-return-type2-tait.rs:28:5: 28:10]`
+note: required because of the requirements on the impl of `Trait` for `[closure@$DIR/nested-return-type2-tait.rs:27:5: 27:10]`
   --> $DIR/nested-return-type2-tait.rs:14:31
    |
 LL | impl<R: Duh, F: FnMut() -> R> Trait for F {
    |                               ^^^^^     ^
 
-error[E0277]: the trait bound `Sendable: Duh` is not satisfied
-  --> $DIR/nested-return-type2-tait.rs:25:42
-   |
-LL |   fn foo() -> impl Trait<Assoc = Sendable> {
-   |  __________________________________________^
-LL | |
-LL | |
-LL | |     || 42
-LL | | }
-   | |_^ the trait `Duh` is not implemented for `Sendable`
-   |
-   = help: the trait `Duh` is implemented for `i32`
-note: required because of the requirements on the impl of `Trait` for `[closure@$DIR/nested-return-type2-tait.rs:28:5: 28:10]`
-  --> $DIR/nested-return-type2-tait.rs:14:31
-   |
-LL | impl<R: Duh, F: FnMut() -> R> Trait for F {
-   |                               ^^^^^     ^
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0277`.
index b1175a5952e592a7a575da8413050c2e18f3d29f..3050f10b2057d05f5d1e8f03ae1267c4e2e1447d 100644 (file)
@@ -1,10 +1,13 @@
 error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/type_parameters_captured.rs:10:5
+  --> $DIR/type_parameters_captured.rs:9:5
    |
 LL |     x
-   |     ^
+   |     ^ ...so that the type `T` will meet its required lifetime bounds
    |
-   = help: consider adding an explicit lifetime bound `T: 'static`...
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn foo<T: 'static>(x: T) -> impl Any + 'static {
+   |         +++++++++
 
 error: aborting due to previous error
 
index bb9cab742a58f81bac9e25365b9a17b1e9058749..6c9c9d4a42af5a2a592fe62a3691aeb4f633a996 100644 (file)
@@ -6,7 +6,6 @@ impl<T> Any for T {}
 // Check that type parameters are captured and not considered 'static
 fn foo<T>(x: T) -> impl Any + 'static {
     //~^ ERROR the parameter type `T` may not live long enough
-    //~| ERROR the parameter type `T` may not live long enough
     x
 }
 
index c4ca34a6ed39b132148980921ab41588227d0df8..9f28a8d44a7b722551ff709fc0dfc374ccfe4333 100644 (file)
@@ -2,23 +2,13 @@ error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/type_parameters_captured.rs:7:20
    |
 LL | fn foo<T>(x: T) -> impl Any + 'static {
-   |        -           ^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
-   |        |
-   |        help: consider adding an explicit lifetime bound...: `T: 'static`
-
-error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/type_parameters_captured.rs:7:39
+   |                    ^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
    |
-LL |   fn foo<T>(x: T) -> impl Any + 'static {
-   |  ________-______________________________^
-   | |        |
-   | |        help: consider adding an explicit lifetime bound...: `T: 'static`
-LL | |
-LL | |
-LL | |     x
-LL | | }
-   | |_^ ...so that the type `T` will meet its required lifetime bounds
+LL | fn foo<T: 'static>(x: T) -> impl Any + 'static {
+   |         +++++++++
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0310`.
index d5a87b5d468340b3673d52c926b971597a9cc834..1a1210d00726d6bf1164f647ed4f8fbb78bbf2c5 100644 (file)
@@ -1,7 +1,6 @@
 use std::fmt::Debug;
 
-// check-pass
-
 fn in_adt_in_return() -> Vec<impl Debug> { panic!() }
+//~^ ERROR type annotations needed
 
 fn main() {}
diff --git a/src/test/ui/impl-trait/where-allowed-2.stderr b/src/test/ui/impl-trait/where-allowed-2.stderr
new file mode 100644 (file)
index 0000000..2b328c0
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0282]: type annotations needed
+  --> $DIR/where-allowed-2.rs:3:30
+   |
+LL | fn in_adt_in_return() -> Vec<impl Debug> { panic!() }
+   |                              ^^^^^^^^^^ cannot infer type
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
index e7d5fee18127fb54dd79b2c738acddd2f41a3134..9b822714f828a71a446fb169782482e6a0deb58c 100644 (file)
@@ -1,15 +1,9 @@
-error[E0284]: type annotations needed
-  --> $DIR/question-mark-type-infer.rs:10:21
+error[E0282]: type annotations needed
+  --> $DIR/question-mark-type-infer.rs:10:30
    |
 LL |     l.iter().map(f).collect()?
-   |                     ^^^^^^^ cannot infer type
-   |
-   = note: cannot satisfy `<_ as Try>::Residual == _`
-help: consider specifying the type argument in the method call
-   |
-LL |     l.iter().map(f).collect::<B>()?
-   |                            +++++
+   |                              ^ cannot infer type
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0284`.
+For more information about this error, try `rustc --explain E0282`.
index 26b2f9f2713118988be3b6db66c55bde479a9e80..5c3728ccdf84317cc9761ba22dfcb08f04402c0a 100644 (file)
@@ -1,4 +1,4 @@
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+error[E0133]: call to unsafe function `unchecked_add` is unsafe and requires unsafe function or block
   --> $DIR/unchecked_math_unsafe.rs:8:15
    |
 LL |     let add = std::intrinsics::unchecked_add(x, y);
@@ -6,7 +6,7 @@ LL |     let add = std::intrinsics::unchecked_add(x, y);
    |
    = note: consult the function's documentation for information on how to avoid undefined behavior
 
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+error[E0133]: call to unsafe function `unchecked_sub` is unsafe and requires unsafe function or block
   --> $DIR/unchecked_math_unsafe.rs:9:15
    |
 LL |     let sub = std::intrinsics::unchecked_sub(x, y);
@@ -14,7 +14,7 @@ LL |     let sub = std::intrinsics::unchecked_sub(x, y);
    |
    = note: consult the function's documentation for information on how to avoid undefined behavior
 
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+error[E0133]: call to unsafe function `unchecked_mul` is unsafe and requires unsafe function or block
   --> $DIR/unchecked_math_unsafe.rs:10:15
    |
 LL |     let mul = std::intrinsics::unchecked_mul(x, y);
index fde59f39b1cd9017e8ed309f4eb6d79bf3c6bea5..14b6c0f35812f8a3e0f67f85650ebccdaa866116 100644 (file)
@@ -1,6 +1,5 @@
 fn test_ref(x: &u32) -> impl std::future::Future<Output = u32> + '_ {
     //~^ ERROR `u32` is not a future
-    //~| ERROR `u32` is not a future
     *x
 }
 
index 63669c0513d6491c3c943bbf549ba7d05f19bd5d..ab72c3e41af97b80c72488c6b7d253fc77847261 100644 (file)
@@ -1,5 +1,5 @@
 error[E0425]: cannot find value `u` in this scope
-  --> $DIR/issues-71798.rs:8:24
+  --> $DIR/issues-71798.rs:7:24
    |
 LL |     let _ = test_ref & u;
    |                        ^ not found in this scope
@@ -13,21 +13,7 @@ LL | fn test_ref(x: &u32) -> impl std::future::Future<Output = u32> + '_ {
    = help: the trait `Future` is not implemented for `u32`
    = note: u32 must be a future or must implement `IntoFuture` to be awaited
 
-error[E0277]: `u32` is not a future
-  --> $DIR/issues-71798.rs:1:69
-   |
-LL |   fn test_ref(x: &u32) -> impl std::future::Future<Output = u32> + '_ {
-   |  _____________________________________________________________________^
-LL | |
-LL | |
-LL | |     *x
-LL | | }
-   | |_^ `u32` is not a future
-   |
-   = help: the trait `Future` is not implemented for `u32`
-   = note: u32 must be a future or must implement `IntoFuture` to be awaited
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 Some errors have detailed explanations: E0277, E0425.
 For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/issues/issue-16602-1.rs b/src/test/ui/issues/issue-16602-1.rs
deleted file mode 100644 (file)
index dd64ee7..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-// run-pass
-fn main() {
-    let mut t = [1; 2];
-    t = [t[1] * 2, t[0] * 2];
-    assert_eq!(&t[..], &[2, 2]);
-}
diff --git a/src/test/ui/issues/issue-16602-2.rs b/src/test/ui/issues/issue-16602-2.rs
deleted file mode 100644 (file)
index 6364630..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-// run-pass
-struct A {
-    pub x: u32,
-    pub y: u32,
-}
-
-fn main() {
-    let mut a = A { x: 1, y: 1 };
-    a = A { x: a.y * 2, y: a.x * 2 };
-    assert_eq!(a.x, 2);
-    assert_eq!(a.y, 2);
-}
diff --git a/src/test/ui/issues/issue-16602-3.rs b/src/test/ui/issues/issue-16602-3.rs
deleted file mode 100644 (file)
index dbfeef0..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-// run-pass
-#![allow(unused_variables)]
-#![allow(unused_assignments)]
-#[derive(Debug)]
-enum Foo {
-    Bar(u32, u32),
-    Baz(&'static u32, &'static u32)
-}
-
-static NUM: u32 = 100;
-
-fn main () {
-    let mut b = Foo::Baz(&NUM, &NUM);
-    b = Foo::Bar(f(&b), g(&b));
-}
-
-static FNUM: u32 = 1;
-
-fn f (b: &Foo) -> u32 {
-    FNUM
-}
-
-static GNUM: u32 = 2;
-
-fn g (b: &Foo) -> u32 {
-    GNUM
-}
index 7f4f5b22eb302cb77a3d187fd9241ea6b3441edb..9d9f32a97c065a0f29a86308087bfae20c36e374 100644 (file)
@@ -5,6 +5,11 @@ LL | fn foo<T: Any>(value: &T) -> Box<dyn Any> {
    |                       - let's call the lifetime of this reference `'1`
 LL |     Box::new(value) as Box<dyn Any>
    |     ^^^^^^^^^^^^^^^ cast requires that `'1` must outlive `'static`
+   |
+help: to declare that the trait object captures data from argument `value`, you can add an explicit `'_` lifetime bound
+   |
+LL | fn foo<T: Any>(value: &T) -> Box<dyn Any + '_> {
+   |                                          ++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-17233.rs b/src/test/ui/issues/issue-17233.rs
deleted file mode 100644 (file)
index 54a12fd..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-// run-pass
-
-const X1: &'static [u8] = &[b'1'];
-const X2: &'static [u8] = b"1";
-const X3: &'static [u8; 1] = &[b'1'];
-const X4: &'static [u8; 1] = b"1";
-
-static Y1: u8 = X1[0];
-static Y2: u8 = X2[0];
-static Y3: u8 = X3[0];
-static Y4: u8 = X4[0];
-
-fn main() {
-    assert_eq!(Y1, Y2);
-    assert_eq!(Y1, Y3);
-    assert_eq!(Y1, Y4);
-}
diff --git a/src/test/ui/issues/issue-1866.rs b/src/test/ui/issues/issue-1866.rs
deleted file mode 100644 (file)
index caac0c5..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-// build-pass
-#![allow(dead_code)]
-#![allow(non_camel_case_types)]
-#![warn(clashing_extern_declarations)]
-
-// pretty-expanded FIXME #23616
-
-mod a {
-    pub type rust_task = usize;
-    pub mod rustrt {
-        use super::rust_task;
-        extern "C" {
-            pub fn rust_task_is_unwinding(rt: *const rust_task) -> bool;
-        }
-    }
-}
-
-mod b {
-    pub type rust_task = bool;
-    pub mod rustrt {
-        use super::rust_task;
-        extern "C" {
-            pub fn rust_task_is_unwinding(rt: *const rust_task) -> bool;
-        //~^ WARN `rust_task_is_unwinding` redeclared with a different signature
-        }
-    }
-}
-
-pub fn main() {}
diff --git a/src/test/ui/issues/issue-1866.stderr b/src/test/ui/issues/issue-1866.stderr
deleted file mode 100644 (file)
index 5edae48..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-warning: `rust_task_is_unwinding` redeclared with a different signature
-  --> $DIR/issue-1866.rs:23:13
-   |
-LL |             pub fn rust_task_is_unwinding(rt: *const rust_task) -> bool;
-   |             ------------------------------------------------------------ `rust_task_is_unwinding` previously declared here
-...
-LL |             pub fn rust_task_is_unwinding(rt: *const rust_task) -> bool;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
-   |
-note: the lint level is defined here
-  --> $DIR/issue-1866.rs:4:9
-   |
-LL | #![warn(clashing_extern_declarations)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: expected `unsafe extern "C" fn(*const usize) -> bool`
-              found `unsafe extern "C" fn(*const bool) -> bool`
-
-warning: 1 warning emitted
-
diff --git a/src/test/ui/issues/issue-19081.rs b/src/test/ui/issues/issue-19081.rs
deleted file mode 100644 (file)
index fbfe4c6..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-// check-pass
-pub trait Hasher {
-    type State;
-
-    fn hash<T: Hash<
-        <Self as Hasher>::State
-    >>(&self, value: &T) -> u64;
-}
-
-pub trait Hash<S> {
-    fn hash(&self, state: &mut S);
-}
-
-fn main() {}
diff --git a/src/test/ui/issues/issue-19244.rs b/src/test/ui/issues/issue-19244.rs
deleted file mode 100644 (file)
index 44d9748..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-// run-pass
-
-struct MyStruct { field: usize }
-struct Nested { nested: MyStruct }
-struct Mix2 { nested: ((usize,),) }
-
-const STRUCT: MyStruct = MyStruct { field: 42 };
-const TUP: (usize,) = (43,);
-const NESTED_S: Nested = Nested { nested: MyStruct { field: 5 } };
-const NESTED_T: ((usize,),) = ((4,),);
-const MIX_1: ((Nested,),) = ((Nested { nested: MyStruct { field: 3 } },),);
-const MIX_2: Mix2 = Mix2 { nested: ((2,),) };
-const INSTANT_1: usize = (MyStruct { field: 1 }).field;
-const INSTANT_2: usize = (0,).0;
-
-fn main() {
-    let a = [0; STRUCT.field];
-    let b = [0; TUP.0];
-    let c = [0; NESTED_S.nested.field];
-    let d = [0; (NESTED_T.0).0];
-    let e = [0; (MIX_1.0).0.nested.field];
-    let f = [0; (MIX_2.nested.0).0];
-    let g = [0; INSTANT_1];
-    let h = [0; INSTANT_2];
-
-    assert_eq!(a.len(), 42);
-    assert_eq!(b.len(), 43);
-    assert_eq!(c.len(), 5);
-    assert_eq!(d.len(), 4);
-    assert_eq!(e.len(), 3);
-    assert_eq!(f.len(), 2);
-    assert_eq!(g.len(), 1);
-    assert_eq!(h.len(), 0);
-}
diff --git a/src/test/ui/issues/issue-19538.rs b/src/test/ui/issues/issue-19538.rs
deleted file mode 100644 (file)
index 7054ef4..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-trait Foo {
-    fn foo<T>(&self, val: T);
-}
-
-trait Bar: Foo { }
-
-pub struct Thing;
-
-impl Foo for Thing {
-    fn foo<T>(&self, val: T) { }
-}
-
-impl Bar for Thing { }
-
-fn main() {
-    let mut thing = Thing;
-    let test: &mut dyn Bar = &mut thing;
-    //~^ ERROR E0038
-    //~| ERROR E0038
-}
diff --git a/src/test/ui/issues/issue-19538.stderr b/src/test/ui/issues/issue-19538.stderr
deleted file mode 100644 (file)
index 7b37e1f..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-error[E0038]: the trait `Bar` cannot be made into an object
-  --> $DIR/issue-19538.rs:17:15
-   |
-LL |     let test: &mut dyn Bar = &mut thing;
-   |               ^^^^^^^^^^^^ `Bar` cannot be made into an object
-   |
-note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
-  --> $DIR/issue-19538.rs:2:8
-   |
-LL |     fn foo<T>(&self, val: T);
-   |        ^^^ ...because method `foo` has generic type parameters
-...
-LL | trait Bar: Foo { }
-   |       --- this trait cannot be made into an object...
-   = help: consider moving `foo` to another trait
-
-error[E0038]: the trait `Bar` cannot be made into an object
-  --> $DIR/issue-19538.rs:17:30
-   |
-LL |     let test: &mut dyn Bar = &mut thing;
-   |                              ^^^^^^^^^^ `Bar` cannot be made into an object
-   |
-note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
-  --> $DIR/issue-19538.rs:2:8
-   |
-LL |     fn foo<T>(&self, val: T);
-   |        ^^^ ...because method `foo` has generic type parameters
-...
-LL | trait Bar: Foo { }
-   |       --- this trait cannot be made into an object...
-   = help: consider moving `foo` to another trait
-   = note: required because of the requirements on the impl of `CoerceUnsized<&mut dyn Bar>` for `&mut Thing`
-   = note: required by cast to type `&mut dyn Bar`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0038`.
diff --git a/src/test/ui/issues/issue-20343.rs b/src/test/ui/issues/issue-20343.rs
deleted file mode 100644 (file)
index 000b639..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-// run-pass
-#![allow(unused_variables)]
-// Regression test for Issue #20343.
-
-// pretty-expanded FIXME #23616
-
-#![deny(dead_code)]
-
-struct B { b: u32 }
-struct C;
-struct D;
-
-trait T<A> { fn dummy(&self, a: A) { } }
-impl<A> T<A> for () {}
-
-impl B {
-    // test for unused code in arguments
-    fn foo(B { b }: B) -> u32 { b }
-
-    // test for unused code in return type
-    fn bar() -> C { unsafe { ::std::mem::transmute(()) } }
-
-    // test for unused code in generics
-    fn baz<A: T<D>>() {}
-}
-
-pub fn main() {
-    let b = B { b: 3 };
-    B::foo(b);
-    B::bar();
-    B::baz::<()>();
-}
diff --git a/src/test/ui/issues/issue-25339.rs b/src/test/ui/issues/issue-25339.rs
deleted file mode 100644 (file)
index 6f8ec70..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-// run-pass
-#![allow(dead_code)]
-#![allow(unused_variables)]
-#![feature(associated_type_defaults)]
-
-use std::marker::PhantomData;
-
-pub trait Routing<I> {
-    type Output;
-    fn resolve(&self, input: I);
-}
-
-pub trait ToRouting {
-    type Input;
-    type Routing : ?Sized = dyn Routing<Self::Input, Output=()>;
-    fn to_routing(self) -> Self::Routing;
-}
-
-pub struct Mount<I, R: Routing<I>> {
-    action: R,
-    _marker: PhantomData<I>
-}
-
-impl<I, R: Routing<I>> Mount<I, R> {
-    pub fn create<T: ToRouting<Routing=R>>(mount: &str, input: T) {
-        input.to_routing();
-    }
-}
-
-fn main() {
-}
diff --git a/src/test/ui/issues/issue-26545.rs b/src/test/ui/issues/issue-26545.rs
deleted file mode 100644 (file)
index 5652ee7..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-mod foo {
-    pub struct B(pub ());
-}
-
-mod baz {
-    fn foo() {
-        B(());
-        //~^ ERROR cannot find function, tuple struct or tuple variant `B` in this scope [E0425]
-    }
-}
-
-fn main() {}
diff --git a/src/test/ui/issues/issue-26545.stderr b/src/test/ui/issues/issue-26545.stderr
deleted file mode 100644 (file)
index d3c8669..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-error[E0425]: cannot find function, tuple struct or tuple variant `B` in this scope
-  --> $DIR/issue-26545.rs:7:9
-   |
-LL |         B(());
-   |         ^ not found in this scope
-   |
-help: consider importing this tuple struct
-   |
-LL |     use foo::B;
-   |
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0425`.
index 1d470fb5e0f00b41904244964b096fafb4954039..e3562810b3aa8f754424ee778615b3c09a7efd34 100644 (file)
@@ -1,4 +1,4 @@
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+error[E0133]: call to unsafe function `std::ptr::write` is unsafe and requires unsafe function or block
   --> $DIR/issue-28776.rs:7:5
    |
 LL |     (&ptr::write)(1 as *mut _, 42);
index 42d89cd01a48e8ed3ef8edcc9262dbbbd9986c45..c5d2ec0840996ac6afc42868ae0082c82226f913 100644 (file)
@@ -2,17 +2,17 @@ error[E0599]: no method named `x` found for fn item `fn() -> Ret {Obj::func}` in
   --> $DIR/issue-29124.rs:15:15
    |
 LL |     Obj::func.x();
-   |               ^ method not found in `fn() -> Ret {Obj::func}`
-   |
-   = note: `Obj::func` is a function, perhaps you wish to call it
+   |     --------- ^ method not found in `fn() -> Ret {Obj::func}`
+   |     |
+   |     this is a function, perhaps you wish to call it
 
 error[E0599]: no method named `x` found for fn item `fn() -> Ret {func}` in the current scope
   --> $DIR/issue-29124.rs:17:10
    |
 LL |     func.x();
-   |          ^ method not found in `fn() -> Ret {func}`
-   |
-   = note: `func` is a function, perhaps you wish to call it
+   |     ---- ^ method not found in `fn() -> Ret {func}`
+   |     |
+   |     this is a function, perhaps you wish to call it
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/issues/issue-29488.rs b/src/test/ui/issues/issue-29488.rs
deleted file mode 100644 (file)
index 3c9a6a8..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-// run-pass
-// ignore-emscripten no threads support
-
-use std::thread;
-
-struct Foo;
-
-impl Drop for Foo {
-    fn drop(&mut self) {
-        println!("test2");
-    }
-}
-
-thread_local!(static FOO: Foo = Foo);
-
-fn main() {
-    // Off the main thread due to #28129, be sure to initialize FOO first before
-    // calling `println!`
-    thread::spawn(|| {
-        FOO.with(|_| {});
-        println!("test1");
-    }).join().unwrap();
-}
index 813c1d3e2cccd9410c86a683bb6ec0b53533adbc..4cf634245be1b30cb7c693634dce3538dfe8a8b2 100644 (file)
@@ -5,6 +5,7 @@
 struct Test<'a> { s: &'a str }
 
 fn silly<'y, 'z>(_s: &'y Test<'z>) -> &'y <Test<'z> as Trait>::Out where 'z: 'static {
+    //~^ WARN unnecessary lifetime parameter `'z`
     let x = Test { s: "this cannot last" };
     &x
     //~^ ERROR: cannot return reference to local variable `x`
index 7c001088097ab54618608442b4772da575b36b7e..a7a5c0500fd236e753e93c1b12363a5a782b82b4 100644 (file)
@@ -1,9 +1,17 @@
+warning: unnecessary lifetime parameter `'z`
+  --> $DIR/issue-30438-c.rs:7:74
+   |
+LL | fn silly<'y, 'z>(_s: &'y Test<'z>) -> &'y <Test<'z> as Trait>::Out where 'z: 'static {
+   |                                                                          ^^
+   |
+   = help: you can use the `'static` lifetime directly, in place of `'z`
+
 error[E0515]: cannot return reference to local variable `x`
-  --> $DIR/issue-30438-c.rs:9:5
+  --> $DIR/issue-30438-c.rs:10:5
    |
 LL |     &x
    |     ^^ returns a reference to data owned by the current function
 
-error: aborting due to previous error
+error: aborting due to previous error; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0515`.
index f395c30b8155a54554e9d97e871e73c7b6529365..4d8acac61d9edc4817f5383de8e9ad355da3f388 100644 (file)
@@ -1,4 +1,4 @@
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+error[E0133]: call to unsafe function `X::with` is unsafe and requires unsafe function or block
   --> $DIR/issue-3080.rs:10:5
    |
 LL |     X(()).with();
index ed5addcbec5170497bc1577e716ad9138c0c5e75..112cb3359322383d564ee0659ab910ccaf6b3574 100644 (file)
@@ -7,7 +7,9 @@ LL |     Err(5)?;
    |           ^ the trait `From<{integer}>` is not implemented for `()`
    |
    = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
-   = help: the trait `FromResidual<Result<Infallible, E>>` is implemented for `Result<T, F>`
+   = help: the following other types implement trait `FromResidual<R>`:
+             <Result<T, F> as FromResidual<Result<Infallible, E>>>
+             <Result<T, F> as FromResidual<Yeet<E>>>
    = note: required because of the requirements on the impl of `FromResidual<Result<Infallible, {integer}>>` for `Result<i32, ()>`
 
 error: aborting due to previous error
diff --git a/src/test/ui/issues/issue-32963.rs b/src/test/ui/issues/issue-32963.rs
deleted file mode 100644 (file)
index 58055cd..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-use std::mem;
-
-trait Misc {}
-
-fn size_of_copy<T: Copy+?Sized>() -> usize { mem::size_of::<T>() }
-
-fn main() {
-    size_of_copy::<dyn Misc + Copy>();
-    //~^ ERROR only auto traits can be used as additional traits in a trait object
-    //~| ERROR only auto traits can be used as additional traits in a trait object
-    //~| ERROR the trait bound `dyn Misc: Copy` is not satisfied
-}
diff --git a/src/test/ui/issues/issue-32963.stderr b/src/test/ui/issues/issue-32963.stderr
deleted file mode 100644 (file)
index 5e7762b..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-error[E0225]: only auto traits can be used as additional traits in a trait object
-  --> $DIR/issue-32963.rs:8:31
-   |
-LL |     size_of_copy::<dyn Misc + Copy>();
-   |                        ----   ^^^^ additional non-auto trait
-   |                        |
-   |                        first non-auto trait
-   |
-   = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Misc + Copy {}`
-   = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
-
-error[E0225]: only auto traits can be used as additional traits in a trait object
-  --> $DIR/issue-32963.rs:8:31
-   |
-LL |     size_of_copy::<dyn Misc + Copy>();
-   |                        ----   ^^^^ additional non-auto trait
-   |                        |
-   |                        first non-auto trait
-   |
-   = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Misc + Copy {}`
-   = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
-
-error[E0277]: the trait bound `dyn Misc: Copy` is not satisfied
-  --> $DIR/issue-32963.rs:8:5
-   |
-LL |     size_of_copy::<dyn Misc + Copy>();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `dyn Misc`
-   |
-note: required by a bound in `size_of_copy`
-  --> $DIR/issue-32963.rs:5:20
-   |
-LL | fn size_of_copy<T: Copy+?Sized>() -> usize { mem::size_of::<T>() }
-   |                    ^^^^ required by this bound in `size_of_copy`
-
-error: aborting due to 3 previous errors
-
-Some errors have detailed explanations: E0225, E0277.
-For more information about an error, try `rustc --explain E0225`.
diff --git a/src/test/ui/issues/issue-35450.rs b/src/test/ui/issues/issue-35450.rs
deleted file mode 100644 (file)
index ac4c163..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-macro_rules! m { ($($t:tt)*) => { $($t)* } }
-
-fn main() {
-    m!($t); //~ ERROR expected expression
-}
diff --git a/src/test/ui/issues/issue-35450.stderr b/src/test/ui/issues/issue-35450.stderr
deleted file mode 100644 (file)
index f206568..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-error: expected expression, found `$`
-  --> $DIR/issue-35450.rs:4:8
-   |
-LL |     m!($t);
-   |        ^ expected expression
-
-error: aborting due to previous error
-
index 04faea9008a11b5ab15ea9131336d1bded9ced7a..07409e9834a4642a903373d3221ac5a89a31736c 100644 (file)
@@ -6,10 +6,10 @@ LL |     a.iter().map(|a| a*a)
    |                      |
    |                      &T
    |
-help: consider restricting type parameter `T`
+help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
    |
-LL | fn func<'a, T: std::ops::Mul<Output = &T>>(a: &'a [T]) -> impl Iterator<Item=&'a T> {
-   |              ++++++++++++++++++++++++++++
+LL | fn func<'a, T>(a: &'a [T]) -> impl Iterator<Item=&'a T> where &T: Mul<&T> {
+   |                                                         +++++++++++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-37323.rs b/src/test/ui/issues/issue-37323.rs
deleted file mode 100644 (file)
index 55f5c5a..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-// check-pass
-// compile-flags: -Zsave-analysis
-
-#![feature(rustc_attrs)]
-#![allow(warnings)]
-
-#[derive(Debug)]
-struct Point {
-}
-
-struct NestedA<'a, 'b> {
-    x: &'a NestedB<'b>
-}
-
-struct NestedB<'a> {
-    x: &'a i32,
-}
-
-fn main() {
-}
diff --git a/src/test/ui/issues/issue-3820.rs b/src/test/ui/issues/issue-3820.rs
deleted file mode 100644 (file)
index b987a90..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-struct Thing {
-    x: isize
-}
-
-impl Thing {
-    fn mul(&self, c: &isize) -> Thing {
-        Thing {x: self.x * *c}
-    }
-}
-
-fn main() {
-    let u = Thing {x: 2};
-    let _v = u.mul(&3); // This is ok
-    let w = u * 3; //~ ERROR cannot multiply `Thing` by `{integer}`
-}
diff --git a/src/test/ui/issues/issue-3820.stderr b/src/test/ui/issues/issue-3820.stderr
deleted file mode 100644 (file)
index d5c24e1..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-error[E0369]: cannot multiply `Thing` by `{integer}`
-  --> $DIR/issue-3820.rs:14:15
-   |
-LL |     let w = u * 3;
-   |             - ^ - {integer}
-   |             |
-   |             Thing
-   |
-note: an implementation of `Mul<_>` might be missing for `Thing`
-  --> $DIR/issue-3820.rs:1:1
-   |
-LL | struct Thing {
-   | ^^^^^^^^^^^^ must implement `Mul<_>`
-note: the following trait must be implemented
-  --> $SRC_DIR/core/src/ops/arith.rs:LL:COL
-   |
-LL | / pub trait Mul<Rhs = Self> {
-LL | |     /// The resulting type after applying the `*` operator.
-LL | |     #[stable(feature = "rust1", since = "1.0.0")]
-LL | |     type Output;
-...  |
-LL | |     fn mul(self, rhs: Rhs) -> Self::Output;
-LL | | }
-   | |_^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0369`.
diff --git a/src/test/ui/issues/issue-4107.rs b/src/test/ui/issues/issue-4107.rs
deleted file mode 100644 (file)
index 98433e8..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-// run-pass
-#![allow(dead_code)]
-
-pub fn main() {
-    let _id: &Mat2<f64> = &Matrix::identity(1.0);
-}
-
-pub trait Index<Index,Result> { fn get(&self, _: Index) -> Result { panic!() } }
-pub trait Dimensional<T>: Index<usize, T> { }
-
-pub struct Mat2<T> { x: T }
-pub struct Vec2<T> { x: T }
-
-impl<T> Dimensional<Vec2<T>> for Mat2<T> { }
-impl<T> Index<usize, Vec2<T>> for Mat2<T> { }
-
-impl<T> Dimensional<T> for Vec2<T> { }
-impl<T> Index<usize, T> for Vec2<T> { }
-
-pub trait Matrix<T,V>: Dimensional<V> {
-    fn identity(t:T) -> Self;
-}
-
-impl<T> Matrix<T, Vec2<T>> for Mat2<T> {
-    fn identity(t:T) -> Mat2<T> { Mat2{ x: t } }
-}
diff --git a/src/test/ui/issues/issue-41776.rs b/src/test/ui/issues/issue-41776.rs
deleted file mode 100644 (file)
index 24696d8..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-fn main() {
-    include!(line!()); //~ ERROR argument must be a string literal
-}
diff --git a/src/test/ui/issues/issue-41776.stderr b/src/test/ui/issues/issue-41776.stderr
deleted file mode 100644 (file)
index e06873b..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-error: argument must be a string literal
-  --> $DIR/issue-41776.rs:2:14
-   |
-LL |     include!(line!());
-   |              ^^^^^^^
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/issues/issue-43132.rs b/src/test/ui/issues/issue-43132.rs
deleted file mode 100644 (file)
index c886f4b..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-// run-pass
-#![allow(unused)]
-
-fn main() {
-}
-
-fn foo() {
-    let b = mk::<
-        Forward<(Box<dyn Future<Error = u32>>,)>,
-    >();
-    b.map_err(|_| ()).join();
-}
-
-fn mk<T>() -> T {
-    loop {}
-}
-
-impl<I: Future<Error = E>, E> Future for (I,) {
-    type Error = E;
-}
-
-struct Forward<T: Future> {
-    _a: T,
-}
-
-impl<T: Future> Future for Forward<T>
-where
-    T::Error: From<u32>,
-{
-    type Error = T::Error;
-}
-
-trait Future {
-    type Error;
-
-    fn map_err<F, E>(self, _: F) -> (Self, F)
-    where
-        F: FnOnce(Self::Error) -> E,
-        Self: Sized,
-    {
-        loop {}
-    }
-
-    fn join(self) -> (MaybeDone<Self>, ())
-    where
-        Self: Sized,
-    {
-        loop {}
-    }
-}
-
-impl<S: ?Sized + Future> Future for Box<S> {
-    type Error = S::Error;
-}
-
-enum MaybeDone<A: Future> {
-    _Done(A::Error),
-}
-
-impl<U, A: Future, F> Future for (A, F)
-where
-    F: FnOnce(A::Error) -> U,
-{
-    type Error = U;
-}
diff --git a/src/test/ui/issues/issue-44127.rs b/src/test/ui/issues/issue-44127.rs
deleted file mode 100644 (file)
index 21b2e68..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-// run-pass
-
-#![feature(decl_macro)]
-
-pub struct Foo {
-    bar: u32,
-}
-pub macro pattern($a:pat) {
-    Foo { bar: $a }
-}
-
-fn main() {
-    match (Foo { bar: 3 }) {
-        pattern!(3) => println!("Test OK"),
-        _ => unreachable!(),
-    }
-}
diff --git a/src/test/ui/issues/issue-45696-no-variant-box-recur.rs b/src/test/ui/issues/issue-45696-no-variant-box-recur.rs
deleted file mode 100644 (file)
index c688261..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-// rust-lang/rust#45696: This test checks the compiler won't infinite loop when
-// you declare a variable of type `struct A(Box<A>, ...);` (which is impossible
-// to construct but *is* possible to declare; see also issues #4287, #44933,
-// and #52852).
-//
-// We will explicitly test NLL, and migration modes; thus we will also skip the
-// automated compare-mode=nll.
-
-// run-pass
-
-// This test has structs and functions that are by definition unusable
-// all over the place, so just go ahead and allow dead_code
-#![allow(dead_code)]
-
-// direct regular recursion with indirect ownership via box
-struct C { field: Box<C> }
-
-// direct non-regular recursion with indirect ownership via box
-struct D { field: Box<(D, D)> }
-
-// indirect regular recursion with indirect ownership via box.
-struct E { field: F }
-struct F { field: Box<E> }
-
-// indirect non-regular recursion with indirect ownership via box.
-struct G { field: (H, H) }
-struct H { field: Box<G> }
-
-// These enums are cases that are not currently hit by the
-// `visit_terminator_drop` recursion down a type's structural
-// definition.
-//
-// But it seems prudent to include them in this test as variants on
-// the above, in that they are similarly non-constructable data types
-// with destructors that would diverge.
-enum I { One(Box<I>) }
-enum J { One(Box<J>), Two(Box<J>) }
-
-fn impossible_to_call_c(_c: C) { }
-fn impossible_to_call_d(_d: D) { }
-fn impossible_to_call_e(_e: E) { }
-fn impossible_to_call_f(_f: F) { }
-fn impossible_to_call_g(_g: G) { }
-fn impossible_to_call_h(_h: H) { }
-fn impossible_to_call_i(_i: I) { }
-fn impossible_to_call_j(_j: J) { }
-
-fn main() {
-
-}
diff --git a/src/test/ui/issues/issue-47706-trait.rs b/src/test/ui/issues/issue-47706-trait.rs
deleted file mode 100644 (file)
index 8fb4e08..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-trait T {
-    fn f(&self, _: ()) {
-        None::<()>.map(Self::f);
-    }
-    //~^^ ERROR function is expected to take a single 0-tuple as argument
-}
-
-fn main() {}
diff --git a/src/test/ui/issues/issue-47706-trait.stderr b/src/test/ui/issues/issue-47706-trait.stderr
deleted file mode 100644 (file)
index d596b4a..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-error[E0593]: function is expected to take a single 0-tuple as argument, but it takes 2 distinct arguments
-  --> $DIR/issue-47706-trait.rs:3:24
-   |
-LL |     fn f(&self, _: ()) {
-   |     ------------------ takes 2 distinct arguments
-LL |         None::<()>.map(Self::f);
-   |                    --- ^^^^^^^ expected function that takes a single 0-tuple as argument
-   |                    |
-   |                    required by a bound introduced by this call
-   |
-note: required by a bound in `Option::<T>::map`
-  --> $SRC_DIR/core/src/option.rs:LL:COL
-   |
-LL |         F: ~const FnOnce(T) -> U,
-   |            ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Option::<T>::map`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0593`.
diff --git a/src/test/ui/issues/issue-47706.rs b/src/test/ui/issues/issue-47706.rs
deleted file mode 100644 (file)
index f47c1e6..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-pub struct Foo {
-    foo: Option<i32>,
-}
-
-impl Foo {
-    pub fn new(foo: Option<i32>, _: ()) -> Foo {
-        Foo { foo }
-    }
-
-    pub fn map(self) -> Option<Foo> {
-        self.foo.map(Foo::new)
-    }
-    //~^^ ERROR function is expected to take 1 argument, but it takes 2 arguments [E0593]
-}
-
-enum Qux {
-    Bar(i32),
-}
-
-fn foo<F>(f: F)
-where
-    F: Fn(),
-{
-}
-
-fn main() {
-    foo(Qux::Bar);
-}
-//~^^ ERROR function is expected to take 0 arguments, but it takes 1 argument [E0593]
diff --git a/src/test/ui/issues/issue-47706.stderr b/src/test/ui/issues/issue-47706.stderr
deleted file mode 100644 (file)
index 0b4f84a..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-error[E0593]: function is expected to take 1 argument, but it takes 2 arguments
-  --> $DIR/issue-47706.rs:11:22
-   |
-LL |     pub fn new(foo: Option<i32>, _: ()) -> Foo {
-   |     ------------------------------------------ takes 2 arguments
-...
-LL |         self.foo.map(Foo::new)
-   |                  --- ^^^^^^^^ expected function that takes 1 argument
-   |                  |
-   |                  required by a bound introduced by this call
-   |
-note: required by a bound in `Option::<T>::map`
-  --> $SRC_DIR/core/src/option.rs:LL:COL
-   |
-LL |         F: ~const FnOnce(T) -> U,
-   |            ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Option::<T>::map`
-
-error[E0593]: function is expected to take 0 arguments, but it takes 1 argument
-  --> $DIR/issue-47706.rs:27:9
-   |
-LL |     Bar(i32),
-   |     -------- takes 1 argument
-...
-LL |     foo(Qux::Bar);
-   |     --- ^^^^^^^^ expected function that takes 0 arguments
-   |     |
-   |     required by a bound introduced by this call
-   |
-note: required by a bound in `foo`
-  --> $DIR/issue-47706.rs:22:8
-   |
-LL | fn foo<F>(f: F)
-   |    --- required by a bound in this
-LL | where
-LL |     F: Fn(),
-   |        ^^^^ required by this bound in `foo`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0593`.
diff --git a/src/test/ui/issues/issue-52213.nll.stderr b/src/test/ui/issues/issue-52213.nll.stderr
deleted file mode 100644 (file)
index da31bcd..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-error: lifetime may not live long enough
-  --> $DIR/issue-52213.rs:3:20
-   |
-LL | fn transmute_lifetime<'a, 'b, T>(t: &'a (T,)) -> &'b T {
-   |                       --  -- lifetime `'b` defined here
-   |                       |
-   |                       lifetime `'a` defined here
-LL |     match (&t,) {
-LL |         ((u,),) => u,
-   |                    ^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
-   |
-   = help: consider adding the following bound: `'a: 'b`
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/issues/issue-52213.rs b/src/test/ui/issues/issue-52213.rs
deleted file mode 100644 (file)
index c4ce494..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-fn transmute_lifetime<'a, 'b, T>(t: &'a (T,)) -> &'b T {
-    match (&t,) { //~ ERROR cannot infer an appropriate lifetime
-        ((u,),) => u,
-    }
-}
-
-fn main() {
-    let x = {
-        let y = Box::new((42,));
-        transmute_lifetime(&y)
-    };
-
-    println!("{}", x);
-}
diff --git a/src/test/ui/issues/issue-52213.stderr b/src/test/ui/issues/issue-52213.stderr
deleted file mode 100644 (file)
index aef5e25..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
-  --> $DIR/issue-52213.rs:2:11
-   |
-LL |     match (&t,) {
-   |           ^^^^^
-   |
-note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
-  --> $DIR/issue-52213.rs:1:23
-   |
-LL | fn transmute_lifetime<'a, 'b, T>(t: &'a (T,)) -> &'b T {
-   |                       ^^
-note: ...so that the types are compatible
-  --> $DIR/issue-52213.rs:2:11
-   |
-LL |     match (&t,) {
-   |           ^^^^^
-   = note: expected `(&&(T,),)`
-              found `(&&'a (T,),)`
-note: but, the lifetime must be valid for the lifetime `'b` as defined here...
-  --> $DIR/issue-52213.rs:1:27
-   |
-LL | fn transmute_lifetime<'a, 'b, T>(t: &'a (T,)) -> &'b T {
-   |                           ^^
-note: ...so that reference does not outlive borrowed content
-  --> $DIR/issue-52213.rs:3:20
-   |
-LL |         ((u,),) => u,
-   |                    ^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0495`.
diff --git a/src/test/ui/issues/issue-53692.rs b/src/test/ui/issues/issue-53692.rs
deleted file mode 100644 (file)
index 30f344e..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-fn main() {
-        let items = vec![1, 2, 3];
-        let ref_items: &[i32] = &items;
-        let items_clone: Vec<i32> = ref_items.clone();
-//~^ ERROR mismatched types
-
-        // in that case no suggestion will be triggered
-        let items_clone_2:Vec<i32> = items.clone();
-
-        let s = "hi";
-        let string: String = s.clone();
-//~^ ERROR mismatched types
-
-        // in that case no suggestion will be triggered
-        let s2 = "hi";
-        let string_2: String = s2.to_string();
-}
diff --git a/src/test/ui/issues/issue-53692.stderr b/src/test/ui/issues/issue-53692.stderr
deleted file mode 100644 (file)
index 09c78da..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-error[E0308]: mismatched types
-  --> $DIR/issue-53692.rs:4:37
-   |
-LL |         let items_clone: Vec<i32> = ref_items.clone();
-   |                          --------   ^^^^^^^^^^^^^^^^^
-   |                          |          |
-   |                          |          expected struct `Vec`, found `&[i32]`
-   |                          |          help: try using a conversion method: `ref_items.to_vec()`
-   |                          expected due to this
-   |
-   = note: expected struct `Vec<i32>`
-           found reference `&[i32]`
-
-error[E0308]: mismatched types
-  --> $DIR/issue-53692.rs:11:30
-   |
-LL |         let string: String = s.clone();
-   |                     ------   ^^^^^^^^^
-   |                     |        |
-   |                     |        expected struct `String`, found `&str`
-   |                     |        help: try using a conversion method: `s.to_string()`
-   |                     expected due to this
-
-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-55846.rs b/src/test/ui/issues/issue-55846.rs
deleted file mode 100644 (file)
index bd76675..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-// run-pass
-
-// Regression test for #55846, which once caused an ICE.
-
-use std::marker::PhantomData;
-
-struct Foo;
-
-struct Bar<A> {
-    a: PhantomData<A>,
-}
-
-impl Fooifier for Foo {
-    type Assoc = Foo;
-}
-
-trait Fooifier {
-    type Assoc;
-}
-
-trait Barifier<H> {
-    fn barify();
-}
-
-impl<H> Barifier<H> for Bar<H> {
-    fn barify() {
-        println!("All correct!");
-    }
-}
-
-impl Bar<<Foo as Fooifier>::Assoc> {
-    fn this_shouldnt_crash() {
-        <Self as Barifier<<Foo as Fooifier>::Assoc>>::barify();
-    }
-}
-
-fn main() {
-    Bar::<Foo>::this_shouldnt_crash();
-}
index 5c611cd43d3ccdf77c39e938c62ecceb778492e8..8e19f14009a0ea92e0498c5f81d2a1c0ff012fe2 100644 (file)
@@ -2,9 +2,10 @@ error[E0599]: no method named `f` found for fn pointer `fn(&u8)` in the current
   --> $DIR/issue-57362-1.rs:20:7
    |
 LL |     a.f();
-   |       ^ method not found in `fn(&u8)`
+   |     - ^ method not found in `fn(&u8)`
+   |     |
+   |     this is a function, perhaps you wish to call it
    |
-   = note: `a` is a function, perhaps you wish to call it
    = help: items from traits can only be used if the trait is implemented and in scope
 note: `Trait` defines an item `f`, perhaps you need to implement it
   --> $DIR/issue-57362-1.rs:8:1
index 6134d6889ff6cb7f2dbae943a469f935dc6f8747..310a2b593fe853c253b3a9653e5a404097d103d4 100644 (file)
@@ -1,4 +1,4 @@
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+error[E0133]: call to unsafe function `rand` is unsafe and requires unsafe function or block
   --> $DIR/issue-5844.rs:8:5
    |
 LL |     issue_5844_aux::rand();
diff --git a/src/test/ui/issues/issue-61858.rs b/src/test/ui/issues/issue-61858.rs
deleted file mode 100644 (file)
index 6c3b565..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-fn main() {
-    (if foobar) //~ ERROR expected `{`, found `)`
-}
diff --git a/src/test/ui/issues/issue-61858.stderr b/src/test/ui/issues/issue-61858.stderr
deleted file mode 100644 (file)
index 8b95d9c..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-error: expected `{`, found `)`
-  --> $DIR/issue-61858.rs:2:15
-   |
-LL |     (if foobar)
-   |      --       ^ expected `{`
-   |      |
-   |      this `if` expression has a condition, but no block
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/issues/issue-71036.rs b/src/test/ui/issues/issue-71036.rs
deleted file mode 100644 (file)
index 3d2df6f..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-#![feature(unsize, dispatch_from_dyn)]
-
-use std::marker::Unsize;
-use std::ops::DispatchFromDyn;
-
-#[allow(unused)]
-struct Foo<'a, T: ?Sized> {
-    _inner: &'a &'a T,
-}
-
-impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Foo<'a, U>> for Foo<'a, T> {}
-//~^ ERROR the trait bound `&'a T: Unsize<&'a U>` is not satisfied
-//~| NOTE the trait `Unsize<&'a U>` is not implemented for `&'a T`
-//~| NOTE all implementations of `Unsize` are provided automatically by the compiler
-//~| NOTE required because of the requirements on the impl
-
-fn main() {}
diff --git a/src/test/ui/issues/issue-71036.stderr b/src/test/ui/issues/issue-71036.stderr
deleted file mode 100644 (file)
index db1f694..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0277]: the trait bound `&'a T: Unsize<&'a U>` is not satisfied
-  --> $DIR/issue-71036.rs:11:1
-   |
-LL | impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Foo<'a, U>> for Foo<'a, T> {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Unsize<&'a U>` is not implemented for `&'a T`
-   |
-   = note: all implementations of `Unsize` are provided automatically by the compiler, see <https://doc.rust-lang.org/stable/std/marker/trait.Unsize.html> for more information
-   = note: required because of the requirements on the impl of `DispatchFromDyn<&'a &'a U>` for `&'a &'a T`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/issues/issue-72574-1.rs b/src/test/ui/issues/issue-72574-1.rs
deleted file mode 100644 (file)
index 1b80a21..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-fn main() {
-    let x = (1, 2, 3);
-    match x {
-        (_a, _x @ ..) => {}
-        _ => {}
-    }
-}
-//~^^^^ ERROR `_x @` is not allowed in a tuple
-//~| ERROR: `..` patterns are not allowed here
-//~| ERROR: mismatched types
diff --git a/src/test/ui/issues/issue-72574-1.stderr b/src/test/ui/issues/issue-72574-1.stderr
deleted file mode 100644 (file)
index 653869a..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-error: `_x @` is not allowed in a tuple
-  --> $DIR/issue-72574-1.rs:4:14
-   |
-LL |         (_a, _x @ ..) => {}
-   |              ^^^^^^^ this is only allowed in slice patterns
-   |
-   = help: remove this and bind each tuple field independently
-help: if you don't need to use the contents of _x, discard the tuple's remaining fields
-   |
-LL |         (_a, ..) => {}
-   |              ~~
-
-error: `..` patterns are not allowed here
-  --> $DIR/issue-72574-1.rs:4:19
-   |
-LL |         (_a, _x @ ..) => {}
-   |                   ^^
-   |
-   = note: only allowed in tuple, tuple struct, and slice patterns
-
-error[E0308]: mismatched types
-  --> $DIR/issue-72574-1.rs:4:9
-   |
-LL |     match x {
-   |           - this expression has type `({integer}, {integer}, {integer})`
-LL |         (_a, _x @ ..) => {}
-   |         ^^^^^^^^^^^^^ expected a tuple with 3 elements, found one with 2 elements
-   |
-   = note: expected tuple `({integer}, {integer}, {integer})`
-              found tuple `(_, _)`
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/issues/issue-73427.rs b/src/test/ui/issues/issue-73427.rs
deleted file mode 100644 (file)
index 3c62782..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-enum A {
-    StructWithFields { x: () },
-    TupleWithFields(()),
-    Struct {},
-    Tuple(),
-    Unit,
-}
-
-enum B {
-    StructWithFields { x: () },
-    TupleWithFields(()),
-}
-
-enum C {
-    StructWithFields { x: () },
-    TupleWithFields(()),
-    Unit,
-}
-
-enum D {
-    TupleWithFields(()),
-    Unit,
-}
-
-fn main() {
-    // Only variants without fields are suggested (and others mentioned in a note) where an enum
-    // is used rather than a variant.
-
-    A.foo();
-    //~^ ERROR expected value, found enum `A`
-    B.foo();
-    //~^ ERROR expected value, found enum `B`
-    C.foo();
-    //~^ ERROR expected value, found enum `C`
-    D.foo();
-    //~^ ERROR expected value, found enum `D`
-
-    // Only tuple variants are suggested in calls or tuple struct pattern matching.
-
-    let x = A(3);
-    //~^ ERROR expected function, tuple struct or tuple variant, found enum `A`
-    if let A(3) = x { }
-    //~^ ERROR expected tuple struct or tuple variant, found enum `A`
-}
diff --git a/src/test/ui/issues/issue-73427.stderr b/src/test/ui/issues/issue-73427.stderr
deleted file mode 100644 (file)
index 59bb98a..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-error[E0423]: expected value, found enum `A`
-  --> $DIR/issue-73427.rs:29:5
-   |
-LL |     A.foo();
-   |     ^
-   |
-note: the enum is defined here
-  --> $DIR/issue-73427.rs:1:1
-   |
-LL | / enum A {
-LL | |     StructWithFields { x: () },
-LL | |     TupleWithFields(()),
-LL | |     Struct {},
-LL | |     Tuple(),
-LL | |     Unit,
-LL | | }
-   | |_^
-help: you might have meant to use one of the following enum variants
-   |
-LL |     (A::Struct {}).foo();
-   |     ~~~~~~~~~~~~~~
-LL |     (A::Tuple()).foo();
-   |     ~~~~~~~~~~~~
-LL |     A::Unit.foo();
-   |     ~~~~~~~
-help: the following enum variants are available
-   |
-LL |     (A::StructWithFields { /* fields */ }).foo();
-   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-LL |     (A::TupleWithFields(/* fields */)).foo();
-   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-error[E0423]: expected value, found enum `B`
-  --> $DIR/issue-73427.rs:31:5
-   |
-LL |     B.foo();
-   |     ^
-   |
-note: the enum is defined here
-  --> $DIR/issue-73427.rs:9:1
-   |
-LL | / enum B {
-LL | |     StructWithFields { x: () },
-LL | |     TupleWithFields(()),
-LL | | }
-   | |_^
-help: the following enum variants are available
-   |
-LL |     (B::StructWithFields { /* fields */ }).foo();
-   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-LL |     (B::TupleWithFields(/* fields */)).foo();
-   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-error[E0423]: expected value, found enum `C`
-  --> $DIR/issue-73427.rs:33:5
-   |
-LL |     C.foo();
-   |     ^
-   |
-note: the enum is defined here
-  --> $DIR/issue-73427.rs:14:1
-   |
-LL | / enum C {
-LL | |     StructWithFields { x: () },
-LL | |     TupleWithFields(()),
-LL | |     Unit,
-LL | | }
-   | |_^
-help: you might have meant to use the following enum variant
-   |
-LL |     C::Unit.foo();
-   |     ~~~~~~~
-help: the following enum variants are available
-   |
-LL |     (C::StructWithFields { /* fields */ }).foo();
-   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-LL |     (C::TupleWithFields(/* fields */)).foo();
-   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-error[E0423]: expected value, found enum `D`
-  --> $DIR/issue-73427.rs:35:5
-   |
-LL |     D.foo();
-   |     ^
-   |
-note: the enum is defined here
-  --> $DIR/issue-73427.rs:20:1
-   |
-LL | / enum D {
-LL | |     TupleWithFields(()),
-LL | |     Unit,
-LL | | }
-   | |_^
-help: you might have meant to use the following enum variant
-   |
-LL |     D::Unit.foo();
-   |     ~~~~~~~
-help: the following enum variant is available
-   |
-LL |     (D::TupleWithFields(/* fields */)).foo();
-   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-error[E0423]: expected function, tuple struct or tuple variant, found enum `A`
-  --> $DIR/issue-73427.rs:40:13
-   |
-LL |     let x = A(3);
-   |             ^
-   |
-   = help: you might have meant to construct one of the enum's non-tuple variants
-note: the enum is defined here
-  --> $DIR/issue-73427.rs:1:1
-   |
-LL | / enum A {
-LL | |     StructWithFields { x: () },
-LL | |     TupleWithFields(()),
-LL | |     Struct {},
-LL | |     Tuple(),
-LL | |     Unit,
-LL | | }
-   | |_^
-help: try to construct one of the enum's variants
-   |
-LL |     let x = A::Tuple(3);
-   |             ~~~~~~~~
-LL |     let x = A::TupleWithFields(3);
-   |             ~~~~~~~~~~~~~~~~~~
-
-error[E0532]: expected tuple struct or tuple variant, found enum `A`
-  --> $DIR/issue-73427.rs:42:12
-   |
-LL |     if let A(3) = x { }
-   |            ^
-   |
-   = help: you might have meant to match against one of the enum's non-tuple variants
-note: the enum is defined here
-  --> $DIR/issue-73427.rs:1:1
-   |
-LL | / enum A {
-LL | |     StructWithFields { x: () },
-LL | |     TupleWithFields(()),
-LL | |     Struct {},
-LL | |     Tuple(),
-LL | |     Unit,
-LL | | }
-   | |_^
-help: try to match against one of the enum's variants
-   |
-LL |     if let A::Tuple(3) = x { }
-   |            ~~~~~~~~
-LL |     if let A::TupleWithFields(3) = x { }
-   |            ~~~~~~~~~~~~~~~~~~
-
-error: aborting due to 6 previous errors
-
-Some errors have detailed explanations: E0423, E0532.
-For more information about an error, try `rustc --explain E0423`.
diff --git a/src/test/ui/issues/issue-80512-param-reordering-with-defaults.rs b/src/test/ui/issues/issue-80512-param-reordering-with-defaults.rs
deleted file mode 100644 (file)
index fe3e4fb..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-#![crate_type = "lib"]
-
-struct S<T = (), 'a>(&'a T);
-//~^ ERROR lifetime parameters must be declared prior to type parameters
diff --git a/src/test/ui/issues/issue-80512-param-reordering-with-defaults.stderr b/src/test/ui/issues/issue-80512-param-reordering-with-defaults.stderr
deleted file mode 100644 (file)
index 119b1a0..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-error: lifetime parameters must be declared prior to type parameters
-  --> $DIR/issue-80512-param-reordering-with-defaults.rs:3:18
-   |
-LL | struct S<T = (), 'a>(&'a T);
-   |         ---------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, T = ()>`
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/iterators/collect-into-array.rs b/src/test/ui/iterators/collect-into-array.rs
new file mode 100644 (file)
index 0000000..a1144c8
--- /dev/null
@@ -0,0 +1,7 @@
+fn main() {
+    //~^ NOTE required by a bound in this
+    let whatever: [u32; 10] = (0..10).collect();
+    //~^ ERROR an array of type `[u32; 10]` cannot be built directly from an iterator
+    //~| NOTE try collecting into a `Vec<{integer}>`, then using `.try_into()`
+    //~| NOTE required by a bound in `collect`
+}
diff --git a/src/test/ui/iterators/collect-into-array.stderr b/src/test/ui/iterators/collect-into-array.stderr
new file mode 100644 (file)
index 0000000..7be53a4
--- /dev/null
@@ -0,0 +1,16 @@
+error[E0277]: an array of type `[u32; 10]` cannot be built directly from an iterator
+  --> $DIR/collect-into-array.rs:3:39
+   |
+LL |     let whatever: [u32; 10] = (0..10).collect();
+   |                                       ^^^^^^^ try collecting into a `Vec<{integer}>`, then using `.try_into()`
+   |
+   = help: the trait `FromIterator<{integer}>` is not implemented for `[u32; 10]`
+note: required by a bound in `collect`
+  --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+   |
+LL |     fn collect<B: FromIterator<Self::Item>>(self) -> B
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `collect`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
index 905752dec7478749119da406f960da1469203698..aafa6bc8b951476245a47f487237e96baa4dc2e8 100644 (file)
@@ -6,7 +6,7 @@ fn process_slice(data: &[i32]) {
 fn main() {
     let some_generated_vec = (0..10).collect();
     //~^ ERROR the size for values of type `[i32]` cannot be known at compilation time
-    //~| ERROR a value of type `[i32]` cannot be built since `[i32]` has no definite size
+    //~| ERROR a slice of type `[i32]` cannot be built since `[i32]` has no definite size
     //~| NOTE try explicitly collecting into a `Vec<{integer}>`
     //~| NOTE required by a bound in `collect`
     //~| NOTE all local variables must have a statically known size
index 521f239451d2f9913793f4488d3403cd26e1f2cb..4842e65fe976b205f05726c4ea876f55e273f460 100644 (file)
@@ -8,7 +8,7 @@ LL |     let some_generated_vec = (0..10).collect();
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
-error[E0277]: a value of type `[i32]` cannot be built since `[i32]` has no definite size
+error[E0277]: a slice of type `[i32]` cannot be built since `[i32]` has no definite size
   --> $DIR/collect-into-slice.rs:7:38
    |
 LL |     let some_generated_vec = (0..10).collect();
diff --git a/src/test/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.rs b/src/test/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.rs
new file mode 100644 (file)
index 0000000..89387e0
--- /dev/null
@@ -0,0 +1,54 @@
+// normalize-stderr-test "pref: Align \{\n *pow2: [1-3],\n *\}" -> "pref: $$PREF_ALIGN"
+#![crate_type = "lib"]
+#![feature(rustc_attrs)]
+
+use std::mem::MaybeUninit;
+
+enum HasNiche {
+    A,
+    B,
+    C,
+}
+
+// This should result in ScalarPair(Initialized, Union),
+// since the u8 payload will be uninit for `None`.
+#[rustc_layout(debug)]
+pub enum MissingPayloadField { //~ ERROR: layout_of
+    Some(u8),
+    None
+}
+
+// This should result in ScalarPair(Initialized, Initialized),
+// since the u8 field is present in all variants,
+// and hence will always be initialized.
+#[rustc_layout(debug)]
+pub enum CommonPayloadField { //~ ERROR: layout_of
+    A(u8),
+    B(u8),
+}
+
+// This should result in ScalarPair(Initialized, Union),
+// since, though a u8-sized field is present in all variants, it might be uninit.
+#[rustc_layout(debug)]
+pub enum CommonPayloadFieldIsMaybeUninit { //~ ERROR: layout_of
+    A(u8),
+    B(MaybeUninit<u8>),
+}
+
+// This should result in ScalarPair(Initialized, Union),
+// since only the niche field (used for the tag) is guaranteed to be initialized.
+#[rustc_layout(debug)]
+pub enum NicheFirst { //~ ERROR: layout_of
+    A(HasNiche, u8),
+    B,
+    C
+}
+
+// This should result in ScalarPair(Union, Initialized),
+// since only the niche field (used for the tag) is guaranteed to be initialized.
+#[rustc_layout(debug)]
+pub enum NicheSecond { //~ ERROR: layout_of
+    A(u8, HasNiche),
+    B,
+    C,
+}
diff --git a/src/test/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr b/src/test/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr
new file mode 100644 (file)
index 0000000..46187aa
--- /dev/null
@@ -0,0 +1,720 @@
+error: layout_of(MissingPayloadField) = Layout {
+           fields: Arbitrary {
+               offsets: [
+                   Size {
+                       raw: 0,
+                   },
+               ],
+               memory_index: [
+                   0,
+               ],
+           },
+           variants: Multiple {
+               tag: Initialized {
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+               tag_encoding: Direct,
+               tag_field: 0,
+               variants: [
+                   Layout {
+                       fields: Arbitrary {
+                           offsets: [
+                               Size {
+                                   raw: 1,
+                               },
+                           ],
+                           memory_index: [
+                               0,
+                           ],
+                       },
+                       variants: Single {
+                           index: 0,
+                       },
+                       abi: Aggregate {
+                           sized: true,
+                       },
+                       largest_niche: None,
+                       align: AbiAndPrefAlign {
+                           abi: Align {
+                               pow2: 0,
+                           },
+                           pref: $PREF_ALIGN,
+                       },
+                       size: Size {
+                           raw: 2,
+                       },
+                   },
+                   Layout {
+                       fields: Arbitrary {
+                           offsets: [],
+                           memory_index: [],
+                       },
+                       variants: Single {
+                           index: 1,
+                       },
+                       abi: Aggregate {
+                           sized: true,
+                       },
+                       largest_niche: None,
+                       align: AbiAndPrefAlign {
+                           abi: Align {
+                               pow2: 0,
+                           },
+                           pref: $PREF_ALIGN,
+                       },
+                       size: Size {
+                           raw: 1,
+                       },
+                   },
+               ],
+           },
+           abi: ScalarPair(
+               Initialized {
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+               Union {
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+               },
+           ),
+           largest_niche: Some(
+               Niche {
+                   offset: Size {
+                       raw: 0,
+                   },
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+           ),
+           align: AbiAndPrefAlign {
+               abi: Align {
+                   pow2: 0,
+               },
+               pref: $PREF_ALIGN,
+           },
+           size: Size {
+               raw: 2,
+           },
+       }
+  --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:16:1
+   |
+LL | / pub enum MissingPayloadField {
+LL | |     Some(u8),
+LL | |     None
+LL | | }
+   | |_^
+
+error: layout_of(CommonPayloadField) = Layout {
+           fields: Arbitrary {
+               offsets: [
+                   Size {
+                       raw: 0,
+                   },
+               ],
+               memory_index: [
+                   0,
+               ],
+           },
+           variants: Multiple {
+               tag: Initialized {
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+               tag_encoding: Direct,
+               tag_field: 0,
+               variants: [
+                   Layout {
+                       fields: Arbitrary {
+                           offsets: [
+                               Size {
+                                   raw: 1,
+                               },
+                           ],
+                           memory_index: [
+                               0,
+                           ],
+                       },
+                       variants: Single {
+                           index: 0,
+                       },
+                       abi: Aggregate {
+                           sized: true,
+                       },
+                       largest_niche: None,
+                       align: AbiAndPrefAlign {
+                           abi: Align {
+                               pow2: 0,
+                           },
+                           pref: $PREF_ALIGN,
+                       },
+                       size: Size {
+                           raw: 2,
+                       },
+                   },
+                   Layout {
+                       fields: Arbitrary {
+                           offsets: [
+                               Size {
+                                   raw: 1,
+                               },
+                           ],
+                           memory_index: [
+                               0,
+                           ],
+                       },
+                       variants: Single {
+                           index: 1,
+                       },
+                       abi: Aggregate {
+                           sized: true,
+                       },
+                       largest_niche: None,
+                       align: AbiAndPrefAlign {
+                           abi: Align {
+                               pow2: 0,
+                           },
+                           pref: $PREF_ALIGN,
+                       },
+                       size: Size {
+                           raw: 2,
+                       },
+                   },
+               ],
+           },
+           abi: ScalarPair(
+               Initialized {
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+               Initialized {
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+                   valid_range: 0..=255,
+               },
+           ),
+           largest_niche: Some(
+               Niche {
+                   offset: Size {
+                       raw: 0,
+                   },
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+           ),
+           align: AbiAndPrefAlign {
+               abi: Align {
+                   pow2: 0,
+               },
+               pref: $PREF_ALIGN,
+           },
+           size: Size {
+               raw: 2,
+           },
+       }
+  --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:25:1
+   |
+LL | / pub enum CommonPayloadField {
+LL | |     A(u8),
+LL | |     B(u8),
+LL | | }
+   | |_^
+
+error: layout_of(CommonPayloadFieldIsMaybeUninit) = Layout {
+           fields: Arbitrary {
+               offsets: [
+                   Size {
+                       raw: 0,
+                   },
+               ],
+               memory_index: [
+                   0,
+               ],
+           },
+           variants: Multiple {
+               tag: Initialized {
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+               tag_encoding: Direct,
+               tag_field: 0,
+               variants: [
+                   Layout {
+                       fields: Arbitrary {
+                           offsets: [
+                               Size {
+                                   raw: 1,
+                               },
+                           ],
+                           memory_index: [
+                               0,
+                           ],
+                       },
+                       variants: Single {
+                           index: 0,
+                       },
+                       abi: Aggregate {
+                           sized: true,
+                       },
+                       largest_niche: None,
+                       align: AbiAndPrefAlign {
+                           abi: Align {
+                               pow2: 0,
+                           },
+                           pref: $PREF_ALIGN,
+                       },
+                       size: Size {
+                           raw: 2,
+                       },
+                   },
+                   Layout {
+                       fields: Arbitrary {
+                           offsets: [
+                               Size {
+                                   raw: 1,
+                               },
+                           ],
+                           memory_index: [
+                               0,
+                           ],
+                       },
+                       variants: Single {
+                           index: 1,
+                       },
+                       abi: Aggregate {
+                           sized: true,
+                       },
+                       largest_niche: None,
+                       align: AbiAndPrefAlign {
+                           abi: Align {
+                               pow2: 0,
+                           },
+                           pref: $PREF_ALIGN,
+                       },
+                       size: Size {
+                           raw: 2,
+                       },
+                   },
+               ],
+           },
+           abi: ScalarPair(
+               Initialized {
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+               Union {
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+               },
+           ),
+           largest_niche: Some(
+               Niche {
+                   offset: Size {
+                       raw: 0,
+                   },
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+           ),
+           align: AbiAndPrefAlign {
+               abi: Align {
+                   pow2: 0,
+               },
+               pref: $PREF_ALIGN,
+           },
+           size: Size {
+               raw: 2,
+           },
+       }
+  --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:33:1
+   |
+LL | / pub enum CommonPayloadFieldIsMaybeUninit {
+LL | |     A(u8),
+LL | |     B(MaybeUninit<u8>),
+LL | | }
+   | |_^
+
+error: layout_of(NicheFirst) = Layout {
+           fields: Arbitrary {
+               offsets: [
+                   Size {
+                       raw: 0,
+                   },
+               ],
+               memory_index: [
+                   0,
+               ],
+           },
+           variants: Multiple {
+               tag: Initialized {
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+                   valid_range: 0..=4,
+               },
+               tag_encoding: Niche {
+                   dataful_variant: 0,
+                   niche_variants: 1..=2,
+                   niche_start: 3,
+               },
+               tag_field: 0,
+               variants: [
+                   Layout {
+                       fields: Arbitrary {
+                           offsets: [
+                               Size {
+                                   raw: 0,
+                               },
+                               Size {
+                                   raw: 1,
+                               },
+                           ],
+                           memory_index: [
+                               0,
+                               1,
+                           ],
+                       },
+                       variants: Single {
+                           index: 0,
+                       },
+                       abi: ScalarPair(
+                           Initialized {
+                               value: Int(
+                                   I8,
+                                   false,
+                               ),
+                               valid_range: 0..=2,
+                           },
+                           Initialized {
+                               value: Int(
+                                   I8,
+                                   false,
+                               ),
+                               valid_range: 0..=255,
+                           },
+                       ),
+                       largest_niche: Some(
+                           Niche {
+                               offset: Size {
+                                   raw: 0,
+                               },
+                               value: Int(
+                                   I8,
+                                   false,
+                               ),
+                               valid_range: 0..=2,
+                           },
+                       ),
+                       align: AbiAndPrefAlign {
+                           abi: Align {
+                               pow2: 0,
+                           },
+                           pref: $PREF_ALIGN,
+                       },
+                       size: Size {
+                           raw: 2,
+                       },
+                   },
+                   Layout {
+                       fields: Arbitrary {
+                           offsets: [],
+                           memory_index: [],
+                       },
+                       variants: Single {
+                           index: 1,
+                       },
+                       abi: Aggregate {
+                           sized: true,
+                       },
+                       largest_niche: None,
+                       align: AbiAndPrefAlign {
+                           abi: Align {
+                               pow2: 0,
+                           },
+                           pref: $PREF_ALIGN,
+                       },
+                       size: Size {
+                           raw: 0,
+                       },
+                   },
+                   Layout {
+                       fields: Arbitrary {
+                           offsets: [],
+                           memory_index: [],
+                       },
+                       variants: Single {
+                           index: 2,
+                       },
+                       abi: Aggregate {
+                           sized: true,
+                       },
+                       largest_niche: None,
+                       align: AbiAndPrefAlign {
+                           abi: Align {
+                               pow2: 0,
+                           },
+                           pref: $PREF_ALIGN,
+                       },
+                       size: Size {
+                           raw: 0,
+                       },
+                   },
+               ],
+           },
+           abi: ScalarPair(
+               Initialized {
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+                   valid_range: 0..=4,
+               },
+               Union {
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+               },
+           ),
+           largest_niche: Some(
+               Niche {
+                   offset: Size {
+                       raw: 0,
+                   },
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+                   valid_range: 0..=4,
+               },
+           ),
+           align: AbiAndPrefAlign {
+               abi: Align {
+                   pow2: 0,
+               },
+               pref: $PREF_ALIGN,
+           },
+           size: Size {
+               raw: 2,
+           },
+       }
+  --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:41:1
+   |
+LL | / pub enum NicheFirst {
+LL | |     A(HasNiche, u8),
+LL | |     B,
+LL | |     C
+LL | | }
+   | |_^
+
+error: layout_of(NicheSecond) = Layout {
+           fields: Arbitrary {
+               offsets: [
+                   Size {
+                       raw: 1,
+                   },
+               ],
+               memory_index: [
+                   0,
+               ],
+           },
+           variants: Multiple {
+               tag: Initialized {
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+                   valid_range: 0..=4,
+               },
+               tag_encoding: Niche {
+                   dataful_variant: 0,
+                   niche_variants: 1..=2,
+                   niche_start: 3,
+               },
+               tag_field: 0,
+               variants: [
+                   Layout {
+                       fields: Arbitrary {
+                           offsets: [
+                               Size {
+                                   raw: 0,
+                               },
+                               Size {
+                                   raw: 1,
+                               },
+                           ],
+                           memory_index: [
+                               0,
+                               1,
+                           ],
+                       },
+                       variants: Single {
+                           index: 0,
+                       },
+                       abi: ScalarPair(
+                           Initialized {
+                               value: Int(
+                                   I8,
+                                   false,
+                               ),
+                               valid_range: 0..=255,
+                           },
+                           Initialized {
+                               value: Int(
+                                   I8,
+                                   false,
+                               ),
+                               valid_range: 0..=2,
+                           },
+                       ),
+                       largest_niche: Some(
+                           Niche {
+                               offset: Size {
+                                   raw: 1,
+                               },
+                               value: Int(
+                                   I8,
+                                   false,
+                               ),
+                               valid_range: 0..=2,
+                           },
+                       ),
+                       align: AbiAndPrefAlign {
+                           abi: Align {
+                               pow2: 0,
+                           },
+                           pref: $PREF_ALIGN,
+                       },
+                       size: Size {
+                           raw: 2,
+                       },
+                   },
+                   Layout {
+                       fields: Arbitrary {
+                           offsets: [],
+                           memory_index: [],
+                       },
+                       variants: Single {
+                           index: 1,
+                       },
+                       abi: Aggregate {
+                           sized: true,
+                       },
+                       largest_niche: None,
+                       align: AbiAndPrefAlign {
+                           abi: Align {
+                               pow2: 0,
+                           },
+                           pref: $PREF_ALIGN,
+                       },
+                       size: Size {
+                           raw: 0,
+                       },
+                   },
+                   Layout {
+                       fields: Arbitrary {
+                           offsets: [],
+                           memory_index: [],
+                       },
+                       variants: Single {
+                           index: 2,
+                       },
+                       abi: Aggregate {
+                           sized: true,
+                       },
+                       largest_niche: None,
+                       align: AbiAndPrefAlign {
+                           abi: Align {
+                               pow2: 0,
+                           },
+                           pref: $PREF_ALIGN,
+                       },
+                       size: Size {
+                           raw: 0,
+                       },
+                   },
+               ],
+           },
+           abi: ScalarPair(
+               Union {
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+               },
+               Initialized {
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+                   valid_range: 0..=4,
+               },
+           ),
+           largest_niche: Some(
+               Niche {
+                   offset: Size {
+                       raw: 1,
+                   },
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+                   valid_range: 0..=4,
+               },
+           ),
+           align: AbiAndPrefAlign {
+               abi: Align {
+                   pow2: 0,
+               },
+               pref: $PREF_ALIGN,
+           },
+           size: Size {
+               raw: 2,
+           },
+       }
+  --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:50:1
+   |
+LL | / pub enum NicheSecond {
+LL | |     A(u8, HasNiche),
+LL | |     B,
+LL | |     C,
+LL | | }
+   | |_^
+
+error: aborting due to 5 previous errors
+
diff --git a/src/test/ui/lifetimes/copy_modulo_regions.rs b/src/test/ui/lifetimes/copy_modulo_regions.rs
new file mode 100644 (file)
index 0000000..1d5d90f
--- /dev/null
@@ -0,0 +1,19 @@
+#![feature(nll)]
+
+#[derive(Clone)]
+struct Foo<'a>(fn(&'a ()) -> &'a ());
+
+impl Copy for Foo<'static> {}
+
+fn mk_foo<'a>() -> Foo<'a> {
+    println!("mk_foo");
+    Foo(|x| x)
+}
+
+fn foo<'a>() -> [Foo<'a>; 100] {
+    [mk_foo::<'a>(); 100] //~ ERROR lifetime may not live long enough
+}
+
+fn main() {
+    foo();
+}
diff --git a/src/test/ui/lifetimes/copy_modulo_regions.stderr b/src/test/ui/lifetimes/copy_modulo_regions.stderr
new file mode 100644 (file)
index 0000000..e027bc4
--- /dev/null
@@ -0,0 +1,14 @@
+error: lifetime may not live long enough
+  --> $DIR/copy_modulo_regions.rs:14:5
+   |
+LL | fn foo<'a>() -> [Foo<'a>; 100] {
+   |        -- lifetime `'a` defined here
+LL |     [mk_foo::<'a>(); 100]
+   |     ^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
+   |
+   = note: requirement occurs because of the type `Foo<'_>`, which makes the generic argument `'_` invariant
+   = note: the struct `Foo<'a>` is invariant over the parameter `'a`
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lifetimes/elided-lifetime-in-path-in-impl-Fn.rs b/src/test/ui/lifetimes/elided-lifetime-in-path-in-impl-Fn.rs
new file mode 100644 (file)
index 0000000..9c9965d
--- /dev/null
@@ -0,0 +1,19 @@
+// check-pass
+
+struct Foo<'a>(&'a ());
+
+fn with_fn() -> fn(Foo) {
+    |_| ()
+}
+
+fn with_impl_fn() -> impl Fn(Foo) {
+    |_| ()
+}
+
+fn with_where_fn<T>()
+where
+    T: Fn(Foo),
+{
+}
+
+fn main() {}
index a5bc7450bbff075acde9234ba685ae230b3832b3..48fb3fb4a2293dc3fad82b9d52d826788bc9cfac 100644 (file)
@@ -6,6 +6,11 @@ LL | pub fn foo(x: &mut Vec<&u8>, y: &u8) { x.push(y); }
    |                        |        |
    |                        |        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
+   |
+LL | pub fn foo<'a>(x: &mut Vec<&'a u8>, y: &'a u8) { x.push(y); }
+   |           ++++              ++          ++
 
 error: lifetime may not live long enough
   --> $DIR/issue-90170-elision-mismatch.rs:5:44
@@ -15,6 +20,11 @@ LL | pub fn foo2(x: &mut Vec<&'_ u8>, y: &u8) { x.push(y); }
    |                         |           |
    |                         |           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
+   |
+LL | pub fn foo2<'a>(x: &mut Vec<&'a u8>, y: &'a u8) { x.push(y); }
+   |            ++++              ~~          ++
 
 error: lifetime may not live long enough
   --> $DIR/issue-90170-elision-mismatch.rs:7:63
@@ -24,6 +34,11 @@ LL | pub fn foo3<'a>(_other: &'a [u8], x: &mut Vec<&u8>, y: &u8) { x.push(y); }
    |                                               |        |
    |                                               |        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
+   |
+LL | pub fn foo3<'a>(_other: &'a [u8], x: &mut Vec<&'a u8>, y: &'a u8) { x.push(y); }
+   |                                                ++          ++
 
 error: aborting due to 3 previous errors
 
index e5083e3a088b6b53be9e6b1f8d8976d8c47d31b2..33f6c498b6f35ca2f97ebcd0c6aab1d3d7c7ae51 100644 (file)
@@ -1,18 +1,24 @@
 error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/lifetime-doesnt-live-long-enough.rs:19:10
    |
-LL | struct Foo<T> {
-   |            - help: consider adding an explicit lifetime bound...: `T: 'static`
 LL |     foo: &'static T
    |          ^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | struct Foo<T: 'static> {
+   |             +++++++++
 
 error[E0309]: the parameter type `K` may not live long enough
   --> $DIR/lifetime-doesnt-live-long-enough.rs:24:19
    |
-LL | trait X<K>: Sized {
-   |         - help: consider adding an explicit lifetime bound...: `K: 'a`
 LL |     fn foo<'a, L: X<&'a Nested<K>>>();
    |                   ^^^^^^^^^^^^^^^^ ...so that the reference type `&'a Nested<K>` does not outlive the data it points at
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | trait X<K: 'a>: Sized {
+   |          ++++
 
 error[E0309]: the parameter type `Self` may not live long enough
   --> $DIR/lifetime-doesnt-live-long-enough.rs:28:19
@@ -27,25 +33,34 @@ error[E0309]: the parameter type `L` may not live long enough
   --> $DIR/lifetime-doesnt-live-long-enough.rs:32:22
    |
 LL |     fn baz<'a, L, M: X<&'a Nested<L>>>() {
-   |                -     ^^^^^^^^^^^^^^^^ ...so that the reference type `&'a Nested<L>` does not outlive the data it points at
-   |                |
-   |                help: consider adding an explicit lifetime bound...: `L: 'a`
+   |                      ^^^^^^^^^^^^^^^^ ...so that the reference type `&'a Nested<L>` does not outlive the data it points at
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL |     fn baz<'a, L: 'a, M: X<&'a Nested<L>>>() {
+   |                 ++++
 
 error[E0309]: the parameter type `K` may not live long enough
   --> $DIR/lifetime-doesnt-live-long-enough.rs:41:33
    |
-LL | impl<K> Nested<K> {
-   |      - help: consider adding an explicit lifetime bound...: `K: 'a`
 LL |     fn generic_in_parent<'a, L: X<&'a Nested<K>>>() {
    |                                 ^^^^^^^^^^^^^^^^ ...so that the reference type `&'a Nested<K>` does not outlive the data it points at
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | impl<K: 'a> Nested<K> {
+   |       ++++
 
 error[E0309]: the parameter type `M` may not live long enough
   --> $DIR/lifetime-doesnt-live-long-enough.rs:44:36
    |
 LL |     fn generic_in_child<'a, 'b, L: X<&'a Nested<M>>, M: 'b>() {
-   |                                    ^^^^^^^^^^^^^^^^  -- help: consider adding an explicit lifetime bound...: `M: 'a +`
-   |                                    |
-   |                                    ...so that the reference type `&'a Nested<M>` does not outlive the data it points at
+   |                                    ^^^^^^^^^^^^^^^^ ...so that the reference type `&'a Nested<M>` does not outlive the data it points at
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL |     fn generic_in_child<'a, 'b, L: X<&'a Nested<M>>, M: 'b + 'a>() {
+   |                                                            ++++
 
 error: aborting due to 6 previous errors
 
index 133679f30f8fb4435a1177c8a1346f311191dc2f..5168cb20d9ec423a1298b5c6eb6accbf205dcb85 100644 (file)
@@ -7,7 +7,6 @@ trait Future {
 
 fn foo() -> impl Future<Item=(), Error=Box<dyn Error>> {
     //~^ ERROR not satisfied
-    //~| ERROR not satisfied
     Ok(())
 }
 
index a3badd7b25add4ab77032aa9862000749917d917..ef1127c59ac4cfee3380c9a506f1b5916723a07b 100644 (file)
@@ -4,17 +4,6 @@ error[E0277]: the trait bound `Result<(), _>: Future` is not satisfied
 LL | fn foo() -> impl Future<Item=(), Error=Box<dyn Error>> {
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Future` is not implemented for `Result<(), _>`
 
-error[E0277]: the trait bound `Result<(), _>: Future` is not satisfied
-  --> $DIR/lifetime-elision-return-type-trait.rs:8:56
-   |
-LL |   fn foo() -> impl Future<Item=(), Error=Box<dyn Error>> {
-   |  ________________________________________________________^
-LL | |
-LL | |
-LL | |     Ok(())
-LL | | }
-   | |_^ the trait `Future` is not implemented for `Result<(), _>`
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0277`.
index a94f9a799061a194c92e317c00feb577774cce86..5a23f1e0e9d99956fd57a25aafa77170e7dae2ba 100644 (file)
@@ -7,6 +7,11 @@ LL | fn foo(&mut (ref mut v, w): &mut (&u8, &u8), x: &u8) {
    |                                   let's call the lifetime of this reference `'2`
 LL |     *v = x;
    |     ^^^^^^ assignment requires that `'1` must outlive `'2`
+   |
+help: consider introducing a named lifetime parameter
+   |
+LL | fn foo<'a>(&mut (ref mut v, w): &mut (&'a u8, &u8), x: &'a u8) {
+   |       ++++                             ++               ++
 
 error: aborting due to previous error
 
index 2ed4d6d4401aa194c4b1e2f6b5731dc479a25cf9..6ba130308a33a82e6bb4938a2b313b41ed6ee60f 100644 (file)
@@ -7,6 +7,11 @@ LL | fn foo(z: &mut Vec<(&u8,&u8)>, (x, y): (&u8, &u8)) {
    |                     let's call the lifetime of this reference `'2`
 LL |     z.push((x,y));
    |     ^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2`
+   |
+help: consider introducing a named lifetime parameter
+   |
+LL | fn foo<'a>(z: &mut Vec<(&'a u8,&u8)>, (x, y): (&'a u8, &u8)) {
+   |       ++++               ++                     ++
 
 error: lifetime may not live long enough
   --> $DIR/ex3-both-anon-regions-3.rs:2:5
@@ -17,6 +22,11 @@ LL | fn foo(z: &mut Vec<(&u8,&u8)>, (x, y): (&u8, &u8)) {
    |                         let's call the lifetime of this reference `'4`
 LL |     z.push((x,y));
    |     ^^^^^^^^^^^^^ argument requires that `'3` must outlive `'4`
+   |
+help: consider introducing a named lifetime parameter
+   |
+LL | fn foo<'a>(z: &mut Vec<(&u8,&'a u8)>, (x, y): (&u8, &'a u8)) {
+   |       ++++                   ++                      ++
 
 error: aborting due to 2 previous errors
 
index 1a19e81f235ba5c984e9eb62d1aae52c11b2c08b..5601335d275c33106472fafc4c90ed3edfaac078 100644 (file)
@@ -7,6 +7,11 @@ LL |   fn foo<'a>(&self, x: &i32) -> &i32 {
    |              let's call the lifetime of this reference `'2`
 LL |     x
    |     ^ 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 |   fn foo<'a>(&'a self, x: &'a i32) -> &i32 {
+   |               ++           ++
 
 error: aborting due to previous error
 
index 87b13dc15914bf7dedf86d39bd37b6493add6a5f..e221902c4a90724e2a41a6937c647be780dcafce 100644 (file)
@@ -7,6 +7,11 @@ LL |     fn foo<'a>(&self, x: &Foo) -> &Foo {
    |                let's call the lifetime of this reference `'2`
 LL |         if true { x } else { self }
    |                   ^ 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 |     fn foo<'a>(&'a self, x: &'a Foo) -> &Foo {
+   |                 ++           ++
 
 error: aborting due to previous error
 
index 825c45b2434411e5b34e6fcdcad6c136b1af1ece..a909c5fa82351ddb2d59dfc4aaf49b5cfc032b8b 100644 (file)
@@ -7,6 +7,11 @@ LL | fn foo(x:fn(&u8, &u8), y: Vec<&u8>, z: &u8) {
    |                               let's call the lifetime of this reference `'2`
 LL |   y.push(z);
    |   ^^^^^^^^^ argument requires that `'1` must outlive `'2`
+   |
+help: consider introducing a named lifetime parameter
+   |
+LL | fn foo<'a>(x:fn(&u8, &u8), y: Vec<&'a u8>, z: &'a u8) {
+   |       ++++                         ++          ++
 
 error[E0596]: cannot borrow `y` as mutable, as it is not declared as mutable
   --> $DIR/ex3-both-anon-regions-using-fn-items.rs:2:3
index f3502674849ef474447f01ed5fc0105974230bdb..9661f1e5144b4b30ccef905f5ecddf9c4305498a 100644 (file)
@@ -7,6 +7,11 @@ LL |     fn foo(x: &mut Vec<&u8>, y: &u8) {
    |                        let's call the lifetime of this reference `'2`
 LL |         x.push(y);
    |         ^^^^^^^^^ argument requires that `'1` must outlive `'2`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     fn foo<'a>(x: &mut Vec<&'a u8>, y: &'a u8) {
+   |           ++++              ++          ++
 
 error: aborting due to previous error
 
index 78a828dde866ff245170947a777750bda0b2f282..cce0a31bfbbf1adc65c7be3ba2b9f49f1cad2463 100644 (file)
@@ -7,6 +7,11 @@ LL | fn foo(x:Box<dyn Fn(&u8, &u8)> , y: Vec<&u8>, z: &u8) {
    |                                         let's call the lifetime of this reference `'2`
 LL |   y.push(z);
    |   ^^^^^^^^^ argument requires that `'1` must outlive `'2`
+   |
+help: consider introducing a named lifetime parameter
+   |
+LL | fn foo<'a>(x:Box<dyn Fn(&'a u8, &'a u8)> , y: Vec<&u8>, z: &u8) {
+   |       ++++               ++      ++
 
 error[E0596]: cannot borrow `y` as mutable, as it is not declared as mutable
   --> $DIR/ex3-both-anon-regions-using-trait-objects.rs:2:3
index 6989acfa1963bce2c239ff5c274ac2d0ecaef0fb..ec9fac0c288e06a76e3d3609069e763754a78150 100644 (file)
@@ -7,6 +7,11 @@ LL | fn foo(x: &mut Vec<&u8>, y: &u8) {
    |                    let's call the lifetime of this reference `'2`
 LL |     x.push(y);
    |     ^^^^^^^^^ argument requires that `'1` must outlive `'2`
+   |
+help: consider introducing a named lifetime parameter
+   |
+LL | fn foo<'a>(x: &mut Vec<&'a u8>, y: &'a u8) {
+   |       ++++              ++          ++
 
 error: aborting due to previous error
 
index 5509226cb1cdd83c5c8eebcc6cae3673e52a9e53..2906c05864bae896970016b21481061568586408 100644 (file)
@@ -2,9 +2,12 @@ error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/issue_74400.rs:12:5
    |
 LL |     f(data, identity)
-   |     ^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
    |
-   = help: consider adding an explicit lifetime bound `T: 'static`...
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn g<T: 'static>(data: &[T]) {
+   |       +++++++++
 
 error[E0308]: mismatched types
   --> $DIR/issue_74400.rs:12:5
diff --git a/src/test/ui/lint/issue-1866.rs b/src/test/ui/lint/issue-1866.rs
new file mode 100644 (file)
index 0000000..caac0c5
--- /dev/null
@@ -0,0 +1,29 @@
+// build-pass
+#![allow(dead_code)]
+#![allow(non_camel_case_types)]
+#![warn(clashing_extern_declarations)]
+
+// pretty-expanded FIXME #23616
+
+mod a {
+    pub type rust_task = usize;
+    pub mod rustrt {
+        use super::rust_task;
+        extern "C" {
+            pub fn rust_task_is_unwinding(rt: *const rust_task) -> bool;
+        }
+    }
+}
+
+mod b {
+    pub type rust_task = bool;
+    pub mod rustrt {
+        use super::rust_task;
+        extern "C" {
+            pub fn rust_task_is_unwinding(rt: *const rust_task) -> bool;
+        //~^ WARN `rust_task_is_unwinding` redeclared with a different signature
+        }
+    }
+}
+
+pub fn main() {}
diff --git a/src/test/ui/lint/issue-1866.stderr b/src/test/ui/lint/issue-1866.stderr
new file mode 100644 (file)
index 0000000..5edae48
--- /dev/null
@@ -0,0 +1,19 @@
+warning: `rust_task_is_unwinding` redeclared with a different signature
+  --> $DIR/issue-1866.rs:23:13
+   |
+LL |             pub fn rust_task_is_unwinding(rt: *const rust_task) -> bool;
+   |             ------------------------------------------------------------ `rust_task_is_unwinding` previously declared here
+...
+LL |             pub fn rust_task_is_unwinding(rt: *const rust_task) -> bool;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+   |
+note: the lint level is defined here
+  --> $DIR/issue-1866.rs:4:9
+   |
+LL | #![warn(clashing_extern_declarations)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: expected `unsafe extern "C" fn(*const usize) -> bool`
+              found `unsafe extern "C" fn(*const bool) -> bool`
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/lint/issue-20343.rs b/src/test/ui/lint/issue-20343.rs
new file mode 100644 (file)
index 0000000..000b639
--- /dev/null
@@ -0,0 +1,32 @@
+// run-pass
+#![allow(unused_variables)]
+// Regression test for Issue #20343.
+
+// pretty-expanded FIXME #23616
+
+#![deny(dead_code)]
+
+struct B { b: u32 }
+struct C;
+struct D;
+
+trait T<A> { fn dummy(&self, a: A) { } }
+impl<A> T<A> for () {}
+
+impl B {
+    // test for unused code in arguments
+    fn foo(B { b }: B) -> u32 { b }
+
+    // test for unused code in return type
+    fn bar() -> C { unsafe { ::std::mem::transmute(()) } }
+
+    // test for unused code in generics
+    fn baz<A: T<D>>() {}
+}
+
+pub fn main() {
+    let b = B { b: 3 };
+    B::foo(b);
+    B::bar();
+    B::baz::<()>();
+}
index 27c31c22311ab7736f1f5aea7a1debc7156dc271..4dc951985ae4d14a398d223b9ade6a4eb71f9bfb 100644 (file)
@@ -26,6 +26,11 @@ impl Hydrogen {
         pub fn count_neutrons(&self) -> usize { self.neutrons } //~ WARNING unreachable_pub
         pub(crate) fn count_electrons(&self) -> usize { self.electrons }
     }
+    impl Clone for Hydrogen {
+        fn clone(&self) -> Hydrogen {
+            Hydrogen { neutrons: self.neutrons, electrons: self.electrons }
+        }
+    }
 
     pub enum Helium {} //~ WARNING unreachable_pub
     pub union Lithium { c1: usize, c2: u8 } //~ WARNING unreachable_pub
index f284db80ff90fcce1bddbfeec401b80791bfdaca..6c05a030138bc04bdd72ba4b85eccc720a7d3e1f 100644 (file)
@@ -50,7 +50,7 @@ LL |         pub fn count_neutrons(&self) -> usize { self.neutrons }
    |         help: consider restricting its visibility: `pub(crate)`
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub-pub_crate.rs:30:5
+  --> $DIR/unreachable_pub-pub_crate.rs:35:5
    |
 LL |     pub enum Helium {}
    |     ---^^^^^^^^^^^^
@@ -60,7 +60,7 @@ LL |     pub enum Helium {}
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub-pub_crate.rs:31:5
+  --> $DIR/unreachable_pub-pub_crate.rs:36:5
    |
 LL |     pub union Lithium { c1: usize, c2: u8 }
    |     ---^^^^^^^^^^^^^^
@@ -70,7 +70,7 @@ LL |     pub union Lithium { c1: usize, c2: u8 }
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub-pub_crate.rs:32:5
+  --> $DIR/unreachable_pub-pub_crate.rs:37:5
    |
 LL |     pub fn beryllium() {}
    |     ---^^^^^^^^^^^^^^^
@@ -80,7 +80,7 @@ LL |     pub fn beryllium() {}
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub-pub_crate.rs:33:5
+  --> $DIR/unreachable_pub-pub_crate.rs:38:5
    |
 LL |     pub trait Boron {}
    |     ---^^^^^^^^^^^^
@@ -90,7 +90,7 @@ LL |     pub trait Boron {}
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub-pub_crate.rs:34:5
+  --> $DIR/unreachable_pub-pub_crate.rs:39:5
    |
 LL |     pub const CARBON: usize = 1;
    |     ---^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -100,7 +100,7 @@ LL |     pub const CARBON: usize = 1;
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub-pub_crate.rs:35:5
+  --> $DIR/unreachable_pub-pub_crate.rs:40:5
    |
 LL |     pub static NITROGEN: usize = 2;
    |     ---^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -110,7 +110,7 @@ LL |     pub static NITROGEN: usize = 2;
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub-pub_crate.rs:36:5
+  --> $DIR/unreachable_pub-pub_crate.rs:41:5
    |
 LL |     pub type Oxygen = bool;
    |     ---^^^^^^^^^^^^^^^^^^^^
@@ -120,7 +120,7 @@ LL |     pub type Oxygen = bool;
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub-pub_crate.rs:39:47
+  --> $DIR/unreachable_pub-pub_crate.rs:44:47
    |
 LL |         ($visibility: vis, $name: ident) => { $visibility struct $name {} }
    |                                               ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -135,7 +135,7 @@ LL |     define_empty_struct_with_visibility!(pub, Fluorine);
    = note: this warning originates in the macro `define_empty_struct_with_visibility` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub-pub_crate.rs:45:9
+  --> $DIR/unreachable_pub-pub_crate.rs:50:9
    |
 LL |         pub fn catalyze() -> bool;
    |         ---^^^^^^^^^^^^^^^^^^^^^^^
index 6bfec0ec5e8b04ef73456a6352f67a3c1180f98c..39e2b5961563087de4d246cdcf8234d19609002d 100644 (file)
@@ -22,6 +22,11 @@ impl Hydrogen {
         pub fn count_neutrons(&self) -> usize { self.neutrons } //~ WARNING unreachable_pub
         crate fn count_electrons(&self) -> usize { self.electrons }
     }
+    impl Clone for Hydrogen {
+        fn clone(&self) -> Hydrogen {
+            Hydrogen { neutrons: self.neutrons, electrons: self.electrons }
+        }
+    }
 
     pub enum Helium {} //~ WARNING unreachable_pub
     pub union Lithium { c1: usize, c2: u8 } //~ WARNING unreachable_pub
index 61c9582287c015ff13372a40eb6e8eee8c59adb8..e8e55be5a478007c9f5b22373203f9820daa20cc 100644 (file)
@@ -50,7 +50,7 @@ LL |         pub fn count_neutrons(&self) -> usize { self.neutrons }
    |         help: consider restricting its visibility: `crate`
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub.rs:26:5
+  --> $DIR/unreachable_pub.rs:31:5
    |
 LL |     pub enum Helium {}
    |     ---^^^^^^^^^^^^
@@ -60,7 +60,7 @@ LL |     pub enum Helium {}
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub.rs:27:5
+  --> $DIR/unreachable_pub.rs:32:5
    |
 LL |     pub union Lithium { c1: usize, c2: u8 }
    |     ---^^^^^^^^^^^^^^
@@ -70,7 +70,7 @@ LL |     pub union Lithium { c1: usize, c2: u8 }
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub.rs:28:5
+  --> $DIR/unreachable_pub.rs:33:5
    |
 LL |     pub fn beryllium() {}
    |     ---^^^^^^^^^^^^^^^
@@ -80,7 +80,7 @@ LL |     pub fn beryllium() {}
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub.rs:29:5
+  --> $DIR/unreachable_pub.rs:34:5
    |
 LL |     pub trait Boron {}
    |     ---^^^^^^^^^^^^
@@ -90,7 +90,7 @@ LL |     pub trait Boron {}
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub.rs:30:5
+  --> $DIR/unreachable_pub.rs:35:5
    |
 LL |     pub const CARBON: usize = 1;
    |     ---^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -100,7 +100,7 @@ LL |     pub const CARBON: usize = 1;
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub.rs:31:5
+  --> $DIR/unreachable_pub.rs:36:5
    |
 LL |     pub static NITROGEN: usize = 2;
    |     ---^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -110,7 +110,7 @@ LL |     pub static NITROGEN: usize = 2;
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub.rs:32:5
+  --> $DIR/unreachable_pub.rs:37:5
    |
 LL |     pub type Oxygen = bool;
    |     ---^^^^^^^^^^^^^^^^^^^^
@@ -120,7 +120,7 @@ LL |     pub type Oxygen = bool;
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub.rs:35:47
+  --> $DIR/unreachable_pub.rs:40:47
    |
 LL |         ($visibility: vis, $name: ident) => { $visibility struct $name {} }
    |                                               ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -135,7 +135,7 @@ LL |     define_empty_struct_with_visibility!(pub, Fluorine);
    = note: this warning originates in the macro `define_empty_struct_with_visibility` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub.rs:41:9
+  --> $DIR/unreachable_pub.rs:46:9
    |
 LL |         pub fn catalyze() -> bool;
    |         ---^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/macros/issue-35450.rs b/src/test/ui/macros/issue-35450.rs
new file mode 100644 (file)
index 0000000..ac4c163
--- /dev/null
@@ -0,0 +1,5 @@
+macro_rules! m { ($($t:tt)*) => { $($t)* } }
+
+fn main() {
+    m!($t); //~ ERROR expected expression
+}
diff --git a/src/test/ui/macros/issue-35450.stderr b/src/test/ui/macros/issue-35450.stderr
new file mode 100644 (file)
index 0000000..f206568
--- /dev/null
@@ -0,0 +1,8 @@
+error: expected expression, found `$`
+  --> $DIR/issue-35450.rs:4:8
+   |
+LL |     m!($t);
+   |        ^ expected expression
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/macros/issue-41776.rs b/src/test/ui/macros/issue-41776.rs
new file mode 100644 (file)
index 0000000..24696d8
--- /dev/null
@@ -0,0 +1,3 @@
+fn main() {
+    include!(line!()); //~ ERROR argument must be a string literal
+}
diff --git a/src/test/ui/macros/issue-41776.stderr b/src/test/ui/macros/issue-41776.stderr
new file mode 100644 (file)
index 0000000..e06873b
--- /dev/null
@@ -0,0 +1,8 @@
+error: argument must be a string literal
+  --> $DIR/issue-41776.rs:2:14
+   |
+LL |     include!(line!());
+   |              ^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/macros/issue-44127.rs b/src/test/ui/macros/issue-44127.rs
new file mode 100644 (file)
index 0000000..21b2e68
--- /dev/null
@@ -0,0 +1,17 @@
+// run-pass
+
+#![feature(decl_macro)]
+
+pub struct Foo {
+    bar: u32,
+}
+pub macro pattern($a:pat) {
+    Foo { bar: $a }
+}
+
+fn main() {
+    match (Foo { bar: 3 }) {
+        pattern!(3) => println!("Test OK"),
+        _ => unreachable!(),
+    }
+}
index c8a0fd684304e4bc18f6f43b26e143faee419ead..43272248c280eb5d6a6555efbb14695b29c1d392 100644 (file)
@@ -5,5 +5,5 @@ LL |     println!("Hello, World!");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: expanding `println! { "Hello, World!" }`
-   = note: to `$crate :: io :: _print($crate :: format_args_nl! ("Hello, World!"))`
+   = note: to `{ $crate :: io :: _print($crate :: format_args_nl! ("Hello, World!")) ; }`
 
index bcab76b7c6b692620ac26809ff9deff472a7a794..ffe730743241d2824c94b848c839f812b3db11e5 100644 (file)
@@ -6,7 +6,7 @@ extern crate std;
 // compile-flags: -Zunpretty=hir,typed
 // check-pass
 
-pub fn main() ({
+fn main() ({
         (if (true as bool)
                 ({ } as
                     ()) else if (let Some(a) =
diff --git a/src/test/ui/methods/issues/issue-90315.rs b/src/test/ui/methods/issues/issue-90315.rs
new file mode 100644 (file)
index 0000000..01bf9f4
--- /dev/null
@@ -0,0 +1,7 @@
+fn main() {
+  let arr = &[0,1,2,3];
+  for _i in 0..arr.len().rev() { //~ERROR not an iterator
+     // The above error used to say “the method `rev` exists for type `usize`”.
+     // This regression test ensures it doesn't say that any more.
+  }
+}
diff --git a/src/test/ui/methods/issues/issue-90315.stderr b/src/test/ui/methods/issues/issue-90315.stderr
new file mode 100644 (file)
index 0000000..c6a76c9
--- /dev/null
@@ -0,0 +1,13 @@
+error[E0599]: `usize` is not an iterator
+  --> $DIR/issue-90315.rs:3:26
+   |
+LL |   for _i in 0..arr.len().rev() {
+   |                          ^^^ `usize` is not an iterator
+   |
+   = note: the following trait bounds were not satisfied:
+           `usize: Iterator`
+           which is required by `&mut usize: Iterator`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/ui/mismatched_types/issue-47706-trait.rs b/src/test/ui/mismatched_types/issue-47706-trait.rs
new file mode 100644 (file)
index 0000000..8fb4e08
--- /dev/null
@@ -0,0 +1,8 @@
+trait T {
+    fn f(&self, _: ()) {
+        None::<()>.map(Self::f);
+    }
+    //~^^ ERROR function is expected to take a single 0-tuple as argument
+}
+
+fn main() {}
diff --git a/src/test/ui/mismatched_types/issue-47706-trait.stderr b/src/test/ui/mismatched_types/issue-47706-trait.stderr
new file mode 100644 (file)
index 0000000..d596b4a
--- /dev/null
@@ -0,0 +1,19 @@
+error[E0593]: function is expected to take a single 0-tuple as argument, but it takes 2 distinct arguments
+  --> $DIR/issue-47706-trait.rs:3:24
+   |
+LL |     fn f(&self, _: ()) {
+   |     ------------------ takes 2 distinct arguments
+LL |         None::<()>.map(Self::f);
+   |                    --- ^^^^^^^ expected function that takes a single 0-tuple as argument
+   |                    |
+   |                    required by a bound introduced by this call
+   |
+note: required by a bound in `Option::<T>::map`
+  --> $SRC_DIR/core/src/option.rs:LL:COL
+   |
+LL |         F: ~const FnOnce(T) -> U,
+   |            ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Option::<T>::map`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0593`.
diff --git a/src/test/ui/mismatched_types/issue-47706.rs b/src/test/ui/mismatched_types/issue-47706.rs
new file mode 100644 (file)
index 0000000..f47c1e6
--- /dev/null
@@ -0,0 +1,29 @@
+pub struct Foo {
+    foo: Option<i32>,
+}
+
+impl Foo {
+    pub fn new(foo: Option<i32>, _: ()) -> Foo {
+        Foo { foo }
+    }
+
+    pub fn map(self) -> Option<Foo> {
+        self.foo.map(Foo::new)
+    }
+    //~^^ ERROR function is expected to take 1 argument, but it takes 2 arguments [E0593]
+}
+
+enum Qux {
+    Bar(i32),
+}
+
+fn foo<F>(f: F)
+where
+    F: Fn(),
+{
+}
+
+fn main() {
+    foo(Qux::Bar);
+}
+//~^^ ERROR function is expected to take 0 arguments, but it takes 1 argument [E0593]
diff --git a/src/test/ui/mismatched_types/issue-47706.stderr b/src/test/ui/mismatched_types/issue-47706.stderr
new file mode 100644 (file)
index 0000000..0b4f84a
--- /dev/null
@@ -0,0 +1,40 @@
+error[E0593]: function is expected to take 1 argument, but it takes 2 arguments
+  --> $DIR/issue-47706.rs:11:22
+   |
+LL |     pub fn new(foo: Option<i32>, _: ()) -> Foo {
+   |     ------------------------------------------ takes 2 arguments
+...
+LL |         self.foo.map(Foo::new)
+   |                  --- ^^^^^^^^ expected function that takes 1 argument
+   |                  |
+   |                  required by a bound introduced by this call
+   |
+note: required by a bound in `Option::<T>::map`
+  --> $SRC_DIR/core/src/option.rs:LL:COL
+   |
+LL |         F: ~const FnOnce(T) -> U,
+   |            ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Option::<T>::map`
+
+error[E0593]: function is expected to take 0 arguments, but it takes 1 argument
+  --> $DIR/issue-47706.rs:27:9
+   |
+LL |     Bar(i32),
+   |     -------- takes 1 argument
+...
+LL |     foo(Qux::Bar);
+   |     --- ^^^^^^^^ expected function that takes 0 arguments
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `foo`
+  --> $DIR/issue-47706.rs:22:8
+   |
+LL | fn foo<F>(f: F)
+   |    --- required by a bound in this
+LL | where
+LL |     F: Fn(),
+   |        ^^^^ required by this bound in `foo`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0593`.
index fb6cf7e8996c0b93107b71fe2ea2d42408c604b1..ba1b745ba84229115cbcd68041bef850ab1f8fa2 100644 (file)
@@ -54,17 +54,17 @@ where
 
 fn duplicate_custom_3<T>(t: S<T>) -> (S<T>, S<T>)
 where
-    T: A,
-    T: B, T: Trait, T: Copy
-    //~^ HELP consider further restricting type parameter `T`
+    T: A + Trait + Copy,
+    //~^ HELP consider further restricting this bound
+    T: B,
 {
     (t, t) //~ use of moved value: `t`
 }
 
-fn duplicate_custom_4<T: A>(t: S<T>) -> (S<T>, S<T>)
+fn duplicate_custom_4<T: A + Trait + Copy>(t: S<T>) -> (S<T>, S<T>)
+//~^ HELP consider further restricting this bound
 where
-    T: B + Trait + Copy,
-    //~^ HELP consider further restricting this bound
+    T: B,
 {
     (t, t) //~ use of moved value: `t`
 }
@@ -77,8 +77,8 @@ fn existing_colon<T: Copy>(t: T) {
 
 fn existing_colon_in_where<T>(t: T)
 where
-    T: Copy,
-    //~^ HELP consider further restricting this bound
+    T:, T: Copy
+    //~^ HELP consider further restricting type parameter `T`
 {
     [t, t]; //~ use of moved value: `t`
 }
index cadbf2a54cc3765dfecc3764d78f0549f65bf862..0a43dd1a9a38722f42141fcf7052448fccb9f5f6 100644 (file)
@@ -55,16 +55,16 @@ fn duplicate_custom_2<T>(t: S<T>) -> (S<T>, S<T>)
 fn duplicate_custom_3<T>(t: S<T>) -> (S<T>, S<T>)
 where
     T: A,
+    //~^ HELP consider further restricting this bound
     T: B,
-    //~^ HELP consider further restricting type parameter `T`
 {
     (t, t) //~ use of moved value: `t`
 }
 
 fn duplicate_custom_4<T: A>(t: S<T>) -> (S<T>, S<T>)
+//~^ HELP consider further restricting this bound
 where
     T: B,
-    //~^ HELP consider further restricting this bound
 {
     (t, t) //~ use of moved value: `t`
 }
@@ -78,7 +78,7 @@ fn existing_colon<T:>(t: T) {
 fn existing_colon_in_where<T>(t: T)
 where
     T:,
-    //~^ HELP consider further restricting this bound
+    //~^ HELP consider further restricting type parameter `T`
 {
     [t, t]; //~ use of moved value: `t`
 }
index f5252084d6884f76534992c0f5f3a0a9a59731e0..2353cd079a3704fab897aab06c24a99f19ae64b2 100644 (file)
@@ -121,10 +121,10 @@ LL |     (t, t)
    |      |
    |      value moved here
    |
-help: consider further restricting type parameter `T`
+help: consider further restricting this bound
    |
-LL |     T: B, T: Trait, T: Copy
-   |         ~~~~~~~~~~~~~~~~~~~
+LL |     T: A + Trait + Copy,
+   |          ++++++++++++++
 
 error[E0382]: use of moved value: `t`
   --> $DIR/use_of_moved_value_copy_suggestions.rs:69:9
@@ -139,8 +139,8 @@ LL |     (t, t)
    |
 help: consider further restricting this bound
    |
-LL |     T: B + Trait + Copy,
-   |          ++++++++++++++
+LL | fn duplicate_custom_4<T: A + Trait + Copy>(t: S<T>) -> (S<T>, S<T>)
+   |                            ++++++++++++++
 
 error[E0382]: use of moved value: `t`
   --> $DIR/use_of_moved_value_copy_suggestions.rs:83:9
@@ -153,10 +153,10 @@ LL |     [t, t];
    |      |
    |      value moved here
    |
-help: consider further restricting this bound
+help: consider further restricting type parameter `T`
    |
-LL |     T: Copy,
-   |        ++++
+LL |     T:, T: Copy
+   |       ~~~~~~~~~
 
 error[E0382]: use of moved value: `t`
   --> $DIR/use_of_moved_value_copy_suggestions.rs:75:9
diff --git a/src/test/ui/multiple-reprs.rs b/src/test/ui/multiple-reprs.rs
deleted file mode 100644 (file)
index 4be503a..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-// run-pass
-
-#![allow(dead_code)]
-
-use std::mem::{size_of, align_of};
-use std::os::raw::c_int;
-
-// The two enums that follow are designed so that bugs trigger layout optimization.
-// Specifically, if either of the following reprs used here is not detected by the compiler,
-// then the sizes will be wrong.
-
-#[repr(C, u8)]
-enum E1 {
-    A(u8, u16, u8),
-    B(u8, u16, u8)
-}
-
-#[repr(u8, C)]
-enum E2 {
-    A(u8, u16, u8),
-    B(u8, u16, u8)
-}
-
-// Check that repr(int) and repr(C) are in fact different from the above
-
-#[repr(u8)]
-enum E3 {
-    A(u8, u16, u8),
-    B(u8, u16, u8)
-}
-
-#[repr(u16)]
-enum E4 {
-    A(u8, u16, u8),
-    B(u8, u16, u8)
-}
-
-#[repr(u32)]
-enum E5 {
-    A(u8, u16, u8),
-    B(u8, u16, u8)
-}
-
-#[repr(u64)]
-enum E6 {
-    A(u8, u16, u8),
-    B(u8, u16, u8)
-}
-
-#[repr(C)]
-enum E7 {
-    A(u8, u16, u8),
-    B(u8, u16, u8)
-}
-
-// From pr 37429
-
-#[repr(C,packed)]
-pub struct p0f_api_query {
-    pub magic: u32,
-    pub addr_type: u8,
-    pub addr: [u8; 16],
-}
-
-pub fn main() {
-    assert_eq!(size_of::<E1>(), 8);
-    assert_eq!(size_of::<E2>(), 8);
-    assert_eq!(size_of::<E3>(), 6);
-    assert_eq!(size_of::<E4>(), 8);
-    assert_eq!(size_of::<E5>(), align_size(10, align_of::<u32>()));
-    assert_eq!(size_of::<E6>(), align_size(14, align_of::<u64>()));
-    assert_eq!(size_of::<E7>(), align_size(6 + size_of::<c_int>(), align_of::<c_int>()));
-    assert_eq!(size_of::<p0f_api_query>(), 21);
-}
-
-fn align_size(size: usize, align: usize) -> usize {
-    if size % align != 0 {
-        size + (align - (size % align))
-    } else {
-        size
-    }
-}
index 8c1755205f0253b82f6026b5d05f2508c4d831f0..c2079a19d0a58059b03637f4d7009c7292d42808 100644 (file)
@@ -47,8 +47,8 @@ LL |     [(); { for _ in 0usize.. {}; 0}];
 note: impl defined here, but it is not `const`
   --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
    |
-LL | impl<I: Iterator> IntoIterator for I {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | impl<I: ~const Iterator> const IntoIterator for I {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
 
 error[E0658]: mutable references are not allowed in constants
diff --git a/src/test/ui/never_type/issue-96335.rs b/src/test/ui/never_type/issue-96335.rs
new file mode 100644 (file)
index 0000000..411a7c9
--- /dev/null
@@ -0,0 +1,5 @@
+fn main() {
+    0.....{loop{}1};
+    //~^ ERROR unexpected token
+    //~| ERROR mismatched types
+}
diff --git a/src/test/ui/never_type/issue-96335.stderr b/src/test/ui/never_type/issue-96335.stderr
new file mode 100644 (file)
index 0000000..168cf2f
--- /dev/null
@@ -0,0 +1,35 @@
+error: unexpected token: `...`
+  --> $DIR/issue-96335.rs:2:6
+   |
+LL |     0.....{loop{}1};
+   |      ^^^
+   |
+help: use `..` for an exclusive range
+   |
+LL |     0....{loop{}1};
+   |      ~~
+help: or `..=` for an inclusive range
+   |
+LL |     0..=..{loop{}1};
+   |      ~~~
+
+error[E0308]: mismatched types
+  --> $DIR/issue-96335.rs:2:9
+   |
+LL |     0.....{loop{}1};
+   |     ----^^^^^^^^^^^
+   |     |   |
+   |     |   expected integer, found struct `RangeTo`
+   |     arguments to this function are incorrect
+   |
+   = note: expected type `{integer}`
+            found struct `RangeTo<{integer}>`
+note: associated function defined here
+  --> $SRC_DIR/core/src/ops/range.rs:LL:COL
+   |
+LL |     pub const fn new(start: Idx, end: Idx) -> Self {
+   |                  ^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
index 4b860a55057b641bba925136020285f983717b74..08605efa2ea9cba750e333d96162a8f7754f1d13 100644 (file)
@@ -44,9 +44,12 @@ LL | |         // This function call requires that
 ...  |
 LL | |         require(value);
 LL | |     });
-   | |_____^
+   | |_____^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
    |
-   = help: consider adding an explicit lifetime bound `T: 'a`...
+LL |     T: Trait<'a> + 'a,
+   |                  ++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nll/issue-45696-no-variant-box-recur.rs b/src/test/ui/nll/issue-45696-no-variant-box-recur.rs
new file mode 100644 (file)
index 0000000..c688261
--- /dev/null
@@ -0,0 +1,50 @@
+// rust-lang/rust#45696: This test checks the compiler won't infinite loop when
+// you declare a variable of type `struct A(Box<A>, ...);` (which is impossible
+// to construct but *is* possible to declare; see also issues #4287, #44933,
+// and #52852).
+//
+// We will explicitly test NLL, and migration modes; thus we will also skip the
+// automated compare-mode=nll.
+
+// run-pass
+
+// This test has structs and functions that are by definition unusable
+// all over the place, so just go ahead and allow dead_code
+#![allow(dead_code)]
+
+// direct regular recursion with indirect ownership via box
+struct C { field: Box<C> }
+
+// direct non-regular recursion with indirect ownership via box
+struct D { field: Box<(D, D)> }
+
+// indirect regular recursion with indirect ownership via box.
+struct E { field: F }
+struct F { field: Box<E> }
+
+// indirect non-regular recursion with indirect ownership via box.
+struct G { field: (H, H) }
+struct H { field: Box<G> }
+
+// These enums are cases that are not currently hit by the
+// `visit_terminator_drop` recursion down a type's structural
+// definition.
+//
+// But it seems prudent to include them in this test as variants on
+// the above, in that they are similarly non-constructable data types
+// with destructors that would diverge.
+enum I { One(Box<I>) }
+enum J { One(Box<J>), Two(Box<J>) }
+
+fn impossible_to_call_c(_c: C) { }
+fn impossible_to_call_d(_d: D) { }
+fn impossible_to_call_e(_e: E) { }
+fn impossible_to_call_f(_f: F) { }
+fn impossible_to_call_g(_g: G) { }
+fn impossible_to_call_h(_h: H) { }
+fn impossible_to_call_i(_i: I) { }
+fn impossible_to_call_j(_j: J) { }
+
+fn main() {
+
+}
diff --git a/src/test/ui/nll/issue-52213.nll.stderr b/src/test/ui/nll/issue-52213.nll.stderr
new file mode 100644 (file)
index 0000000..da31bcd
--- /dev/null
@@ -0,0 +1,15 @@
+error: lifetime may not live long enough
+  --> $DIR/issue-52213.rs:3:20
+   |
+LL | fn transmute_lifetime<'a, 'b, T>(t: &'a (T,)) -> &'b T {
+   |                       --  -- lifetime `'b` defined here
+   |                       |
+   |                       lifetime `'a` defined here
+LL |     match (&t,) {
+LL |         ((u,),) => u,
+   |                    ^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
+   |
+   = help: consider adding the following bound: `'a: 'b`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/nll/issue-52213.rs b/src/test/ui/nll/issue-52213.rs
new file mode 100644 (file)
index 0000000..c4ce494
--- /dev/null
@@ -0,0 +1,14 @@
+fn transmute_lifetime<'a, 'b, T>(t: &'a (T,)) -> &'b T {
+    match (&t,) { //~ ERROR cannot infer an appropriate lifetime
+        ((u,),) => u,
+    }
+}
+
+fn main() {
+    let x = {
+        let y = Box::new((42,));
+        transmute_lifetime(&y)
+    };
+
+    println!("{}", x);
+}
diff --git a/src/test/ui/nll/issue-52213.stderr b/src/test/ui/nll/issue-52213.stderr
new file mode 100644 (file)
index 0000000..aef5e25
--- /dev/null
@@ -0,0 +1,32 @@
+error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
+  --> $DIR/issue-52213.rs:2:11
+   |
+LL |     match (&t,) {
+   |           ^^^^^
+   |
+note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
+  --> $DIR/issue-52213.rs:1:23
+   |
+LL | fn transmute_lifetime<'a, 'b, T>(t: &'a (T,)) -> &'b T {
+   |                       ^^
+note: ...so that the types are compatible
+  --> $DIR/issue-52213.rs:2:11
+   |
+LL |     match (&t,) {
+   |           ^^^^^
+   = note: expected `(&&(T,),)`
+              found `(&&'a (T,),)`
+note: but, the lifetime must be valid for the lifetime `'b` as defined here...
+  --> $DIR/issue-52213.rs:1:27
+   |
+LL | fn transmute_lifetime<'a, 'b, T>(t: &'a (T,)) -> &'b T {
+   |                           ^^
+note: ...so that reference does not outlive borrowed content
+  --> $DIR/issue-52213.rs:3:20
+   |
+LL |         ((u,),) => u,
+   |                    ^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0495`.
index 364d6c17ea7f695afb6342f9e1045dcd3947e806..8d02ef71d1bc6c3636e906620b1debf76b8b0d06 100644 (file)
@@ -5,6 +5,11 @@ LL | fn bar<'a>(x: &'a u32) -> &'static dyn Debug {
    |        -- lifetime `'a` defined here
 LL |     x
    |     ^ returning this value requires that `'a` must outlive `'static`
+   |
+help: to declare that the trait object captures data from argument `x`, you can add an explicit `'a` lifetime bound
+   |
+LL | fn bar<'a>(x: &'a u32) -> &'static dyn Debug + 'a {
+   |                                              ++++
 
 error: aborting due to previous error
 
index 31ee540cce9f70ccf63bcd4f9baed4e8f5276ae7..64b08a9b32fb31be779fe6e03bdd398eb525cbd6 100644 (file)
@@ -2,17 +2,23 @@ error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/impl-trait-outlives.rs:11:5
    |
 LL |     x
-   |     ^
+   |     ^ ...so that the type `T` will meet its required lifetime bounds
    |
-   = help: consider adding an explicit lifetime bound `T: 'a`...
+help: consider adding an explicit lifetime bound...
+   |
+LL |     T: Debug + 'a,
+   |              ++++
 
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/impl-trait-outlives.rs:26:5
    |
 LL |     x
-   |     ^
+   |     ^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
    |
-   = help: consider adding an explicit lifetime bound `T: 'a`...
+LL |     T: 'b + Debug + 'a,
+   |                   ++++
 
 error: aborting due to 2 previous errors
 
index 9f0c60c1e1705a34424e546f32cc55a44bdb440f..3b9b2956c5183b47571f1f6561107e44d25280f2 100644 (file)
@@ -2,9 +2,12 @@ error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/projection-implied-bounds.rs:30:18
    |
 LL |     twice(value, |value_ref, item| invoke2(value_ref, item));
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
    |
-   = help: consider adding an explicit lifetime bound `T: 'static`...
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn generic2<T: Iterator + 'static>(value: T) {
+   |                         +++++++++
 
 error: aborting due to previous error
 
index 983d6a06afada75c7edffd8500d13cacbf15bc7b..8fe25181da1a035c8a7572ee0cebd352861123f7 100644 (file)
@@ -33,6 +33,7 @@ LL |     with_signature(x, |mut y| Box::new(y.next()))
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: consider adding an explicit lifetime bound `<T as Iterator>::Item: 'a`...
+   = note: ...so that the type `<T as Iterator>::Item` will meet its required lifetime bounds
 
 note: external requirements
   --> $DIR/projection-no-regions-closure.rs:34:23
@@ -96,6 +97,7 @@ LL |     with_signature(x, |mut y| Box::new(y.next()))
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: consider adding an explicit lifetime bound `<T as Iterator>::Item: 'a`...
+   = note: ...so that the type `<T as Iterator>::Item` will meet its required lifetime bounds
 
 note: external requirements
   --> $DIR/projection-no-regions-closure.rs:52:23
index c4df04b99b525723d345fab4a41d07f694370a53..e0ff544fe471333a384714d69ea6b372a1c765c3 100644 (file)
@@ -5,6 +5,7 @@ LL |     Box::new(x.next())
    |     ^^^^^^^^^^^^^^^^^^
    |
    = help: consider adding an explicit lifetime bound `<T as Iterator>::Item: 'a`...
+   = note: ...so that the type `<T as Iterator>::Item` will meet its required lifetime bounds
 
 error[E0309]: the associated type `<T as Iterator>::Item` may not live long enough
   --> $DIR/projection-no-regions-fn.rs:28:5
@@ -13,6 +14,7 @@ LL |     Box::new(x.next())
    |     ^^^^^^^^^^^^^^^^^^
    |
    = help: consider adding an explicit lifetime bound `<T as Iterator>::Item: 'a`...
+   = note: ...so that the type `<T as Iterator>::Item` will meet its required lifetime bounds
 
 error: aborting due to 2 previous errors
 
index 2513b0bfccbf188d3ffbb2a71b47e4f8a1cca0fb..caf2e3c47475564a69ef1dda33abc380a417441f 100644 (file)
@@ -32,9 +32,12 @@ error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/projection-one-region-closure.rs:45:29
    |
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
-   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
    |
-   = help: consider adding an explicit lifetime bound `T: 'a`...
+LL |     T: Anything<'b> + 'a,
+   |                     ++++
 
 error: lifetime may not live long enough
   --> $DIR/projection-one-region-closure.rs:45:39
@@ -82,9 +85,12 @@ error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/projection-one-region-closure.rs:56:29
    |
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
-   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
    |
-   = help: consider adding an explicit lifetime bound `T: 'a`...
+LL |     T: Anything<'b> + 'a,
+   |                     ++++
 
 error: lifetime may not live long enough
   --> $DIR/projection-one-region-closure.rs:56:39
index 4e0155bdf2cd0388280d8d990de511180657d498..1ee788b40ab9ea296f965e32b8d523dc5801c150 100644 (file)
@@ -34,6 +34,7 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: consider adding an explicit lifetime bound `<T as Anything<ReEarlyBound(0, 'b), ReEarlyBound(1, 'c)>>::AssocType: 'a`...
+   = note: ...so that the type `<T as Anything<ReEarlyBound(0, 'b), ReEarlyBound(1, 'c)>>::AssocType` will meet its required lifetime bounds
 
 note: external requirements
   --> $DIR/projection-two-region-trait-bound-closure.rs:48:29
@@ -70,6 +71,7 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: consider adding an explicit lifetime bound `<T as Anything<ReEarlyBound(1, 'b), ReEarlyBound(2, 'c)>>::AssocType: 'a`...
+   = note: ...so that the type `<T as Anything<ReEarlyBound(1, 'b), ReEarlyBound(2, 'c)>>::AssocType` will meet its required lifetime bounds
 
 note: external requirements
   --> $DIR/projection-two-region-trait-bound-closure.rs:61:29
index 3a84cbfbedc09b7b306697fb491a742834e09b3d..b4435fe06bccca5de87f1d50a99492fd9468cb19 100644 (file)
@@ -5,6 +5,7 @@ LL |     bar::<T::Output>()
    |     ^^^^^^^^^^^^^^^^
    |
    = help: consider adding an explicit lifetime bound `<T as MyTrait<'_>>::Output: 'a`...
+   = note: ...so that the type `<T as MyTrait<'_>>::Output` will meet its required lifetime bounds
 
 error: aborting due to previous error
 
index 58bfb600452e036a48745130134eda0278982757..ddeaf3c1f9e8ca7947add0d32df76dcd5c13bcb2 100644 (file)
@@ -5,6 +5,7 @@ LL |     bar::<<T as MyTrait<'a>>::Output>()
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: consider adding an explicit lifetime bound `<T as MyTrait<'_>>::Output: 'a`...
+   = note: ...so that the type `<T as MyTrait<'_>>::Output` will meet its required lifetime bounds
 
 error: aborting due to previous error
 
index 8175c302155a580446476e2b5b17de0d4104366e..e28b89580bc4c346d3ad310eeb4d06edc5855fa5 100644 (file)
@@ -2,9 +2,12 @@ error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/projection-where-clause-none.rs:16:5
    |
 LL |     bar::<T::Output>()
-   |     ^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
    |
-   = help: consider adding an explicit lifetime bound `T: 'a`...
+help: consider adding an explicit lifetime bound...
+   |
+LL |     T: MyTrait<'a> + 'a,
+   |                    ++++
 
 error: aborting due to previous error
 
index baf223b786b080709fd7ba3629f507d1f96f3d36..a4588730b3f8746d26c3dd1fb51e944509012405 100644 (file)
@@ -53,9 +53,12 @@ error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/ty-param-closure-approximate-lower-bound.rs:29:24
    |
 LL |     twice(cell, value, |a, b| invoke(a, b));
-   |                        ^^^^^^^^^^^^^^^^^^^
+   |                        ^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
    |
-   = help: consider adding an explicit lifetime bound `T: 'a`...
+LL | fn generic_fail<'a, T: 'a>(cell: Cell<&'a ()>, value: T) {
+   |                      ++++
 
 error: aborting due to previous error
 
index 88d73e7a729a92f5826d545af0bcf947c986f650..084dd93cb86b9b3376312c46d03ea202a0c201f9 100644 (file)
@@ -30,17 +30,23 @@ error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/ty-param-closure-outlives-from-return-type.rs:26:23
    |
 LL |     with_signature(x, |y| y)
-   |                       ^^^^^
+   |                       ^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
    |
-   = help: consider adding an explicit lifetime bound `T: 'a`...
+LL |     T: Debug + 'a,
+   |              ++++
 
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/ty-param-closure-outlives-from-return-type.rs:41:5
    |
 LL |     x
-   |     ^
+   |     ^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
    |
-   = help: consider adding an explicit lifetime bound `T: 'a`...
+LL |     T: 'b + Debug + 'a,
+   |                   ++++
 
 error: aborting due to 2 previous errors
 
index 5b175aac1e1cb774de1787b5ca8cdac6abbb2fd8..11a737ba291f06670be5603f2556d8a35b27a795 100644 (file)
@@ -45,9 +45,12 @@ LL | |         // See `correct_region`, which explains the point of this
 ...  |
 LL | |         require(&x, &y)
 LL | |     })
-   | |_____^
+   | |_____^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
    |
-   = help: consider adding an explicit lifetime bound `T: 'a`...
+LL | fn no_region<'a, T: 'a>(a: Cell<&'a ()>, b: T) {
+   |                   ++++
 
 note: external requirements
   --> $DIR/ty-param-closure-outlives-from-where-clause.rs:43:26
@@ -127,9 +130,12 @@ LL | |
 LL | |         // See `correct_region`
 LL | |         require(&x, &y)
 LL | |     })
-   | |_____^
+   | |_____^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
    |
-   = help: consider adding an explicit lifetime bound `T: 'a`...
+LL |     T: 'b + 'a,
+   |           ++++
 
 note: external requirements
   --> $DIR/ty-param-closure-outlives-from-where-clause.rs:77:26
index 9a023a0e58e5f061efe3a2f517dbe947378ad663..ba79137d18d8cb832aff363bd90bbd1bb454041c 100644 (file)
@@ -2,9 +2,12 @@ error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/ty-param-fn-body.rs:19:5
    |
 LL |     outlives(cell, t)
-   |     ^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
    |
-   = help: consider adding an explicit lifetime bound `T: 'a`...
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn region_static<'a, T: 'a>(cell: Cell<&'a usize>, t: T) {
+   |                       ++++
 
 error: aborting due to previous error
 
index 8c8529620d57fd401b23b7e54693b49a7b9546d7..729f14d84adafe589b634a595fecd98057070b9e 100644 (file)
@@ -2,17 +2,23 @@ error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/ty-param-fn.rs:11:5
    |
 LL |     x
-   |     ^
+   |     ^ ...so that the type `T` will meet its required lifetime bounds
    |
-   = help: consider adding an explicit lifetime bound `T: 'a`...
+help: consider adding an explicit lifetime bound...
+   |
+LL |     T: Debug + 'a,
+   |              ++++
 
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/ty-param-fn.rs:26:5
    |
 LL |     x
-   |     ^
+   |     ^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
    |
-   = help: consider adding an explicit lifetime bound `T: 'a`...
+LL |     T: 'b + Debug + 'a,
+   |                   ++++
 
 error: aborting due to 2 previous errors
 
index ae02c58d080aaaa3ecdcdaf64f8ff07534226730..43695a7511d275b711eee07a87e59b51086c17c1 100644 (file)
@@ -6,6 +6,11 @@ LL | fn load(ss: &mut SomeStruct) -> Box<dyn SomeTrait> {
 ...
 LL |     ss.r
    |     ^^^^ returning this value requires that `'1` must outlive `'static`
+   |
+help: to declare that the trait object captures data from argument `ss`, you can add an explicit `'_` lifetime bound
+   |
+LL | fn load(ss: &mut SomeStruct) -> Box<dyn SomeTrait + '_> {
+   |                                                   ++++
 
 error[E0507]: cannot move out of `ss.r` which is behind a mutable reference
   --> $DIR/object-lifetime-default-from-box-error.rs:18:5
diff --git a/src/test/ui/object-safety/issue-19538.rs b/src/test/ui/object-safety/issue-19538.rs
new file mode 100644 (file)
index 0000000..7054ef4
--- /dev/null
@@ -0,0 +1,20 @@
+trait Foo {
+    fn foo<T>(&self, val: T);
+}
+
+trait Bar: Foo { }
+
+pub struct Thing;
+
+impl Foo for Thing {
+    fn foo<T>(&self, val: T) { }
+}
+
+impl Bar for Thing { }
+
+fn main() {
+    let mut thing = Thing;
+    let test: &mut dyn Bar = &mut thing;
+    //~^ ERROR E0038
+    //~| ERROR E0038
+}
diff --git a/src/test/ui/object-safety/issue-19538.stderr b/src/test/ui/object-safety/issue-19538.stderr
new file mode 100644 (file)
index 0000000..7b37e1f
--- /dev/null
@@ -0,0 +1,37 @@
+error[E0038]: the trait `Bar` cannot be made into an object
+  --> $DIR/issue-19538.rs:17:15
+   |
+LL |     let test: &mut dyn Bar = &mut thing;
+   |               ^^^^^^^^^^^^ `Bar` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/issue-19538.rs:2:8
+   |
+LL |     fn foo<T>(&self, val: T);
+   |        ^^^ ...because method `foo` has generic type parameters
+...
+LL | trait Bar: Foo { }
+   |       --- this trait cannot be made into an object...
+   = help: consider moving `foo` to another trait
+
+error[E0038]: the trait `Bar` cannot be made into an object
+  --> $DIR/issue-19538.rs:17:30
+   |
+LL |     let test: &mut dyn Bar = &mut thing;
+   |                              ^^^^^^^^^^ `Bar` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/issue-19538.rs:2:8
+   |
+LL |     fn foo<T>(&self, val: T);
+   |        ^^^ ...because method `foo` has generic type parameters
+...
+LL | trait Bar: Foo { }
+   |       --- this trait cannot be made into an object...
+   = help: consider moving `foo` to another trait
+   = note: required because of the requirements on the impl of `CoerceUnsized<&mut dyn Bar>` for `&mut Thing`
+   = note: required by cast to type `&mut dyn Bar`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0038`.
index c173a3a9aba200053ad6e0cff16a26ba7ebb3089..8fafa275b5c2736d007b97af3122beb4ec19de36 100644 (file)
@@ -103,6 +103,22 @@ LL |     let (A(A(a, b) | B(c), d) | B(e)) = Y;
    |            |
    |            pattern doesn't bind `c`
 
+error[E0408]: variable `d` is not bound in all patterns
+  --> $DIR/missing-bindings.rs:45:33
+   |
+LL |     let (A(A(a, b) | B(c), d) | B(e)) = Y;
+   |                            -    ^^^^ pattern doesn't bind `d`
+   |                            |
+   |                            variable not in all patterns
+
+error[E0408]: variable `e` is not bound in all patterns
+  --> $DIR/missing-bindings.rs:45:10
+   |
+LL |     let (A(A(a, b) | B(c), d) | B(e)) = Y;
+   |          ^^^^^^^^^^^^^^^^^^^^     - variable not in all patterns
+   |          |
+   |          pattern doesn't bind `e`
+
 error[E0408]: variable `a` is not bound in all patterns
   --> $DIR/missing-bindings.rs:45:33
    |
@@ -127,22 +143,6 @@ LL |     let (A(A(a, b) | B(c), d) | B(e)) = Y;
    |                        |
    |                        variable not in all patterns
 
-error[E0408]: variable `d` is not bound in all patterns
-  --> $DIR/missing-bindings.rs:45:33
-   |
-LL |     let (A(A(a, b) | B(c), d) | B(e)) = Y;
-   |                            -    ^^^^ pattern doesn't bind `d`
-   |                            |
-   |                            variable not in all patterns
-
-error[E0408]: variable `e` is not bound in all patterns
-  --> $DIR/missing-bindings.rs:45:10
-   |
-LL |     let (A(A(a, b) | B(c), d) | B(e)) = Y;
-   |          ^^^^^^^^^^^^^^^^^^^^     - variable not in all patterns
-   |          |
-   |          pattern doesn't bind `e`
-
 error[E0408]: variable `a` is not bound in all patterns
   --> $DIR/missing-bindings.rs:61:29
    |
diff --git a/src/test/ui/parser/issue-61858.rs b/src/test/ui/parser/issue-61858.rs
new file mode 100644 (file)
index 0000000..6c3b565
--- /dev/null
@@ -0,0 +1,3 @@
+fn main() {
+    (if foobar) //~ ERROR expected `{`, found `)`
+}
diff --git a/src/test/ui/parser/issue-61858.stderr b/src/test/ui/parser/issue-61858.stderr
new file mode 100644 (file)
index 0000000..8b95d9c
--- /dev/null
@@ -0,0 +1,10 @@
+error: expected `{`, found `)`
+  --> $DIR/issue-61858.rs:2:15
+   |
+LL |     (if foobar)
+   |      --       ^ expected `{`
+   |      |
+   |      this `if` expression has a condition, but no block
+
+error: aborting due to previous error
+
index f9c3ca763f26ea5728103dad29d7f723d551b3fd..bbd85374b4bcfb9a0393ded136f72d2c4bc2dc54 100644 (file)
@@ -12,7 +12,7 @@ LL |
 LL | }
    | - the item list ends here
    |
-   = note: keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`
+   = note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`
 
 error: aborting due to previous error
 
index 86fdb78cce8aba23f39e4ce9d36c583e346d67ed..bbebc99e94b8236a280d78a37081eaf63917c663 100644 (file)
@@ -11,4 +11,4 @@
 //~| NOTE expected one of `extern` or `fn`
 //~| HELP `const` must come before `async unsafe`
 //~| SUGGESTION const async unsafe
-//~| NOTE keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`
+//~| NOTE keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`
index 65cce77be896bc6c0d1b359c4a84159be1ed6e14..f455caba158c77728c43d9ffd54ab37d50b64e4e 100644 (file)
@@ -7,7 +7,7 @@ LL | async unsafe const fn test() {}
    | |            expected one of `extern` or `fn`
    | help: `const` must come before `async unsafe`: `const async unsafe`
    |
-   = note: keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`
+   = note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`
 
 error: aborting due to previous error
 
index edfb330d6713a31e8602f190fedea7903a55cfaa..4ff4cf5c8ca8768e625084a6ca4babaad35bcfd8 100644 (file)
@@ -11,4 +11,4 @@
 //~| NOTE expected one of `extern` or `fn`
 //~| HELP `async` must come before `unsafe`
 //~| SUGGESTION async unsafe
-//~| NOTE keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`
+//~| NOTE keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`
index 3acd9e4400432b304a83dff28139dfc7f5afafaf..e9eb14bf00e77ecc5d988e38c6db7798b01be6b0 100644 (file)
@@ -7,7 +7,7 @@ LL | unsafe async fn test() {}
    | |      expected one of `extern` or `fn`
    | help: `async` must come before `unsafe`: `async unsafe`
    |
-   = note: keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`
+   = note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`
 
 error: aborting due to previous error
 
index abd692b80d54b1ad45a89852fd28b294a95367eb..2f5fbc513ee3658051aa788acfd35edd47e520ac 100644 (file)
@@ -11,4 +11,4 @@
 //~| NOTE expected one of `extern` or `fn`
 //~| HELP `const` must come before `unsafe`
 //~| SUGGESTION const unsafe
-//~| NOTE keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`
+//~| NOTE keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`
index 9a3e07b1e87f64638c5604b09ac1d7515a7cb470..0d2bc3472965f6c576a8764c3e821e1b016057ca 100644 (file)
@@ -7,7 +7,7 @@ LL | unsafe const fn test() {}
    | |      expected one of `extern` or `fn`
    | help: `const` must come before `unsafe`: `const unsafe`
    |
-   = note: keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`
+   = note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`
 
 error: aborting due to previous error
 
index 7f0761e99386a3c43a8f4a5c477327f94fc0831f..df2412e3e9b32e4b3e71b158eb059abbe50d4f6e 100644 (file)
@@ -11,4 +11,4 @@
 //~| NOTE expected `fn`
 //~| HELP `unsafe` must come before `extern`
 //~| SUGGESTION unsafe extern
-//~| NOTE keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`
+//~| NOTE keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`
index 395ee9fedbc0726d4b82b2384c333daeceeb9ec7..4224713ccb53af36e3fd62a64dfc6ba675937268 100644 (file)
@@ -7,7 +7,7 @@ LL | extern unsafe fn test() {}
    | |      expected `fn`
    | help: `unsafe` must come before `extern`: `unsafe extern`
    |
-   = note: keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`
+   = note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`
 
 error: aborting due to previous error
 
index 35f118f5ce6eed46af1e1b3a89f2be036f7204ea..38537f8b31e64e1bd392faa7b63c81bb83c8a6ad 100644 (file)
@@ -1,4 +1,22 @@
 static s: &'static str =
+    r#""## //~ ERROR too many `#` when terminating raw string
+;
+
+static s2: &'static str =
     r#"
-      "## //~ too many `#` when terminating raw string
+      "#### //~ ERROR too many `#` when terminating raw string
 ;
+
+const A: &'static str = r"" //~ ERROR expected `;`, found `#`
+
+// Test
+#[test]
+fn test() {}
+
+const B: &'static str = r""## //~ ERROR too many `#` when terminating raw string
+
+// Test
+#[test]
+fn test2() {}
+
+fn main() {}
index bf8f3a7a5a4bd833cc012ec8f3cc23d5831945df..eac8c06c1df5cad02fecadddb6ade773a060d3a9 100644 (file)
@@ -1,10 +1,36 @@
 error: too many `#` when terminating raw string
-  --> $DIR/raw-str-unbalanced.rs:3:9
+  --> $DIR/raw-str-unbalanced.rs:2:10
    |
-LL |       "##
-   |         ^ help: remove the extra `#`
+LL |     r#""##
+   |     -----^ help: remove the extra `#`
+   |     |
+   |     this raw string started with 1 `#`
+
+error: too many `#` when terminating raw string
+  --> $DIR/raw-str-unbalanced.rs:7:9
+   |
+LL | /     r#"
+LL | |       "####
+   | |        -^^^ help: remove the extra `#`s
+   | |________|
+   |          this raw string started with 1 `#`
+
+error: expected `;`, found `#`
+  --> $DIR/raw-str-unbalanced.rs:10:28
+   |
+LL | const A: &'static str = r""
+   |                            ^ help: add `;` here
+...
+LL | #[test]
+   | - unexpected token
+
+error: too many `#` when terminating raw string
+  --> $DIR/raw-str-unbalanced.rs:16:28
    |
-   = note: the raw string started with 1 `#`s
+LL | const B: &'static str = r""##
+   |                         ---^^ help: remove the extra `#`s
+   |                         |
+   |                         this raw string started with 0 `#`s
 
-error: aborting due to previous error
+error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/pattern/issue-72574-1.rs b/src/test/ui/pattern/issue-72574-1.rs
new file mode 100644 (file)
index 0000000..1b80a21
--- /dev/null
@@ -0,0 +1,10 @@
+fn main() {
+    let x = (1, 2, 3);
+    match x {
+        (_a, _x @ ..) => {}
+        _ => {}
+    }
+}
+//~^^^^ ERROR `_x @` is not allowed in a tuple
+//~| ERROR: `..` patterns are not allowed here
+//~| ERROR: mismatched types
diff --git a/src/test/ui/pattern/issue-72574-1.stderr b/src/test/ui/pattern/issue-72574-1.stderr
new file mode 100644 (file)
index 0000000..653869a
--- /dev/null
@@ -0,0 +1,34 @@
+error: `_x @` is not allowed in a tuple
+  --> $DIR/issue-72574-1.rs:4:14
+   |
+LL |         (_a, _x @ ..) => {}
+   |              ^^^^^^^ this is only allowed in slice patterns
+   |
+   = help: remove this and bind each tuple field independently
+help: if you don't need to use the contents of _x, discard the tuple's remaining fields
+   |
+LL |         (_a, ..) => {}
+   |              ~~
+
+error: `..` patterns are not allowed here
+  --> $DIR/issue-72574-1.rs:4:19
+   |
+LL |         (_a, _x @ ..) => {}
+   |                   ^^
+   |
+   = note: only allowed in tuple, tuple struct, and slice patterns
+
+error[E0308]: mismatched types
+  --> $DIR/issue-72574-1.rs:4:9
+   |
+LL |     match x {
+   |           - this expression has type `({integer}, {integer}, {integer})`
+LL |         (_a, _x @ ..) => {}
+   |         ^^^^^^^^^^^^^ expected a tuple with 3 elements, found one with 2 elements
+   |
+   = note: expected tuple `({integer}, {integer}, {integer})`
+              found tuple `(_, _)`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
index e2a65ff8524040062aefcaad59b284c07e11921a..fc0430d06fa1c03354a6875b6040d6793548f9b2 100644 (file)
@@ -12,7 +12,7 @@ LL | struct Foo(isize, isize);
    = note: the matched value is of type `Foo`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         Foo(2, b) => println!("{}", b),
+LL ~         Foo(2, b) => println!("{}", b)
 LL +         Foo(_, _) => todo!()
    |
 
index 9cabb21e784adff9c0da3d333b29e72569567717..5edbb119f78690c54ede7789661bf60e0242c482 100644 (file)
@@ -19,6 +19,12 @@ LL | |         2
 LL | |     }
    | |_____^
 
+note: the above error was encountered while instantiating `fn finish::<[generator@$DIR/generators.rs:35:5: 39:6], u32, u32>`
+  --> $DIR/generators.rs:86:5
+   |
+LL |     finish(unused_type::<u32>());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
 error: item has unused generic parameters
   --> $DIR/generators.rs:60:5
    |
@@ -31,5 +37,11 @@ LL | |         2
 LL | |     }
    | |_____^
 
+note: the above error was encountered while instantiating `fn finish::<[generator@$DIR/generators.rs:60:5: 64:6], u32, u32>`
+  --> $DIR/generators.rs:89:5
+   |
+LL |     finish(unused_const::<1u32>());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
 error: aborting due to 2 previous errors; 1 warning emitted
 
index 5fc51e58d728a3ec3d5a191ef65abd0a4c956bb1..dc6ebceae2197a15b66d1e9883958e658e533f8f 100644 (file)
@@ -41,5 +41,11 @@ error: item has unused generic parameters
 LL | fn bar<I>() {
    |    ^^^ - generic parameter `I` is unused
 
+note: the above error was encountered while instantiating `fn foo::<std::slice::Iter<u32>, T>`
+  --> $DIR/predicates.rs:85:5
+   |
+LL |     foo(x.iter());
+   |     ^^^^^^^^^^^^^
+
 error: aborting due to 6 previous errors
 
index db2a879f405040c77a9d4b2537e4b51b3a240d08..ec30199028142730015818db08cb0f56b298fd02 100644 (file)
@@ -3,7 +3,7 @@
 // compile-flags: -Z span-debug
 // edition:2018
 //
-// Tests the pretty-printing behavior of inserting `NoDelim` groups
+// Tests the pretty-printing behavior of inserting `Invisible`-delimited groups
 
 #![no_std] // Don't load unnecessary hygiene information from std
 extern crate std;
diff --git a/src/test/ui/regions/issue-28848.base.stderr b/src/test/ui/regions/issue-28848.base.stderr
new file mode 100644 (file)
index 0000000..f10b197
--- /dev/null
@@ -0,0 +1,20 @@
+error[E0478]: lifetime bound not satisfied
+  --> $DIR/issue-28848.rs:14:5
+   |
+LL |     Foo::<'a, 'b>::xmute(u)
+   |     ^^^^^^^^^^^^^
+   |
+note: lifetime parameter instantiated with the lifetime `'b` as defined here
+  --> $DIR/issue-28848.rs:13:16
+   |
+LL | pub fn foo<'a, 'b>(u: &'b ()) -> &'a () {
+   |                ^^
+note: but lifetime parameter must outlive the lifetime `'a` as defined here
+  --> $DIR/issue-28848.rs:13:12
+   |
+LL | pub fn foo<'a, 'b>(u: &'b ()) -> &'a () {
+   |            ^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0478`.
index a29dac4c9c87c3c8f73656d0c32531d187baf219..f9de8948272af6b01bb47b3d3d25fdb7b8351257 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/issue-28848.rs:10:5
+  --> $DIR/issue-28848.rs:14:5
    |
 LL | pub fn foo<'a, 'b>(u: &'b ()) -> &'a () {
    |            --  -- lifetime `'b` defined here
index a62502390302b4f7c0ce5339f925757eb26811e1..d8ab42a08d448f579af0fbbb8598be34c0072f1d 100644 (file)
@@ -1,3 +1,7 @@
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 struct Foo<'a, 'b: 'a>(&'a &'b ());
 
 impl<'a, 'b> Foo<'a, 'b> {
@@ -7,7 +11,9 @@ fn xmute(a: &'b ()) -> &'a () {
 }
 
 pub fn foo<'a, 'b>(u: &'b ()) -> &'a () {
-    Foo::<'a, 'b>::xmute(u) //~ ERROR lifetime bound not satisfied
+    Foo::<'a, 'b>::xmute(u)
+    //[base]~^ ERROR lifetime bound not satisfied
+    //[nll]~^^ ERROR lifetime may not live long enough
 }
 
 fn main() {}
diff --git a/src/test/ui/regions/issue-28848.stderr b/src/test/ui/regions/issue-28848.stderr
deleted file mode 100644 (file)
index afa0c9c..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-error[E0478]: lifetime bound not satisfied
-  --> $DIR/issue-28848.rs:10:5
-   |
-LL |     Foo::<'a, 'b>::xmute(u)
-   |     ^^^^^^^^^^^^^
-   |
-note: lifetime parameter instantiated with the lifetime `'b` as defined here
-  --> $DIR/issue-28848.rs:9:16
-   |
-LL | pub fn foo<'a, 'b>(u: &'b ()) -> &'a () {
-   |                ^^
-note: but lifetime parameter must outlive the lifetime `'a` as defined here
-  --> $DIR/issue-28848.rs:9:12
-   |
-LL | pub fn foo<'a, 'b>(u: &'b ()) -> &'a () {
-   |            ^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0478`.
diff --git a/src/test/ui/regions/region-invariant-static-error-reporting.base.stderr b/src/test/ui/regions/region-invariant-static-error-reporting.base.stderr
new file mode 100644 (file)
index 0000000..ce21751
--- /dev/null
@@ -0,0 +1,25 @@
+error[E0308]: `if` and `else` have incompatible types
+  --> $DIR/region-invariant-static-error-reporting.rs:21:9
+   |
+LL |       let bad = if x.is_some() {
+   |  _______________-
+LL | |         x.unwrap()
+   | |         ---------- expected because of this
+LL | |     } else {
+LL | |         mk_static()
+   | |         ^^^^^^^^^^^ lifetime mismatch
+LL | |     };
+   | |_____- `if` and `else` have incompatible types
+   |
+   = note: expected struct `Invariant<'a>`
+              found struct `Invariant<'static>`
+note: the lifetime `'a` as defined here...
+  --> $DIR/region-invariant-static-error-reporting.rs:17:10
+   |
+LL | fn unify<'a>(x: Option<Invariant<'a>>, f: fn(Invariant<'a>)) {
+   |          ^^
+   = note: ...does not necessarily outlive the static lifetime
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
index 6e7eb734a50eac9ef35f08e84d81bfc2fe129316..6905fd008c525df8367324e2c3d45569b9c68c9c 100644 (file)
@@ -1,5 +1,5 @@
 error[E0521]: borrowed data escapes outside of function
-  --> $DIR/region-invariant-static-error-reporting.rs:15:9
+  --> $DIR/region-invariant-static-error-reporting.rs:19:9
    |
 LL | fn unify<'a>(x: Option<Invariant<'a>>, f: fn(Invariant<'a>)) {
    |          --  - `x` is a reference that is only valid in the function body
index 911904813d0eba241b597141531fcf035a6168c4..b81022ca4b40bacddc6ea35a0516d392dda756f3 100644 (file)
@@ -3,8 +3,12 @@
 // over time, but this test used to exhibit some pretty bogus messages
 // that were not remotely helpful.
 
-// error-pattern:the lifetime `'a`
-// error-pattern:the static lifetime
+// revisions: base nll
+// ignore-compare-mode-nll
+//[base] error-pattern:the lifetime `'a`
+//[base] error-pattern:the static lifetime
+//[nll] compile-flags: -Z borrowck=mir
+//[nll] error-pattern:argument requires that `'a` must outlive `'static`
 
 struct Invariant<'a>(Option<&'a mut &'a mut ()>);
 
@@ -12,9 +16,9 @@ fn mk_static() -> Invariant<'static> { Invariant(None) }
 
 fn unify<'a>(x: Option<Invariant<'a>>, f: fn(Invariant<'a>)) {
     let bad = if x.is_some() {
-        x.unwrap()
+        x.unwrap() //[nll]~ ERROR borrowed data escapes outside of function [E0521]
     } else {
-        mk_static()
+        mk_static() //[base]~ ERROR `if` and `else` have incompatible types [E0308]
     };
     f(bad);
 }
diff --git a/src/test/ui/regions/region-invariant-static-error-reporting.stderr b/src/test/ui/regions/region-invariant-static-error-reporting.stderr
deleted file mode 100644 (file)
index 3428707..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-error[E0308]: `if` and `else` have incompatible types
-  --> $DIR/region-invariant-static-error-reporting.rs:17:9
-   |
-LL |       let bad = if x.is_some() {
-   |  _______________-
-LL | |         x.unwrap()
-   | |         ---------- expected because of this
-LL | |     } else {
-LL | |         mk_static()
-   | |         ^^^^^^^^^^^ lifetime mismatch
-LL | |     };
-   | |_____- `if` and `else` have incompatible types
-   |
-   = note: expected struct `Invariant<'a>`
-              found struct `Invariant<'static>`
-note: the lifetime `'a` as defined here...
-  --> $DIR/region-invariant-static-error-reporting.rs:13:10
-   |
-LL | fn unify<'a>(x: Option<Invariant<'a>>, f: fn(Invariant<'a>)) {
-   |          ^^
-   = note: ...does not necessarily outlive the static lifetime
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.base.stderr b/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.base.stderr
new file mode 100644 (file)
index 0000000..2ba4f4f
--- /dev/null
@@ -0,0 +1,31 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:12:10
+   |
+LL | fn b<'a, 'b>(x: &mut &'a isize, y: &mut &'b isize) {
+   |                      ---------          --------- these two types are declared with different lifetimes...
+LL |     // Illegal now because there is no `'b:'a` declaration.
+LL |     *x = *y;
+   |          ^^ ...but data from `y` flows into `x` here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:20:7
+   |
+LL | fn c<'a,'b>(x: &mut &'a isize, y: &mut &'b isize) {
+   |                     ---------          --------- these two types are declared with different lifetimes...
+...
+LL |     a(x, y);
+   |       ^ ...but data from `y` flows into `x` here
+
+error[E0308]: mismatched types
+  --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:28:43
+   |
+LL |     let _: fn(&mut &isize, &mut &isize) = a;
+   |                                           ^ one type is more general than the other
+   |
+   = note: expected fn pointer `for<'r, 's, 't0, 't1> fn(&'r mut &'s isize, &'t0 mut &'t1 isize)`
+              found fn pointer `for<'r, 's> fn(&'r mut &isize, &'s mut &isize)`
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0308, E0623.
+For more information about an error, try `rustc --explain E0308`.
index 233a040491c660a28573accbcb48b9ba2a55501d..c64309743346d09b7815d8eab4feabe8cd9b84d1 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:8:5
+  --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:12:5
    |
 LL | fn b<'a, 'b>(x: &mut &'a isize, y: &mut &'b isize) {
    |      --  -- lifetime `'b` defined here
@@ -12,7 +12,7 @@ LL |     *x = *y;
    = help: consider adding the following bound: `'b: 'a`
 
 error: lifetime may not live long enough
-  --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:14:5
+  --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:20:5
    |
 LL | fn c<'a,'b>(x: &mut &'a isize, y: &mut &'b isize) {
    |      -- -- lifetime `'b` defined here
@@ -28,7 +28,7 @@ LL |     a(x, y);
    = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error[E0308]: mismatched types
-  --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:20:12
+  --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:28:12
    |
 LL |     let _: fn(&mut &isize, &mut &isize) = a;
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
@@ -37,7 +37,7 @@ LL |     let _: fn(&mut &isize, &mut &isize) = a;
               found fn pointer `for<'r, 's> fn(&'r mut &isize, &'s mut &isize)`
 
 error[E0308]: mismatched types
-  --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:20:12
+  --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:28:12
    |
 LL |     let _: fn(&mut &isize, &mut &isize) = a;
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
index ab4c6d9cf9198d541f9a050d39bfb09706f812f1..ec91d1798083c5c63b196f1ea1307620539e3923 100644 (file)
@@ -1,3 +1,7 @@
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 fn a<'a, 'b>(x: &mut &'a isize, y: &mut &'b isize) where 'b: 'a {
     // Note: this is legal because of the `'b:'a` declaration.
     *x = *y;
@@ -5,19 +9,25 @@ fn a<'a, 'b>(x: &mut &'a isize, y: &mut &'b isize) where 'b: 'a {
 
 fn b<'a, 'b>(x: &mut &'a isize, y: &mut &'b isize) {
     // Illegal now because there is no `'b:'a` declaration.
-    *x = *y; //~ ERROR E0623
+    *x = *y;
+    //[base]~^ ERROR E0623
+    //[nll]~^^ ERROR lifetime may not live long enough
 }
 
 fn c<'a,'b>(x: &mut &'a isize, y: &mut &'b isize) {
     // Here we try to call `foo` but do not know that `'a` and `'b` are
     // related as required.
-    a(x, y); //~ ERROR lifetime mismatch [E0623]
+    a(x, y);
+    //[base]~^ ERROR lifetime mismatch [E0623]
+    //[nll]~^^ ERROR lifetime may not live long enough
 }
 
 fn d() {
     // 'a and 'b are early bound in the function `a` because they appear
     // inconstraints:
-    let _: fn(&mut &isize, &mut &isize) = a; //~ ERROR mismatched types
+    let _: fn(&mut &isize, &mut &isize) = a;
+    //~^ ERROR mismatched types [E0308]
+    //[nll]~^^ ERROR mismatched types [E0308]
 }
 
 fn e() {
diff --git a/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.stderr b/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.stderr
deleted file mode 100644 (file)
index b83e076..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-error[E0623]: lifetime mismatch
-  --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:8:10
-   |
-LL | fn b<'a, 'b>(x: &mut &'a isize, y: &mut &'b isize) {
-   |                      ---------          --------- these two types are declared with different lifetimes...
-LL |     // Illegal now because there is no `'b:'a` declaration.
-LL |     *x = *y;
-   |          ^^ ...but data from `y` flows into `x` here
-
-error[E0623]: lifetime mismatch
-  --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:14:7
-   |
-LL | fn c<'a,'b>(x: &mut &'a isize, y: &mut &'b isize) {
-   |                     ---------          --------- these two types are declared with different lifetimes...
-...
-LL |     a(x, y);
-   |       ^ ...but data from `y` flows into `x` here
-
-error[E0308]: mismatched types
-  --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:20:43
-   |
-LL |     let _: fn(&mut &isize, &mut &isize) = a;
-   |                                           ^ one type is more general than the other
-   |
-   = note: expected fn pointer `for<'r, 's, 't0, 't1> fn(&'r mut &'s isize, &'t0 mut &'t1 isize)`
-              found fn pointer `for<'r, 's> fn(&'r mut &isize, &'s mut &isize)`
-
-error: aborting due to 3 previous errors
-
-Some errors have detailed explanations: E0308, E0623.
-For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.base.stderr b/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.base.stderr
new file mode 100644 (file)
index 0000000..537a1fb
--- /dev/null
@@ -0,0 +1,42 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:13:10
+   |
+LL | fn b<'a, 'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) {
+   |                          ---------          --------- these two types are declared with different lifetimes...
+LL |     // Illegal now because there is no `'b:'a` declaration.
+LL |     *x = *y;
+   |          ^^ ...but data from `y` flows into `x` here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:16:10
+   |
+LL | fn b<'a, 'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) {
+   |                                             ---------          ---------
+   |                                             |
+   |                                             these two types are declared with different lifetimes...
+...
+LL |     *z = *y;
+   |          ^^ ...but data from `y` flows into `z` here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:7
+   |
+LL | fn c<'a,'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) {
+   |                         ---------          --------- these two types are declared with different lifetimes...
+...
+LL |     a(x, y, z);
+   |       ^ ...but data from `y` flows into `x` here
+
+error[E0308]: mismatched types
+  --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:30:56
+   |
+LL |     let _: fn(&mut &isize, &mut &isize, &mut &isize) = a;
+   |                                                        ^ one type is more general than the other
+   |
+   = note: expected fn pointer `for<'r, 's, 't0, 't1, 't2, 't3> fn(&'r mut &'s isize, &'t0 mut &'t1 isize, &'t2 mut &'t3 isize)`
+              found fn pointer `for<'r, 's, 't0> fn(&'r mut &isize, &'s mut &isize, &'t0 mut &isize)`
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0308, E0623.
+For more information about an error, try `rustc --explain E0308`.
index 00119743acd780842f4b6b65acafdf3eb24473a7..053078f58df93d54ddafe4a7595f10a24c6d274b 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:9:5
+  --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:13:5
    |
 LL | fn b<'a, 'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) {
    |      --  -- lifetime `'b` defined here
@@ -12,7 +12,7 @@ LL |     *x = *y;
    = help: consider adding the following bound: `'b: 'a`
 
 error: lifetime may not live long enough
-  --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:16:5
+  --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:5
    |
 LL | fn c<'a,'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) {
    |      -- -- lifetime `'b` defined here
@@ -28,7 +28,7 @@ LL |     a(x, y, z);
    = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error[E0308]: mismatched types
-  --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:12
+  --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:30:12
    |
 LL |     let _: fn(&mut &isize, &mut &isize, &mut &isize) = a;
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
@@ -37,7 +37,7 @@ LL |     let _: fn(&mut &isize, &mut &isize, &mut &isize) = a;
               found fn pointer `for<'r, 's, 't0> fn(&'r mut &isize, &'s mut &isize, &'t0 mut &isize)`
 
 error[E0308]: mismatched types
-  --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:12
+  --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:30:12
    |
 LL |     let _: fn(&mut &isize, &mut &isize, &mut &isize) = a;
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
@@ -46,7 +46,7 @@ LL |     let _: fn(&mut &isize, &mut &isize, &mut &isize) = a;
               found fn pointer `for<'r, 's, 't0> fn(&'r mut &isize, &'s mut &isize, &'t0 mut &isize)`
 
 error[E0308]: mismatched types
-  --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:12
+  --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:30:12
    |
 LL |     let _: fn(&mut &isize, &mut &isize, &mut &isize) = a;
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
diff --git a/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.polonius.stderr b/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.polonius.stderr
deleted file mode 100644 (file)
index 1374166..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-error: lifetime may not live long enough
-  --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:9:5
-   |
-LL | fn b<'a, 'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) {
-   |      --  -- lifetime `'b` defined here
-   |      |
-   |      lifetime `'a` defined here
-LL |     // Illegal now because there is no `'b:'a` declaration.
-LL |     *x = *y;
-   |     ^^^^^^^ assignment requires that `'b` must outlive `'a`
-   |
-   = help: consider adding the following bound: `'b: 'a`
-
-error: lifetime may not live long enough
-  --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:10:5
-   |
-LL | fn b<'a, 'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) {
-   |          --  -- lifetime `'c` defined here
-   |          |
-   |          lifetime `'b` defined here
-...
-LL |     *z = *y;
-   |     ^^^^^^^ assignment requires that `'b` must outlive `'c`
-   |
-   = help: consider adding the following bound: `'b: 'c`
-
-help: add bound `'b: 'a + 'c`
-
-error: lifetime may not live long enough
-  --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:16:5
-   |
-LL | fn c<'a,'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) {
-   |      -- -- lifetime `'b` defined here
-   |      |
-   |      lifetime `'a` defined here
-...
-LL |     a(x, y, z);
-   |     ^^^^^^^^^^ argument requires that `'b` must outlive `'a`
-   |
-   = help: consider adding the following bound: `'b: 'a`
-   = note: requirement occurs because of a mutable reference to &isize
-   = note: mutable references are invariant over their type parameter
-   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
-
-error: lifetime may not live long enough
-  --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:16:5
-   |
-LL | fn c<'a,'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) {
-   |         --  -- lifetime `'c` defined here
-   |         |
-   |         lifetime `'b` defined here
-...
-LL |     a(x, y, z);
-   |     ^^^^^^^^^^ argument requires that `'b` must outlive `'c`
-   |
-   = help: consider adding the following bound: `'b: 'c`
-   = note: requirement occurs because of a mutable reference to &isize
-   = note: mutable references are invariant over their type parameter
-   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
-
-help: add bound `'b: 'a + 'c`
-
-error: higher-ranked subtype error
-  --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:12
-   |
-LL |     let _: fn(&mut &isize, &mut &isize, &mut &isize) = a;
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: higher-ranked subtype error
-  --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:12
-   |
-LL |     let _: fn(&mut &isize, &mut &isize, &mut &isize) = a;
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: higher-ranked subtype error
-  --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:12
-   |
-LL |     let _: fn(&mut &isize, &mut &isize, &mut &isize) = a;
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 7 previous errors
-
index 066522548ad4567d98c7e9673718d0051cadfc81..8b5c1d47ec61b506f42e5ad9a0fe567f42ea53da 100644 (file)
@@ -1,3 +1,7 @@
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 fn a<'a, 'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) where 'b: 'a + 'c {
     // Note: this is legal because of the `'b:'a` declaration.
     *x = *y;
@@ -6,20 +10,27 @@ fn a<'a, 'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) where
 
 fn b<'a, 'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) {
     // Illegal now because there is no `'b:'a` declaration.
-    *x = *y; //~ ERROR E0623
-    *z = *y; //~ ERROR E0623
+    *x = *y;
+    //[base]~^ ERROR E0623
+    //[nll]~^^ ERROR lifetime may not live long enough
+    *z = *y; //[base]~ ERROR E0623
 }
 
 fn c<'a,'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) {
     // Here we try to call `foo` but do not know that `'a` and `'b` are
     // related as required.
-    a(x, y, z); //~ ERROR lifetime mismatch [E0623]
+    a(x, y, z);
+    //[base]~^ ERROR lifetime mismatch [E0623]
+    //[nll]~^^ ERROR lifetime may not live long enough
 }
 
 fn d() {
     // 'a and 'b are early bound in the function `a` because they appear
     // inconstraints:
-    let _: fn(&mut &isize, &mut &isize, &mut &isize) = a; //~ ERROR E0308
+    let _: fn(&mut &isize, &mut &isize, &mut &isize) = a;
+    //~^ ERROR E0308
+    //[nll]~^^ ERROR mismatched types [E0308]
+    //[nll]~| ERROR mismatched types [E0308]
 }
 
 fn e() {
diff --git a/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.stderr b/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.stderr
deleted file mode 100644 (file)
index c93f289..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-error[E0623]: lifetime mismatch
-  --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:9:10
-   |
-LL | fn b<'a, 'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) {
-   |                          ---------          --------- these two types are declared with different lifetimes...
-LL |     // Illegal now because there is no `'b:'a` declaration.
-LL |     *x = *y;
-   |          ^^ ...but data from `y` flows into `x` here
-
-error[E0623]: lifetime mismatch
-  --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:10:10
-   |
-LL | fn b<'a, 'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) {
-   |                                             ---------          ---------
-   |                                             |
-   |                                             these two types are declared with different lifetimes...
-...
-LL |     *z = *y;
-   |          ^^ ...but data from `y` flows into `z` here
-
-error[E0623]: lifetime mismatch
-  --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:16:7
-   |
-LL | fn c<'a,'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) {
-   |                         ---------          --------- these two types are declared with different lifetimes...
-...
-LL |     a(x, y, z);
-   |       ^ ...but data from `y` flows into `x` here
-
-error[E0308]: mismatched types
-  --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:56
-   |
-LL |     let _: fn(&mut &isize, &mut &isize, &mut &isize) = a;
-   |                                                        ^ one type is more general than the other
-   |
-   = note: expected fn pointer `for<'r, 's, 't0, 't1, 't2, 't3> fn(&'r mut &'s isize, &'t0 mut &'t1 isize, &'t2 mut &'t3 isize)`
-              found fn pointer `for<'r, 's, 't0> fn(&'r mut &isize, &'s mut &isize, &'t0 mut &isize)`
-
-error: aborting due to 4 previous errors
-
-Some errors have detailed explanations: E0308, E0623.
-For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/regions/region-object-lifetime-2.base.stderr b/src/test/ui/regions/region-object-lifetime-2.base.stderr
new file mode 100644 (file)
index 0000000..118fe47
--- /dev/null
@@ -0,0 +1,30 @@
+error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
+  --> $DIR/region-object-lifetime-2.rs:14:7
+   |
+LL |     x.borrowed()
+   |       ^^^^^^^^
+   |
+note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
+  --> $DIR/region-object-lifetime-2.rs:13:42
+   |
+LL | fn borrowed_receiver_different_lifetimes<'a,'b>(x: &'a dyn Foo) -> &'b () {
+   |                                          ^^
+note: ...so that reference does not outlive borrowed content
+  --> $DIR/region-object-lifetime-2.rs:14:5
+   |
+LL |     x.borrowed()
+   |     ^
+note: but, the lifetime must be valid for the lifetime `'b` as defined here...
+  --> $DIR/region-object-lifetime-2.rs:13:45
+   |
+LL | fn borrowed_receiver_different_lifetimes<'a,'b>(x: &'a dyn Foo) -> &'b () {
+   |                                             ^^
+note: ...so that reference does not outlive borrowed content
+  --> $DIR/region-object-lifetime-2.rs:14:5
+   |
+LL |     x.borrowed()
+   |     ^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0495`.
index d95289f3f9def09c27b6261dde5aa814558a4822..c0b09ebb6f58b5e50014c58c8a4fdacfaa282511 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/region-object-lifetime-2.rs:10:5
+  --> $DIR/region-object-lifetime-2.rs:14:5
    |
 LL | fn borrowed_receiver_different_lifetimes<'a,'b>(x: &'a dyn Foo) -> &'b () {
    |                                          -- -- lifetime `'b` defined here
index 42798487893382471dbc364cfb1cf4a31350a5f5..e12b9822f60845e7e1e8d0091fe0a7de6bc96e93 100644 (file)
@@ -1,13 +1,19 @@
 // Various tests related to testing how region inference works
 // with respect to the object receivers.
 
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 trait Foo {
     fn borrowed<'a>(&'a self) -> &'a ();
 }
 
 // Borrowed receiver but two distinct lifetimes, we get an error.
 fn borrowed_receiver_different_lifetimes<'a,'b>(x: &'a dyn Foo) -> &'b () {
-    x.borrowed() //~ ERROR cannot infer
+    x.borrowed()
+    //[base]~^ ERROR cannot infer
+    //[nll]~^^ ERROR lifetime may not live long enough
 }
 
 fn main() {}
diff --git a/src/test/ui/regions/region-object-lifetime-2.stderr b/src/test/ui/regions/region-object-lifetime-2.stderr
deleted file mode 100644 (file)
index 380e27a..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
-  --> $DIR/region-object-lifetime-2.rs:10:7
-   |
-LL |     x.borrowed()
-   |       ^^^^^^^^
-   |
-note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
-  --> $DIR/region-object-lifetime-2.rs:9:42
-   |
-LL | fn borrowed_receiver_different_lifetimes<'a,'b>(x: &'a dyn Foo) -> &'b () {
-   |                                          ^^
-note: ...so that reference does not outlive borrowed content
-  --> $DIR/region-object-lifetime-2.rs:10:5
-   |
-LL |     x.borrowed()
-   |     ^
-note: but, the lifetime must be valid for the lifetime `'b` as defined here...
-  --> $DIR/region-object-lifetime-2.rs:9:45
-   |
-LL | fn borrowed_receiver_different_lifetimes<'a,'b>(x: &'a dyn Foo) -> &'b () {
-   |                                             ^^
-note: ...so that reference does not outlive borrowed content
-  --> $DIR/region-object-lifetime-2.rs:10:5
-   |
-LL |     x.borrowed()
-   |     ^^^^^^^^^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0495`.
diff --git a/src/test/ui/regions/region-object-lifetime-4.base.stderr b/src/test/ui/regions/region-object-lifetime-4.base.stderr
new file mode 100644 (file)
index 0000000..3765076
--- /dev/null
@@ -0,0 +1,30 @@
+error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
+  --> $DIR/region-object-lifetime-4.rs:16:7
+   |
+LL |     x.borrowed()
+   |       ^^^^^^^^
+   |
+note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
+  --> $DIR/region-object-lifetime-4.rs:15:41
+   |
+LL | fn borrowed_receiver_related_lifetimes2<'a,'b>(x: &'a (dyn Foo + 'b)) -> &'b () {
+   |                                         ^^
+note: ...so that reference does not outlive borrowed content
+  --> $DIR/region-object-lifetime-4.rs:16:5
+   |
+LL |     x.borrowed()
+   |     ^
+note: but, the lifetime must be valid for the lifetime `'b` as defined here...
+  --> $DIR/region-object-lifetime-4.rs:15:44
+   |
+LL | fn borrowed_receiver_related_lifetimes2<'a,'b>(x: &'a (dyn Foo + 'b)) -> &'b () {
+   |                                            ^^
+note: ...so that reference does not outlive borrowed content
+  --> $DIR/region-object-lifetime-4.rs:16:5
+   |
+LL |     x.borrowed()
+   |     ^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0495`.
index fda66a2412ccb85ebb7c8a4c084c3ec34e198304..a2a958f90b234e16369d5e6ee50577a5712f385a 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/region-object-lifetime-4.rs:12:5
+  --> $DIR/region-object-lifetime-4.rs:16:5
    |
 LL | fn borrowed_receiver_related_lifetimes2<'a,'b>(x: &'a (dyn Foo + 'b)) -> &'b () {
    |                                         -- -- lifetime `'b` defined here
index 4fe12b2acfc69895ebc3fdb2494a2ab0fa94ef01..aad9c2c95217ba259b9865f3c7393de954c7441a 100644 (file)
@@ -1,6 +1,10 @@
 // Various tests related to testing how region inference works
 // with respect to the object receivers.
 
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 trait Foo {
     fn borrowed<'a>(&'a self) -> &'a ();
 }
@@ -9,7 +13,9 @@ trait Foo {
 // with the longer lifetime when (from the signature) we only know
 // that it lives as long as the shorter lifetime. Therefore, error.
 fn borrowed_receiver_related_lifetimes2<'a,'b>(x: &'a (dyn Foo + 'b)) -> &'b () {
-    x.borrowed() //~ ERROR cannot infer
+    x.borrowed()
+    //[base]~^ ERROR cannot infer
+    //[nll]~^^ ERROR lifetime may not live long enough
 }
 
 fn main() {}
diff --git a/src/test/ui/regions/region-object-lifetime-4.stderr b/src/test/ui/regions/region-object-lifetime-4.stderr
deleted file mode 100644 (file)
index b59163e..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
-  --> $DIR/region-object-lifetime-4.rs:12:7
-   |
-LL |     x.borrowed()
-   |       ^^^^^^^^
-   |
-note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
-  --> $DIR/region-object-lifetime-4.rs:11:41
-   |
-LL | fn borrowed_receiver_related_lifetimes2<'a,'b>(x: &'a (dyn Foo + 'b)) -> &'b () {
-   |                                         ^^
-note: ...so that reference does not outlive borrowed content
-  --> $DIR/region-object-lifetime-4.rs:12:5
-   |
-LL |     x.borrowed()
-   |     ^
-note: but, the lifetime must be valid for the lifetime `'b` as defined here...
-  --> $DIR/region-object-lifetime-4.rs:11:44
-   |
-LL | fn borrowed_receiver_related_lifetimes2<'a,'b>(x: &'a (dyn Foo + 'b)) -> &'b () {
-   |                                            ^^
-note: ...so that reference does not outlive borrowed content
-  --> $DIR/region-object-lifetime-4.rs:12:5
-   |
-LL |     x.borrowed()
-   |     ^^^^^^^^^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0495`.
diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.base.stderr b/src/test/ui/regions/region-object-lifetime-in-coercion.base.stderr
new file mode 100644 (file)
index 0000000..85bfa16
--- /dev/null
@@ -0,0 +1,98 @@
+error[E0759]: `v` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
+  --> $DIR/region-object-lifetime-in-coercion.rs:12:46
+   |
+LL | fn a(v: &[u8]) -> Box<dyn Foo + 'static> {
+   |         ----- this data with an anonymous lifetime `'_`...
+LL |     let x: Box<dyn Foo + 'static> = Box::new(v);
+   |                                              ^ ...is used and required to live as long as `'static` here
+   |
+help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v`
+   |
+LL | fn a(v: &[u8]) -> Box<dyn Foo + '_> {
+   |                                 ~~
+help: alternatively, add an explicit `'static` bound to this reference
+   |
+LL | fn a(v: &'static [u8]) -> Box<dyn Foo + 'static> {
+   |         ~~~~~~~~~~~~~
+
+error[E0759]: `v` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
+  --> $DIR/region-object-lifetime-in-coercion.rs:19:14
+   |
+LL | fn b(v: &[u8]) -> Box<dyn Foo + 'static> {
+   |         ----- this data with an anonymous lifetime `'_`...
+LL |     Box::new(v)
+   |              ^ ...is used and required to live as long as `'static` here
+   |
+note: `'static` lifetime requirement introduced by the return type
+  --> $DIR/region-object-lifetime-in-coercion.rs:18:33
+   |
+LL | fn b(v: &[u8]) -> Box<dyn Foo + 'static> {
+   |                                 ^^^^^^^ `'static` requirement introduced here
+LL |     Box::new(v)
+   |     ----------- because of this returned expression
+help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v`
+   |
+LL | fn b(v: &[u8]) -> Box<dyn Foo + '_> {
+   |                                 ~~
+help: alternatively, add an explicit `'static` bound to this reference
+   |
+LL | fn b(v: &'static [u8]) -> Box<dyn Foo + 'static> {
+   |         ~~~~~~~~~~~~~
+
+error[E0759]: `v` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
+  --> $DIR/region-object-lifetime-in-coercion.rs:27:14
+   |
+LL | fn c(v: &[u8]) -> Box<dyn Foo> {
+   |         ----- this data with an anonymous lifetime `'_`...
+...
+LL |     Box::new(v)
+   |              ^ ...is used and required to live as long as `'static` here
+   |
+note: `'static` lifetime requirement introduced by the return type
+  --> $DIR/region-object-lifetime-in-coercion.rs:24:23
+   |
+LL | fn c(v: &[u8]) -> Box<dyn Foo> {
+   |                       ^^^^^^^ `'static` requirement introduced here
+...
+LL |     Box::new(v)
+   |     ----------- because of this returned expression
+help: to declare that the trait object captures data from argument `v`, you can add an explicit `'_` lifetime bound
+   |
+LL | fn c(v: &[u8]) -> Box<dyn Foo + '_> {
+   |                               ++++
+
+error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
+  --> $DIR/region-object-lifetime-in-coercion.rs:33:14
+   |
+LL |     Box::new(v)
+   |              ^
+   |
+note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
+  --> $DIR/region-object-lifetime-in-coercion.rs:32:6
+   |
+LL | fn d<'a,'b>(v: &'a [u8]) -> Box<dyn Foo+'b> {
+   |      ^^
+note: ...so that the expression is assignable
+  --> $DIR/region-object-lifetime-in-coercion.rs:33:14
+   |
+LL |     Box::new(v)
+   |              ^
+   = note: expected `&[u8]`
+              found `&'a [u8]`
+note: but, the lifetime must be valid for the lifetime `'b` as defined here...
+  --> $DIR/region-object-lifetime-in-coercion.rs:32:9
+   |
+LL | fn d<'a,'b>(v: &'a [u8]) -> Box<dyn Foo+'b> {
+   |         ^^
+note: ...so that the types are compatible
+  --> $DIR/region-object-lifetime-in-coercion.rs:33:5
+   |
+LL |     Box::new(v)
+   |     ^^^^^^^^^^^
+   = note: expected `Box<(dyn Foo + 'b)>`
+              found `Box<dyn Foo>`
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0495, E0759.
+For more information about an error, try `rustc --explain E0495`.
index 92588819076d35ae9ef382e5e78c8bbbe2c34672..724b06ce8b168563f110d8b80f4f4edd4d90eebb 100644 (file)
@@ -1,30 +1,53 @@
 error: lifetime may not live long enough
-  --> $DIR/region-object-lifetime-in-coercion.rs:8:12
+  --> $DIR/region-object-lifetime-in-coercion.rs:12:12
    |
 LL | fn a(v: &[u8]) -> Box<dyn Foo + 'static> {
    |         - let's call the lifetime of this reference `'1`
 LL |     let x: Box<dyn Foo + 'static> = Box::new(v);
    |            ^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'1` must outlive `'static`
+   |
+help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v`
+   |
+LL | fn a(v: &[u8]) -> Box<dyn Foo + '_> {
+   |                                 ~~
+help: alternatively, add an explicit `'static` bound to this reference
+   |
+LL | fn a(v: &'static [u8]) -> Box<dyn Foo + 'static> {
+   |         ~~~~~~~~~~~~~
 
 error: lifetime may not live long enough
-  --> $DIR/region-object-lifetime-in-coercion.rs:13:5
+  --> $DIR/region-object-lifetime-in-coercion.rs:19:5
    |
 LL | fn b(v: &[u8]) -> Box<dyn Foo + 'static> {
    |         - let's call the lifetime of this reference `'1`
 LL |     Box::new(v)
    |     ^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static`
+   |
+help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v`
+   |
+LL | fn b(v: &[u8]) -> Box<dyn Foo + '_> {
+   |                                 ~~
+help: alternatively, add an explicit `'static` bound to this reference
+   |
+LL | fn b(v: &'static [u8]) -> Box<dyn Foo + 'static> {
+   |         ~~~~~~~~~~~~~
 
 error: lifetime may not live long enough
-  --> $DIR/region-object-lifetime-in-coercion.rs:19:5
+  --> $DIR/region-object-lifetime-in-coercion.rs:27:5
    |
 LL | fn c(v: &[u8]) -> Box<dyn Foo> {
    |         - let's call the lifetime of this reference `'1`
 ...
 LL |     Box::new(v)
    |     ^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static`
+   |
+help: to declare that the trait object captures data from argument `v`, you can add an explicit `'_` lifetime bound
+   |
+LL | fn c(v: &[u8]) -> Box<dyn Foo + '_> {
+   |                               ++++
 
 error: lifetime may not live long enough
-  --> $DIR/region-object-lifetime-in-coercion.rs:23:5
+  --> $DIR/region-object-lifetime-in-coercion.rs:33:5
    |
 LL | fn d<'a,'b>(v: &'a [u8]) -> Box<dyn Foo+'b> {
    |      -- -- lifetime `'b` defined here
index 9d3f485e314385148fd081174954b3faaf1cedb7..ed28d6c0ff1aeeae28939de84474bd0cff27553e 100644 (file)
@@ -1,26 +1,38 @@
 // Test that attempts to implicitly coerce a value into an
 // object respect the lifetime bound on the object type.
 
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 trait Foo {}
 impl<'a> Foo for &'a [u8] {}
 
 fn a(v: &[u8]) -> Box<dyn Foo + 'static> {
-    let x: Box<dyn Foo + 'static> = Box::new(v); //~ ERROR E0759
+    let x: Box<dyn Foo + 'static> = Box::new(v);
+    //[base]~^ ERROR E0759
+    //[nll]~^^ ERROR lifetime may not live long enough
     x
 }
 
 fn b(v: &[u8]) -> Box<dyn Foo + 'static> {
-    Box::new(v) //~ ERROR E0759
+    Box::new(v)
+    //[base]~^ ERROR E0759
+    //[nll]~^^ ERROR lifetime may not live long enough
 }
 
 fn c(v: &[u8]) -> Box<dyn Foo> {
     // same as previous case due to RFC 599
 
-    Box::new(v) //~ ERROR E0759
+    Box::new(v)
+    //[base]~^ ERROR E0759
+    //[nll]~^^ ERROR lifetime may not live long enough
 }
 
 fn d<'a,'b>(v: &'a [u8]) -> Box<dyn Foo+'b> {
-    Box::new(v) //~ ERROR cannot infer an appropriate lifetime due to conflicting
+    Box::new(v)
+    //[base]~^ ERROR cannot infer an appropriate lifetime due to conflicting
+    //[nll]~^^ ERROR lifetime may not live long enough
 }
 
 fn e<'a:'b,'b>(v: &'a [u8]) -> Box<dyn Foo+'b> {
diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr
deleted file mode 100644 (file)
index d8932c0..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-error[E0759]: `v` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
-  --> $DIR/region-object-lifetime-in-coercion.rs:8:46
-   |
-LL | fn a(v: &[u8]) -> Box<dyn Foo + 'static> {
-   |         ----- this data with an anonymous lifetime `'_`...
-LL |     let x: Box<dyn Foo + 'static> = Box::new(v);
-   |                                              ^ ...is used and required to live as long as `'static` here
-   |
-help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v`
-   |
-LL | fn a(v: &[u8]) -> Box<dyn Foo + '_> {
-   |                                 ~~
-help: alternatively, add an explicit `'static` bound to this reference
-   |
-LL | fn a(v: &'static [u8]) -> Box<dyn Foo + 'static> {
-   |         ~~~~~~~~~~~~~
-
-error[E0759]: `v` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
-  --> $DIR/region-object-lifetime-in-coercion.rs:13:14
-   |
-LL | fn b(v: &[u8]) -> Box<dyn Foo + 'static> {
-   |         ----- this data with an anonymous lifetime `'_`...
-LL |     Box::new(v)
-   |              ^ ...is used and required to live as long as `'static` here
-   |
-note: `'static` lifetime requirement introduced by the return type
-  --> $DIR/region-object-lifetime-in-coercion.rs:12:33
-   |
-LL | fn b(v: &[u8]) -> Box<dyn Foo + 'static> {
-   |                                 ^^^^^^^ `'static` requirement introduced here
-LL |     Box::new(v)
-   |     ----------- because of this returned expression
-help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v`
-   |
-LL | fn b(v: &[u8]) -> Box<dyn Foo + '_> {
-   |                                 ~~
-help: alternatively, add an explicit `'static` bound to this reference
-   |
-LL | fn b(v: &'static [u8]) -> Box<dyn Foo + 'static> {
-   |         ~~~~~~~~~~~~~
-
-error[E0759]: `v` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
-  --> $DIR/region-object-lifetime-in-coercion.rs:19:14
-   |
-LL | fn c(v: &[u8]) -> Box<dyn Foo> {
-   |         ----- this data with an anonymous lifetime `'_`...
-...
-LL |     Box::new(v)
-   |              ^ ...is used and required to live as long as `'static` here
-   |
-note: `'static` lifetime requirement introduced by the return type
-  --> $DIR/region-object-lifetime-in-coercion.rs:16:23
-   |
-LL | fn c(v: &[u8]) -> Box<dyn Foo> {
-   |                       ^^^^^^^ `'static` requirement introduced here
-...
-LL |     Box::new(v)
-   |     ----------- because of this returned expression
-help: to declare that the trait object captures data from argument `v`, you can add an explicit `'_` lifetime bound
-   |
-LL | fn c(v: &[u8]) -> Box<dyn Foo + '_> {
-   |                               ++++
-
-error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
-  --> $DIR/region-object-lifetime-in-coercion.rs:23:14
-   |
-LL |     Box::new(v)
-   |              ^
-   |
-note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
-  --> $DIR/region-object-lifetime-in-coercion.rs:22:6
-   |
-LL | fn d<'a,'b>(v: &'a [u8]) -> Box<dyn Foo+'b> {
-   |      ^^
-note: ...so that the expression is assignable
-  --> $DIR/region-object-lifetime-in-coercion.rs:23:14
-   |
-LL |     Box::new(v)
-   |              ^
-   = note: expected `&[u8]`
-              found `&'a [u8]`
-note: but, the lifetime must be valid for the lifetime `'b` as defined here...
-  --> $DIR/region-object-lifetime-in-coercion.rs:22:9
-   |
-LL | fn d<'a,'b>(v: &'a [u8]) -> Box<dyn Foo+'b> {
-   |         ^^
-note: ...so that the types are compatible
-  --> $DIR/region-object-lifetime-in-coercion.rs:23:5
-   |
-LL |     Box::new(v)
-   |     ^^^^^^^^^^^
-   = note: expected `Box<(dyn Foo + 'b)>`
-              found `Box<dyn Foo>`
-
-error: aborting due to 4 previous errors
-
-Some errors have detailed explanations: E0495, E0759.
-For more information about an error, try `rustc --explain E0495`.
diff --git a/src/test/ui/regions/regions-addr-of-self.base.stderr b/src/test/ui/regions/regions-addr-of-self.base.stderr
new file mode 100644 (file)
index 0000000..3167c2f
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
+  --> $DIR/regions-addr-of-self.rs:11:37
+   |
+LL |     pub fn chase_cat(&mut self) {
+   |                      --------- this data with an anonymous lifetime `'_`...
+LL |         let p: &'static mut usize = &mut self.cats_chased;
+   |                                     ^^^^^^^^^^^^^^^^^^^^^ ...is used and required to live as long as `'static` here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0759`.
index 3d7aac74bd4f75a327ec674ab385a6d880b6ca1f..1f720520f6ba6c24f9ee29c26403f59a25008d55 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/regions-addr-of-self.rs:7:16
+  --> $DIR/regions-addr-of-self.rs:11:16
    |
 LL |     pub fn chase_cat(&mut self) {
    |                      - let's call the lifetime of this reference `'1`
index 4eb1b275f163ec77af5f50bb86c28b486e72644f..698433c71b3804ba9e8f4a5d02af555a0f978a3f 100644 (file)
@@ -1,10 +1,16 @@
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 struct Dog {
     cats_chased: usize,
 }
 
 impl Dog {
     pub fn chase_cat(&mut self) {
-        let p: &'static mut usize = &mut self.cats_chased; //~ ERROR E0759
+        let p: &'static mut usize = &mut self.cats_chased;
+        //[base]~^ ERROR E0759
+        //[nll]~^^ ERROR lifetime may not live long enough
         *p += 1;
     }
 
diff --git a/src/test/ui/regions/regions-addr-of-self.stderr b/src/test/ui/regions/regions-addr-of-self.stderr
deleted file mode 100644 (file)
index 3453c64..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
-  --> $DIR/regions-addr-of-self.rs:7:37
-   |
-LL |     pub fn chase_cat(&mut self) {
-   |                      --------- this data with an anonymous lifetime `'_`...
-LL |         let p: &'static mut usize = &mut self.cats_chased;
-   |                                     ^^^^^^^^^^^^^^^^^^^^^ ...is used and required to live as long as `'static` here
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0759`.
diff --git a/src/test/ui/regions/regions-addr-of-upvar-self.base.stderr b/src/test/ui/regions/regions-addr-of-upvar-self.base.stderr
new file mode 100644 (file)
index 0000000..42d0638
--- /dev/null
@@ -0,0 +1,26 @@
+error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
+  --> $DIR/regions-addr-of-upvar-self.rs:12:41
+   |
+LL |             let p: &'static mut usize = &mut self.food;
+   |                                         ^^^^^^^^^^^^^^
+   |
+note: first, the lifetime cannot outlive the lifetime `'_` as defined here...
+  --> $DIR/regions-addr-of-upvar-self.rs:11:18
+   |
+LL |         let _f = || {
+   |                  ^^
+note: ...so that closure can access `self`
+  --> $DIR/regions-addr-of-upvar-self.rs:12:41
+   |
+LL |             let p: &'static mut usize = &mut self.food;
+   |                                         ^^^^^^^^^^^^^^
+   = note: but, the lifetime must be valid for the static lifetime...
+note: ...so that reference does not outlive borrowed content
+  --> $DIR/regions-addr-of-upvar-self.rs:12:41
+   |
+LL |             let p: &'static mut usize = &mut self.food;
+   |                                         ^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0495`.
index c16a6f8585b692098134b4d1e7ea392cdcb4b6b1..b8e37e92316dbf5755d8b52c804bb9b229bfbe6d 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/regions-addr-of-upvar-self.rs:8:20
+  --> $DIR/regions-addr-of-upvar-self.rs:12:20
    |
 LL |         let _f = || {
    |                  -- lifetime `'1` represents this closure's body
@@ -9,7 +9,7 @@ LL |             let p: &'static mut usize = &mut self.food;
    = note: closure implements `FnMut`, so references to captured variables can't escape the closure
 
 error: lifetime may not live long enough
-  --> $DIR/regions-addr-of-upvar-self.rs:8:20
+  --> $DIR/regions-addr-of-upvar-self.rs:12:20
    |
 LL |     pub fn chase_cat(&mut self) {
    |                      - let's call the lifetime of this reference `'1`
@@ -18,7 +18,7 @@ LL |             let p: &'static mut usize = &mut self.food;
    |                    ^^^^^^^^^^^^^^^^^^ type annotation requires that `'1` must outlive `'static`
 
 error[E0597]: `self` does not live long enough
-  --> $DIR/regions-addr-of-upvar-self.rs:8:46
+  --> $DIR/regions-addr-of-upvar-self.rs:12:46
    |
 LL |         let _f = || {
    |                  -- value captured here
index 6159ab02d3d95161aa697138f24f8ba1832e68a6..36cc592d47c93e98bc2ff80b6cbc20d272325baa 100644 (file)
@@ -1,3 +1,7 @@
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 struct Dog {
     food: usize,
 }
@@ -5,7 +9,11 @@ struct Dog {
 impl Dog {
     pub fn chase_cat(&mut self) {
         let _f = || {
-            let p: &'static mut usize = &mut self.food; //~ ERROR cannot infer
+            let p: &'static mut usize = &mut self.food;
+            //[base]~^ ERROR cannot infer
+            //[nll]~^^ ERROR lifetime may not live long enough
+            //[nll]~^^^ ERROR lifetime may not live long enough
+            //[nll]~^^^^ ERROR E0597
             *p = 3;
         };
     }
diff --git a/src/test/ui/regions/regions-addr-of-upvar-self.stderr b/src/test/ui/regions/regions-addr-of-upvar-self.stderr
deleted file mode 100644 (file)
index f638064..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
-  --> $DIR/regions-addr-of-upvar-self.rs:8:41
-   |
-LL |             let p: &'static mut usize = &mut self.food;
-   |                                         ^^^^^^^^^^^^^^
-   |
-note: first, the lifetime cannot outlive the lifetime `'_` as defined here...
-  --> $DIR/regions-addr-of-upvar-self.rs:7:18
-   |
-LL |         let _f = || {
-   |                  ^^
-note: ...so that closure can access `self`
-  --> $DIR/regions-addr-of-upvar-self.rs:8:41
-   |
-LL |             let p: &'static mut usize = &mut self.food;
-   |                                         ^^^^^^^^^^^^^^
-   = note: but, the lifetime must be valid for the static lifetime...
-note: ...so that reference does not outlive borrowed content
-  --> $DIR/regions-addr-of-upvar-self.rs:8:41
-   |
-LL |             let p: &'static mut usize = &mut self.food;
-   |                                         ^^^^^^^^^^^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0495`.
diff --git a/src/test/ui/regions/regions-bounded-by-trait-requiring-static.base.stderr b/src/test/ui/regions/regions-bounded-by-trait-requiring-static.base.stderr
new file mode 100644 (file)
index 0000000..9b45dcf
--- /dev/null
@@ -0,0 +1,75 @@
+error[E0477]: the type `&'a isize` does not fulfill the required lifetime
+  --> $DIR/regions-bounded-by-trait-requiring-static.rs:26:5
+   |
+LL |     assert_send::<&'a isize>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: type must satisfy the static lifetime as required by this binding
+  --> $DIR/regions-bounded-by-trait-requiring-static.rs:10:18
+   |
+LL | fn assert_send<T:'static>() { }
+   |                  ^^^^^^^
+
+error[E0477]: the type `&'a str` does not fulfill the required lifetime
+  --> $DIR/regions-bounded-by-trait-requiring-static.rs:32:5
+   |
+LL |     assert_send::<&'a str>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: type must satisfy the static lifetime as required by this binding
+  --> $DIR/regions-bounded-by-trait-requiring-static.rs:10:18
+   |
+LL | fn assert_send<T:'static>() { }
+   |                  ^^^^^^^
+
+error[E0477]: the type `&'a [isize]` does not fulfill the required lifetime
+  --> $DIR/regions-bounded-by-trait-requiring-static.rs:38:5
+   |
+LL |     assert_send::<&'a [isize]>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: type must satisfy the static lifetime as required by this binding
+  --> $DIR/regions-bounded-by-trait-requiring-static.rs:10:18
+   |
+LL | fn assert_send<T:'static>() { }
+   |                  ^^^^^^^
+
+error[E0477]: the type `Box<&'a isize>` does not fulfill the required lifetime
+  --> $DIR/regions-bounded-by-trait-requiring-static.rs:54:5
+   |
+LL |     assert_send::<Box<&'a isize>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: type must satisfy the static lifetime as required by this binding
+  --> $DIR/regions-bounded-by-trait-requiring-static.rs:10:18
+   |
+LL | fn assert_send<T:'static>() { }
+   |                  ^^^^^^^
+
+error[E0477]: the type `*const &'a isize` does not fulfill the required lifetime
+  --> $DIR/regions-bounded-by-trait-requiring-static.rs:67:5
+   |
+LL |     assert_send::<*const &'a isize>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: type must satisfy the static lifetime as required by this binding
+  --> $DIR/regions-bounded-by-trait-requiring-static.rs:10:18
+   |
+LL | fn assert_send<T:'static>() { }
+   |                  ^^^^^^^
+
+error[E0477]: the type `*mut &'a isize` does not fulfill the required lifetime
+  --> $DIR/regions-bounded-by-trait-requiring-static.rs:73:5
+   |
+LL |     assert_send::<*mut &'a isize>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: type must satisfy the static lifetime as required by this binding
+  --> $DIR/regions-bounded-by-trait-requiring-static.rs:10:18
+   |
+LL | fn assert_send<T:'static>() { }
+   |                  ^^^^^^^
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0477`.
index 86bd100538d70ce5341cfcdc798a2ef48791028d..558a77516bbf73e48f496de63bf7f877ac098edb 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/regions-bounded-by-trait-requiring-static.rs:22:5
+  --> $DIR/regions-bounded-by-trait-requiring-static.rs:26:5
    |
 LL | fn param_not_ok<'a>(x: &'a isize) {
    |                 -- lifetime `'a` defined here
@@ -7,7 +7,7 @@ LL |     assert_send::<&'a isize>();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
 
 error: lifetime may not live long enough
-  --> $DIR/regions-bounded-by-trait-requiring-static.rs:26:5
+  --> $DIR/regions-bounded-by-trait-requiring-static.rs:32:5
    |
 LL | fn param_not_ok1<'a>(_: &'a isize) {
    |                  -- lifetime `'a` defined here
@@ -15,7 +15,7 @@ LL |     assert_send::<&'a str>();
    |     ^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
 
 error: lifetime may not live long enough
-  --> $DIR/regions-bounded-by-trait-requiring-static.rs:30:5
+  --> $DIR/regions-bounded-by-trait-requiring-static.rs:38:5
    |
 LL | fn param_not_ok2<'a>(_: &'a isize) {
    |                  -- lifetime `'a` defined here
@@ -23,7 +23,7 @@ LL |     assert_send::<&'a [isize]>();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
 
 error: lifetime may not live long enough
-  --> $DIR/regions-bounded-by-trait-requiring-static.rs:44:5
+  --> $DIR/regions-bounded-by-trait-requiring-static.rs:54:5
    |
 LL | fn box_with_region_not_ok<'a>() {
    |                           -- lifetime `'a` defined here
@@ -31,7 +31,7 @@ LL |     assert_send::<Box<&'a isize>>();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
 
 error: lifetime may not live long enough
-  --> $DIR/regions-bounded-by-trait-requiring-static.rs:55:5
+  --> $DIR/regions-bounded-by-trait-requiring-static.rs:67:5
    |
 LL | fn unsafe_ok2<'a>(_: &'a isize) {
    |               -- lifetime `'a` defined here
@@ -39,7 +39,7 @@ LL |     assert_send::<*const &'a isize>();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
 
 error: lifetime may not live long enough
-  --> $DIR/regions-bounded-by-trait-requiring-static.rs:59:5
+  --> $DIR/regions-bounded-by-trait-requiring-static.rs:73:5
    |
 LL | fn unsafe_ok3<'a>(_: &'a isize) {
    |               -- lifetime `'a` defined here
index c583f43638af37c14d2faede82779667fa122918..37dc1300d398329de11be9be47acf62ed4a23f25 100644 (file)
@@ -2,6 +2,10 @@
 // in this file all test region bound and lifetime violations that are
 // detected during type check.
 
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 trait Dummy : 'static { }
 fn assert_send<T:'static>() { }
 
@@ -19,15 +23,21 @@ fn static_lifime_ok<'a,T,U:Send>(_: &'a isize) {
 // otherwise lifetime pointers are not ok
 
 fn param_not_ok<'a>(x: &'a isize) {
-    assert_send::<&'a isize>(); //~ ERROR does not fulfill the required lifetime
+    assert_send::<&'a isize>();
+    //[base]~^ ERROR does not fulfill the required lifetime
+    //[nll]~^^ ERROR lifetime may not live long enough
 }
 
 fn param_not_ok1<'a>(_: &'a isize) {
-    assert_send::<&'a str>(); //~ ERROR does not fulfill the required lifetime
+    assert_send::<&'a str>();
+    //[base]~^ ERROR does not fulfill the required lifetime
+    //[nll]~^^ ERROR lifetime may not live long enough
 }
 
 fn param_not_ok2<'a>(_: &'a isize) {
-    assert_send::<&'a [isize]>(); //~ ERROR does not fulfill the required lifetime
+    assert_send::<&'a [isize]>();
+    //[base]~^ ERROR does not fulfill the required lifetime
+    //[nll]~^^ ERROR lifetime may not live long enough
 }
 
 // boxes are ok
@@ -41,7 +51,9 @@ fn box_ok() {
 // but not if they own a bad thing
 
 fn box_with_region_not_ok<'a>() {
-    assert_send::<Box<&'a isize>>(); //~ ERROR does not fulfill the required lifetime
+    assert_send::<Box<&'a isize>>();
+    //[base]~^ ERROR does not fulfill the required lifetime
+    //[nll]~^^ ERROR lifetime may not live long enough
 }
 
 // raw pointers are ok unless they point at unsendable things
@@ -52,11 +64,15 @@ fn unsafe_ok1<'a>(_: &'a isize) {
 }
 
 fn unsafe_ok2<'a>(_: &'a isize) {
-    assert_send::<*const &'a isize>(); //~ ERROR does not fulfill the required lifetime
+    assert_send::<*const &'a isize>();
+    //[base]~^ ERROR does not fulfill the required lifetime
+    //[nll]~^^ ERROR lifetime may not live long enough
 }
 
 fn unsafe_ok3<'a>(_: &'a isize) {
-    assert_send::<*mut &'a isize>(); //~ ERROR does not fulfill the required lifetime
+    assert_send::<*mut &'a isize>();
+    //[base]~^ ERROR does not fulfill the required lifetime
+    //[nll]~^^ ERROR lifetime may not live long enough
 }
 
 fn main() {
diff --git a/src/test/ui/regions/regions-bounded-by-trait-requiring-static.stderr b/src/test/ui/regions/regions-bounded-by-trait-requiring-static.stderr
deleted file mode 100644 (file)
index 68b90ee..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-error[E0477]: the type `&'a isize` does not fulfill the required lifetime
-  --> $DIR/regions-bounded-by-trait-requiring-static.rs:22:5
-   |
-LL |     assert_send::<&'a isize>();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: type must satisfy the static lifetime as required by this binding
-  --> $DIR/regions-bounded-by-trait-requiring-static.rs:6:18
-   |
-LL | fn assert_send<T:'static>() { }
-   |                  ^^^^^^^
-
-error[E0477]: the type `&'a str` does not fulfill the required lifetime
-  --> $DIR/regions-bounded-by-trait-requiring-static.rs:26:5
-   |
-LL |     assert_send::<&'a str>();
-   |     ^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: type must satisfy the static lifetime as required by this binding
-  --> $DIR/regions-bounded-by-trait-requiring-static.rs:6:18
-   |
-LL | fn assert_send<T:'static>() { }
-   |                  ^^^^^^^
-
-error[E0477]: the type `&'a [isize]` does not fulfill the required lifetime
-  --> $DIR/regions-bounded-by-trait-requiring-static.rs:30:5
-   |
-LL |     assert_send::<&'a [isize]>();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: type must satisfy the static lifetime as required by this binding
-  --> $DIR/regions-bounded-by-trait-requiring-static.rs:6:18
-   |
-LL | fn assert_send<T:'static>() { }
-   |                  ^^^^^^^
-
-error[E0477]: the type `Box<&'a isize>` does not fulfill the required lifetime
-  --> $DIR/regions-bounded-by-trait-requiring-static.rs:44:5
-   |
-LL |     assert_send::<Box<&'a isize>>();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: type must satisfy the static lifetime as required by this binding
-  --> $DIR/regions-bounded-by-trait-requiring-static.rs:6:18
-   |
-LL | fn assert_send<T:'static>() { }
-   |                  ^^^^^^^
-
-error[E0477]: the type `*const &'a isize` does not fulfill the required lifetime
-  --> $DIR/regions-bounded-by-trait-requiring-static.rs:55:5
-   |
-LL |     assert_send::<*const &'a isize>();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: type must satisfy the static lifetime as required by this binding
-  --> $DIR/regions-bounded-by-trait-requiring-static.rs:6:18
-   |
-LL | fn assert_send<T:'static>() { }
-   |                  ^^^^^^^
-
-error[E0477]: the type `*mut &'a isize` does not fulfill the required lifetime
-  --> $DIR/regions-bounded-by-trait-requiring-static.rs:59:5
-   |
-LL |     assert_send::<*mut &'a isize>();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: type must satisfy the static lifetime as required by this binding
-  --> $DIR/regions-bounded-by-trait-requiring-static.rs:6:18
-   |
-LL | fn assert_send<T:'static>() { }
-   |                  ^^^^^^^
-
-error: aborting due to 6 previous errors
-
-For more information about this error, try `rustc --explain E0477`.
diff --git a/src/test/ui/regions/regions-bounded-method-type-parameters-cross-crate.base.stderr b/src/test/ui/regions/regions-bounded-method-type-parameters-cross-crate.base.stderr
new file mode 100644 (file)
index 0000000..e031f0d
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/regions-bounded-method-type-parameters-cross-crate.rs:23:7
+   |
+LL | fn call_bigger_region<'x, 'y>(a: Inv<'x>, b: Inv<'y>) {
+   |                                  -------     ------- these two types are declared with different lifetimes...
+LL |     // Here the value provided for 'y is 'y, and hence 'y:'x does not hold.
+LL |     a.bigger_region(b)
+   |       ^^^^^^^^^^^^^ ...but data from `b` flows into `a` here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0623`.
index 6193bf02f6d0d4f7ffaf089a2d9268f973e4b28c..4f5d747be711bc8cb5efbcef4ae301d2fcfe36e3 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/regions-bounded-method-type-parameters-cross-crate.rs:20:5
+  --> $DIR/regions-bounded-method-type-parameters-cross-crate.rs:23:5
    |
 LL | fn call_bigger_region<'x, 'y>(a: Inv<'x>, b: Inv<'y>) {
    |                       --  -- lifetime `'y` defined here
index a7987d0e1feb0acf8c19da5131c1d1c9c6429edc..e0965613f1dbec7c5ccef7bb8c7a2dc32880509f 100644 (file)
@@ -1,4 +1,7 @@
 // aux-build:rbmtp_cross_crate_lib.rs
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
 
 // Check explicit region bounds on methods in the cross crate case.
 
@@ -17,7 +20,9 @@ fn call_into_maybe_owned<'x,F:IntoMaybeOwned<'x>>(f: F) {
 
 fn call_bigger_region<'x, 'y>(a: Inv<'x>, b: Inv<'y>) {
     // Here the value provided for 'y is 'y, and hence 'y:'x does not hold.
-    a.bigger_region(b) //~ ERROR lifetime mismatch [E0623]
+    a.bigger_region(b)
+    //[base]~^ ERROR lifetime mismatch [E0623]
+    //[nll]~^^ ERROR lifetime may not live long enough
 }
 
 fn main() { }
diff --git a/src/test/ui/regions/regions-bounded-method-type-parameters-cross-crate.stderr b/src/test/ui/regions/regions-bounded-method-type-parameters-cross-crate.stderr
deleted file mode 100644 (file)
index eb205a3..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0623]: lifetime mismatch
-  --> $DIR/regions-bounded-method-type-parameters-cross-crate.rs:20:7
-   |
-LL | fn call_bigger_region<'x, 'y>(a: Inv<'x>, b: Inv<'y>) {
-   |                                  -------     ------- these two types are declared with different lifetimes...
-LL |     // Here the value provided for 'y is 'y, and hence 'y:'x does not hold.
-LL |     a.bigger_region(b)
-   |       ^^^^^^^^^^^^^ ...but data from `b` flows into `a` here
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0623`.
diff --git a/src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.base.stderr b/src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.base.stderr
new file mode 100644 (file)
index 0000000..0a213e3
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/regions-bounded-method-type-parameters-trait-bound.rs:24:7
+   |
+LL | fn caller2<'a,'b,F:Foo<'a>>(a: Inv<'a>, b: Inv<'b>, f: F) {
+   |                                -------     ------- these two types are declared with different lifetimes...
+LL |     // Here the value provided for 'y is 'b, and hence 'b:'a does not hold.
+LL |     f.method(b);
+   |       ^^^^^^ ...but data from `b` flows into `a` here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0623`.
index 0e0086be9ea8d588e72d9593cb85cc3d4f06171f..1c2f46a5fc1b2ced2dc4a7cf698842781c593814 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/regions-bounded-method-type-parameters-trait-bound.rs:20:5
+  --> $DIR/regions-bounded-method-type-parameters-trait-bound.rs:24:5
    |
 LL | fn caller2<'a,'b,F:Foo<'a>>(a: Inv<'a>, b: Inv<'b>, f: F) {
    |            -- -- lifetime `'b` defined here
index 8adf496b2304da6ef9d6ec8e0538f1c7f456dc92..8a52a1549abf2a328ffe6a8acb07c31a6f986624 100644 (file)
@@ -2,6 +2,10 @@
 // nominal types (but not on other types) and that they are type
 // checked.
 
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 struct Inv<'a> { // invariant w/r/t 'a
     x: &'a mut &'a isize
 }
@@ -17,7 +21,9 @@ fn caller1<'a,'b,F:Foo<'a>>(a: Inv<'a>, b: Inv<'b>, f: F) {
 
 fn caller2<'a,'b,F:Foo<'a>>(a: Inv<'a>, b: Inv<'b>, f: F) {
     // Here the value provided for 'y is 'b, and hence 'b:'a does not hold.
-    f.method(b); //~ ERROR lifetime mismatch [E0623]
+    f.method(b);
+    //[base]~^ ERROR lifetime mismatch [E0623]
+    //[nll]~^^ ERROR lifetime may not live long enough
 }
 
 fn caller3<'a,'b:'a,F:Foo<'a>>(a: Inv<'a>, b: Inv<'b>, f: F) {
diff --git a/src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.stderr b/src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.stderr
deleted file mode 100644 (file)
index de1073c..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0623]: lifetime mismatch
-  --> $DIR/regions-bounded-method-type-parameters-trait-bound.rs:20:7
-   |
-LL | fn caller2<'a,'b,F:Foo<'a>>(a: Inv<'a>, b: Inv<'b>, f: F) {
-   |                                -------     ------- these two types are declared with different lifetimes...
-LL |     // Here the value provided for 'y is 'b, and hence 'b:'a does not hold.
-LL |     f.method(b);
-   |       ^^^^^^ ...but data from `b` flows into `a` here
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0623`.
diff --git a/src/test/ui/regions/regions-bounded-method-type-parameters.base.stderr b/src/test/ui/regions/regions-bounded-method-type-parameters.base.stderr
new file mode 100644 (file)
index 0000000..3d37a1b
--- /dev/null
@@ -0,0 +1,15 @@
+error[E0477]: the type `&'a isize` does not fulfill the required lifetime
+  --> $DIR/regions-bounded-method-type-parameters.rs:16:9
+   |
+LL |     Foo.some_method::<&'a isize>();
+   |         ^^^^^^^^^^^
+   |
+note: type must satisfy the static lifetime as required by this binding
+  --> $DIR/regions-bounded-method-type-parameters.rs:12:22
+   |
+LL |     fn some_method<A:'static>(self) { }
+   |                      ^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0477`.
index b6d7b8aac5f19f927e399aa28aaec81af9eb87b6..05c3fa58ea363482cdf0cfb3f9fabeaa46375016 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/regions-bounded-method-type-parameters.rs:12:9
+  --> $DIR/regions-bounded-method-type-parameters.rs:16:9
    |
 LL | fn caller<'a>(x: &isize) {
    |           -- lifetime `'a` defined here
index 90af120f052b0c199b83c3d3d3bc151184ce4918..06bc1544a3807e3d55319fdb2e84fc5878b2dc7b 100644 (file)
@@ -2,6 +2,10 @@
 // nominal types (but not on other types) and that they are type
 // checked.
 
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 struct Foo;
 
 impl Foo {
@@ -10,7 +14,8 @@ fn some_method<A:'static>(self) { }
 
 fn caller<'a>(x: &isize) {
     Foo.some_method::<&'a isize>();
-    //~^ ERROR does not fulfill the required lifetime
+    //[base]~^ ERROR does not fulfill the required lifetime
+    //[nll]~^^ ERROR lifetime may not live long enough
 }
 
 fn main() { }
diff --git a/src/test/ui/regions/regions-bounded-method-type-parameters.stderr b/src/test/ui/regions/regions-bounded-method-type-parameters.stderr
deleted file mode 100644 (file)
index 318e9d0..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-error[E0477]: the type `&'a isize` does not fulfill the required lifetime
-  --> $DIR/regions-bounded-method-type-parameters.rs:12:9
-   |
-LL |     Foo.some_method::<&'a isize>();
-   |         ^^^^^^^^^^^
-   |
-note: type must satisfy the static lifetime as required by this binding
-  --> $DIR/regions-bounded-method-type-parameters.rs:8:22
-   |
-LL |     fn some_method<A:'static>(self) { }
-   |                      ^^^^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0477`.
diff --git a/src/test/ui/regions/regions-bounds.base.stderr b/src/test/ui/regions/regions-bounds.base.stderr
new file mode 100644 (file)
index 0000000..d853cdd
--- /dev/null
@@ -0,0 +1,41 @@
+error[E0308]: mismatched types
+  --> $DIR/regions-bounds.rs:13:12
+   |
+LL |     return e;
+   |            ^ lifetime mismatch
+   |
+   = note: expected struct `TupleStruct<'b>`
+              found struct `TupleStruct<'a>`
+note: the lifetime `'a` as defined here...
+  --> $DIR/regions-bounds.rs:12:10
+   |
+LL | fn a_fn1<'a,'b>(e: TupleStruct<'a>) -> TupleStruct<'b> {
+   |          ^^
+note: ...does not necessarily outlive the lifetime `'b` as defined here
+  --> $DIR/regions-bounds.rs:12:13
+   |
+LL | fn a_fn1<'a,'b>(e: TupleStruct<'a>) -> TupleStruct<'b> {
+   |             ^^
+
+error[E0308]: mismatched types
+  --> $DIR/regions-bounds.rs:19:12
+   |
+LL |     return e;
+   |            ^ lifetime mismatch
+   |
+   = note: expected struct `Struct<'b>`
+              found struct `Struct<'a>`
+note: the lifetime `'a` as defined here...
+  --> $DIR/regions-bounds.rs:18:10
+   |
+LL | fn a_fn3<'a,'b>(e: Struct<'a>) -> Struct<'b> {
+   |          ^^
+note: ...does not necessarily outlive the lifetime `'b` as defined here
+  --> $DIR/regions-bounds.rs:18:13
+   |
+LL | fn a_fn3<'a,'b>(e: Struct<'a>) -> Struct<'b> {
+   |             ^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
index 84226a5755319cf0e06572867df3b81fed9051c1..7109220165f129f489512086f9b9bf4f262ebf4e 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/regions-bounds.rs:9:12
+  --> $DIR/regions-bounds.rs:13:12
    |
 LL | fn a_fn1<'a,'b>(e: TupleStruct<'a>) -> TupleStruct<'b> {
    |          -- -- lifetime `'b` defined here
@@ -11,7 +11,7 @@ LL |     return e;
    = help: consider adding the following bound: `'a: 'b`
 
 error: lifetime may not live long enough
-  --> $DIR/regions-bounds.rs:13:12
+  --> $DIR/regions-bounds.rs:19:12
    |
 LL | fn a_fn3<'a,'b>(e: Struct<'a>) -> Struct<'b> {
    |          -- -- lifetime `'b` defined here
index d3e4e6e8712bf2d2ebb9f94a4a41411bfbf19f7b..b13dac49f8c85ebd46919104680d27d9eb2ddab4 100644 (file)
@@ -2,15 +2,23 @@
 // nominal types (but not on other types) and that they are type
 // checked.
 
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 struct TupleStruct<'a>(&'a isize);
 struct Struct<'a> { x:&'a isize }
 
 fn a_fn1<'a,'b>(e: TupleStruct<'a>) -> TupleStruct<'b> {
-    return e; //~ ERROR mismatched types
+    return e;
+    //[base]~^ ERROR mismatched types
+    //[nll]~^^ ERROR lifetime may not live long enough
 }
 
 fn a_fn3<'a,'b>(e: Struct<'a>) -> Struct<'b> {
-    return e; //~ ERROR mismatched types
+    return e;
+    //[base]~^ ERROR mismatched types
+    //[nll]~^^ ERROR lifetime may not live long enough
 }
 
 fn main() { }
diff --git a/src/test/ui/regions/regions-bounds.stderr b/src/test/ui/regions/regions-bounds.stderr
deleted file mode 100644 (file)
index 90227e5..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-error[E0308]: mismatched types
-  --> $DIR/regions-bounds.rs:9:12
-   |
-LL |     return e;
-   |            ^ lifetime mismatch
-   |
-   = note: expected struct `TupleStruct<'b>`
-              found struct `TupleStruct<'a>`
-note: the lifetime `'a` as defined here...
-  --> $DIR/regions-bounds.rs:8:10
-   |
-LL | fn a_fn1<'a,'b>(e: TupleStruct<'a>) -> TupleStruct<'b> {
-   |          ^^
-note: ...does not necessarily outlive the lifetime `'b` as defined here
-  --> $DIR/regions-bounds.rs:8:13
-   |
-LL | fn a_fn1<'a,'b>(e: TupleStruct<'a>) -> TupleStruct<'b> {
-   |             ^^
-
-error[E0308]: mismatched types
-  --> $DIR/regions-bounds.rs:13:12
-   |
-LL |     return e;
-   |            ^ lifetime mismatch
-   |
-   = note: expected struct `Struct<'b>`
-              found struct `Struct<'a>`
-note: the lifetime `'a` as defined here...
-  --> $DIR/regions-bounds.rs:12:10
-   |
-LL | fn a_fn3<'a,'b>(e: Struct<'a>) -> Struct<'b> {
-   |          ^^
-note: ...does not necessarily outlive the lifetime `'b` as defined here
-  --> $DIR/regions-bounds.rs:12:13
-   |
-LL | fn a_fn3<'a,'b>(e: Struct<'a>) -> Struct<'b> {
-   |             ^^
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/regions/regions-close-associated-type-into-object.base.stderr b/src/test/ui/regions/regions-close-associated-type-into-object.base.stderr
new file mode 100644 (file)
index 0000000..fbbb598
--- /dev/null
@@ -0,0 +1,40 @@
+error[E0310]: the associated type `<T as Iter>::Item` may not live long enough
+  --> $DIR/regions-close-associated-type-into-object.rs:19:5
+   |
+LL |     Box::new(item)
+   |     ^^^^^^^^^^^^^^
+   |
+   = help: consider adding an explicit lifetime bound `<T as Iter>::Item: 'static`...
+   = note: ...so that the type `<T as Iter>::Item` will meet its required lifetime bounds
+
+error[E0310]: the associated type `<T as Iter>::Item` may not live long enough
+  --> $DIR/regions-close-associated-type-into-object.rs:26:5
+   |
+LL |     Box::new(item)
+   |     ^^^^^^^^^^^^^^
+   |
+   = help: consider adding an explicit lifetime bound `<T as Iter>::Item: 'static`...
+   = note: ...so that the type `Box<<T as Iter>::Item>` will meet its required lifetime bounds
+
+error[E0309]: the associated type `<T as Iter>::Item` may not live long enough
+  --> $DIR/regions-close-associated-type-into-object.rs:32:5
+   |
+LL |     Box::new(item)
+   |     ^^^^^^^^^^^^^^
+   |
+   = help: consider adding an explicit lifetime bound `<T as Iter>::Item: 'a`...
+   = note: ...so that the type `<T as Iter>::Item` will meet its required lifetime bounds
+
+error[E0309]: the associated type `<T as Iter>::Item` may not live long enough
+  --> $DIR/regions-close-associated-type-into-object.rs:39:5
+   |
+LL |     Box::new(item)
+   |     ^^^^^^^^^^^^^^
+   |
+   = help: consider adding an explicit lifetime bound `<T as Iter>::Item: 'a`...
+   = note: ...so that the type `Box<<T as Iter>::Item>` will meet its required lifetime bounds
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0309, E0310.
+For more information about an error, try `rustc --explain E0309`.
index 92c4956da02d26c0eebb0f3df84f631b215a3591..dd4b97aa5628aea116c149f90bb685ae5638e054 100644 (file)
@@ -1,34 +1,38 @@
 error[E0310]: the associated type `<T as Iter>::Item` may not live long enough
-  --> $DIR/regions-close-associated-type-into-object.rs:15:5
+  --> $DIR/regions-close-associated-type-into-object.rs:19:5
    |
 LL |     Box::new(item)
    |     ^^^^^^^^^^^^^^
    |
    = help: consider adding an explicit lifetime bound `<T as Iter>::Item: 'static`...
+   = note: ...so that the type `<T as Iter>::Item` will meet its required lifetime bounds
 
 error[E0310]: the associated type `<T as Iter>::Item` may not live long enough
-  --> $DIR/regions-close-associated-type-into-object.rs:22:5
+  --> $DIR/regions-close-associated-type-into-object.rs:26:5
    |
 LL |     Box::new(item)
    |     ^^^^^^^^^^^^^^
    |
    = help: consider adding an explicit lifetime bound `<T as Iter>::Item: 'static`...
+   = note: ...so that the type `<T as Iter>::Item` will meet its required lifetime bounds
 
 error[E0309]: the associated type `<T as Iter>::Item` may not live long enough
-  --> $DIR/regions-close-associated-type-into-object.rs:28:5
+  --> $DIR/regions-close-associated-type-into-object.rs:32:5
    |
 LL |     Box::new(item)
    |     ^^^^^^^^^^^^^^
    |
    = help: consider adding an explicit lifetime bound `<T as Iter>::Item: 'a`...
+   = note: ...so that the type `<T as Iter>::Item` will meet its required lifetime bounds
 
 error[E0309]: the associated type `<T as Iter>::Item` may not live long enough
-  --> $DIR/regions-close-associated-type-into-object.rs:35:5
+  --> $DIR/regions-close-associated-type-into-object.rs:39:5
    |
 LL |     Box::new(item)
    |     ^^^^^^^^^^^^^^
    |
    = help: consider adding an explicit lifetime bound `<T as Iter>::Item: 'a`...
+   = note: ...so that the type `<T as Iter>::Item` will meet its required lifetime bounds
 
 error: aborting due to 4 previous errors
 
index 428477e24899a8437733de8f6b04924a8e41e4ae..94199f562122828d72a6a3152b7df17270d80097 100644 (file)
@@ -1,3 +1,7 @@
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 trait X {}
 
 
diff --git a/src/test/ui/regions/regions-close-associated-type-into-object.stderr b/src/test/ui/regions/regions-close-associated-type-into-object.stderr
deleted file mode 100644 (file)
index 536a1b5..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-error[E0310]: the associated type `<T as Iter>::Item` may not live long enough
-  --> $DIR/regions-close-associated-type-into-object.rs:15:5
-   |
-LL |     Box::new(item)
-   |     ^^^^^^^^^^^^^^
-   |
-   = help: consider adding an explicit lifetime bound `<T as Iter>::Item: 'static`...
-   = note: ...so that the type `<T as Iter>::Item` will meet its required lifetime bounds
-
-error[E0310]: the associated type `<T as Iter>::Item` may not live long enough
-  --> $DIR/regions-close-associated-type-into-object.rs:22:5
-   |
-LL |     Box::new(item)
-   |     ^^^^^^^^^^^^^^
-   |
-   = help: consider adding an explicit lifetime bound `<T as Iter>::Item: 'static`...
-   = note: ...so that the type `Box<<T as Iter>::Item>` will meet its required lifetime bounds
-
-error[E0309]: the associated type `<T as Iter>::Item` may not live long enough
-  --> $DIR/regions-close-associated-type-into-object.rs:28:5
-   |
-LL |     Box::new(item)
-   |     ^^^^^^^^^^^^^^
-   |
-   = help: consider adding an explicit lifetime bound `<T as Iter>::Item: 'a`...
-   = note: ...so that the type `<T as Iter>::Item` will meet its required lifetime bounds
-
-error[E0309]: the associated type `<T as Iter>::Item` may not live long enough
-  --> $DIR/regions-close-associated-type-into-object.rs:35:5
-   |
-LL |     Box::new(item)
-   |     ^^^^^^^^^^^^^^
-   |
-   = help: consider adding an explicit lifetime bound `<T as Iter>::Item: 'a`...
-   = note: ...so that the type `Box<<T as Iter>::Item>` will meet its required lifetime bounds
-
-error: aborting due to 4 previous errors
-
-Some errors have detailed explanations: E0309, E0310.
-For more information about an error, try `rustc --explain E0309`.
diff --git a/src/test/ui/regions/regions-close-object-into-object-2.base.stderr b/src/test/ui/regions/regions-close-object-into-object-2.base.stderr
new file mode 100644 (file)
index 0000000..ddf168f
--- /dev/null
@@ -0,0 +1,27 @@
+error[E0759]: `v` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
+  --> $DIR/regions-close-object-into-object-2.rs:13:16
+   |
+LL | fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'static> {
+   |                         ------------------ this data with lifetime `'a`...
+LL |     Box::new(B(&*v)) as Box<dyn X>
+   |                ^^^ ...is used and required to live as long as `'static` here
+   |
+note: `'static` lifetime requirement introduced by the return type
+  --> $DIR/regions-close-object-into-object-2.rs:12:60
+   |
+LL | fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'static> {
+   |                                                            ^^^^^^^ `'static` requirement introduced here
+LL |     Box::new(B(&*v)) as Box<dyn X>
+   |     ------------------------------ because of this returned expression
+help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v`
+   |
+LL | fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'a> {
+   |                                                            ~~
+help: alternatively, add an explicit `'static` bound to this reference
+   |
+LL | fn g<'a, T: 'static>(v: Box<(dyn A<T> + 'static)>) -> Box<dyn X + 'static> {
+   |                         ~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0759`.
index 6a0e95861610173296f1de7589244c36e5285699..473c99b672fb692125395e117e4bcd0241a2385f 100644 (file)
@@ -1,13 +1,22 @@
 error: lifetime may not live long enough
-  --> $DIR/regions-close-object-into-object-2.rs:9:5
+  --> $DIR/regions-close-object-into-object-2.rs:13:5
    |
 LL | fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'static> {
    |      -- lifetime `'a` defined here
 LL |     Box::new(B(&*v)) as Box<dyn X>
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
+   |
+help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v`
+   |
+LL | fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'a> {
+   |                                                            ~~
+help: alternatively, add an explicit `'static` bound to this reference
+   |
+LL | fn g<'a, T: 'static>(v: Box<(dyn A<T> + 'static)>) -> Box<dyn X + 'static> {
+   |                         ~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error[E0515]: cannot return value referencing local data `*v`
-  --> $DIR/regions-close-object-into-object-2.rs:9:5
+  --> $DIR/regions-close-object-into-object-2.rs:13:5
    |
 LL |     Box::new(B(&*v)) as Box<dyn X>
    |     ^^^^^^^^^^^---^^^^^^^^^^^^^^^^
index 9c41174e24d8db96cc84b0c58fc2a99948fe3f86..33ea03f061e093ee7402c62aae9e9d04292910dc 100644 (file)
@@ -1,3 +1,7 @@
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 trait A<T> { }
 
 struct B<'a, T:'a>(&'a (dyn A<T> + 'a));
@@ -6,7 +10,10 @@ trait X { }
 impl<'a, T> X for B<'a, T> {}
 
 fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'static> {
-    Box::new(B(&*v)) as Box<dyn X> //~ ERROR E0759
+    Box::new(B(&*v)) as Box<dyn X>
+    //[base]~^ ERROR E0759
+    //[nll]~^^ ERROR lifetime may not live long enough
+    //[nll]~| ERROR cannot return value referencing local data `*v` [E0515]
 }
 
 fn main() { }
diff --git a/src/test/ui/regions/regions-close-object-into-object-2.stderr b/src/test/ui/regions/regions-close-object-into-object-2.stderr
deleted file mode 100644 (file)
index 4153f4f..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-error[E0759]: `v` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
-  --> $DIR/regions-close-object-into-object-2.rs:9:16
-   |
-LL | fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'static> {
-   |                         ------------------ this data with lifetime `'a`...
-LL |     Box::new(B(&*v)) as Box<dyn X>
-   |                ^^^ ...is used and required to live as long as `'static` here
-   |
-note: `'static` lifetime requirement introduced by the return type
-  --> $DIR/regions-close-object-into-object-2.rs:8:60
-   |
-LL | fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'static> {
-   |                                                            ^^^^^^^ `'static` requirement introduced here
-LL |     Box::new(B(&*v)) as Box<dyn X>
-   |     ------------------------------ because of this returned expression
-help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v`
-   |
-LL | fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'a> {
-   |                                                            ~~
-help: alternatively, add an explicit `'static` bound to this reference
-   |
-LL | fn g<'a, T: 'static>(v: Box<(dyn A<T> + 'static)>) -> Box<dyn X + 'static> {
-   |                         ~~~~~~~~~~~~~~~~~~~~~~~~~
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0759`.
diff --git a/src/test/ui/regions/regions-close-object-into-object-4.base.stderr b/src/test/ui/regions/regions-close-object-into-object-4.base.stderr
new file mode 100644 (file)
index 0000000..33d4df3
--- /dev/null
@@ -0,0 +1,27 @@
+error[E0759]: `v` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
+  --> $DIR/regions-close-object-into-object-4.rs:13:16
+   |
+LL | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
+   |                   ---------------- this data with lifetime `'a`...
+LL |     Box::new(B(&*v)) as Box<dyn X>
+   |                ^^^ ...is used and required to live as long as `'static` here
+   |
+note: `'static` lifetime requirement introduced by the return type
+  --> $DIR/regions-close-object-into-object-4.rs:12:52
+   |
+LL | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
+   |                                                    ^^^^^^^ `'static` requirement introduced here
+LL |     Box::new(B(&*v)) as Box<dyn X>
+   |     ------------------------------ because of this returned expression
+help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v`
+   |
+LL | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'a> {
+   |                                                    ~~
+help: alternatively, add an explicit `'static` bound to this reference
+   |
+LL | fn i<'a, T, U>(v: Box<(dyn A<U> + 'static)>) -> Box<dyn X + 'static> {
+   |                   ~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0759`.
index b30626830ad6bbbe5d345ce7eb183be51ecb9cf4..66d3102225ecc809ddd2885266ee3829ca184791 100644 (file)
@@ -1,37 +1,55 @@
 error[E0310]: the parameter type `U` may not live long enough
-  --> $DIR/regions-close-object-into-object-4.rs:9:5
+  --> $DIR/regions-close-object-into-object-4.rs:13:5
    |
 LL |     Box::new(B(&*v)) as Box<dyn X>
-   |     ^^^^^^^^
+   |     ^^^^^^^^ ...so that the type `U` will meet its required lifetime bounds
    |
-   = help: consider adding an explicit lifetime bound `U: 'static`...
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn i<'a, T, U: 'static>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
+   |              +++++++++
 
 error[E0310]: the parameter type `U` may not live long enough
-  --> $DIR/regions-close-object-into-object-4.rs:9:5
+  --> $DIR/regions-close-object-into-object-4.rs:13:5
    |
 LL |     Box::new(B(&*v)) as Box<dyn X>
-   |     ^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^ ...so that the type `U` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
    |
-   = help: consider adding an explicit lifetime bound `U: 'static`...
+LL | fn i<'a, T, U: 'static>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
+   |              +++++++++
 
 error[E0310]: the parameter type `U` may not live long enough
-  --> $DIR/regions-close-object-into-object-4.rs:9:5
+  --> $DIR/regions-close-object-into-object-4.rs:13:5
    |
 LL |     Box::new(B(&*v)) as Box<dyn X>
-   |     ^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^ ...so that the type `U` will meet its required lifetime bounds
    |
-   = help: consider adding an explicit lifetime bound `U: 'static`...
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn i<'a, T, U: 'static>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
+   |              +++++++++
 
 error: lifetime may not live long enough
-  --> $DIR/regions-close-object-into-object-4.rs:9:5
+  --> $DIR/regions-close-object-into-object-4.rs:13:5
    |
 LL | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
    |      -- lifetime `'a` defined here
 LL |     Box::new(B(&*v)) as Box<dyn X>
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
+   |
+help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v`
+   |
+LL | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'a> {
+   |                                                    ~~
+help: alternatively, add an explicit `'static` bound to this reference
+   |
+LL | fn i<'a, T, U>(v: Box<(dyn A<U> + 'static)>) -> Box<dyn X + 'static> {
+   |                   ~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error[E0515]: cannot return value referencing local data `*v`
-  --> $DIR/regions-close-object-into-object-4.rs:9:5
+  --> $DIR/regions-close-object-into-object-4.rs:13:5
    |
 LL |     Box::new(B(&*v)) as Box<dyn X>
    |     ^^^^^^^^^^^---^^^^^^^^^^^^^^^^
@@ -40,12 +58,15 @@ LL |     Box::new(B(&*v)) as Box<dyn X>
    |     returns a value referencing data owned by the current function
 
 error[E0310]: the parameter type `U` may not live long enough
-  --> $DIR/regions-close-object-into-object-4.rs:9:14
+  --> $DIR/regions-close-object-into-object-4.rs:13:14
    |
 LL |     Box::new(B(&*v)) as Box<dyn X>
-   |              ^^^^^^
+   |              ^^^^^^ ...so that the type `U` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
    |
-   = help: consider adding an explicit lifetime bound `U: 'static`...
+LL | fn i<'a, T, U: 'static>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
+   |              +++++++++
 
 error: aborting due to 6 previous errors
 
index 2a06a2b7c0513630af945507700c46592af52a26..5a852b7329a0f87f917fe19a4e568cf12a06a02d 100644 (file)
@@ -1,3 +1,7 @@
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 trait A<T> { }
 
 struct B<'a, T:'a>(&'a (dyn A<T> + 'a));
@@ -6,7 +10,15 @@ trait X { }
 impl<'a, T> X for B<'a, T> {}
 
 fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
-    Box::new(B(&*v)) as Box<dyn X> //~ ERROR E0759
+    Box::new(B(&*v)) as Box<dyn X>
+    //[base]~^ ERROR E0759
+    //[nll]~^^ ERROR the parameter type `U` may not live long enough [E0310]
+    //[nll]~| ERROR the parameter type `U` may not live long enough [E0310]
+    //[nll]~| ERROR the parameter type `U` may not live long enough [E0310]
+    //[nll]~| ERROR lifetime may not live long enough
+    //[nll]~| ERROR cannot return value referencing local data `*v` [E0515]
+    //[nll]~| ERROR the parameter type `U` may not live long enough [E0310]
+
 }
 
 fn main() {}
diff --git a/src/test/ui/regions/regions-close-object-into-object-4.stderr b/src/test/ui/regions/regions-close-object-into-object-4.stderr
deleted file mode 100644 (file)
index 2ea4b43..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-error[E0759]: `v` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
-  --> $DIR/regions-close-object-into-object-4.rs:9:16
-   |
-LL | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
-   |                   ---------------- this data with lifetime `'a`...
-LL |     Box::new(B(&*v)) as Box<dyn X>
-   |                ^^^ ...is used and required to live as long as `'static` here
-   |
-note: `'static` lifetime requirement introduced by the return type
-  --> $DIR/regions-close-object-into-object-4.rs:8:52
-   |
-LL | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
-   |                                                    ^^^^^^^ `'static` requirement introduced here
-LL |     Box::new(B(&*v)) as Box<dyn X>
-   |     ------------------------------ because of this returned expression
-help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v`
-   |
-LL | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'a> {
-   |                                                    ~~
-help: alternatively, add an explicit `'static` bound to this reference
-   |
-LL | fn i<'a, T, U>(v: Box<(dyn A<U> + 'static)>) -> Box<dyn X + 'static> {
-   |                   ~~~~~~~~~~~~~~~~~~~~~~~~~
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0759`.
diff --git a/src/test/ui/regions/regions-close-object-into-object-5.base.stderr b/src/test/ui/regions/regions-close-object-into-object-5.base.stderr
new file mode 100644 (file)
index 0000000..1a78079
--- /dev/null
@@ -0,0 +1,95 @@
+error[E0310]: the parameter type `T` may not live long enough
+  --> $DIR/regions-close-object-into-object-5.rs:21:5
+   |
+LL |     Box::new(B(&*v)) as Box<dyn X>
+   |     ^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds...
+   |
+note: ...that is required by this bound
+  --> $DIR/regions-close-object-into-object-5.rs:13:17
+   |
+LL | struct B<'a, T: 'a>(&'a (A<T> + 'a));
+   |                 ^^
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn f<'a, T: 'static, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
+   |           +++++++++
+
+error[E0310]: the parameter type `T` may not live long enough
+  --> $DIR/regions-close-object-into-object-5.rs:21:5
+   |
+LL |     Box::new(B(&*v)) as Box<dyn X>
+   |     ^^^^^^^^^^^^^^^^ ...so that the type `B<'_, T>` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn f<'a, T: 'static, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
+   |           +++++++++
+
+error[E0310]: the parameter type `T` may not live long enough
+  --> $DIR/regions-close-object-into-object-5.rs:21:14
+   |
+LL |     Box::new(B(&*v)) as Box<dyn X>
+   |              ^ ...so that the type `T` will meet its required lifetime bounds...
+   |
+note: ...that is required by this bound
+  --> $DIR/regions-close-object-into-object-5.rs:13:17
+   |
+LL | struct B<'a, T: 'a>(&'a (A<T> + 'a));
+   |                 ^^
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn f<'a, T: 'static, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
+   |           +++++++++
+
+error[E0310]: the parameter type `T` may not live long enough
+  --> $DIR/regions-close-object-into-object-5.rs:21:14
+   |
+LL |     Box::new(B(&*v)) as Box<dyn X>
+   |              ^^^^^^ ...so that the type `T` will meet its required lifetime bounds...
+   |
+note: ...that is required by this bound
+  --> $DIR/regions-close-object-into-object-5.rs:13:17
+   |
+LL | struct B<'a, T: 'a>(&'a (A<T> + 'a));
+   |                 ^^
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn f<'a, T: 'static, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
+   |           +++++++++
+
+error[E0310]: the parameter type `T` may not live long enough
+  --> $DIR/regions-close-object-into-object-5.rs:21:16
+   |
+LL |     Box::new(B(&*v)) as Box<dyn X>
+   |                ^^^ ...so that the reference type `&dyn A<T>` does not outlive the data it points at
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn f<'a, T: 'static, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
+   |           +++++++++
+
+error[E0310]: the parameter type `T` may not live long enough
+  --> $DIR/regions-close-object-into-object-5.rs:21:16
+   |
+LL |     Box::new(B(&*v)) as Box<dyn X>
+   |                ^^^ ...so that the type `(dyn A<T> + 'static)` is not borrowed for too long
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn f<'a, T: 'static, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
+   |           +++++++++
+
+error[E0310]: the parameter type `T` may not live long enough
+  --> $DIR/regions-close-object-into-object-5.rs:21:16
+   |
+LL |     Box::new(B(&*v)) as Box<dyn X>
+   |                ^^^ ...so that the type `(dyn A<T> + 'static)` is not borrowed for too long
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn f<'a, T: 'static, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
+   |           +++++++++
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0310`.
index 7486e73e66ab31122bda6f9b0af5301668a2cc94..cb06326130e10c800b602f19670685e7359eb101 100644 (file)
@@ -1,29 +1,38 @@
 error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/regions-close-object-into-object-5.rs:17:5
+  --> $DIR/regions-close-object-into-object-5.rs:21:5
    |
 LL |     Box::new(B(&*v)) as Box<dyn X>
-   |     ^^^^^^^^
+   |     ^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
    |
-   = help: consider adding an explicit lifetime bound `T: 'static`...
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn f<'a, T: 'static, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
+   |           +++++++++
 
 error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/regions-close-object-into-object-5.rs:17:5
+  --> $DIR/regions-close-object-into-object-5.rs:21:5
    |
 LL |     Box::new(B(&*v)) as Box<dyn X>
-   |     ^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
    |
-   = help: consider adding an explicit lifetime bound `T: 'static`...
+LL | fn f<'a, T: 'static, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
+   |           +++++++++
 
 error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/regions-close-object-into-object-5.rs:17:5
+  --> $DIR/regions-close-object-into-object-5.rs:21:5
    |
 LL |     Box::new(B(&*v)) as Box<dyn X>
-   |     ^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
    |
-   = help: consider adding an explicit lifetime bound `T: 'static`...
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn f<'a, T: 'static, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
+   |           +++++++++
 
 error[E0515]: cannot return value referencing local data `*v`
-  --> $DIR/regions-close-object-into-object-5.rs:17:5
+  --> $DIR/regions-close-object-into-object-5.rs:21:5
    |
 LL |     Box::new(B(&*v)) as Box<dyn X>
    |     ^^^^^^^^^^^---^^^^^^^^^^^^^^^^
@@ -32,12 +41,15 @@ LL |     Box::new(B(&*v)) as Box<dyn X>
    |     returns a value referencing data owned by the current function
 
 error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/regions-close-object-into-object-5.rs:17:14
+  --> $DIR/regions-close-object-into-object-5.rs:21:14
    |
 LL |     Box::new(B(&*v)) as Box<dyn X>
-   |              ^^^^^^
+   |              ^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
    |
-   = help: consider adding an explicit lifetime bound `T: 'static`...
+LL | fn f<'a, T: 'static, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
+   |           +++++++++
 
 error: aborting due to 5 previous errors
 
index 5471c375b4990ddf903a171fb21679825955e69e..0e5fec28d19b0b086cc0388aee68d3334f598962 100644 (file)
@@ -1,3 +1,7 @@
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 #![allow(warnings)]
 
 
@@ -19,9 +23,10 @@ fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
     //~| ERROR the parameter type `T` may not live long enough
     //~| ERROR the parameter type `T` may not live long enough
     //~| ERROR the parameter type `T` may not live long enough
-    //~| ERROR the parameter type `T` may not live long enough
-    //~| ERROR the parameter type `T` may not live long enough
-    //~| ERROR the parameter type `T` may not live long enough
+    //[base]~| ERROR the parameter type `T` may not live long enough
+    //[base]~| ERROR the parameter type `T` may not live long enough
+    //[base]~| ERROR the parameter type `T` may not live long enough
+    //[nll]~| ERROR cannot return value referencing local data `*v` [E0515]
 }
 
 fn main() {}
diff --git a/src/test/ui/regions/regions-close-object-into-object-5.stderr b/src/test/ui/regions/regions-close-object-into-object-5.stderr
deleted file mode 100644 (file)
index 512a7ab..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/regions-close-object-into-object-5.rs:17:5
-   |
-LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
-   |          - help: consider adding an explicit lifetime bound...: `T: 'static`
-LL |     // oh dear!
-LL |     Box::new(B(&*v)) as Box<dyn X>
-   |     ^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds...
-   |
-note: ...that is required by this bound
-  --> $DIR/regions-close-object-into-object-5.rs:9:17
-   |
-LL | struct B<'a, T: 'a>(&'a (A<T> + 'a));
-   |                 ^^
-
-error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/regions-close-object-into-object-5.rs:17:5
-   |
-LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
-   |          - help: consider adding an explicit lifetime bound...: `T: 'static`
-LL |     // oh dear!
-LL |     Box::new(B(&*v)) as Box<dyn X>
-   |     ^^^^^^^^^^^^^^^^ ...so that the type `B<'_, T>` will meet its required lifetime bounds
-
-error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/regions-close-object-into-object-5.rs:17:14
-   |
-LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
-   |          - help: consider adding an explicit lifetime bound...: `T: 'static`
-LL |     // oh dear!
-LL |     Box::new(B(&*v)) as Box<dyn X>
-   |              ^ ...so that the type `T` will meet its required lifetime bounds...
-   |
-note: ...that is required by this bound
-  --> $DIR/regions-close-object-into-object-5.rs:9:17
-   |
-LL | struct B<'a, T: 'a>(&'a (A<T> + 'a));
-   |                 ^^
-
-error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/regions-close-object-into-object-5.rs:17:14
-   |
-LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
-   |          - help: consider adding an explicit lifetime bound...: `T: 'static`
-LL |     // oh dear!
-LL |     Box::new(B(&*v)) as Box<dyn X>
-   |              ^^^^^^ ...so that the type `T` will meet its required lifetime bounds...
-   |
-note: ...that is required by this bound
-  --> $DIR/regions-close-object-into-object-5.rs:9:17
-   |
-LL | struct B<'a, T: 'a>(&'a (A<T> + 'a));
-   |                 ^^
-
-error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/regions-close-object-into-object-5.rs:17:16
-   |
-LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
-   |          - help: consider adding an explicit lifetime bound...: `T: 'static`
-LL |     // oh dear!
-LL |     Box::new(B(&*v)) as Box<dyn X>
-   |                ^^^ ...so that the reference type `&dyn A<T>` does not outlive the data it points at
-
-error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/regions-close-object-into-object-5.rs:17:16
-   |
-LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
-   |          - help: consider adding an explicit lifetime bound...: `T: 'static`
-LL |     // oh dear!
-LL |     Box::new(B(&*v)) as Box<dyn X>
-   |                ^^^ ...so that the type `(dyn A<T> + 'static)` is not borrowed for too long
-
-error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/regions-close-object-into-object-5.rs:17:16
-   |
-LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
-   |          - help: consider adding an explicit lifetime bound...: `T: 'static`
-LL |     // oh dear!
-LL |     Box::new(B(&*v)) as Box<dyn X>
-   |                ^^^ ...so that the type `(dyn A<T> + 'static)` is not borrowed for too long
-
-error: aborting due to 7 previous errors
-
-For more information about this error, try `rustc --explain E0310`.
diff --git a/src/test/ui/regions/regions-close-over-type-parameter-1.base.stderr b/src/test/ui/regions/regions-close-over-type-parameter-1.base.stderr
new file mode 100644 (file)
index 0000000..d8f77ad
--- /dev/null
@@ -0,0 +1,26 @@
+error[E0310]: the parameter type `A` may not live long enough
+  --> $DIR/regions-close-over-type-parameter-1.rs:15:5
+   |
+LL |     Box::new(v) as Box<dyn SomeTrait + 'static>
+   |     ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn make_object1<A: SomeTrait + 'static>(v: A) -> Box<dyn SomeTrait + 'static> {
+   |                              +++++++++
+
+error[E0309]: the parameter type `A` may not live long enough
+  --> $DIR/regions-close-over-type-parameter-1.rs:24:5
+   |
+LL |     Box::new(v) as Box<dyn SomeTrait + 'b>
+   |     ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn make_object3<'a, 'b, A: SomeTrait + 'a + 'b>(v: A) -> Box<dyn SomeTrait + 'b> {
+   |                                           ++++
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0309, E0310.
+For more information about an error, try `rustc --explain E0309`.
index b576ae87011377d25a1a6f8c53a1554ef63fdc81..d8f77ad85c96689ee50f0832f0a0ceca864e22bd 100644 (file)
@@ -1,18 +1,24 @@
 error[E0310]: the parameter type `A` may not live long enough
-  --> $DIR/regions-close-over-type-parameter-1.rs:12:5
+  --> $DIR/regions-close-over-type-parameter-1.rs:15:5
    |
 LL |     Box::new(v) as Box<dyn SomeTrait + 'static>
-   |     ^^^^^^^^^^^
+   |     ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
    |
-   = help: consider adding an explicit lifetime bound `A: 'static`...
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn make_object1<A: SomeTrait + 'static>(v: A) -> Box<dyn SomeTrait + 'static> {
+   |                              +++++++++
 
 error[E0309]: the parameter type `A` may not live long enough
-  --> $DIR/regions-close-over-type-parameter-1.rs:21:5
+  --> $DIR/regions-close-over-type-parameter-1.rs:24:5
    |
 LL |     Box::new(v) as Box<dyn SomeTrait + 'b>
-   |     ^^^^^^^^^^^
+   |     ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
    |
-   = help: consider adding an explicit lifetime bound `A: 'b`...
+LL | fn make_object3<'a, 'b, A: SomeTrait + 'a + 'b>(v: A) -> Box<dyn SomeTrait + 'b> {
+   |                                           ++++
 
 error: aborting due to 2 previous errors
 
index 52d18c5d7a6fa1f113d5fedc7b27197265fbe488..cf425bcd4f342742b65bbae00d0f4c7c5a97337b 100644 (file)
@@ -2,6 +2,9 @@
 // an object. This should yield errors unless `A` (and the object)
 // both have suitable bounds.
 
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
 
 trait SomeTrait {
     fn get(&self) -> isize;
diff --git a/src/test/ui/regions/regions-close-over-type-parameter-1.stderr b/src/test/ui/regions/regions-close-over-type-parameter-1.stderr
deleted file mode 100644 (file)
index 063c3b1..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-error[E0310]: the parameter type `A` may not live long enough
-  --> $DIR/regions-close-over-type-parameter-1.rs:12:5
-   |
-LL | fn make_object1<A: SomeTrait>(v: A) -> Box<dyn SomeTrait + 'static> {
-   |                 -- help: consider adding an explicit lifetime bound...: `A: 'static +`
-LL |     Box::new(v) as Box<dyn SomeTrait + 'static>
-   |     ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
-
-error[E0309]: the parameter type `A` may not live long enough
-  --> $DIR/regions-close-over-type-parameter-1.rs:21:5
-   |
-LL | fn make_object3<'a, 'b, A: SomeTrait + 'a>(v: A) -> Box<dyn SomeTrait + 'b> {
-   |                         -- help: consider adding an explicit lifetime bound...: `A: 'b +`
-LL |     Box::new(v) as Box<dyn SomeTrait + 'b>
-   |     ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
-
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0309, E0310.
-For more information about an error, try `rustc --explain E0309`.
diff --git a/src/test/ui/regions/regions-close-over-type-parameter-multiple.base.stderr b/src/test/ui/regions/regions-close-over-type-parameter-multiple.base.stderr
new file mode 100644 (file)
index 0000000..1712038
--- /dev/null
@@ -0,0 +1,32 @@
+error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
+  --> $DIR/regions-close-over-type-parameter-multiple.rs:23:5
+   |
+LL |     Box::new(v) as Box<dyn SomeTrait + 'a>
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
+  --> $DIR/regions-close-over-type-parameter-multiple.rs:21:20
+   |
+LL | fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box<dyn SomeTrait + 'c> {
+   |                    ^^
+note: ...so that the declared lifetime parameter bounds are satisfied
+  --> $DIR/regions-close-over-type-parameter-multiple.rs:23:5
+   |
+LL |     Box::new(v) as Box<dyn SomeTrait + 'a>
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: but, the lifetime must be valid for the lifetime `'c` as defined here...
+  --> $DIR/regions-close-over-type-parameter-multiple.rs:21:26
+   |
+LL | fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box<dyn SomeTrait + 'c> {
+   |                          ^^
+note: ...so that the types are compatible
+  --> $DIR/regions-close-over-type-parameter-multiple.rs:23:5
+   |
+LL |     Box::new(v) as Box<dyn SomeTrait + 'a>
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: expected `Box<(dyn SomeTrait + 'c)>`
+              found `Box<dyn SomeTrait>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0495`.
index 25566742099c261f23a13284b71232185a881bcb..66459957ed466db24a3cfecd13d1a2b6a830b5fe 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/regions-close-over-type-parameter-multiple.rs:20:5
+  --> $DIR/regions-close-over-type-parameter-multiple.rs:23:5
    |
 LL | fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box<dyn SomeTrait + 'c> {
    |                    --    -- lifetime `'c` defined here
index fc7696e7e03201e3e9b8fdcaaef36dc1ffc9f056..3d5f4e12665b8f0c818204e1c7ed4905e8310ed7 100644 (file)
@@ -1,6 +1,9 @@
 // Various tests where we over type parameters with multiple lifetime
 // bounds.
 
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
 
 trait SomeTrait { fn get(&self) -> isize; }
 
@@ -17,7 +20,9 @@ fn make_object_good2<'a,'b,A:SomeTrait+'a+'b>(v: A) -> Box<dyn SomeTrait + 'b> {
 
 fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box<dyn SomeTrait + 'c> {
     // A outlives 'a AND 'b...but not 'c.
-    Box::new(v) as Box<dyn SomeTrait + 'a> //~ ERROR cannot infer an appropriate lifetime
+    Box::new(v) as Box<dyn SomeTrait + 'a>
+    //[base]~^ ERROR cannot infer an appropriate lifetime
+    //[nll]~^^ ERROR lifetime may not live long enough
 }
 
 fn main() {
diff --git a/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr b/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr
deleted file mode 100644 (file)
index aa22fd9..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
-  --> $DIR/regions-close-over-type-parameter-multiple.rs:20:5
-   |
-LL |     Box::new(v) as Box<dyn SomeTrait + 'a>
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
-  --> $DIR/regions-close-over-type-parameter-multiple.rs:18:20
-   |
-LL | fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box<dyn SomeTrait + 'c> {
-   |                    ^^
-note: ...so that the declared lifetime parameter bounds are satisfied
-  --> $DIR/regions-close-over-type-parameter-multiple.rs:20:5
-   |
-LL |     Box::new(v) as Box<dyn SomeTrait + 'a>
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: but, the lifetime must be valid for the lifetime `'c` as defined here...
-  --> $DIR/regions-close-over-type-parameter-multiple.rs:18:26
-   |
-LL | fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box<dyn SomeTrait + 'c> {
-   |                          ^^
-note: ...so that the types are compatible
-  --> $DIR/regions-close-over-type-parameter-multiple.rs:20:5
-   |
-LL |     Box::new(v) as Box<dyn SomeTrait + 'a>
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: expected `Box<(dyn SomeTrait + 'c)>`
-              found `Box<dyn SomeTrait>`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0495`.
diff --git a/src/test/ui/regions/regions-close-param-into-object.base.stderr b/src/test/ui/regions/regions-close-param-into-object.base.stderr
new file mode 100644 (file)
index 0000000..79a5d34
--- /dev/null
@@ -0,0 +1,48 @@
+error[E0310]: the parameter type `T` may not live long enough
+  --> $DIR/regions-close-param-into-object.rs:10:5
+   |
+LL |     Box::new(v)
+   |     ^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL |     where T : X + 'static
+   |                 +++++++++
+
+error[E0310]: the parameter type `T` may not live long enough
+  --> $DIR/regions-close-param-into-object.rs:16:5
+   |
+LL |     Box::new(v)
+   |     ^^^^^^^^^^^ ...so that the type `Box<T>` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn p2<T: 'static>(v: Box<T>) -> Box<dyn X + 'static>
+   |        +++++++++
+
+error[E0309]: the parameter type `T` may not live long enough
+  --> $DIR/regions-close-param-into-object.rs:22:5
+   |
+LL |     Box::new(v)
+   |     ^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL |     where T : X + 'a
+   |                 ++++
+
+error[E0309]: the parameter type `T` may not live long enough
+  --> $DIR/regions-close-param-into-object.rs:28:5
+   |
+LL |     Box::new(v)
+   |     ^^^^^^^^^^^ ...so that the type `Box<T>` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn p4<'a,T: 'a>(v: Box<T>) -> Box<dyn X + 'a>
+   |           ++++
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0309, E0310.
+For more information about an error, try `rustc --explain E0309`.
index 7bd7824f00a462ccebf0da80ebbc0aa95c385ccc..6ee12d5b82c6910add9eeb26b46481bd34fef3ba 100644 (file)
@@ -1,34 +1,46 @@
 error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/regions-close-param-into-object.rs:6:5
+  --> $DIR/regions-close-param-into-object.rs:10:5
    |
 LL |     Box::new(v)
-   |     ^^^^^^^^^^^
+   |     ^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
    |
-   = help: consider adding an explicit lifetime bound `T: 'static`...
+help: consider adding an explicit lifetime bound...
+   |
+LL |     where T : X + 'static
+   |                 +++++++++
 
 error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/regions-close-param-into-object.rs:12:5
+  --> $DIR/regions-close-param-into-object.rs:16:5
    |
 LL |     Box::new(v)
-   |     ^^^^^^^^^^^
+   |     ^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
    |
-   = help: consider adding an explicit lifetime bound `T: 'static`...
+LL | fn p2<T: 'static>(v: Box<T>) -> Box<dyn X + 'static>
+   |        +++++++++
 
 error[E0309]: the parameter type `T` may not live long enough
-  --> $DIR/regions-close-param-into-object.rs:18:5
+  --> $DIR/regions-close-param-into-object.rs:22:5
    |
 LL |     Box::new(v)
-   |     ^^^^^^^^^^^
+   |     ^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
    |
-   = help: consider adding an explicit lifetime bound `T: 'a`...
+help: consider adding an explicit lifetime bound...
+   |
+LL |     where T : X + 'a
+   |                 ++++
 
 error[E0309]: the parameter type `T` may not live long enough
-  --> $DIR/regions-close-param-into-object.rs:24:5
+  --> $DIR/regions-close-param-into-object.rs:28:5
    |
 LL |     Box::new(v)
-   |     ^^^^^^^^^^^
+   |     ^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
    |
-   = help: consider adding an explicit lifetime bound `T: 'a`...
+LL | fn p4<'a,T: 'a>(v: Box<T>) -> Box<dyn X + 'a>
+   |           ++++
 
 error: aborting due to 4 previous errors
 
index 2760e5eed9595c5be1ede8cde7f2c785bc42c443..aab3ad202e6c0bbf3ff9eaeaec4b4ef2d1f78cd5 100644 (file)
@@ -1,3 +1,7 @@
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 trait X { fn foo(&self) {} }
 
 fn p1<T>(v: T) -> Box<dyn X + 'static>
diff --git a/src/test/ui/regions/regions-close-param-into-object.stderr b/src/test/ui/regions/regions-close-param-into-object.stderr
deleted file mode 100644 (file)
index 5c355bb..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/regions-close-param-into-object.rs:6:5
-   |
-LL | fn p1<T>(v: T) -> Box<dyn X + 'static>
-   |       - help: consider adding an explicit lifetime bound...: `T: 'static`
-...
-LL |     Box::new(v)
-   |     ^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
-
-error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/regions-close-param-into-object.rs:12:5
-   |
-LL | fn p2<T>(v: Box<T>) -> Box<dyn X + 'static>
-   |       - help: consider adding an explicit lifetime bound...: `T: 'static`
-...
-LL |     Box::new(v)
-   |     ^^^^^^^^^^^ ...so that the type `Box<T>` will meet its required lifetime bounds
-
-error[E0309]: the parameter type `T` may not live long enough
-  --> $DIR/regions-close-param-into-object.rs:18:5
-   |
-LL | fn p3<'a,T>(v: T) -> Box<dyn X + 'a>
-   |          - help: consider adding an explicit lifetime bound...: `T: 'a`
-...
-LL |     Box::new(v)
-   |     ^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
-
-error[E0309]: the parameter type `T` may not live long enough
-  --> $DIR/regions-close-param-into-object.rs:24:5
-   |
-LL | fn p4<'a,T>(v: Box<T>) -> Box<dyn X + 'a>
-   |          - help: consider adding an explicit lifetime bound...: `T: 'a`
-...
-LL |     Box::new(v)
-   |     ^^^^^^^^^^^ ...so that the type `Box<T>` will meet its required lifetime bounds
-
-error: aborting due to 4 previous errors
-
-Some errors have detailed explanations: E0309, E0310.
-For more information about an error, try `rustc --explain E0309`.
diff --git a/src/test/ui/regions/regions-creating-enums3.base.stderr b/src/test/ui/regions/regions-creating-enums3.base.stderr
new file mode 100644 (file)
index 0000000..68a7b47
--- /dev/null
@@ -0,0 +1,13 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/regions-creating-enums3.rs:11:5
+   |
+LL | fn mk_add_bad1<'a,'b>(x: &'a Ast<'a>, y: &'b Ast<'b>) -> Ast<'a> {
+   |                                          -----------     -------
+   |                                          |
+   |                                          this parameter and the return type are declared with different lifetimes...
+LL |     Ast::Add(x, y)
+   |     ^^^^^^^^^^^^^^ ...but data from `y` is returned here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0623`.
index 41d609b56d233a2967822f30f7f120e52dcaf668..8334dc77687012e2cc93a46fa4f402b4643a7ebe 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/regions-creating-enums3.rs:7:5
+  --> $DIR/regions-creating-enums3.rs:11:5
    |
 LL | fn mk_add_bad1<'a,'b>(x: &'a Ast<'a>, y: &'b Ast<'b>) -> Ast<'a> {
    |                -- -- lifetime `'b` defined here
index 3da0cb4cb819749df2d26db7c98fa69bdaf4ad49..dcea761d33fd6e7115581719147016325f88a18d 100644 (file)
@@ -1,10 +1,16 @@
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 enum Ast<'a> {
     Num(usize),
     Add(&'a Ast<'a>, &'a Ast<'a>)
 }
 
 fn mk_add_bad1<'a,'b>(x: &'a Ast<'a>, y: &'b Ast<'b>) -> Ast<'a> {
-    Ast::Add(x, y) //~ ERROR lifetime mismatch [E0623]
+    Ast::Add(x, y)
+    //[base]~^ ERROR lifetime mismatch [E0623]
+    //[nll]~^^ ERROR lifetime may not live long enough
 }
 
 fn main() {
diff --git a/src/test/ui/regions/regions-creating-enums3.stderr b/src/test/ui/regions/regions-creating-enums3.stderr
deleted file mode 100644 (file)
index 2fc1fc3..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-error[E0623]: lifetime mismatch
-  --> $DIR/regions-creating-enums3.rs:7:5
-   |
-LL | fn mk_add_bad1<'a,'b>(x: &'a Ast<'a>, y: &'b Ast<'b>) -> Ast<'a> {
-   |                                          -----------     -------
-   |                                          |
-   |                                          this parameter and the return type are declared with different lifetimes...
-LL |     Ast::Add(x, y)
-   |     ^^^^^^^^^^^^^^ ...but data from `y` is returned here
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0623`.
diff --git a/src/test/ui/regions/regions-creating-enums4.base.stderr b/src/test/ui/regions/regions-creating-enums4.base.stderr
new file mode 100644 (file)
index 0000000..445a429
--- /dev/null
@@ -0,0 +1,34 @@
+error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
+  --> $DIR/regions-creating-enums4.rs:11:5
+   |
+LL |     Ast::Add(x, y)
+   |     ^^^^^^^^
+   |
+note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
+  --> $DIR/regions-creating-enums4.rs:10:16
+   |
+LL | fn mk_add_bad2<'a,'b>(x: &'a Ast<'a>, y: &'a Ast<'a>, z: &Ast) -> Ast<'b> {
+   |                ^^
+note: ...so that the expression is assignable
+  --> $DIR/regions-creating-enums4.rs:11:14
+   |
+LL |     Ast::Add(x, y)
+   |              ^
+   = note: expected `&Ast<'_>`
+              found `&Ast<'a>`
+note: but, the lifetime must be valid for the lifetime `'b` as defined here...
+  --> $DIR/regions-creating-enums4.rs:10:19
+   |
+LL | fn mk_add_bad2<'a,'b>(x: &'a Ast<'a>, y: &'a Ast<'a>, z: &Ast) -> Ast<'b> {
+   |                   ^^
+note: ...so that the types are compatible
+  --> $DIR/regions-creating-enums4.rs:11:5
+   |
+LL |     Ast::Add(x, y)
+   |     ^^^^^^^^^^^^^^
+   = note: expected `Ast<'b>`
+              found `Ast<'_>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0495`.
index 91cf57e099df9485273dcd83fbf95e7e88b6f497..e215c63d39d5a4d15b652b0efbdd7de291dfb4b2 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/regions-creating-enums4.rs:7:5
+  --> $DIR/regions-creating-enums4.rs:11:5
    |
 LL | fn mk_add_bad2<'a,'b>(x: &'a Ast<'a>, y: &'a Ast<'a>, z: &Ast) -> Ast<'b> {
    |                -- -- lifetime `'b` defined here
index 11d3d831151214c299823355fb4cd3423a12ddf4..18bd592b1c3eb77a99d0241755b24b0b1701ba27 100644 (file)
@@ -1,10 +1,16 @@
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 enum Ast<'a> {
     Num(usize),
     Add(&'a Ast<'a>, &'a Ast<'a>)
 }
 
 fn mk_add_bad2<'a,'b>(x: &'a Ast<'a>, y: &'a Ast<'a>, z: &Ast) -> Ast<'b> {
-    Ast::Add(x, y) //~ ERROR cannot infer
+    Ast::Add(x, y)
+    //[base]~^ ERROR cannot infer
+    //[nll]~^^ ERROR lifetime may not live long enough
 }
 
 fn main() {
diff --git a/src/test/ui/regions/regions-creating-enums4.stderr b/src/test/ui/regions/regions-creating-enums4.stderr
deleted file mode 100644 (file)
index 8b1b90f..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
-  --> $DIR/regions-creating-enums4.rs:7:5
-   |
-LL |     Ast::Add(x, y)
-   |     ^^^^^^^^
-   |
-note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
-  --> $DIR/regions-creating-enums4.rs:6:16
-   |
-LL | fn mk_add_bad2<'a,'b>(x: &'a Ast<'a>, y: &'a Ast<'a>, z: &Ast) -> Ast<'b> {
-   |                ^^
-note: ...so that the expression is assignable
-  --> $DIR/regions-creating-enums4.rs:7:14
-   |
-LL |     Ast::Add(x, y)
-   |              ^
-   = note: expected `&Ast<'_>`
-              found `&Ast<'a>`
-note: but, the lifetime must be valid for the lifetime `'b` as defined here...
-  --> $DIR/regions-creating-enums4.rs:6:19
-   |
-LL | fn mk_add_bad2<'a,'b>(x: &'a Ast<'a>, y: &'a Ast<'a>, z: &Ast) -> Ast<'b> {
-   |                   ^^
-note: ...so that the types are compatible
-  --> $DIR/regions-creating-enums4.rs:7:5
-   |
-LL |     Ast::Add(x, y)
-   |     ^^^^^^^^^^^^^^
-   = note: expected `Ast<'b>`
-              found `Ast<'_>`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0495`.
diff --git a/src/test/ui/regions/regions-early-bound-error-method.base.stderr b/src/test/ui/regions/regions-early-bound-error-method.base.stderr
new file mode 100644 (file)
index 0000000..9e1f2b0
--- /dev/null
@@ -0,0 +1,20 @@
+error[E0312]: lifetime of reference outlives lifetime of borrowed content...
+  --> $DIR/regions-early-bound-error-method.rs:24:9
+   |
+LL |         g2.get()
+   |         ^^^^^^^^
+   |
+note: ...the reference is valid for the lifetime `'a` as defined here...
+  --> $DIR/regions-early-bound-error-method.rs:22:6
+   |
+LL | impl<'a> Box<'a> {
+   |      ^^
+note: ...but the borrowed content is only valid for the lifetime `'b` as defined here
+  --> $DIR/regions-early-bound-error-method.rs:23:11
+   |
+LL |     fn or<'b,G:GetRef<'b>>(&self, g2: G) -> &'a isize {
+   |           ^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0312`.
index 7f10c051f2998eb63288d53376b2bf365275ef2d..98389ed0ca5b639cf3516cac1a9f1e7aad054b83 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/regions-early-bound-error-method.rs:20:9
+  --> $DIR/regions-early-bound-error-method.rs:24:9
    |
 LL | impl<'a> Box<'a> {
    |      -- lifetime `'a` defined here
index 32428143ef9d90f3506fbf6bdaa7694b9948d3b4..44ee19fa898b8f6735f47bc809393ea8e080acdf 100644 (file)
@@ -1,6 +1,10 @@
 // Tests that you can use a fn lifetime parameter as part of
 // the value for a type parameter in a bound.
 
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 trait GetRef<'a> {
     fn get(&self) -> &'a isize;
 }
@@ -18,7 +22,8 @@ fn get(&self) -> &'a isize {
 impl<'a> Box<'a> {
     fn or<'b,G:GetRef<'b>>(&self, g2: G) -> &'a isize {
         g2.get()
-        //~^ ERROR E0312
+        //[base]~^ ERROR E0312
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 }
 
diff --git a/src/test/ui/regions/regions-early-bound-error-method.stderr b/src/test/ui/regions/regions-early-bound-error-method.stderr
deleted file mode 100644 (file)
index 99a5f0c..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-error[E0312]: lifetime of reference outlives lifetime of borrowed content...
-  --> $DIR/regions-early-bound-error-method.rs:20:9
-   |
-LL |         g2.get()
-   |         ^^^^^^^^
-   |
-note: ...the reference is valid for the lifetime `'a` as defined here...
-  --> $DIR/regions-early-bound-error-method.rs:18:6
-   |
-LL | impl<'a> Box<'a> {
-   |      ^^
-note: ...but the borrowed content is only valid for the lifetime `'b` as defined here
-  --> $DIR/regions-early-bound-error-method.rs:19:11
-   |
-LL |     fn or<'b,G:GetRef<'b>>(&self, g2: G) -> &'a isize {
-   |           ^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0312`.
diff --git a/src/test/ui/regions/regions-early-bound-error.base.stderr b/src/test/ui/regions/regions-early-bound-error.base.stderr
new file mode 100644 (file)
index 0000000..e1b6053
--- /dev/null
@@ -0,0 +1,20 @@
+error[E0312]: lifetime of reference outlives lifetime of borrowed content...
+  --> $DIR/regions-early-bound-error.rs:23:5
+   |
+LL |     g1.get()
+   |     ^^^^^^^^
+   |
+note: ...the reference is valid for the lifetime `'b` as defined here...
+  --> $DIR/regions-early-bound-error.rs:22:11
+   |
+LL | fn get<'a,'b,G:GetRef<'a, isize>>(g1: G, b: &'b isize) -> &'b isize {
+   |           ^^
+note: ...but the borrowed content is only valid for the lifetime `'a` as defined here
+  --> $DIR/regions-early-bound-error.rs:22:8
+   |
+LL | fn get<'a,'b,G:GetRef<'a, isize>>(g1: G, b: &'b isize) -> &'b isize {
+   |        ^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0312`.
index eb4cd5ca72ea11e2fb3511f18e5127c932d0b33a..f57249e4e8f77d5b41940af9955db9791801707b 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/regions-early-bound-error.rs:19:5
+  --> $DIR/regions-early-bound-error.rs:23:5
    |
 LL | fn get<'a,'b,G:GetRef<'a, isize>>(g1: G, b: &'b isize) -> &'b isize {
    |        -- -- lifetime `'b` defined here
index 78dad4f2649d12bf7ec92c596fb344661b836aab..372596cd5f4b11571f85d5da58b1f414eb45dab2 100644 (file)
@@ -1,6 +1,10 @@
 // Tests that you can use a fn lifetime parameter as part of
 // the value for a type parameter in a bound.
 
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 trait GetRef<'a, T> {
     fn get(&self) -> &'a T;
 }
@@ -17,7 +21,8 @@ fn get(&self) -> &'a T {
 
 fn get<'a,'b,G:GetRef<'a, isize>>(g1: G, b: &'b isize) -> &'b isize {
     g1.get()
-    //~^ ERROR E0312
+    //[base]~^ ERROR E0312
+    //[nll]~^^ ERROR lifetime may not live long enough
 }
 
 fn main() {
diff --git a/src/test/ui/regions/regions-early-bound-error.stderr b/src/test/ui/regions/regions-early-bound-error.stderr
deleted file mode 100644 (file)
index df9e979..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-error[E0312]: lifetime of reference outlives lifetime of borrowed content...
-  --> $DIR/regions-early-bound-error.rs:19:5
-   |
-LL |     g1.get()
-   |     ^^^^^^^^
-   |
-note: ...the reference is valid for the lifetime `'b` as defined here...
-  --> $DIR/regions-early-bound-error.rs:18:11
-   |
-LL | fn get<'a,'b,G:GetRef<'a, isize>>(g1: G, b: &'b isize) -> &'b isize {
-   |           ^^
-note: ...but the borrowed content is only valid for the lifetime `'a` as defined here
-  --> $DIR/regions-early-bound-error.rs:18:8
-   |
-LL | fn get<'a,'b,G:GetRef<'a, isize>>(g1: G, b: &'b isize) -> &'b isize {
-   |        ^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0312`.
diff --git a/src/test/ui/regions/regions-fn-subtyping-return-static-fail.base.stderr b/src/test/ui/regions/regions-fn-subtyping-return-static-fail.base.stderr
new file mode 100644 (file)
index 0000000..2182d8f
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0308]: mismatched types
+  --> $DIR/regions-fn-subtyping-return-static-fail.rs:52:12
+   |
+LL |     want_G(baz);
+   |            ^^^ one type is more general than the other
+   |
+   = note: expected fn pointer `for<'cx> fn(&'cx S) -> &'static S`
+              found fn pointer `for<'r> fn(&'r S) -> &'r S`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
index c2956cd89580f757e4c66c47c49f05794301267d..0bca2cfbefd9f2a4b884eddca27ef8768b380359 100644 (file)
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/regions-fn-subtyping-return-static-fail.rs:48:5
+  --> $DIR/regions-fn-subtyping-return-static-fail.rs:52:5
    |
 LL |     want_G(baz);
    |     ^^^^^^^^^^^ one type is more general than the other
index 539221b5a046c20c694430ab05cb46f77305282c..05c6ac0cb1ae4e57215a4dc9553ca501f91d5904 100644 (file)
@@ -6,6 +6,10 @@
 // This can safely be considered to be an instance of `F` because all
 // lifetimes are sublifetimes of 'static.
 
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 #![allow(dead_code)]
 #![allow(unused_variables)]
 
diff --git a/src/test/ui/regions/regions-fn-subtyping-return-static-fail.stderr b/src/test/ui/regions/regions-fn-subtyping-return-static-fail.stderr
deleted file mode 100644 (file)
index c9ce936..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0308]: mismatched types
-  --> $DIR/regions-fn-subtyping-return-static-fail.rs:48:12
-   |
-LL |     want_G(baz);
-   |            ^^^ one type is more general than the other
-   |
-   = note: expected fn pointer `for<'cx> fn(&'cx S) -> &'static S`
-              found fn pointer `for<'r> fn(&'r S) -> &'r S`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/regions/regions-free-region-ordering-callee.base.stderr b/src/test/ui/regions/regions-free-region-ordering-callee.base.stderr
new file mode 100644 (file)
index 0000000..ae6d95d
--- /dev/null
@@ -0,0 +1,25 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/regions-free-region-ordering-callee.rs:17:5
+   |
+LL | fn ordering2<'a, 'b>(x: &'a &'b usize, y: &'a usize) -> &'b usize {
+   |                         -------------                   ---------
+   |                         |
+   |                         this parameter and the return type are declared with different lifetimes...
+LL |     // However, it is not safe to assume that 'b <= 'a
+LL |     &*y
+   |     ^^^ ...but data from `x` is returned here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/regions-free-region-ordering-callee.rs:24:24
+   |
+LL | fn ordering3<'a, 'b>(x: &'a usize, y: &'b usize) -> &'a &'b usize {
+   |                                       ---------     -------------
+   |                                       |
+   |                                       this parameter and the return type are declared with different lifetimes...
+LL |     // Do not infer an ordering from the return value.
+LL |     let z: &'b usize = &*x;
+   |                        ^^^ ...but data from `x` is returned here
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0623`.
index f61f068a4861bb6addd395ada164514e173eae45..7dfff2bb060d3815619a089d8ce21ebc85632d2f 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/regions-free-region-ordering-callee.rs:13:5
+  --> $DIR/regions-free-region-ordering-callee.rs:17:5
    |
 LL | fn ordering2<'a, 'b>(x: &'a &'b usize, y: &'a usize) -> &'b usize {
    |              --  -- lifetime `'b` defined here
@@ -12,7 +12,7 @@ LL |     &*y
    = help: consider adding the following bound: `'a: 'b`
 
 error: lifetime may not live long enough
-  --> $DIR/regions-free-region-ordering-callee.rs:18:12
+  --> $DIR/regions-free-region-ordering-callee.rs:24:12
    |
 LL | fn ordering3<'a, 'b>(x: &'a usize, y: &'b usize) -> &'a &'b usize {
    |              --  -- lifetime `'b` defined here
index ee9a977a74f2d77ad7bda37007e10f3cb5020e60..eca863f2e79583134a3b41bae3066257f26425da 100644 (file)
@@ -2,6 +2,10 @@
 // that appear in their parameter list.  See also
 // regions-free-region-ordering-caller.rs
 
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 fn ordering1<'a, 'b>(x: &'a &'b usize) -> &'a usize {
     // It is safe to assume that 'a <= 'b due to the type of x
     let y: &'b usize = &**x;
@@ -10,13 +14,16 @@ fn ordering1<'a, 'b>(x: &'a &'b usize) -> &'a usize {
 
 fn ordering2<'a, 'b>(x: &'a &'b usize, y: &'a usize) -> &'b usize {
     // However, it is not safe to assume that 'b <= 'a
-    &*y //~ ERROR lifetime mismatch [E0623]
+    &*y
+    //[base]~^ ERROR lifetime mismatch [E0623]
+    //[nll]~^^ ERROR lifetime may not live long enough
 }
 
 fn ordering3<'a, 'b>(x: &'a usize, y: &'b usize) -> &'a &'b usize {
     // Do not infer an ordering from the return value.
     let z: &'b usize = &*x;
-    //~^ ERROR lifetime mismatch [E0623]
+    //[base]~^ ERROR lifetime mismatch [E0623]
+    //[nll]~^^ ERROR lifetime may not live long enough
     panic!();
 }
 
diff --git a/src/test/ui/regions/regions-free-region-ordering-callee.stderr b/src/test/ui/regions/regions-free-region-ordering-callee.stderr
deleted file mode 100644 (file)
index 4648bf0..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-error[E0623]: lifetime mismatch
-  --> $DIR/regions-free-region-ordering-callee.rs:13:5
-   |
-LL | fn ordering2<'a, 'b>(x: &'a &'b usize, y: &'a usize) -> &'b usize {
-   |                         -------------                   ---------
-   |                         |
-   |                         this parameter and the return type are declared with different lifetimes...
-LL |     // However, it is not safe to assume that 'b <= 'a
-LL |     &*y
-   |     ^^^ ...but data from `x` is returned here
-
-error[E0623]: lifetime mismatch
-  --> $DIR/regions-free-region-ordering-callee.rs:18:24
-   |
-LL | fn ordering3<'a, 'b>(x: &'a usize, y: &'b usize) -> &'a &'b usize {
-   |                                       ---------     -------------
-   |                                       |
-   |                                       this parameter and the return type are declared with different lifetimes...
-LL |     // Do not infer an ordering from the return value.
-LL |     let z: &'b usize = &*x;
-   |                        ^^^ ...but data from `x` is returned here
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0623`.
diff --git a/src/test/ui/regions/regions-free-region-ordering-incorrect.base.stderr b/src/test/ui/regions/regions-free-region-ordering-incorrect.base.stderr
new file mode 100644 (file)
index 0000000..eb4ffce
--- /dev/null
@@ -0,0 +1,33 @@
+error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
+  --> $DIR/regions-free-region-ordering-incorrect.rs:21:21
+   |
+LL |             None => &self.val
+   |                     ^^^^^^^^^
+   |
+note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
+  --> $DIR/regions-free-region-ordering-incorrect.rs:18:12
+   |
+LL |     fn get<'a>(&'a self) -> &'b T {
+   |            ^^
+note: ...so that reference does not outlive borrowed content
+  --> $DIR/regions-free-region-ordering-incorrect.rs:21:21
+   |
+LL |             None => &self.val
+   |                     ^^^^^^^^^
+note: but, the lifetime must be valid for the lifetime `'b` as defined here...
+  --> $DIR/regions-free-region-ordering-incorrect.rs:17:6
+   |
+LL | impl<'b, T> Node<'b, T> {
+   |      ^^
+note: ...so that reference does not outlive borrowed content
+  --> $DIR/regions-free-region-ordering-incorrect.rs:19:9
+   |
+LL | /         match self.next {
+LL | |             Some(ref next) => next.get(),
+LL | |             None => &self.val
+LL | |         }
+   | |_________^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0495`.
index f7c75033c04865f3b2d28fb1849d49c751bf2654..336cfd3e6c529fc467edb4128ec8020cacf5aa25 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/regions-free-region-ordering-incorrect.rs:15:9
+  --> $DIR/regions-free-region-ordering-incorrect.rs:19:9
    |
 LL |   impl<'b, T> Node<'b, T> {
    |        -- lifetime `'b` defined here
index 65e3f52609eebca2d78365dc620e08469f839ee8..43427d13ffa715e15c1b8a8382edaa4b1027a7ab 100644 (file)
@@ -5,6 +5,10 @@
 //
 // This test began its life as a test for issue #4325.
 
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 struct Node<'b, T: 'b> {
     val: T,
     next: Option<&'b Node<'b, T>>
@@ -12,9 +16,9 @@ struct Node<'b, T: 'b> {
 
 impl<'b, T> Node<'b, T> {
     fn get<'a>(&'a self) -> &'b T {
-        match self.next {
+        match self.next { //[nll]~ ERROR lifetime may not live long enough
             Some(ref next) => next.get(),
-            None => &self.val //~ ERROR cannot infer
+            None => &self.val //[base]~ ERROR cannot infer
         }
     }
 }
diff --git a/src/test/ui/regions/regions-free-region-ordering-incorrect.stderr b/src/test/ui/regions/regions-free-region-ordering-incorrect.stderr
deleted file mode 100644 (file)
index b0a8f4a..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
-  --> $DIR/regions-free-region-ordering-incorrect.rs:17:21
-   |
-LL |             None => &self.val
-   |                     ^^^^^^^^^
-   |
-note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
-  --> $DIR/regions-free-region-ordering-incorrect.rs:14:12
-   |
-LL |     fn get<'a>(&'a self) -> &'b T {
-   |            ^^
-note: ...so that reference does not outlive borrowed content
-  --> $DIR/regions-free-region-ordering-incorrect.rs:17:21
-   |
-LL |             None => &self.val
-   |                     ^^^^^^^^^
-note: but, the lifetime must be valid for the lifetime `'b` as defined here...
-  --> $DIR/regions-free-region-ordering-incorrect.rs:13:6
-   |
-LL | impl<'b, T> Node<'b, T> {
-   |      ^^
-note: ...so that reference does not outlive borrowed content
-  --> $DIR/regions-free-region-ordering-incorrect.rs:15:9
-   |
-LL | /         match self.next {
-LL | |             Some(ref next) => next.get(),
-LL | |             None => &self.val
-LL | |         }
-   | |_________^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0495`.
index f464cab75541d426cb0baaf85413482d4dd4d326..7c2e1aeeea619bcabc9b2be24e855afac37af61c 100644 (file)
@@ -9,7 +9,7 @@
 //     'a : 'b
 
 fn test<'a,'b>(x: &'a i32) -> &'b i32
-    where 'a: 'static
+    where 'a: 'static //~ WARN unnecessary lifetime parameter `'a`
 {
     x
 }
diff --git a/src/test/ui/regions/regions-free-region-outlives-static-outlives-free-region.stderr b/src/test/ui/regions/regions-free-region-outlives-static-outlives-free-region.stderr
new file mode 100644 (file)
index 0000000..70ed418
--- /dev/null
@@ -0,0 +1,10 @@
+warning: unnecessary lifetime parameter `'a`
+  --> $DIR/regions-free-region-outlives-static-outlives-free-region.rs:12:11
+   |
+LL |     where 'a: 'static
+   |           ^^
+   |
+   = help: you can use the `'static` lifetime directly, in place of `'a`
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/regions/regions-implied-bounds-projection-gap-1.base.stderr b/src/test/ui/regions/regions-implied-bounds-projection-gap-1.base.stderr
new file mode 100644 (file)
index 0000000..85ced4b
--- /dev/null
@@ -0,0 +1,14 @@
+error[E0309]: the parameter type `T` may not live long enough
+  --> $DIR/regions-implied-bounds-projection-gap-1.rs:20:10
+   |
+LL |     wf::<&'x T>();
+   |          ^^^^^ ...so that the reference type `&'x T` does not outlive the data it points at
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn func<'x, T:Trait1<'x> + 'x>(t: &'x T::Foo)
+   |                          ++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0309`.
index 0f0f86dfcdd693c4221cd7010e357ac243282870..1a428eb25d7d0a1c17d47e0143e1662ba62e085c 100644 (file)
@@ -1,10 +1,13 @@
 error[E0309]: the parameter type `T` may not live long enough
-  --> $DIR/regions-implied-bounds-projection-gap-1.rs:16:5
+  --> $DIR/regions-implied-bounds-projection-gap-1.rs:20:5
    |
 LL |     wf::<&'x T>();
-   |     ^^^^^^^^^^^
+   |     ^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
    |
-   = help: consider adding an explicit lifetime bound `T: 'x`...
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn func<'x, T:Trait1<'x> + 'x>(t: &'x T::Foo)
+   |                          ++++
 
 error: aborting due to previous error
 
index 38fc9c462da4eafc36a8601d2ec7c1af7656af26..f11fc207b91c6f9a6492d49a86dfd36ea3e6bd6f 100644 (file)
@@ -3,6 +3,10 @@
 // there might be other ways for the caller of `func` to show that
 // `T::Foo: 'x` holds (e.g., where-clause).
 
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 trait Trait1<'x> {
     type Foo;
 }
diff --git a/src/test/ui/regions/regions-implied-bounds-projection-gap-1.stderr b/src/test/ui/regions/regions-implied-bounds-projection-gap-1.stderr
deleted file mode 100644 (file)
index ea59ea1..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0309]: the parameter type `T` may not live long enough
-  --> $DIR/regions-implied-bounds-projection-gap-1.rs:16:10
-   |
-LL | fn func<'x, T:Trait1<'x>>(t: &'x T::Foo)
-   |             -- help: consider adding an explicit lifetime bound...: `T: 'x +`
-LL | {
-LL |     wf::<&'x T>();
-   |          ^^^^^ ...so that the reference type `&'x T` does not outlive the data it points at
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0309`.
diff --git a/src/test/ui/regions/regions-infer-bound-from-trait-self.base.stderr b/src/test/ui/regions/regions-infer-bound-from-trait-self.base.stderr
new file mode 100644 (file)
index 0000000..faa638a
--- /dev/null
@@ -0,0 +1,17 @@
+error[E0309]: the parameter type `Self` may not live long enough
+  --> $DIR/regions-infer-bound-from-trait-self.rs:50:9
+   |
+LL |         check_bound(x, self)
+   |         ^^^^^^^^^^^
+   |
+   = help: consider adding an explicit lifetime bound `Self: 'a`...
+   = note: ...so that the type `Self` will meet its required lifetime bounds...
+note: ...that is required by this bound
+  --> $DIR/regions-infer-bound-from-trait-self.rs:16:21
+   |
+LL | fn check_bound<'a,A:'a>(x: Inv<'a>, a: A) { }
+   |                     ^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0309`.
index 0651e305cde35031b160e9c609b5ab1d491e802b..9c886c42c72acdf5d1e7d992a82b066a92baee62 100644 (file)
@@ -1,10 +1,11 @@
 error[E0309]: the parameter type `Self` may not live long enough
-  --> $DIR/regions-infer-bound-from-trait-self.rs:46:9
+  --> $DIR/regions-infer-bound-from-trait-self.rs:50:9
    |
 LL |         check_bound(x, self)
    |         ^^^^^^^^^^^^^^^^^^^^
    |
    = help: consider adding an explicit lifetime bound `Self: 'a`...
+   = note: ...so that the type `Self` will meet its required lifetime bounds
 
 error: aborting due to previous error
 
index d15bfffe9d92659ab02607409719b57af3c5540f..ef8be05b2d26a4688457f6a5e8be36f1fe898905 100644 (file)
@@ -1,6 +1,10 @@
 // Test that we can derive lifetime bounds on `Self` from trait
 // inheritance.
 
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 trait Static : 'static { }
 
 trait Is<'a> : 'a { }
diff --git a/src/test/ui/regions/regions-infer-bound-from-trait-self.stderr b/src/test/ui/regions/regions-infer-bound-from-trait-self.stderr
deleted file mode 100644 (file)
index 97a3947..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-error[E0309]: the parameter type `Self` may not live long enough
-  --> $DIR/regions-infer-bound-from-trait-self.rs:46:9
-   |
-LL |         check_bound(x, self)
-   |         ^^^^^^^^^^^
-   |
-   = help: consider adding an explicit lifetime bound `Self: 'a`...
-   = note: ...so that the type `Self` will meet its required lifetime bounds...
-note: ...that is required by this bound
-  --> $DIR/regions-infer-bound-from-trait-self.rs:12:21
-   |
-LL | fn check_bound<'a,A:'a>(x: Inv<'a>, a: A) { }
-   |                     ^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0309`.
diff --git a/src/test/ui/regions/regions-infer-bound-from-trait.base.stderr b/src/test/ui/regions/regions-infer-bound-from-trait.base.stderr
new file mode 100644 (file)
index 0000000..658740f
--- /dev/null
@@ -0,0 +1,35 @@
+error[E0309]: the parameter type `A` may not live long enough
+  --> $DIR/regions-infer-bound-from-trait.rs:37:5
+   |
+LL |     check_bound(x, a)
+   |     ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds...
+   |
+note: ...that is required by this bound
+  --> $DIR/regions-infer-bound-from-trait.rs:16:21
+   |
+LL | fn check_bound<'a,A:'a>(x: Inv<'a>, a: A) { }
+   |                     ^^
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn bar1<'a,A: 'a>(x: Inv<'a>, a: A) {
+   |             ++++
+
+error[E0309]: the parameter type `A` may not live long enough
+  --> $DIR/regions-infer-bound-from-trait.rs:41:5
+   |
+LL |     check_bound(x, a)
+   |     ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds...
+   |
+note: ...that is required by this bound
+  --> $DIR/regions-infer-bound-from-trait.rs:16:21
+   |
+LL | fn check_bound<'a,A:'a>(x: Inv<'a>, a: A) { }
+   |                     ^^
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn bar2<'a,'b,A:Is<'b> + 'a>(x: Inv<'a>, y: Inv<'b>, a: A) {
+   |                        ++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0309`.
index 1f7b34fc69962937095054765c206c8fed2dc255..5cc2d20c2e0d16129b5c59fa2c0bfe5898815ffa 100644 (file)
@@ -1,18 +1,24 @@
 error[E0309]: the parameter type `A` may not live long enough
-  --> $DIR/regions-infer-bound-from-trait.rs:33:5
+  --> $DIR/regions-infer-bound-from-trait.rs:37:5
    |
 LL |     check_bound(x, a)
-   |     ^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
    |
-   = help: consider adding an explicit lifetime bound `A: 'a`...
+LL | fn bar1<'a,A: 'a>(x: Inv<'a>, a: A) {
+   |             ++++
 
 error[E0309]: the parameter type `A` may not live long enough
-  --> $DIR/regions-infer-bound-from-trait.rs:37:5
+  --> $DIR/regions-infer-bound-from-trait.rs:41:5
    |
 LL |     check_bound(x, a)
-   |     ^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
    |
-   = help: consider adding an explicit lifetime bound `A: 'a`...
+LL | fn bar2<'a,'b,A:Is<'b> + 'a>(x: Inv<'a>, y: Inv<'b>, a: A) {
+   |                        ++++
 
 error: aborting due to 2 previous errors
 
index 610452182f8852165854dde248ef0d750bb29a38..96f9125313bf95d0c170c7ba02fc6290a8f44e00 100644 (file)
@@ -1,6 +1,10 @@
 // Test that we can derive lifetime bounds on type parameters
 // from trait inheritance.
 
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 trait Static : 'static { }
 
 trait Is<'a> : 'a { }
diff --git a/src/test/ui/regions/regions-infer-bound-from-trait.stderr b/src/test/ui/regions/regions-infer-bound-from-trait.stderr
deleted file mode 100644 (file)
index fd1090d..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-error[E0309]: the parameter type `A` may not live long enough
-  --> $DIR/regions-infer-bound-from-trait.rs:33:5
-   |
-LL | fn bar1<'a,A>(x: Inv<'a>, a: A) {
-   |            - help: consider adding an explicit lifetime bound...: `A: 'a`
-LL |     check_bound(x, a)
-   |     ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds...
-   |
-note: ...that is required by this bound
-  --> $DIR/regions-infer-bound-from-trait.rs:12:21
-   |
-LL | fn check_bound<'a,A:'a>(x: Inv<'a>, a: A) { }
-   |                     ^^
-
-error[E0309]: the parameter type `A` may not live long enough
-  --> $DIR/regions-infer-bound-from-trait.rs:37:5
-   |
-LL | fn bar2<'a,'b,A:Is<'b>>(x: Inv<'a>, y: Inv<'b>, a: A) {
-   |               -- help: consider adding an explicit lifetime bound...: `A: 'a +`
-LL |     check_bound(x, a)
-   |     ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds...
-   |
-note: ...that is required by this bound
-  --> $DIR/regions-infer-bound-from-trait.rs:12:21
-   |
-LL | fn check_bound<'a,A:'a>(x: Inv<'a>, a: A) { }
-   |                     ^^
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0309`.
diff --git a/src/test/ui/regions/regions-infer-contravariance-due-to-decl.base.stderr b/src/test/ui/regions/regions-infer-contravariance-due-to-decl.base.stderr
new file mode 100644 (file)
index 0000000..fbe2c0d
--- /dev/null
@@ -0,0 +1,15 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/regions-infer-contravariance-due-to-decl.rs:29:35
+   |
+LL | fn use_<'short,'long>(c: Contravariant<'short>,
+   |                          --------------------- these two types are declared with different lifetimes...
+LL |                       s: &'short isize,
+LL |                       l: &'long isize,
+   |                          ------------
+...
+LL |     let _: Contravariant<'long> = c;
+   |                                   ^ ...but data from `c` flows into `l` here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0623`.
index 94b80852d01242b86162ae834520c551f7e272f8..0b1bf5271a7798f4f3ae83b52451355323c866b7 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/regions-infer-contravariance-due-to-decl.rs:25:12
+  --> $DIR/regions-infer-contravariance-due-to-decl.rs:29:12
    |
 LL | fn use_<'short,'long>(c: Contravariant<'short>,
    |         ------ ----- lifetime `'long` defined here
index 84161388a6e611ad0e2d0cefcc946c4895534c20..233f72fd2964938b66239a212c489b87f762f1f0 100644 (file)
@@ -4,6 +4,10 @@
 // Note: see variance-regions-*.rs for the tests that check that the
 // variance inference works in the first place.
 
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 use std::marker;
 
 // This is contravariant with respect to 'a, meaning that
@@ -22,7 +26,9 @@ fn use_<'short,'long>(c: Contravariant<'short>,
     // 'short <= 'long, this would be true if the Contravariant type were
     // covariant with respect to its parameter 'a.
 
-    let _: Contravariant<'long> = c; //~ ERROR E0623
+    let _: Contravariant<'long> = c;
+    //[base]~^ ERROR E0623
+    //[nll]~^^ ERROR lifetime may not live long enough
 }
 
 fn main() {}
diff --git a/src/test/ui/regions/regions-infer-contravariance-due-to-decl.stderr b/src/test/ui/regions/regions-infer-contravariance-due-to-decl.stderr
deleted file mode 100644 (file)
index f3a0358..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-error[E0623]: lifetime mismatch
-  --> $DIR/regions-infer-contravariance-due-to-decl.rs:25:35
-   |
-LL | fn use_<'short,'long>(c: Contravariant<'short>,
-   |                          --------------------- these two types are declared with different lifetimes...
-LL |                       s: &'short isize,
-LL |                       l: &'long isize,
-   |                          ------------
-...
-LL |     let _: Contravariant<'long> = c;
-   |                                   ^ ...but data from `c` flows into `l` here
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0623`.
diff --git a/src/test/ui/regions/regions-infer-covariance-due-to-decl.base.stderr b/src/test/ui/regions/regions-infer-covariance-due-to-decl.base.stderr
new file mode 100644 (file)
index 0000000..bb22e15
--- /dev/null
@@ -0,0 +1,14 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/regions-infer-covariance-due-to-decl.rs:26:32
+   |
+LL | fn use_<'short,'long>(c: Covariant<'long>,
+   |                          ----------------
+LL |                       s: &'short isize,
+   |                          ------------- these two types are declared with different lifetimes...
+...
+LL |     let _: Covariant<'short> = c;
+   |                                ^ ...but data from `s` flows into `c` here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0623`.
index f44a0fad59b2e58d40623e98591d2fbccaacd292..4d72b8471dcb2ffce4da2877c34d3d4d08c71fb8 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/regions-infer-covariance-due-to-decl.rs:22:12
+  --> $DIR/regions-infer-covariance-due-to-decl.rs:26:12
    |
 LL | fn use_<'short,'long>(c: Covariant<'long>,
    |         ------ ----- lifetime `'long` defined here
index b5079206578dc3ec73b524317a44df05453b7237..c4225e76967ef7b7addf74e81b1e755ca765dbc7 100644 (file)
@@ -4,6 +4,10 @@
 // Note: see variance-regions-*.rs for the tests that check that the
 // variance inference works in the first place.
 
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 use std::marker;
 
 struct Covariant<'a> {
@@ -19,7 +23,9 @@ fn use_<'short,'long>(c: Covariant<'long>,
     // 'short <= 'long, this would be true if the Covariant type were
     // contravariant with respect to its parameter 'a.
 
-    let _: Covariant<'short> = c; //~ ERROR E0623
+    let _: Covariant<'short> = c;
+    //[base]~^ ERROR E0623
+    //[nll]~^^ ERROR lifetime may not live long enough
 }
 
 fn main() {}
diff --git a/src/test/ui/regions/regions-infer-covariance-due-to-decl.stderr b/src/test/ui/regions/regions-infer-covariance-due-to-decl.stderr
deleted file mode 100644 (file)
index c3e2075..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-error[E0623]: lifetime mismatch
-  --> $DIR/regions-infer-covariance-due-to-decl.rs:22:32
-   |
-LL | fn use_<'short,'long>(c: Covariant<'long>,
-   |                          ----------------
-LL |                       s: &'short isize,
-   |                          ------------- these two types are declared with different lifetimes...
-...
-LL |     let _: Covariant<'short> = c;
-   |                                ^ ...but data from `s` flows into `c` here
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0623`.
diff --git a/src/test/ui/regions/regions-infer-invariance-due-to-decl.base.stderr b/src/test/ui/regions/regions-infer-invariance-due-to-decl.base.stderr
new file mode 100644 (file)
index 0000000..dc7d000
--- /dev/null
@@ -0,0 +1,18 @@
+error[E0308]: mismatched types
+  --> $DIR/regions-infer-invariance-due-to-decl.rs:16:5
+   |
+LL |     b_isize
+   |     ^^^^^^^ lifetime mismatch
+   |
+   = note: expected struct `Invariant<'static>`
+              found struct `Invariant<'r>`
+note: the lifetime `'r` as defined here...
+  --> $DIR/regions-infer-invariance-due-to-decl.rs:15:23
+   |
+LL | fn to_longer_lifetime<'r>(b_isize: Invariant<'r>) -> Invariant<'static> {
+   |                       ^^
+   = note: ...does not necessarily outlive the static lifetime
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
index c8c7808e06c5f9e0d320cbd1c37c231c86693455..d7b7f9883a763d6f41f5f8e115cbd35af28c4c2b 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/regions-infer-invariance-due-to-decl.rs:12:5
+  --> $DIR/regions-infer-invariance-due-to-decl.rs:16:5
    |
 LL | fn to_longer_lifetime<'r>(b_isize: Invariant<'r>) -> Invariant<'static> {
    |                       -- lifetime `'r` defined here
index e0fa904e8fe371facae6cc81d2167ac649e26bed..6433773b2d18699e863b4a007c8b4882e72be765 100644 (file)
@@ -1,3 +1,7 @@
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 use std::marker;
 
 struct Invariant<'a> {
@@ -9,7 +13,9 @@ fn to_same_lifetime<'r>(b_isize: Invariant<'r>) {
 }
 
 fn to_longer_lifetime<'r>(b_isize: Invariant<'r>) -> Invariant<'static> {
-    b_isize //~ ERROR mismatched types
+    b_isize
+    //[base]~^ ERROR mismatched types
+    //[nll]~^^ ERROR lifetime may not live long enough
 }
 
 fn main() {
diff --git a/src/test/ui/regions/regions-infer-invariance-due-to-decl.stderr b/src/test/ui/regions/regions-infer-invariance-due-to-decl.stderr
deleted file mode 100644 (file)
index afd522a..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-error[E0308]: mismatched types
-  --> $DIR/regions-infer-invariance-due-to-decl.rs:12:5
-   |
-LL |     b_isize
-   |     ^^^^^^^ lifetime mismatch
-   |
-   = note: expected struct `Invariant<'static>`
-              found struct `Invariant<'r>`
-note: the lifetime `'r` as defined here...
-  --> $DIR/regions-infer-invariance-due-to-decl.rs:11:23
-   |
-LL | fn to_longer_lifetime<'r>(b_isize: Invariant<'r>) -> Invariant<'static> {
-   |                       ^^
-   = note: ...does not necessarily outlive the static lifetime
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.base.stderr b/src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.base.stderr
new file mode 100644 (file)
index 0000000..b2530d7
--- /dev/null
@@ -0,0 +1,18 @@
+error[E0308]: mismatched types
+  --> $DIR/regions-infer-invariance-due-to-mutability-3.rs:14:5
+   |
+LL |     b_isize
+   |     ^^^^^^^ lifetime mismatch
+   |
+   = note: expected struct `Invariant<'static>`
+              found struct `Invariant<'r>`
+note: the lifetime `'r` as defined here...
+  --> $DIR/regions-infer-invariance-due-to-mutability-3.rs:13:23
+   |
+LL | fn to_longer_lifetime<'r>(b_isize: Invariant<'r>) -> Invariant<'static> {
+   |                       ^^
+   = note: ...does not necessarily outlive the static lifetime
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
index 1165011c1f4fc19adf4dfd20df4db31ec26cafa4..37fa5e3bf447706e7da892caee745f43d0f5f385 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/regions-infer-invariance-due-to-mutability-3.rs:10:5
+  --> $DIR/regions-infer-invariance-due-to-mutability-3.rs:14:5
    |
 LL | fn to_longer_lifetime<'r>(b_isize: Invariant<'r>) -> Invariant<'static> {
    |                       -- lifetime `'r` defined here
index 5843598ab48e47cb358167d8e51059d05b95a096..4690f9d8b08fc9025f3d3a8404f1e30d914235aa 100644 (file)
@@ -1,3 +1,7 @@
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 struct Invariant<'a> {
     f: Box<dyn FnOnce(&mut &'a isize) + 'static>,
 }
@@ -7,7 +11,9 @@ fn to_same_lifetime<'r>(b_isize: Invariant<'r>) {
 }
 
 fn to_longer_lifetime<'r>(b_isize: Invariant<'r>) -> Invariant<'static> {
-    b_isize //~ ERROR mismatched types
+    b_isize
+    //[base]~^ ERROR mismatched types
+    //[nll]~^^ ERROR lifetime may not live long enough
 }
 
 fn main() {
diff --git a/src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.stderr b/src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.stderr
deleted file mode 100644 (file)
index bb594f3..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-error[E0308]: mismatched types
-  --> $DIR/regions-infer-invariance-due-to-mutability-3.rs:10:5
-   |
-LL |     b_isize
-   |     ^^^^^^^ lifetime mismatch
-   |
-   = note: expected struct `Invariant<'static>`
-              found struct `Invariant<'r>`
-note: the lifetime `'r` as defined here...
-  --> $DIR/regions-infer-invariance-due-to-mutability-3.rs:9:23
-   |
-LL | fn to_longer_lifetime<'r>(b_isize: Invariant<'r>) -> Invariant<'static> {
-   |                       ^^
-   = note: ...does not necessarily outlive the static lifetime
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.base.stderr b/src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.base.stderr
new file mode 100644 (file)
index 0000000..12774ca
--- /dev/null
@@ -0,0 +1,18 @@
+error[E0308]: mismatched types
+  --> $DIR/regions-infer-invariance-due-to-mutability-4.rs:14:5
+   |
+LL |     b_isize
+   |     ^^^^^^^ lifetime mismatch
+   |
+   = note: expected struct `Invariant<'static>`
+              found struct `Invariant<'r>`
+note: the lifetime `'r` as defined here...
+  --> $DIR/regions-infer-invariance-due-to-mutability-4.rs:13:23
+   |
+LL | fn to_longer_lifetime<'r>(b_isize: Invariant<'r>) -> Invariant<'static> {
+   |                       ^^
+   = note: ...does not necessarily outlive the static lifetime
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
index f3973a93bad84337c1343ef100e495bca7380c72..1b3ef7bc0289490cd1e68f6211e153c6bbb86df0 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/regions-infer-invariance-due-to-mutability-4.rs:10:5
+  --> $DIR/regions-infer-invariance-due-to-mutability-4.rs:14:5
    |
 LL | fn to_longer_lifetime<'r>(b_isize: Invariant<'r>) -> Invariant<'static> {
    |                       -- lifetime `'r` defined here
index f0af18cf61804e353b148688399c1046cb98b8f0..8e257c4fd0ebe2e83076071316ed7fb722dfa64e 100644 (file)
@@ -1,3 +1,7 @@
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 struct Invariant<'a> {
     f: Box<dyn FnOnce() -> *mut &'a isize + 'static>,
 }
@@ -7,7 +11,9 @@ fn to_same_lifetime<'r>(b_isize: Invariant<'r>) {
 }
 
 fn to_longer_lifetime<'r>(b_isize: Invariant<'r>) -> Invariant<'static> {
-    b_isize //~ ERROR mismatched types
+    b_isize
+    //[base]~^ ERROR mismatched types
+    //[nll]~^^ ERROR lifetime may not live long enough
 }
 
 fn main() {
diff --git a/src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.stderr b/src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.stderr
deleted file mode 100644 (file)
index 04d11b5..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-error[E0308]: mismatched types
-  --> $DIR/regions-infer-invariance-due-to-mutability-4.rs:10:5
-   |
-LL |     b_isize
-   |     ^^^^^^^ lifetime mismatch
-   |
-   = note: expected struct `Invariant<'static>`
-              found struct `Invariant<'r>`
-note: the lifetime `'r` as defined here...
-  --> $DIR/regions-infer-invariance-due-to-mutability-4.rs:9:23
-   |
-LL | fn to_longer_lifetime<'r>(b_isize: Invariant<'r>) -> Invariant<'static> {
-   |                       ^^
-   = note: ...does not necessarily outlive the static lifetime
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/regions/regions-infer-not-param.base.stderr b/src/test/ui/regions/regions-infer-not-param.base.stderr
new file mode 100644 (file)
index 0000000..f432741
--- /dev/null
@@ -0,0 +1,60 @@
+error[E0308]: mismatched types
+  --> $DIR/regions-infer-not-param.rs:19:54
+   |
+LL | fn take_direct<'a,'b>(p: Direct<'a>) -> Direct<'b> { p }
+   |                                                      ^ lifetime mismatch
+   |
+   = note: expected struct `Direct<'b>`
+              found struct `Direct<'a>`
+note: the lifetime `'a` as defined here...
+  --> $DIR/regions-infer-not-param.rs:19:16
+   |
+LL | fn take_direct<'a,'b>(p: Direct<'a>) -> Direct<'b> { p }
+   |                ^^
+note: ...does not necessarily outlive the lifetime `'b` as defined here
+  --> $DIR/regions-infer-not-param.rs:19:19
+   |
+LL | fn take_direct<'a,'b>(p: Direct<'a>) -> Direct<'b> { p }
+   |                   ^^
+
+error[E0308]: mismatched types
+  --> $DIR/regions-infer-not-param.rs:25:63
+   |
+LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p }
+   |                                                               ^ lifetime mismatch
+   |
+   = note: expected struct `Indirect2<'b>`
+              found struct `Indirect2<'a>`
+note: the lifetime `'a` as defined here...
+  --> $DIR/regions-infer-not-param.rs:25:19
+   |
+LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p }
+   |                   ^^
+note: ...does not necessarily outlive the lifetime `'b` as defined here
+  --> $DIR/regions-infer-not-param.rs:25:22
+   |
+LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p }
+   |                      ^^
+
+error[E0308]: mismatched types
+  --> $DIR/regions-infer-not-param.rs:25:63
+   |
+LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p }
+   |                                                               ^ lifetime mismatch
+   |
+   = note: expected struct `Indirect2<'b>`
+              found struct `Indirect2<'a>`
+note: the lifetime `'b` as defined here...
+  --> $DIR/regions-infer-not-param.rs:25:22
+   |
+LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p }
+   |                      ^^
+note: ...does not necessarily outlive the lifetime `'a` as defined here
+  --> $DIR/regions-infer-not-param.rs:25:19
+   |
+LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p }
+   |                   ^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
index f4875e49c3da4145765dc334113c962a304577c1..95e6b03c350a3ff8a9bafb7e484ff436cd16b829 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/regions-infer-not-param.rs:15:54
+  --> $DIR/regions-infer-not-param.rs:19:54
    |
 LL | fn take_direct<'a,'b>(p: Direct<'a>) -> Direct<'b> { p }
    |                -- -- lifetime `'b` defined here      ^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
@@ -9,7 +9,7 @@ LL | fn take_direct<'a,'b>(p: Direct<'a>) -> Direct<'b> { p }
    = help: consider adding the following bound: `'a: 'b`
 
 error: lifetime may not live long enough
-  --> $DIR/regions-infer-not-param.rs:19:63
+  --> $DIR/regions-infer-not-param.rs:25:63
    |
 LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p }
    |                   -- -- lifetime `'b` defined here            ^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
@@ -22,7 +22,7 @@ LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p }
    = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: lifetime may not live long enough
-  --> $DIR/regions-infer-not-param.rs:19:63
+  --> $DIR/regions-infer-not-param.rs:25:63
    |
 LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p }
    |                   -- -- lifetime `'b` defined here            ^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
index 7643be64d5b234eb8e6901d54d9e92f5b600e456..0b8af5bc152ba6173a54f79adce7e2227d75e795 100644 (file)
@@ -1,3 +1,7 @@
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 struct Direct<'a> {
     f: &'a isize
 }
@@ -12,15 +16,20 @@ struct Indirect2<'a> {
     g: Box<dyn FnOnce(Direct<'a>) + 'static>
 }
 
-fn take_direct<'a,'b>(p: Direct<'a>) -> Direct<'b> { p } //~ ERROR mismatched types
+fn take_direct<'a,'b>(p: Direct<'a>) -> Direct<'b> { p }
+//[base]~^ ERROR mismatched types
+//[nll]~^^ ERROR lifetime may not live long enough
 
 fn take_indirect1(p: Indirect1) -> Indirect1 { p }
 
-fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p } //~ ERROR mismatched types
-//~| expected struct `Indirect2<'b>`
-//~| found struct `Indirect2<'a>`
-//~| ERROR mismatched types
-//~| expected struct `Indirect2<'b>`
-//~| found struct `Indirect2<'a>`
+fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p }
+//[base]~^ ERROR mismatched types
+//[base]~| expected struct `Indirect2<'b>`
+//[base]~| found struct `Indirect2<'a>`
+//[base]~| ERROR mismatched types
+//[base]~| expected struct `Indirect2<'b>`
+//[base]~| found struct `Indirect2<'a>`
+//[nll]~^^^^^^^ ERROR lifetime may not live long enough
+//[nll]~| ERROR lifetime may not live long enough
 
 fn main() {}
diff --git a/src/test/ui/regions/regions-infer-not-param.stderr b/src/test/ui/regions/regions-infer-not-param.stderr
deleted file mode 100644 (file)
index a23bdeb..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-error[E0308]: mismatched types
-  --> $DIR/regions-infer-not-param.rs:15:54
-   |
-LL | fn take_direct<'a,'b>(p: Direct<'a>) -> Direct<'b> { p }
-   |                                                      ^ lifetime mismatch
-   |
-   = note: expected struct `Direct<'b>`
-              found struct `Direct<'a>`
-note: the lifetime `'a` as defined here...
-  --> $DIR/regions-infer-not-param.rs:15:16
-   |
-LL | fn take_direct<'a,'b>(p: Direct<'a>) -> Direct<'b> { p }
-   |                ^^
-note: ...does not necessarily outlive the lifetime `'b` as defined here
-  --> $DIR/regions-infer-not-param.rs:15:19
-   |
-LL | fn take_direct<'a,'b>(p: Direct<'a>) -> Direct<'b> { p }
-   |                   ^^
-
-error[E0308]: mismatched types
-  --> $DIR/regions-infer-not-param.rs:19:63
-   |
-LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p }
-   |                                                               ^ lifetime mismatch
-   |
-   = note: expected struct `Indirect2<'b>`
-              found struct `Indirect2<'a>`
-note: the lifetime `'a` as defined here...
-  --> $DIR/regions-infer-not-param.rs:19:19
-   |
-LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p }
-   |                   ^^
-note: ...does not necessarily outlive the lifetime `'b` as defined here
-  --> $DIR/regions-infer-not-param.rs:19:22
-   |
-LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p }
-   |                      ^^
-
-error[E0308]: mismatched types
-  --> $DIR/regions-infer-not-param.rs:19:63
-   |
-LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p }
-   |                                                               ^ lifetime mismatch
-   |
-   = note: expected struct `Indirect2<'b>`
-              found struct `Indirect2<'a>`
-note: the lifetime `'b` as defined here...
-  --> $DIR/regions-infer-not-param.rs:19:22
-   |
-LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p }
-   |                      ^^
-note: ...does not necessarily outlive the lifetime `'a` as defined here
-  --> $DIR/regions-infer-not-param.rs:19:19
-   |
-LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p }
-   |                   ^^
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/regions/regions-infer-paramd-indirect.base.stderr b/src/test/ui/regions/regions-infer-paramd-indirect.base.stderr
new file mode 100644 (file)
index 0000000..1d4471f
--- /dev/null
@@ -0,0 +1,22 @@
+error[E0308]: mismatched types
+  --> $DIR/regions-infer-paramd-indirect.rs:26:18
+   |
+LL |         self.f = b;
+   |                  ^ lifetime mismatch
+   |
+   = note: expected struct `Box<Box<&'a isize>>`
+              found struct `Box<Box<&isize>>`
+note: the anonymous lifetime defined here...
+  --> $DIR/regions-infer-paramd-indirect.rs:25:36
+   |
+LL |     fn set_f_bad(&mut self, b: Box<B>) {
+   |                                    ^
+note: ...does not necessarily outlive the lifetime `'a` as defined here
+  --> $DIR/regions-infer-paramd-indirect.rs:20:6
+   |
+LL | impl<'a> SetF<'a> for C<'a> {
+   |      ^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
index afabdc1de1c7d9502689713ed154563cf73e11ba..96377cbdab4ae9474cb9d4634cfbf3b727ee9d0e 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/regions-infer-paramd-indirect.rs:22:9
+  --> $DIR/regions-infer-paramd-indirect.rs:26:9
    |
 LL | impl<'a> SetF<'a> for C<'a> {
    |      -- lifetime `'a` defined here
index 3b18bbf1df3d0b5eac37aaca06846845a2efb840..060306f611e1debeb8543d5ebd8f24a9f8fb948c 100644 (file)
@@ -1,6 +1,10 @@
 // Check that we correctly infer that b and c must be region
 // parameterized because they reference a which requires a region.
 
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 type A<'a> = &'a isize;
 type B<'a> = Box<A<'a>>;
 
@@ -20,10 +24,11 @@ fn set_f_ok(&mut self, b: Box<B<'a>>) {
 
     fn set_f_bad(&mut self, b: Box<B>) {
         self.f = b;
-        //~^ ERROR mismatched types
-        //~| expected struct `Box<Box<&'a isize>>`
-        //~| found struct `Box<Box<&isize>>`
-        //~| lifetime mismatch
+        //[base]~^ ERROR mismatched types
+        //[base]~| expected struct `Box<Box<&'a isize>>`
+        //[base]~| found struct `Box<Box<&isize>>`
+        //[base]~| lifetime mismatch
+        //[nll]~^^^^^ ERROR lifetime may not live long enough
     }
 }
 
diff --git a/src/test/ui/regions/regions-infer-paramd-indirect.stderr b/src/test/ui/regions/regions-infer-paramd-indirect.stderr
deleted file mode 100644 (file)
index d2b369f..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-error[E0308]: mismatched types
-  --> $DIR/regions-infer-paramd-indirect.rs:22:18
-   |
-LL |         self.f = b;
-   |                  ^ lifetime mismatch
-   |
-   = note: expected struct `Box<Box<&'a isize>>`
-              found struct `Box<Box<&isize>>`
-note: the anonymous lifetime defined here...
-  --> $DIR/regions-infer-paramd-indirect.rs:21:36
-   |
-LL |     fn set_f_bad(&mut self, b: Box<B>) {
-   |                                    ^
-note: ...does not necessarily outlive the lifetime `'a` as defined here
-  --> $DIR/regions-infer-paramd-indirect.rs:16:6
-   |
-LL | impl<'a> SetF<'a> for C<'a> {
-   |      ^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/regions/regions-lifetime-bounds-on-fns.base.stderr b/src/test/ui/regions/regions-lifetime-bounds-on-fns.base.stderr
new file mode 100644 (file)
index 0000000..e57b06a
--- /dev/null
@@ -0,0 +1,31 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/regions-lifetime-bounds-on-fns.rs:12:10
+   |
+LL | fn b<'a, 'b>(x: &mut &'a isize, y: &mut &'b isize) {
+   |                      ---------          --------- these two types are declared with different lifetimes...
+LL |     // Illegal now because there is no `'b:'a` declaration.
+LL |     *x = *y;
+   |          ^^ ...but data from `y` flows into `x` here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/regions-lifetime-bounds-on-fns.rs:20:7
+   |
+LL | fn c<'a,'b>(x: &mut &'a isize, y: &mut &'b isize) {
+   |                     ---------          --------- these two types are declared with different lifetimes...
+...
+LL |     a(x, y);
+   |       ^ ...but data from `y` flows into `x` here
+
+error[E0308]: mismatched types
+  --> $DIR/regions-lifetime-bounds-on-fns.rs:28:43
+   |
+LL |     let _: fn(&mut &isize, &mut &isize) = a;
+   |                                           ^ one type is more general than the other
+   |
+   = note: expected fn pointer `for<'r, 's, 't0, 't1> fn(&'r mut &'s isize, &'t0 mut &'t1 isize)`
+              found fn pointer `for<'r, 's> fn(&'r mut &isize, &'s mut &isize)`
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0308, E0623.
+For more information about an error, try `rustc --explain E0308`.
index ee3dcef1cb5c4455350c3fbf62fdd4274726ce9e..7fe8b4bf57fc197c2e23fb1c049a0aeb12d68be1 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/regions-lifetime-bounds-on-fns.rs:8:5
+  --> $DIR/regions-lifetime-bounds-on-fns.rs:12:5
    |
 LL | fn b<'a, 'b>(x: &mut &'a isize, y: &mut &'b isize) {
    |      --  -- lifetime `'b` defined here
@@ -12,7 +12,7 @@ LL |     *x = *y;
    = help: consider adding the following bound: `'b: 'a`
 
 error: lifetime may not live long enough
-  --> $DIR/regions-lifetime-bounds-on-fns.rs:14:5
+  --> $DIR/regions-lifetime-bounds-on-fns.rs:20:5
    |
 LL | fn c<'a,'b>(x: &mut &'a isize, y: &mut &'b isize) {
    |      -- -- lifetime `'b` defined here
@@ -28,7 +28,7 @@ LL |     a(x, y);
    = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error[E0308]: mismatched types
-  --> $DIR/regions-lifetime-bounds-on-fns.rs:20:12
+  --> $DIR/regions-lifetime-bounds-on-fns.rs:28:12
    |
 LL |     let _: fn(&mut &isize, &mut &isize) = a;
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
@@ -37,7 +37,7 @@ LL |     let _: fn(&mut &isize, &mut &isize) = a;
               found fn pointer `for<'r, 's> fn(&'r mut &isize, &'s mut &isize)`
 
 error[E0308]: mismatched types
-  --> $DIR/regions-lifetime-bounds-on-fns.rs:20:12
+  --> $DIR/regions-lifetime-bounds-on-fns.rs:28:12
    |
 LL |     let _: fn(&mut &isize, &mut &isize) = a;
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
index 7d7f62e19792f1847158ad3a76f726ddac6bd353..97c08d8ab0e3c9810f6268434e126a7f3f7bd33c 100644 (file)
@@ -1,3 +1,7 @@
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 fn a<'a, 'b:'a>(x: &mut &'a isize, y: &mut &'b isize) {
     // Note: this is legal because of the `'b:'a` declaration.
     *x = *y;
@@ -5,19 +9,25 @@ fn a<'a, 'b:'a>(x: &mut &'a isize, y: &mut &'b isize) {
 
 fn b<'a, 'b>(x: &mut &'a isize, y: &mut &'b isize) {
     // Illegal now because there is no `'b:'a` declaration.
-    *x = *y; //~ ERROR E0623
+    *x = *y;
+    //[base]~^ ERROR lifetime mismatch [E0623]
+    //[nll]~^^ ERROR lifetime may not live long enough
 }
 
 fn c<'a,'b>(x: &mut &'a isize, y: &mut &'b isize) {
     // Here we try to call `foo` but do not know that `'a` and `'b` are
     // related as required.
-    a(x, y); //~ ERROR lifetime mismatch [E0623]
+    a(x, y);
+    //[base]~^ ERROR lifetime mismatch [E0623]
+    //[nll]~^^ ERROR lifetime may not live long enough
 }
 
 fn d() {
     // 'a and 'b are early bound in the function `a` because they appear
     // inconstraints:
-    let _: fn(&mut &isize, &mut &isize) = a; //~ ERROR E0308
+    let _: fn(&mut &isize, &mut &isize) = a;
+    //~^ ERROR mismatched types [E0308]
+    //[nll]~^^ ERROR mismatched types [E0308]
 }
 
 fn e() {
diff --git a/src/test/ui/regions/regions-lifetime-bounds-on-fns.stderr b/src/test/ui/regions/regions-lifetime-bounds-on-fns.stderr
deleted file mode 100644 (file)
index 2b2dd0d..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-error[E0623]: lifetime mismatch
-  --> $DIR/regions-lifetime-bounds-on-fns.rs:8:10
-   |
-LL | fn b<'a, 'b>(x: &mut &'a isize, y: &mut &'b isize) {
-   |                      ---------          --------- these two types are declared with different lifetimes...
-LL |     // Illegal now because there is no `'b:'a` declaration.
-LL |     *x = *y;
-   |          ^^ ...but data from `y` flows into `x` here
-
-error[E0623]: lifetime mismatch
-  --> $DIR/regions-lifetime-bounds-on-fns.rs:14:7
-   |
-LL | fn c<'a,'b>(x: &mut &'a isize, y: &mut &'b isize) {
-   |                     ---------          --------- these two types are declared with different lifetimes...
-...
-LL |     a(x, y);
-   |       ^ ...but data from `y` flows into `x` here
-
-error[E0308]: mismatched types
-  --> $DIR/regions-lifetime-bounds-on-fns.rs:20:43
-   |
-LL |     let _: fn(&mut &isize, &mut &isize) = a;
-   |                                           ^ one type is more general than the other
-   |
-   = note: expected fn pointer `for<'r, 's, 't0, 't1> fn(&'r mut &'s isize, &'t0 mut &'t1 isize)`
-              found fn pointer `for<'r, 's> fn(&'r mut &isize, &'s mut &isize)`
-
-error: aborting due to 3 previous errors
-
-Some errors have detailed explanations: E0308, E0623.
-For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/regions/regions-nested-fns.base.stderr b/src/test/ui/regions/regions-nested-fns.base.stderr
new file mode 100644 (file)
index 0000000..37ce569
--- /dev/null
@@ -0,0 +1,78 @@
+error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
+  --> $DIR/regions-nested-fns.rs:9:18
+   |
+LL |     let mut ay = &y;
+   |                  ^^
+   |
+note: first, the lifetime cannot outlive the anonymous lifetime #1 defined here...
+  --> $DIR/regions-nested-fns.rs:13:58
+   |
+LL |       ignore::<Box<dyn for<'z> FnMut(&'z isize)>>(Box::new(|z| {
+   |  __________________________________________________________^
+LL | |         ay = x;
+LL | |         ay = &y;
+LL | |
+LL | |         ay = z;
+LL | |
+LL | |     }));
+   | |_____^
+note: ...so that reference does not outlive borrowed content
+  --> $DIR/regions-nested-fns.rs:17:14
+   |
+LL |         ay = z;
+   |              ^
+note: but, the lifetime must be valid for the anonymous lifetime #1 defined here...
+  --> $DIR/regions-nested-fns.rs:21:72
+   |
+LL |       ignore::< Box<dyn for<'z> FnMut(&'z isize) -> &'z isize>>(Box::new(|z| {
+   |  ________________________________________________________________________^
+LL | |         if false { return x; }
+LL | |
+LL | |
+LL | |         if false { return ay; }
+LL | |         return z;
+LL | |     }));
+   | |_____^
+note: ...so that the types are compatible
+  --> $DIR/regions-nested-fns.rs:21:76
+   |
+LL |       ignore::< Box<dyn for<'z> FnMut(&'z isize) -> &'z isize>>(Box::new(|z| {
+   |  ____________________________________________________________________________^
+LL | |         if false { return x; }
+LL | |
+LL | |
+LL | |         if false { return ay; }
+LL | |         return z;
+LL | |     }));
+   | |_____^
+   = note: expected `&isize`
+              found `&isize`
+
+error[E0312]: lifetime of reference outlives lifetime of borrowed content...
+  --> $DIR/regions-nested-fns.rs:22:27
+   |
+LL |         if false { return x; }
+   |                           ^
+   |
+note: ...the reference is valid for the anonymous lifetime #1 defined here...
+  --> $DIR/regions-nested-fns.rs:21:72
+   |
+LL |       ignore::< Box<dyn for<'z> FnMut(&'z isize) -> &'z isize>>(Box::new(|z| {
+   |  ________________________________________________________________________^
+LL | |         if false { return x; }
+LL | |
+LL | |
+LL | |         if false { return ay; }
+LL | |         return z;
+LL | |     }));
+   | |_____^
+note: ...but the borrowed content is only valid for the lifetime `'x` as defined here
+  --> $DIR/regions-nested-fns.rs:7:11
+   |
+LL | fn nested<'x>(x: &'x isize) {
+   |           ^^
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0312, E0495.
+For more information about an error, try `rustc --explain E0312`.
index a0cfa3624722897e5f5479158a389a5af7e7d0dd..6f2a89994b0475f3090cb76faf6165d9f8a66f46 100644 (file)
@@ -1,9 +1,9 @@
 error[E0521]: borrowed data escapes outside of closure
-  --> $DIR/regions-nested-fns.rs:10:9
+  --> $DIR/regions-nested-fns.rs:17:9
    |
 LL |     let mut ay = &y;
    |         ------ `ay` declared here, outside of the closure body
-LL | 
+...
 LL |     ignore::<Box<dyn for<'z> FnMut(&'z isize)>>(Box::new(|z| {
    |                                                           - `z` is a reference that is only valid in the closure body
 ...
@@ -11,7 +11,7 @@ LL |         ay = z;
    |         ^^^^^^ `z` escapes the closure body here
 
 error[E0597]: `y` does not live long enough
-  --> $DIR/regions-nested-fns.rs:5:18
+  --> $DIR/regions-nested-fns.rs:9:18
    |
 LL |     let mut ay = &y;
    |                  ^^ borrowed value does not live long enough
@@ -23,7 +23,7 @@ LL | }
    | - `y` dropped here while still borrowed
 
 error[E0597]: `y` does not live long enough
-  --> $DIR/regions-nested-fns.rs:9:15
+  --> $DIR/regions-nested-fns.rs:15:15
    |
 LL |     ignore::<Box<dyn for<'z> FnMut(&'z isize)>>(Box::new(|z| {
    |                                                          --- value captured here
@@ -38,7 +38,7 @@ LL | }
    | - `y` dropped here while still borrowed
 
 error: lifetime may not live long enough
-  --> $DIR/regions-nested-fns.rs:14:27
+  --> $DIR/regions-nested-fns.rs:22:27
    |
 LL | fn nested<'x>(x: &'x isize) {
    |           -- lifetime `'x` defined here
index c02d4e0ce453b1629c7a2fc93c14e584a3810012..8cc39792bd978d122dd0af92a32f146a74c89105 100644 (file)
@@ -1,17 +1,27 @@
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 fn ignore<T>(t: T) {}
 
 fn nested<'x>(x: &'x isize) {
     let y = 3;
-    let mut ay = &y; //~ ERROR E0495
+    let mut ay = &y;
+    //[base]~^ ERROR E0495
+    //[nll]~^^ ERROR `y` does not live long enough [E0597]
 
     ignore::<Box<dyn for<'z> FnMut(&'z isize)>>(Box::new(|z| {
         ay = x;
         ay = &y;
+        //[nll]~^ ERROR `y` does not live long enough
         ay = z;
+        //[nll]~^ ERROR borrowed data escapes outside of closure [E0521]
     }));
 
     ignore::< Box<dyn for<'z> FnMut(&'z isize) -> &'z isize>>(Box::new(|z| {
-        if false { return x; } //~ ERROR E0312
+        if false { return x; }
+        //[base]~^ ERROR E0312
+        //[nll]~^^ ERROR lifetime may not live long enough
         if false { return ay; }
         return z;
     }));
diff --git a/src/test/ui/regions/regions-nested-fns.stderr b/src/test/ui/regions/regions-nested-fns.stderr
deleted file mode 100644 (file)
index 11affca..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
-  --> $DIR/regions-nested-fns.rs:5:18
-   |
-LL |     let mut ay = &y;
-   |                  ^^
-   |
-note: first, the lifetime cannot outlive the anonymous lifetime #1 defined here...
-  --> $DIR/regions-nested-fns.rs:7:58
-   |
-LL |       ignore::<Box<dyn for<'z> FnMut(&'z isize)>>(Box::new(|z| {
-   |  __________________________________________________________^
-LL | |         ay = x;
-LL | |         ay = &y;
-LL | |         ay = z;
-LL | |     }));
-   | |_____^
-note: ...so that reference does not outlive borrowed content
-  --> $DIR/regions-nested-fns.rs:10:14
-   |
-LL |         ay = z;
-   |              ^
-note: but, the lifetime must be valid for the anonymous lifetime #1 defined here...
-  --> $DIR/regions-nested-fns.rs:13:72
-   |
-LL |       ignore::< Box<dyn for<'z> FnMut(&'z isize) -> &'z isize>>(Box::new(|z| {
-   |  ________________________________________________________________________^
-LL | |         if false { return x; }
-LL | |         if false { return ay; }
-LL | |         return z;
-LL | |     }));
-   | |_____^
-note: ...so that the types are compatible
-  --> $DIR/regions-nested-fns.rs:13:76
-   |
-LL |       ignore::< Box<dyn for<'z> FnMut(&'z isize) -> &'z isize>>(Box::new(|z| {
-   |  ____________________________________________________________________________^
-LL | |         if false { return x; }
-LL | |         if false { return ay; }
-LL | |         return z;
-LL | |     }));
-   | |_____^
-   = note: expected `&isize`
-              found `&isize`
-
-error[E0312]: lifetime of reference outlives lifetime of borrowed content...
-  --> $DIR/regions-nested-fns.rs:14:27
-   |
-LL |         if false { return x; }
-   |                           ^
-   |
-note: ...the reference is valid for the anonymous lifetime #1 defined here...
-  --> $DIR/regions-nested-fns.rs:13:72
-   |
-LL |       ignore::< Box<dyn for<'z> FnMut(&'z isize) -> &'z isize>>(Box::new(|z| {
-   |  ________________________________________________________________________^
-LL | |         if false { return x; }
-LL | |         if false { return ay; }
-LL | |         return z;
-LL | |     }));
-   | |_____^
-note: ...but the borrowed content is only valid for the lifetime `'x` as defined here
-  --> $DIR/regions-nested-fns.rs:3:11
-   |
-LL | fn nested<'x>(x: &'x isize) {
-   |           ^^
-
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0312, E0495.
-For more information about an error, try `rustc --explain E0312`.
diff --git a/src/test/ui/regions/regions-outlives-projection-container.base.stderr b/src/test/ui/regions/regions-outlives-projection-container.base.stderr
new file mode 100644 (file)
index 0000000..9a66f67
--- /dev/null
@@ -0,0 +1,71 @@
+error[E0491]: in type `&'a WithAssoc<TheType<'b>>`, reference has a longer lifetime than the data it references
+  --> $DIR/regions-outlives-projection-container.rs:40:13
+   |
+LL |     let _x: &'a WithAssoc<TheType<'b>> = loop { };
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: the pointer is valid for the lifetime `'a` as defined here
+  --> $DIR/regions-outlives-projection-container.rs:32:15
+   |
+LL | fn with_assoc<'a,'b>() {
+   |               ^^
+note: but the referenced data is only valid for the lifetime `'b` as defined here
+  --> $DIR/regions-outlives-projection-container.rs:32:18
+   |
+LL | fn with_assoc<'a,'b>() {
+   |                  ^^
+
+error[E0491]: in type `&'a WithoutAssoc<TheType<'b>>`, reference has a longer lifetime than the data it references
+  --> $DIR/regions-outlives-projection-container.rs:59:13
+   |
+LL |     let _x: &'a WithoutAssoc<TheType<'b>> = loop { };
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: the pointer is valid for the lifetime `'a` as defined here
+  --> $DIR/regions-outlives-projection-container.rs:55:18
+   |
+LL | fn without_assoc<'a,'b>() {
+   |                  ^^
+note: but the referenced data is only valid for the lifetime `'b` as defined here
+  --> $DIR/regions-outlives-projection-container.rs:55:21
+   |
+LL | fn without_assoc<'a,'b>() {
+   |                     ^^
+
+error[E0491]: in type `&'a WithAssoc<TheType<'b>>`, reference has a longer lifetime than the data it references
+  --> $DIR/regions-outlives-projection-container.rs:69:12
+   |
+LL |     call::<&'a WithAssoc<TheType<'b>>>();
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: the pointer is valid for the lifetime `'a` as defined here
+  --> $DIR/regions-outlives-projection-container.rs:64:20
+   |
+LL | fn call_with_assoc<'a,'b>() {
+   |                    ^^
+note: but the referenced data is only valid for the lifetime `'b` as defined here
+  --> $DIR/regions-outlives-projection-container.rs:64:23
+   |
+LL | fn call_with_assoc<'a,'b>() {
+   |                       ^^
+
+error[E0491]: in type `&'a WithoutAssoc<TheType<'b>>`, reference has a longer lifetime than the data it references
+  --> $DIR/regions-outlives-projection-container.rs:77:12
+   |
+LL |     call::<&'a WithoutAssoc<TheType<'b>>>();
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: the pointer is valid for the lifetime `'a` as defined here
+  --> $DIR/regions-outlives-projection-container.rs:74:23
+   |
+LL | fn call_without_assoc<'a,'b>() {
+   |                       ^^
+note: but the referenced data is only valid for the lifetime `'b` as defined here
+  --> $DIR/regions-outlives-projection-container.rs:74:26
+   |
+LL | fn call_without_assoc<'a,'b>() {
+   |                          ^^
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0491`.
index 073a31900227e43e357b339d947df136eba08b9a..d93eef9ce0b5c2d60fb4f5703127a96627627909 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/regions-outlives-projection-container.rs:36:13
+  --> $DIR/regions-outlives-projection-container.rs:40:13
    |
 LL | fn with_assoc<'a,'b>() {
    |               -- -- lifetime `'b` defined here
@@ -12,7 +12,7 @@ LL |     let _x: &'a WithAssoc<TheType<'b>> = loop { };
    = help: consider adding the following bound: `'b: 'a`
 
 error: lifetime may not live long enough
-  --> $DIR/regions-outlives-projection-container.rs:54:13
+  --> $DIR/regions-outlives-projection-container.rs:59:13
    |
 LL | fn without_assoc<'a,'b>() {
    |                  -- -- lifetime `'b` defined here
@@ -25,7 +25,7 @@ LL |     let _x: &'a WithoutAssoc<TheType<'b>> = loop { };
    = help: consider adding the following bound: `'b: 'a`
 
 error: lifetime may not live long enough
-  --> $DIR/regions-outlives-projection-container.rs:63:5
+  --> $DIR/regions-outlives-projection-container.rs:69:5
    |
 LL | fn call_with_assoc<'a,'b>() {
    |                    -- -- lifetime `'b` defined here
@@ -38,7 +38,7 @@ LL |     call::<&'a WithAssoc<TheType<'b>>>();
    = help: consider adding the following bound: `'b: 'a`
 
 error: lifetime may not live long enough
-  --> $DIR/regions-outlives-projection-container.rs:70:5
+  --> $DIR/regions-outlives-projection-container.rs:77:5
    |
 LL | fn call_without_assoc<'a,'b>() {
    |                       -- -- lifetime `'b` defined here
index 3afc600becb6e4c7309b65b5d2e7ef251b24c1cf..ccfd2213b6f33f05377e77ab944950b88c279851 100644 (file)
@@ -2,6 +2,10 @@
 // type of a bound that appears in the where clause on a struct must
 // outlive the location in which the type appears. Issue #22246.
 
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 #![allow(dead_code)]
 #![feature(rustc_attrs)]
 
@@ -34,7 +38,8 @@ fn with_assoc<'a,'b>() {
     // FIXME (#54943) NLL doesn't enforce WF condition in unreachable code if
     // `_x` is changed to `_`
     let _x: &'a WithAssoc<TheType<'b>> = loop { };
-    //~^ ERROR reference has a longer lifetime
+    //[base]~^ ERROR reference has a longer lifetime
+    //[nll]~^^ ERROR lifetime may not live long enough
 }
 
 fn with_assoc1<'a,'b>() where 'b : 'a {
@@ -52,7 +57,8 @@ fn without_assoc<'a,'b>() {
     // that `'b:'a` holds because the `'b` appears in `TheType<'b>`.
 
     let _x: &'a WithoutAssoc<TheType<'b>> = loop { };
-    //~^ ERROR reference has a longer lifetime
+    //[base]~^ ERROR reference has a longer lifetime
+    //[nll]~^^ ERROR lifetime may not live long enough
 }
 
 fn call_with_assoc<'a,'b>() {
@@ -61,13 +67,16 @@ fn call_with_assoc<'a,'b>() {
     // no data.
 
     call::<&'a WithAssoc<TheType<'b>>>();
-    //~^ ERROR reference has a longer lifetime
+    //[base]~^ ERROR reference has a longer lifetime
+    //[nll]~^^ ERROR lifetime may not live long enough
 }
 
 fn call_without_assoc<'a,'b>() {
     // As `without_assoc`, but in a distinct scenario.
 
-    call::<&'a WithoutAssoc<TheType<'b>>>(); //~ ERROR reference has a longer lifetime
+    call::<&'a WithoutAssoc<TheType<'b>>>();
+    //[base]~^ ERROR reference has a longer lifetime
+    //[nll]~^^ ERROR lifetime may not live long enough
 }
 
 fn call<T>() { }
diff --git a/src/test/ui/regions/regions-outlives-projection-container.stderr b/src/test/ui/regions/regions-outlives-projection-container.stderr
deleted file mode 100644 (file)
index 8c2b2c1..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-error[E0491]: in type `&'a WithAssoc<TheType<'b>>`, reference has a longer lifetime than the data it references
-  --> $DIR/regions-outlives-projection-container.rs:36:13
-   |
-LL |     let _x: &'a WithAssoc<TheType<'b>> = loop { };
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: the pointer is valid for the lifetime `'a` as defined here
-  --> $DIR/regions-outlives-projection-container.rs:28:15
-   |
-LL | fn with_assoc<'a,'b>() {
-   |               ^^
-note: but the referenced data is only valid for the lifetime `'b` as defined here
-  --> $DIR/regions-outlives-projection-container.rs:28:18
-   |
-LL | fn with_assoc<'a,'b>() {
-   |                  ^^
-
-error[E0491]: in type `&'a WithoutAssoc<TheType<'b>>`, reference has a longer lifetime than the data it references
-  --> $DIR/regions-outlives-projection-container.rs:54:13
-   |
-LL |     let _x: &'a WithoutAssoc<TheType<'b>> = loop { };
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: the pointer is valid for the lifetime `'a` as defined here
-  --> $DIR/regions-outlives-projection-container.rs:50:18
-   |
-LL | fn without_assoc<'a,'b>() {
-   |                  ^^
-note: but the referenced data is only valid for the lifetime `'b` as defined here
-  --> $DIR/regions-outlives-projection-container.rs:50:21
-   |
-LL | fn without_assoc<'a,'b>() {
-   |                     ^^
-
-error[E0491]: in type `&'a WithAssoc<TheType<'b>>`, reference has a longer lifetime than the data it references
-  --> $DIR/regions-outlives-projection-container.rs:63:12
-   |
-LL |     call::<&'a WithAssoc<TheType<'b>>>();
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: the pointer is valid for the lifetime `'a` as defined here
-  --> $DIR/regions-outlives-projection-container.rs:58:20
-   |
-LL | fn call_with_assoc<'a,'b>() {
-   |                    ^^
-note: but the referenced data is only valid for the lifetime `'b` as defined here
-  --> $DIR/regions-outlives-projection-container.rs:58:23
-   |
-LL | fn call_with_assoc<'a,'b>() {
-   |                       ^^
-
-error[E0491]: in type `&'a WithoutAssoc<TheType<'b>>`, reference has a longer lifetime than the data it references
-  --> $DIR/regions-outlives-projection-container.rs:70:12
-   |
-LL |     call::<&'a WithoutAssoc<TheType<'b>>>();
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: the pointer is valid for the lifetime `'a` as defined here
-  --> $DIR/regions-outlives-projection-container.rs:67:23
-   |
-LL | fn call_without_assoc<'a,'b>() {
-   |                       ^^
-note: but the referenced data is only valid for the lifetime `'b` as defined here
-  --> $DIR/regions-outlives-projection-container.rs:67:26
-   |
-LL | fn call_without_assoc<'a,'b>() {
-   |                          ^^
-
-error: aborting due to 4 previous errors
-
-For more information about this error, try `rustc --explain E0491`.
diff --git a/src/test/ui/regions/regions-proc-bound-capture.base.stderr b/src/test/ui/regions/regions-proc-bound-capture.base.stderr
new file mode 100644 (file)
index 0000000..427c6f4
--- /dev/null
@@ -0,0 +1,29 @@
+error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
+  --> $DIR/regions-proc-bound-capture.rs:13:14
+   |
+LL | fn static_proc(x: &isize) -> Box<dyn FnMut() -> (isize) + 'static> {
+   |                   ------ this data with an anonymous lifetime `'_`...
+LL |     // This is illegal, because the region bound on `proc` is 'static.
+LL |     Box::new(move || { *x })
+   |              ^^^^^^^^^^^^^^ ...is used and required to live as long as `'static` here
+   |
+note: `'static` lifetime requirement introduced by the return type
+  --> $DIR/regions-proc-bound-capture.rs:11:59
+   |
+LL | fn static_proc(x: &isize) -> Box<dyn FnMut() -> (isize) + 'static> {
+   |                                                           ^^^^^^^ `'static` requirement introduced here
+LL |     // This is illegal, because the region bound on `proc` is 'static.
+LL |     Box::new(move || { *x })
+   |     ------------------------ because of this returned expression
+help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `x`
+   |
+LL | fn static_proc(x: &isize) -> Box<dyn FnMut() -> (isize) + '_> {
+   |                                                           ~~
+help: alternatively, add an explicit `'static` bound to this reference
+   |
+LL | fn static_proc(x: &'static isize) -> Box<dyn FnMut() -> (isize) + 'static> {
+   |                   ~~~~~~~~~~~~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0759`.
index 75890b8581537fc7b6ef6d36a42c00cdc94a232f..ce4d2d4d111c3dc7d4c2745dfa53e155119e6a5b 100644 (file)
@@ -1,11 +1,20 @@
 error: lifetime may not live long enough
-  --> $DIR/regions-proc-bound-capture.rs:9:5
+  --> $DIR/regions-proc-bound-capture.rs:13:5
    |
 LL | fn static_proc(x: &isize) -> Box<dyn FnMut() -> (isize) + 'static> {
    |                   - let's call the lifetime of this reference `'1`
 LL |     // This is illegal, because the region bound on `proc` is 'static.
 LL |     Box::new(move || { *x })
    |     ^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static`
+   |
+help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `x`
+   |
+LL | fn static_proc(x: &isize) -> Box<dyn FnMut() -> (isize) + '_> {
+   |                                                           ~~
+help: alternatively, add an explicit `'static` bound to this reference
+   |
+LL | fn static_proc(x: &'static isize) -> Box<dyn FnMut() -> (isize) + 'static> {
+   |                   ~~~~~~~~~~~~~~
 
 error: aborting due to previous error
 
index 55d964ac5340569b287a993d650fe88ba70b2f94..1033163c8dd9c10d6df82f43729b7b9ca8defa64 100644 (file)
@@ -1,3 +1,7 @@
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 fn borrowed_proc<'a>(x: &'a isize) -> Box<dyn FnMut()->(isize) + 'a> {
     // This is legal, because the region bound on `proc`
     // states that it captures `x`.
@@ -6,7 +10,9 @@ fn borrowed_proc<'a>(x: &'a isize) -> Box<dyn FnMut()->(isize) + 'a> {
 
 fn static_proc(x: &isize) -> Box<dyn FnMut() -> (isize) + 'static> {
     // This is illegal, because the region bound on `proc` is 'static.
-    Box::new(move || { *x }) //~ ERROR E0759
+    Box::new(move || { *x })
+    //[base]~^ ERROR E0759
+    //[nll]~^^ ERROR lifetime may not live long enough
 }
 
 fn main() { }
diff --git a/src/test/ui/regions/regions-proc-bound-capture.stderr b/src/test/ui/regions/regions-proc-bound-capture.stderr
deleted file mode 100644 (file)
index 2ebe874..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
-  --> $DIR/regions-proc-bound-capture.rs:9:14
-   |
-LL | fn static_proc(x: &isize) -> Box<dyn FnMut() -> (isize) + 'static> {
-   |                   ------ this data with an anonymous lifetime `'_`...
-LL |     // This is illegal, because the region bound on `proc` is 'static.
-LL |     Box::new(move || { *x })
-   |              ^^^^^^^^^^^^^^ ...is used and required to live as long as `'static` here
-   |
-note: `'static` lifetime requirement introduced by the return type
-  --> $DIR/regions-proc-bound-capture.rs:7:59
-   |
-LL | fn static_proc(x: &isize) -> Box<dyn FnMut() -> (isize) + 'static> {
-   |                                                           ^^^^^^^ `'static` requirement introduced here
-LL |     // This is illegal, because the region bound on `proc` is 'static.
-LL |     Box::new(move || { *x })
-   |     ------------------------ because of this returned expression
-help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `x`
-   |
-LL | fn static_proc(x: &isize) -> Box<dyn FnMut() -> (isize) + '_> {
-   |                                                           ~~
-help: alternatively, add an explicit `'static` bound to this reference
-   |
-LL | fn static_proc(x: &'static isize) -> Box<dyn FnMut() -> (isize) + 'static> {
-   |                   ~~~~~~~~~~~~~~
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0759`.
diff --git a/src/test/ui/regions/regions-reborrow-from-shorter-mut-ref-mut-ref.base.stderr b/src/test/ui/regions/regions-reborrow-from-shorter-mut-ref-mut-ref.base.stderr
new file mode 100644 (file)
index 0000000..7ecdb0c
--- /dev/null
@@ -0,0 +1,13 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/regions-reborrow-from-shorter-mut-ref-mut-ref.rs:8:5
+   |
+LL | fn copy_borrowed_ptr<'a, 'b, 'c>(p: &'a mut &'b mut &'c mut isize) -> &'b mut isize {
+   |                                     -----------------------------     -------------
+   |                                     |
+   |                                     this parameter and the return type are declared with different lifetimes...
+LL |     &mut ***p
+   |     ^^^^^^^^^ ...but data from `p` is returned here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0623`.
index dc905d076bb7d5ce4f99e292833aa5b28d16732f..519ada7bdfc966b94d9a8a05e448c5d9f891876d 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/regions-reborrow-from-shorter-mut-ref-mut-ref.rs:4:5
+  --> $DIR/regions-reborrow-from-shorter-mut-ref-mut-ref.rs:8:5
    |
 LL | fn copy_borrowed_ptr<'a, 'b, 'c>(p: &'a mut &'b mut &'c mut isize) -> &'b mut isize {
    |                      --  -- lifetime `'b` defined here
index 35aca8be25beb58351fa55c0175ed4878dd7a595..c4ad05010fb6d17a4397f130778f47f7ff2800d4 100644 (file)
@@ -1,7 +1,13 @@
 // Issue #8624. Test for reborrowing with 3 levels, not just two.
 
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 fn copy_borrowed_ptr<'a, 'b, 'c>(p: &'a mut &'b mut &'c mut isize) -> &'b mut isize {
-    &mut ***p //~ ERROR lifetime mismatch [E0623]
+    &mut ***p
+    //[base]~^ ERROR lifetime mismatch [E0623]
+    //[nll]~^^ ERROR lifetime may not live long enough
 }
 
 fn main() {
diff --git a/src/test/ui/regions/regions-reborrow-from-shorter-mut-ref-mut-ref.stderr b/src/test/ui/regions/regions-reborrow-from-shorter-mut-ref-mut-ref.stderr
deleted file mode 100644 (file)
index aca3a1e..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-error[E0623]: lifetime mismatch
-  --> $DIR/regions-reborrow-from-shorter-mut-ref-mut-ref.rs:4:5
-   |
-LL | fn copy_borrowed_ptr<'a, 'b, 'c>(p: &'a mut &'b mut &'c mut isize) -> &'b mut isize {
-   |                                     -----------------------------     -------------
-   |                                     |
-   |                                     this parameter and the return type are declared with different lifetimes...
-LL |     &mut ***p
-   |     ^^^^^^^^^ ...but data from `p` is returned here
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0623`.
diff --git a/src/test/ui/regions/regions-reborrow-from-shorter-mut-ref.base.stderr b/src/test/ui/regions/regions-reborrow-from-shorter-mut-ref.base.stderr
new file mode 100644 (file)
index 0000000..3cb7de1
--- /dev/null
@@ -0,0 +1,13 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/regions-reborrow-from-shorter-mut-ref.rs:10:5
+   |
+LL | fn copy_borrowed_ptr<'a, 'b>(p: &'a mut &'b mut isize) -> &'b mut isize {
+   |                                 ---------------------     -------------
+   |                                 |
+   |                                 this parameter and the return type are declared with different lifetimes...
+LL |     &mut **p
+   |     ^^^^^^^^ ...but data from `p` is returned here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0623`.
index c98ec477417bd3e5ffc70426e184f8146ad681c4..4dd2a83739ca74e3322e893a88dab976b13d48c6 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/regions-reborrow-from-shorter-mut-ref.rs:6:5
+  --> $DIR/regions-reborrow-from-shorter-mut-ref.rs:10:5
    |
 LL | fn copy_borrowed_ptr<'a, 'b>(p: &'a mut &'b mut isize) -> &'b mut isize {
    |                      --  -- lifetime `'b` defined here
index 77041ab4f05cbf8de9456c8cc65c9b70249c2d8f..c41e76e4d2a115f635b290ef2934555dbbe02a00 100644 (file)
@@ -2,8 +2,14 @@
 // pointer which is backed by another `&'a mut` can only be done
 // for `'a` (which must be a sublifetime of `'b`).
 
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 fn copy_borrowed_ptr<'a, 'b>(p: &'a mut &'b mut isize) -> &'b mut isize {
-    &mut **p //~ ERROR lifetime mismatch [E0623]
+    &mut **p
+    //[base]~^ ERROR lifetime mismatch [E0623]
+    //[nll]~^^ ERROR lifetime may not live long enough
 }
 
 fn main() {
diff --git a/src/test/ui/regions/regions-reborrow-from-shorter-mut-ref.stderr b/src/test/ui/regions/regions-reborrow-from-shorter-mut-ref.stderr
deleted file mode 100644 (file)
index a9916db..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-error[E0623]: lifetime mismatch
-  --> $DIR/regions-reborrow-from-shorter-mut-ref.rs:6:5
-   |
-LL | fn copy_borrowed_ptr<'a, 'b>(p: &'a mut &'b mut isize) -> &'b mut isize {
-   |                                 ---------------------     -------------
-   |                                 |
-   |                                 this parameter and the return type are declared with different lifetimes...
-LL |     &mut **p
-   |     ^^^^^^^^ ...but data from `p` is returned here
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0623`.
diff --git a/src/test/ui/regions/regions-ret-borrowed-1.base.stderr b/src/test/ui/regions/regions-ret-borrowed-1.base.stderr
new file mode 100644 (file)
index 0000000..d102f93
--- /dev/null
@@ -0,0 +1,32 @@
+error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
+  --> $DIR/regions-ret-borrowed-1.rs:14:14
+   |
+LL |     with(|o| o)
+   |              ^
+   |
+note: first, the lifetime cannot outlive the anonymous lifetime #1 defined here...
+  --> $DIR/regions-ret-borrowed-1.rs:14:10
+   |
+LL |     with(|o| o)
+   |          ^^^^^
+note: ...so that the types are compatible
+  --> $DIR/regions-ret-borrowed-1.rs:14:14
+   |
+LL |     with(|o| o)
+   |              ^
+   = note: expected `&isize`
+              found `&isize`
+note: but, the lifetime must be valid for the lifetime `'a` as defined here...
+  --> $DIR/regions-ret-borrowed-1.rs:13:14
+   |
+LL | fn return_it<'a>() -> &'a isize {
+   |              ^^
+note: ...so that reference does not outlive borrowed content
+  --> $DIR/regions-ret-borrowed-1.rs:14:5
+   |
+LL |     with(|o| o)
+   |     ^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0495`.
index 0784e894ea9200f77d764568211eefd82e6b34eb..4fdadccab15f9f6f77bb62d95924e0e06bfdf1a9 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/regions-ret-borrowed-1.rs:10:14
+  --> $DIR/regions-ret-borrowed-1.rs:14:14
    |
 LL |     with(|o| o)
    |           -- ^ returning this value requires that `'1` must outlive `'2`
index 1be5edee599c43ddc8e81d3b2e1effa374fb3d95..fed631320b44270aadafd73d223d3ad3988e8ae5 100644 (file)
@@ -2,13 +2,18 @@
 // some point regions-ret-borrowed reported an error but this file did
 // not, due to special hardcoding around the anonymous region.
 
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 fn with<R, F>(f: F) -> R where F: for<'a> FnOnce(&'a isize) -> R {
     f(&3)
 }
 
 fn return_it<'a>() -> &'a isize {
     with(|o| o)
-        //~^ ERROR cannot infer
+    //[base]~^ ERROR cannot infer an appropriate lifetime due to conflicting requirements [E0495]
+    //[nll]~^^ ERROR lifetime may not live long enough
 }
 
 fn main() {
diff --git a/src/test/ui/regions/regions-ret-borrowed-1.stderr b/src/test/ui/regions/regions-ret-borrowed-1.stderr
deleted file mode 100644 (file)
index 86df7bf..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
-  --> $DIR/regions-ret-borrowed-1.rs:10:14
-   |
-LL |     with(|o| o)
-   |              ^
-   |
-note: first, the lifetime cannot outlive the anonymous lifetime #1 defined here...
-  --> $DIR/regions-ret-borrowed-1.rs:10:10
-   |
-LL |     with(|o| o)
-   |          ^^^^^
-note: ...so that the types are compatible
-  --> $DIR/regions-ret-borrowed-1.rs:10:14
-   |
-LL |     with(|o| o)
-   |              ^
-   = note: expected `&isize`
-              found `&isize`
-note: but, the lifetime must be valid for the lifetime `'a` as defined here...
-  --> $DIR/regions-ret-borrowed-1.rs:9:14
-   |
-LL | fn return_it<'a>() -> &'a isize {
-   |              ^^
-note: ...so that reference does not outlive borrowed content
-  --> $DIR/regions-ret-borrowed-1.rs:10:5
-   |
-LL |     with(|o| o)
-   |     ^^^^^^^^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0495`.
diff --git a/src/test/ui/regions/regions-ret-borrowed.base.stderr b/src/test/ui/regions/regions-ret-borrowed.base.stderr
new file mode 100644 (file)
index 0000000..62b42b5
--- /dev/null
@@ -0,0 +1,32 @@
+error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
+  --> $DIR/regions-ret-borrowed.rs:17:14
+   |
+LL |     with(|o| o)
+   |              ^
+   |
+note: first, the lifetime cannot outlive the anonymous lifetime #1 defined here...
+  --> $DIR/regions-ret-borrowed.rs:17:10
+   |
+LL |     with(|o| o)
+   |          ^^^^^
+note: ...so that the types are compatible
+  --> $DIR/regions-ret-borrowed.rs:17:14
+   |
+LL |     with(|o| o)
+   |              ^
+   = note: expected `&isize`
+              found `&isize`
+note: but, the lifetime must be valid for the lifetime `'a` as defined here...
+  --> $DIR/regions-ret-borrowed.rs:16:14
+   |
+LL | fn return_it<'a>() -> &'a isize {
+   |              ^^
+note: ...so that reference does not outlive borrowed content
+  --> $DIR/regions-ret-borrowed.rs:17:5
+   |
+LL |     with(|o| o)
+   |     ^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0495`.
index d9be5ef89ccebd23da3af441abd270ce2a1b209a..d3ea5bd875f9b32bb0d9f3b0b83fdb0f36c83725 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/regions-ret-borrowed.rs:13:14
+  --> $DIR/regions-ret-borrowed.rs:17:14
    |
 LL |     with(|o| o)
    |           -- ^ returning this value requires that `'1` must outlive `'2`
index 5fca92d68b65caa958c1f604a3e57da0904bb9ca..2b6855d1c71ef0872fe580530efb0af281c49ad9 100644 (file)
@@ -5,13 +5,18 @@
 // used to successfully compile because we failed to account for the
 // fact that fn(x: &isize) rebound the region &.
 
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 fn with<R, F>(f: F) -> R where F: FnOnce(&isize) -> R {
     f(&3)
 }
 
 fn return_it<'a>() -> &'a isize {
     with(|o| o)
-        //~^ ERROR cannot infer
+    //[base]~^ ERROR cannot infer an appropriate lifetime due to conflicting requirements [E0495]
+    //[nll]~^^ ERROR lifetime may not live long enough
 }
 
 fn main() {
diff --git a/src/test/ui/regions/regions-ret-borrowed.stderr b/src/test/ui/regions/regions-ret-borrowed.stderr
deleted file mode 100644 (file)
index b9a06d9..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
-  --> $DIR/regions-ret-borrowed.rs:13:14
-   |
-LL |     with(|o| o)
-   |              ^
-   |
-note: first, the lifetime cannot outlive the anonymous lifetime #1 defined here...
-  --> $DIR/regions-ret-borrowed.rs:13:10
-   |
-LL |     with(|o| o)
-   |          ^^^^^
-note: ...so that the types are compatible
-  --> $DIR/regions-ret-borrowed.rs:13:14
-   |
-LL |     with(|o| o)
-   |              ^
-   = note: expected `&isize`
-              found `&isize`
-note: but, the lifetime must be valid for the lifetime `'a` as defined here...
-  --> $DIR/regions-ret-borrowed.rs:12:14
-   |
-LL | fn return_it<'a>() -> &'a isize {
-   |              ^^
-note: ...so that reference does not outlive borrowed content
-  --> $DIR/regions-ret-borrowed.rs:13:5
-   |
-LL |     with(|o| o)
-   |     ^^^^^^^^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0495`.
index c91c6f874931b8ddfc5d560a0dc6c5a36098d82f..25232b455b687329e69a19a16f5cbd0692ff9be3 100644 (file)
@@ -1,10 +1,17 @@
 // run-pass
+
 fn invariant_id<'a,'b>(t: &'b mut &'static ()) -> &'b mut &'a ()
     where 'a: 'static { t }
+//~^ WARN unnecessary lifetime parameter `'a`
+
 fn static_id<'a>(t: &'a ()) -> &'static ()
     where 'a: 'static { t }
+//~^ WARN unnecessary lifetime parameter `'a`
+
 fn static_id_indirect<'a,'b>(t: &'a ()) -> &'static ()
     where 'a: 'b, 'b: 'static { t }
+//~^ WARN unnecessary lifetime parameter `'b`
+
 fn ref_id<'a>(t: &'a ()) -> &'a () where 'static: 'a { t }
 
 static UNIT: () = ();
diff --git a/src/test/ui/regions/regions-static-bound-rpass.stderr b/src/test/ui/regions/regions-static-bound-rpass.stderr
new file mode 100644 (file)
index 0000000..9355a40
--- /dev/null
@@ -0,0 +1,26 @@
+warning: unnecessary lifetime parameter `'a`
+  --> $DIR/regions-static-bound-rpass.rs:4:11
+   |
+LL |     where 'a: 'static { t }
+   |           ^^
+   |
+   = help: you can use the `'static` lifetime directly, in place of `'a`
+
+warning: unnecessary lifetime parameter `'a`
+  --> $DIR/regions-static-bound-rpass.rs:8:11
+   |
+LL |     where 'a: 'static { t }
+   |           ^^
+   |
+   = help: you can use the `'static` lifetime directly, in place of `'a`
+
+warning: unnecessary lifetime parameter `'b`
+  --> $DIR/regions-static-bound-rpass.rs:12:19
+   |
+LL |     where 'a: 'b, 'b: 'static { t }
+   |                   ^^
+   |
+   = help: you can use the `'static` lifetime directly, in place of `'b`
+
+warning: 3 warnings emitted
+
diff --git a/src/test/ui/regions/regions-static-bound.base.stderr b/src/test/ui/regions/regions-static-bound.base.stderr
new file mode 100644 (file)
index 0000000..6b81204
--- /dev/null
@@ -0,0 +1,62 @@
+warning: unnecessary lifetime parameter `'a`
+  --> $DIR/regions-static-bound.rs:6:11
+   |
+LL |     where 'a: 'static { t }
+   |           ^^
+   |
+   = help: you can use the `'static` lifetime directly, in place of `'a`
+
+warning: unnecessary lifetime parameter `'b`
+  --> $DIR/regions-static-bound.rs:10:19
+   |
+LL |     where 'a: 'b, 'b: 'static { t }
+   |                   ^^
+   |
+   = help: you can use the `'static` lifetime directly, in place of `'b`
+
+error[E0312]: lifetime of reference outlives lifetime of borrowed content...
+  --> $DIR/regions-static-bound.rs:14:5
+   |
+LL |     t
+   |     ^
+   |
+   = note: ...the reference is valid for the static lifetime...
+note: ...but the borrowed content is only valid for the lifetime `'a` as defined here
+  --> $DIR/regions-static-bound.rs:13:24
+   |
+LL | fn static_id_wrong_way<'a>(t: &'a ()) -> &'static () where 'static: 'a {
+   |                        ^^
+
+error[E0759]: `u` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
+  --> $DIR/regions-static-bound.rs:20:5
+   |
+LL | fn error(u: &(), v: &()) {
+   |             --- this data with an anonymous lifetime `'_`...
+LL |     static_id(&u);
+   |     ^^^^^^^^^ -- ...is used here...
+   |
+note: ...and is required to live as long as `'static` here
+  --> $DIR/regions-static-bound.rs:20:5
+   |
+LL |     static_id(&u);
+   |     ^^^^^^^^^
+
+error[E0759]: `v` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
+  --> $DIR/regions-static-bound.rs:23:5
+   |
+LL | fn error(u: &(), v: &()) {
+   |                     --- this data with an anonymous lifetime `'_`...
+...
+LL |     static_id_indirect(&v);
+   |     ^^^^^^^^^^^^^^^^^^ -- ...is used here...
+   |
+note: ...and is required to live as long as `'static` here
+  --> $DIR/regions-static-bound.rs:23:5
+   |
+LL |     static_id_indirect(&v);
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors; 2 warnings emitted
+
+Some errors have detailed explanations: E0312, E0759.
+For more information about an error, try `rustc --explain E0312`.
index 699638c7ef9b23142eb303efdc02d3a00d14cf58..68e36f3aeea8f514fe2513f9d5de1126fac48e24 100644 (file)
@@ -1,5 +1,21 @@
+warning: unnecessary lifetime parameter `'a`
+  --> $DIR/regions-static-bound.rs:6:11
+   |
+LL |     where 'a: 'static { t }
+   |           ^^
+   |
+   = help: you can use the `'static` lifetime directly, in place of `'a`
+
+warning: unnecessary lifetime parameter `'b`
+  --> $DIR/regions-static-bound.rs:10:19
+   |
+LL |     where 'a: 'b, 'b: 'static { t }
+   |                   ^^
+   |
+   = help: you can use the `'static` lifetime directly, in place of `'b`
+
 error: lifetime may not live long enough
-  --> $DIR/regions-static-bound.rs:6:5
+  --> $DIR/regions-static-bound.rs:14:5
    |
 LL | fn static_id_wrong_way<'a>(t: &'a ()) -> &'static () where 'static: 'a {
    |                        -- lifetime `'a` defined here
@@ -7,7 +23,7 @@ LL |     t
    |     ^ returning this value requires that `'a` must outlive `'static`
 
 error[E0521]: borrowed data escapes outside of function
-  --> $DIR/regions-static-bound.rs:10:5
+  --> $DIR/regions-static-bound.rs:20:5
    |
 LL | fn error(u: &(), v: &()) {
    |          -  - let's call the lifetime of this reference `'1`
@@ -20,19 +36,19 @@ LL |     static_id(&u);
    |     argument requires that `'1` must outlive `'static`
 
 error[E0521]: borrowed data escapes outside of function
-  --> $DIR/regions-static-bound.rs:11:5
+  --> $DIR/regions-static-bound.rs:23:5
    |
 LL | fn error(u: &(), v: &()) {
    |                  -  - let's call the lifetime of this reference `'2`
    |                  |
    |                  `v` is a reference that is only valid in the function body
-LL |     static_id(&u);
+...
 LL |     static_id_indirect(&v);
    |     ^^^^^^^^^^^^^^^^^^^^^^
    |     |
    |     `v` escapes the function body here
    |     argument requires that `'2` must outlive `'static`
 
-error: aborting due to 3 previous errors
+error: aborting due to 3 previous errors; 2 warnings emitted
 
 For more information about this error, try `rustc --explain E0521`.
index a977a8b36d0563babb348b4eb1b7af78a5cd0f29..1eed7e71745d8f3877c6ba8e7f1b7a415d235274 100644 (file)
@@ -1,14 +1,28 @@
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 fn static_id<'a,'b>(t: &'a ()) -> &'static ()
     where 'a: 'static { t }
+//~^ WARN unnecessary lifetime parameter `'a`
+
 fn static_id_indirect<'a,'b>(t: &'a ()) -> &'static ()
     where 'a: 'b, 'b: 'static { t }
+//~^ WARN unnecessary lifetime parameter `'b`
+
 fn static_id_wrong_way<'a>(t: &'a ()) -> &'static () where 'static: 'a {
-    t //~ ERROR E0312
+    t
+    //[base]~^ ERROR E0312
+    //[nll]~^^ ERROR lifetime may not live long enough
 }
 
 fn error(u: &(), v: &()) {
-    static_id(&u); //~ ERROR `u` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement [E0759]
-    static_id_indirect(&v); //~ ERROR `v` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement [E0759]
+    static_id(&u);
+    //[base]~^ ERROR `u` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement [E0759]
+    //[nll]~^^ ERROR borrowed data escapes outside of function [E0521]
+    static_id_indirect(&v);
+    //[base]~^ ERROR `v` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement [E0759]
+    //[nll]~^^ ERROR borrowed data escapes outside of function [E0521]
 }
 
 fn main() {}
diff --git a/src/test/ui/regions/regions-static-bound.stderr b/src/test/ui/regions/regions-static-bound.stderr
deleted file mode 100644 (file)
index b8e69e0..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-error[E0312]: lifetime of reference outlives lifetime of borrowed content...
-  --> $DIR/regions-static-bound.rs:6:5
-   |
-LL |     t
-   |     ^
-   |
-   = note: ...the reference is valid for the static lifetime...
-note: ...but the borrowed content is only valid for the lifetime `'a` as defined here
-  --> $DIR/regions-static-bound.rs:5:24
-   |
-LL | fn static_id_wrong_way<'a>(t: &'a ()) -> &'static () where 'static: 'a {
-   |                        ^^
-
-error[E0759]: `u` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
-  --> $DIR/regions-static-bound.rs:10:5
-   |
-LL | fn error(u: &(), v: &()) {
-   |             --- this data with an anonymous lifetime `'_`...
-LL |     static_id(&u);
-   |     ^^^^^^^^^ -- ...is used here...
-   |
-note: ...and is required to live as long as `'static` here
-  --> $DIR/regions-static-bound.rs:10:5
-   |
-LL |     static_id(&u);
-   |     ^^^^^^^^^
-
-error[E0759]: `v` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
-  --> $DIR/regions-static-bound.rs:11:5
-   |
-LL | fn error(u: &(), v: &()) {
-   |                     --- this data with an anonymous lifetime `'_`...
-LL |     static_id(&u);
-LL |     static_id_indirect(&v);
-   |     ^^^^^^^^^^^^^^^^^^ -- ...is used here...
-   |
-note: ...and is required to live as long as `'static` here
-  --> $DIR/regions-static-bound.rs:11:5
-   |
-LL |     static_id_indirect(&v);
-   |     ^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 3 previous errors
-
-Some errors have detailed explanations: E0312, E0759.
-For more information about an error, try `rustc --explain E0312`.
diff --git a/src/test/ui/regions/regions-trait-object-subtyping.base.stderr b/src/test/ui/regions/regions-trait-object-subtyping.base.stderr
new file mode 100644 (file)
index 0000000..9f52136
--- /dev/null
@@ -0,0 +1,69 @@
+error[E0478]: lifetime bound not satisfied
+  --> $DIR/regions-trait-object-subtyping.rs:19:5
+   |
+LL |     x
+   |     ^
+   |
+note: lifetime parameter instantiated with the lifetime `'a` as defined here
+  --> $DIR/regions-trait-object-subtyping.rs:17:9
+   |
+LL | fn foo3<'a,'b>(x: &'a mut dyn Dummy) -> &'b mut dyn Dummy {
+   |         ^^
+note: but lifetime parameter must outlive the lifetime `'b` as defined here
+  --> $DIR/regions-trait-object-subtyping.rs:17:12
+   |
+LL | fn foo3<'a,'b>(x: &'a mut dyn Dummy) -> &'b mut dyn Dummy {
+   |            ^^
+
+error[E0495]: cannot infer an appropriate lifetime for automatic coercion due to conflicting requirements
+  --> $DIR/regions-trait-object-subtyping.rs:19:5
+   |
+LL |     x
+   |     ^
+   |
+note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
+  --> $DIR/regions-trait-object-subtyping.rs:17:9
+   |
+LL | fn foo3<'a,'b>(x: &'a mut dyn Dummy) -> &'b mut dyn Dummy {
+   |         ^^
+note: ...so that reference does not outlive borrowed content
+  --> $DIR/regions-trait-object-subtyping.rs:19:5
+   |
+LL |     x
+   |     ^
+note: but, the lifetime must be valid for the lifetime `'b` as defined here...
+  --> $DIR/regions-trait-object-subtyping.rs:17:12
+   |
+LL | fn foo3<'a,'b>(x: &'a mut dyn Dummy) -> &'b mut dyn Dummy {
+   |            ^^
+note: ...so that the types are compatible
+  --> $DIR/regions-trait-object-subtyping.rs:19:5
+   |
+LL |     x
+   |     ^
+   = note: expected `&'b mut (dyn Dummy + 'b)`
+              found `&mut (dyn Dummy + 'b)`
+
+error[E0308]: mismatched types
+  --> $DIR/regions-trait-object-subtyping.rs:28:5
+   |
+LL |     x
+   |     ^ lifetime mismatch
+   |
+   = note: expected struct `Wrapper<&'b mut (dyn Dummy + 'b)>`
+              found struct `Wrapper<&'a mut (dyn Dummy + 'a)>`
+note: the lifetime `'b` as defined here...
+  --> $DIR/regions-trait-object-subtyping.rs:26:15
+   |
+LL | fn foo4<'a:'b,'b>(x: Wrapper<&'a mut dyn Dummy>) -> Wrapper<&'b mut dyn Dummy> {
+   |               ^^
+note: ...does not necessarily outlive the lifetime `'a` as defined here
+  --> $DIR/regions-trait-object-subtyping.rs:26:9
+   |
+LL | fn foo4<'a:'b,'b>(x: Wrapper<&'a mut dyn Dummy>) -> Wrapper<&'b mut dyn Dummy> {
+   |         ^^
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0308, E0478, E0495.
+For more information about an error, try `rustc --explain E0308`.
index 1b3a116d508fad8334ed83b32ed726e2ea61160f..c8cec3bd37797a0f51501b5038c8c56b1b597a75 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/regions-trait-object-subtyping.rs:15:5
+  --> $DIR/regions-trait-object-subtyping.rs:19:5
    |
 LL | fn foo3<'a,'b>(x: &'a mut dyn Dummy) -> &'b mut dyn Dummy {
    |         -- -- lifetime `'b` defined here
@@ -15,7 +15,7 @@ LL |     x
    = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: lifetime may not live long enough
-  --> $DIR/regions-trait-object-subtyping.rs:22:5
+  --> $DIR/regions-trait-object-subtyping.rs:28:5
    |
 LL | fn foo4<'a:'b,'b>(x: Wrapper<&'a mut dyn Dummy>) -> Wrapper<&'b mut dyn Dummy> {
    |         --    -- lifetime `'b` defined here
index 5b36194870ef697c9955082957f3520359331efc..f108fc81cea4fed2a6aad99f024f557f1a8169a4 100644 (file)
@@ -1,3 +1,7 @@
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 trait Dummy { fn dummy(&self); }
 
 fn foo1<'a:'b,'b>(x: &'a mut (dyn Dummy+'a)) -> &'b mut (dyn Dummy+'b) {
@@ -12,14 +16,18 @@ fn foo2<'a:'b,'b>(x: &'b mut (dyn Dummy+'a)) -> &'b mut (dyn Dummy+'b) {
 
 fn foo3<'a,'b>(x: &'a mut dyn Dummy) -> &'b mut dyn Dummy {
     // Without knowing 'a:'b, we can't coerce
-    x //~ ERROR lifetime bound not satisfied
-     //~^ ERROR cannot infer an appropriate lifetime
+    x
+    //[base]~^ ERROR lifetime bound not satisfied
+    //[base]~| ERROR cannot infer an appropriate lifetime
+    //[nll]~^^^ ERROR lifetime may not live long enough
 }
 
 struct Wrapper<T>(T);
 fn foo4<'a:'b,'b>(x: Wrapper<&'a mut dyn Dummy>) -> Wrapper<&'b mut dyn Dummy> {
     // We can't coerce because it is packed in `Wrapper`
-    x //~ ERROR mismatched types
+    x
+    //[base]~^ ERROR mismatched types
+    //[nll]~^^ ERROR lifetime may not live long enough
 }
 
 fn main() {}
diff --git a/src/test/ui/regions/regions-trait-object-subtyping.stderr b/src/test/ui/regions/regions-trait-object-subtyping.stderr
deleted file mode 100644 (file)
index d45ca94..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-error[E0478]: lifetime bound not satisfied
-  --> $DIR/regions-trait-object-subtyping.rs:15:5
-   |
-LL |     x
-   |     ^
-   |
-note: lifetime parameter instantiated with the lifetime `'a` as defined here
-  --> $DIR/regions-trait-object-subtyping.rs:13:9
-   |
-LL | fn foo3<'a,'b>(x: &'a mut dyn Dummy) -> &'b mut dyn Dummy {
-   |         ^^
-note: but lifetime parameter must outlive the lifetime `'b` as defined here
-  --> $DIR/regions-trait-object-subtyping.rs:13:12
-   |
-LL | fn foo3<'a,'b>(x: &'a mut dyn Dummy) -> &'b mut dyn Dummy {
-   |            ^^
-
-error[E0495]: cannot infer an appropriate lifetime for automatic coercion due to conflicting requirements
-  --> $DIR/regions-trait-object-subtyping.rs:15:5
-   |
-LL |     x
-   |     ^
-   |
-note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
-  --> $DIR/regions-trait-object-subtyping.rs:13:9
-   |
-LL | fn foo3<'a,'b>(x: &'a mut dyn Dummy) -> &'b mut dyn Dummy {
-   |         ^^
-note: ...so that reference does not outlive borrowed content
-  --> $DIR/regions-trait-object-subtyping.rs:15:5
-   |
-LL |     x
-   |     ^
-note: but, the lifetime must be valid for the lifetime `'b` as defined here...
-  --> $DIR/regions-trait-object-subtyping.rs:13:12
-   |
-LL | fn foo3<'a,'b>(x: &'a mut dyn Dummy) -> &'b mut dyn Dummy {
-   |            ^^
-note: ...so that the types are compatible
-  --> $DIR/regions-trait-object-subtyping.rs:15:5
-   |
-LL |     x
-   |     ^
-   = note: expected `&'b mut (dyn Dummy + 'b)`
-              found `&mut (dyn Dummy + 'b)`
-
-error[E0308]: mismatched types
-  --> $DIR/regions-trait-object-subtyping.rs:22:5
-   |
-LL |     x
-   |     ^ lifetime mismatch
-   |
-   = note: expected struct `Wrapper<&'b mut (dyn Dummy + 'b)>`
-              found struct `Wrapper<&'a mut (dyn Dummy + 'a)>`
-note: the lifetime `'b` as defined here...
-  --> $DIR/regions-trait-object-subtyping.rs:20:15
-   |
-LL | fn foo4<'a:'b,'b>(x: Wrapper<&'a mut dyn Dummy>) -> Wrapper<&'b mut dyn Dummy> {
-   |               ^^
-note: ...does not necessarily outlive the lifetime `'a` as defined here
-  --> $DIR/regions-trait-object-subtyping.rs:20:9
-   |
-LL | fn foo4<'a:'b,'b>(x: Wrapper<&'a mut dyn Dummy>) -> Wrapper<&'b mut dyn Dummy> {
-   |         ^^
-
-error: aborting due to 3 previous errors
-
-Some errors have detailed explanations: E0308, E0478, E0495.
-For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/regions/regions-variance-contravariant-use-covariant-in-second-position.base.stderr b/src/test/ui/regions/regions-variance-contravariant-use-covariant-in-second-position.base.stderr
new file mode 100644 (file)
index 0000000..23b3dea
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/regions-variance-contravariant-use-covariant-in-second-position.rs:29:30
+   |
+LL | fn use_<'short,'long>(c: S<'long, 'short>,
+   |                          ---------------- this type is declared with multiple lifetimes...
+...
+LL |     let _: S<'long, 'long> = c;
+   |                              ^ ...but data with one lifetime flows into the other here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0623`.
index 5352be430fbc57158a2daef5731049561ece29d1..f364f423f4ecf818ed194ad89cea39a440142e72 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/regions-variance-contravariant-use-covariant-in-second-position.rs:25:12
+  --> $DIR/regions-variance-contravariant-use-covariant-in-second-position.rs:29:12
    |
 LL | fn use_<'short,'long>(c: S<'long, 'short>,
    |         ------ ----- lifetime `'long` defined here
index 8ddd041d4573191e588842fb6e4494ec5456a355..4bf32ec308247a4a3e1eb379a963df323d1285e6 100644 (file)
@@ -4,6 +4,10 @@
 // Note: see variance-regions-*.rs for the tests that check that the
 // variance inference works in the first place.
 
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 // `S` is contravariant with respect to both parameters.
 struct S<'a, 'b> {
     f: &'a isize,
@@ -22,7 +26,9 @@ fn use_<'short,'long>(c: S<'long, 'short>,
     // 'short <= 'long, this would be true if the Contravariant type were
     // covariant with respect to its parameter 'a.
 
-    let _: S<'long, 'long> = c; //~ ERROR E0623
+    let _: S<'long, 'long> = c;
+    //[base]~^ ERROR E0623
+    //[nll]~^^ ERROR lifetime may not live long enough
 }
 
 fn main() {}
diff --git a/src/test/ui/regions/regions-variance-contravariant-use-covariant-in-second-position.stderr b/src/test/ui/regions/regions-variance-contravariant-use-covariant-in-second-position.stderr
deleted file mode 100644 (file)
index 98f7a81..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0623]: lifetime mismatch
-  --> $DIR/regions-variance-contravariant-use-covariant-in-second-position.rs:25:30
-   |
-LL | fn use_<'short,'long>(c: S<'long, 'short>,
-   |                          ---------------- this type is declared with multiple lifetimes...
-...
-LL |     let _: S<'long, 'long> = c;
-   |                              ^ ...but data with one lifetime flows into the other here
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0623`.
diff --git a/src/test/ui/regions/regions-variance-contravariant-use-covariant.base.stderr b/src/test/ui/regions/regions-variance-contravariant-use-covariant.base.stderr
new file mode 100644 (file)
index 0000000..8eca0d4
--- /dev/null
@@ -0,0 +1,15 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/regions-variance-contravariant-use-covariant.rs:27:35
+   |
+LL | fn use_<'short,'long>(c: Contravariant<'short>,
+   |                          --------------------- these two types are declared with different lifetimes...
+LL |                       s: &'short isize,
+LL |                       l: &'long isize,
+   |                          ------------
+...
+LL |     let _: Contravariant<'long> = c;
+   |                                   ^ ...but data from `c` flows into `l` here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0623`.
index 22c9b915bb9ee6574db1af52905795e9d2e0864b..bc6dd6e69ed08ffd1282ff8f8ebdfc571e6609b0 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/regions-variance-contravariant-use-covariant.rs:23:12
+  --> $DIR/regions-variance-contravariant-use-covariant.rs:27:12
    |
 LL | fn use_<'short,'long>(c: Contravariant<'short>,
    |         ------ ----- lifetime `'long` defined here
index cbdf62ecb613fee2a68ed1978f39a7a83b13040f..ea08a7092305ea6e35f44788e05504165df7f405 100644 (file)
@@ -4,6 +4,10 @@
 // Note: see variance-regions-*.rs for the tests that check that the
 // variance inference works in the first place.
 
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 // This is contravariant with respect to 'a, meaning that
 // Contravariant<'long> <: Contravariant<'short> iff
 // 'short <= 'long
@@ -20,7 +24,9 @@ fn use_<'short,'long>(c: Contravariant<'short>,
     // 'short <= 'long, this would be true if the Contravariant type were
     // covariant with respect to its parameter 'a.
 
-    let _: Contravariant<'long> = c; //~ ERROR E0623
+    let _: Contravariant<'long> = c;
+    //[base]~^ ERROR E0623
+    //[nll]~^^ ERROR lifetime may not live long enough
 }
 
 fn main() {}
diff --git a/src/test/ui/regions/regions-variance-contravariant-use-covariant.stderr b/src/test/ui/regions/regions-variance-contravariant-use-covariant.stderr
deleted file mode 100644 (file)
index e7c106c..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-error[E0623]: lifetime mismatch
-  --> $DIR/regions-variance-contravariant-use-covariant.rs:23:35
-   |
-LL | fn use_<'short,'long>(c: Contravariant<'short>,
-   |                          --------------------- these two types are declared with different lifetimes...
-LL |                       s: &'short isize,
-LL |                       l: &'long isize,
-   |                          ------------
-...
-LL |     let _: Contravariant<'long> = c;
-   |                                   ^ ...but data from `c` flows into `l` here
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0623`.
diff --git a/src/test/ui/regions/regions-variance-covariant-use-contravariant.base.stderr b/src/test/ui/regions/regions-variance-covariant-use-contravariant.base.stderr
new file mode 100644 (file)
index 0000000..565de38
--- /dev/null
@@ -0,0 +1,14 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/regions-variance-covariant-use-contravariant.rs:27:32
+   |
+LL | fn use_<'short,'long>(c: Covariant<'long>,
+   |                          ----------------
+LL |                       s: &'short isize,
+   |                          ------------- these two types are declared with different lifetimes...
+...
+LL |     let _: Covariant<'short> = c;
+   |                                ^ ...but data from `s` flows into `c` here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0623`.
index a07181ad553e6f4ccb3ca4804058691850573765..9d3cebc9a4d561df3f7dc832462a016855b42a92 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/regions-variance-covariant-use-contravariant.rs:23:12
+  --> $DIR/regions-variance-covariant-use-contravariant.rs:27:12
    |
 LL | fn use_<'short,'long>(c: Covariant<'long>,
    |         ------ ----- lifetime `'long` defined here
index 9aa0c819271970ec7c90caccbb12778ad99c4452..748ad84840a07a00ab2319b2eff00d3a0023703b 100644 (file)
@@ -4,6 +4,10 @@
 // Note: see variance-regions-*.rs for the tests that check that the
 // variance inference works in the first place.
 
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 // This is covariant with respect to 'a, meaning that
 // Covariant<'foo> <: Covariant<'static> because
 // 'foo <= 'static
@@ -20,7 +24,9 @@ fn use_<'short,'long>(c: Covariant<'long>,
     // 'short <= 'long, this would be true if the Covariant type were
     // contravariant with respect to its parameter 'a.
 
-    let _: Covariant<'short> = c; //~ ERROR E0623
+    let _: Covariant<'short> = c;
+    //[base]~^ ERROR E0623
+    //[nll]~^^ ERROR lifetime may not live long enough
 }
 
 fn main() {}
diff --git a/src/test/ui/regions/regions-variance-covariant-use-contravariant.stderr b/src/test/ui/regions/regions-variance-covariant-use-contravariant.stderr
deleted file mode 100644 (file)
index e5e5261..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-error[E0623]: lifetime mismatch
-  --> $DIR/regions-variance-covariant-use-contravariant.rs:23:32
-   |
-LL | fn use_<'short,'long>(c: Covariant<'long>,
-   |                          ----------------
-LL |                       s: &'short isize,
-   |                          ------------- these two types are declared with different lifetimes...
-...
-LL |     let _: Covariant<'short> = c;
-   |                                ^ ...but data from `s` flows into `c` here
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0623`.
diff --git a/src/test/ui/regions/regions-variance-invariant-use-contravariant.base.stderr b/src/test/ui/regions/regions-variance-invariant-use-contravariant.base.stderr
new file mode 100644 (file)
index 0000000..e2e8958
--- /dev/null
@@ -0,0 +1,14 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/regions-variance-invariant-use-contravariant.rs:24:32
+   |
+LL | fn use_<'short,'long>(c: Invariant<'long>,
+   |                          ----------------
+LL |                       s: &'short isize,
+   |                          ------------- these two types are declared with different lifetimes...
+...
+LL |     let _: Invariant<'short> = c;
+   |                                ^ ...but data from `s` flows into `c` here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0623`.
index b35a2cb905dc3c6ad5ef5e4a6a8c31f96101821f..b4ccb1693a7533c54bace8007ebdb5dd3d84b8e9 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/regions-variance-invariant-use-contravariant.rs:20:12
+  --> $DIR/regions-variance-invariant-use-contravariant.rs:24:12
    |
 LL | fn use_<'short,'long>(c: Invariant<'long>,
    |         ------ ----- lifetime `'long` defined here
index 663b23b37d46a856b67200da74d4ec005e3bac63..788f9b1b4d0f3a94ff0c904b1b5c09fb9ad43cae 100644 (file)
@@ -4,6 +4,10 @@
 // Note: see variance-regions-*.rs for the tests that check that the
 // variance inference works in the first place.
 
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 struct Invariant<'a> {
     f: &'a mut &'a isize
 }
@@ -17,7 +21,9 @@ fn use_<'short,'long>(c: Invariant<'long>,
     // 'short <= 'long, this would be true if the Invariant type were
     // contravariant with respect to its parameter 'a.
 
-    let _: Invariant<'short> = c; //~ ERROR E0623
+    let _: Invariant<'short> = c;
+    //[base]~^ ERROR E0623
+    //[nll]~^^ ERROR lifetime may not live long enough
 }
 
 fn main() { }
diff --git a/src/test/ui/regions/regions-variance-invariant-use-contravariant.stderr b/src/test/ui/regions/regions-variance-invariant-use-contravariant.stderr
deleted file mode 100644 (file)
index 2a2d5d0..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-error[E0623]: lifetime mismatch
-  --> $DIR/regions-variance-invariant-use-contravariant.rs:20:32
-   |
-LL | fn use_<'short,'long>(c: Invariant<'long>,
-   |                          ----------------
-LL |                       s: &'short isize,
-   |                          ------------- these two types are declared with different lifetimes...
-...
-LL |     let _: Invariant<'short> = c;
-   |                                ^ ...but data from `s` flows into `c` here
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0623`.
diff --git a/src/test/ui/regions/regions-variance-invariant-use-covariant.base.stderr b/src/test/ui/regions/regions-variance-invariant-use-covariant.base.stderr
new file mode 100644 (file)
index 0000000..da91db1
--- /dev/null
@@ -0,0 +1,18 @@
+error[E0308]: mismatched types
+  --> $DIR/regions-variance-invariant-use-covariant.rs:21:33
+   |
+LL |     let _: Invariant<'static> = c;
+   |                                 ^ lifetime mismatch
+   |
+   = note: expected struct `Invariant<'static>`
+              found struct `Invariant<'b>`
+note: the lifetime `'b` as defined here...
+  --> $DIR/regions-variance-invariant-use-covariant.rs:15:9
+   |
+LL | fn use_<'b>(c: Invariant<'b>) {
+   |         ^^
+   = note: ...does not necessarily outlive the static lifetime
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
index 761e78d179e414f3d17b59703fe26dbd0641269c..7b05c357589e91e1ae4ecaa32fb3f7d52eaadbdf 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/regions-variance-invariant-use-covariant.rs:17:12
+  --> $DIR/regions-variance-invariant-use-covariant.rs:21:12
    |
 LL | fn use_<'b>(c: Invariant<'b>) {
    |         -- lifetime `'b` defined here
index 07482e6fd19e11b62cd9d7878d0925990a8f82f7..4b7da4493acffe402b594c1c4315c004007d5f3b 100644 (file)
@@ -4,6 +4,10 @@
 // Note: see variance-regions-*.rs for the tests that check that the
 // variance inference works in the first place.
 
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 struct Invariant<'a> {
     f: &'a mut &'a isize
 }
@@ -14,7 +18,9 @@ fn use_<'b>(c: Invariant<'b>) {
     // Since 'b <= 'static, this would be true if Invariant were covariant
     // with respect to its parameter 'a.
 
-    let _: Invariant<'static> = c; //~ ERROR mismatched types
+    let _: Invariant<'static> = c;
+    //[base]~^ ERROR mismatched types [E0308]
+    //[nll]~^^ ERROR lifetime may not live long enough
 }
 
 fn main() { }
diff --git a/src/test/ui/regions/regions-variance-invariant-use-covariant.stderr b/src/test/ui/regions/regions-variance-invariant-use-covariant.stderr
deleted file mode 100644 (file)
index 7801517..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-error[E0308]: mismatched types
-  --> $DIR/regions-variance-invariant-use-covariant.rs:17:33
-   |
-LL |     let _: Invariant<'static> = c;
-   |                                 ^ lifetime mismatch
-   |
-   = note: expected struct `Invariant<'static>`
-              found struct `Invariant<'b>`
-note: the lifetime `'b` as defined here...
-  --> $DIR/regions-variance-invariant-use-covariant.rs:11:9
-   |
-LL | fn use_<'b>(c: Invariant<'b>) {
-   |         ^^
-   = note: ...does not necessarily outlive the static lifetime
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/repeat-expr-in-static.rs b/src/test/ui/repeat-expr-in-static.rs
deleted file mode 100644 (file)
index 0b89537..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-// run-pass
-
-static FOO: [isize; 4] = [32; 4];
-static BAR: [isize; 4] = [32, 32, 32, 32];
-
-pub fn main() {
-    assert_eq!(FOO, BAR);
-}
diff --git a/src/test/ui/repeat-expr/infer.rs b/src/test/ui/repeat-expr/infer.rs
new file mode 100644 (file)
index 0000000..8197713
--- /dev/null
@@ -0,0 +1,16 @@
+// check-pass
+
+#[derive(Clone, Default)]
+struct MaybeCopy<T>(T);
+
+impl Copy for MaybeCopy<u8> {}
+
+fn is_copy<T: Copy>(x: T) {
+    println!("{}", std::any::type_name::<T>());
+}
+
+fn main() {
+    is_copy(MaybeCopy::default());
+    [MaybeCopy::default(); 13];
+    // didn't work, because `Copy` was only checked in the mir
+}
diff --git a/src/test/ui/repeat-expr/repeat-expr-in-static.rs b/src/test/ui/repeat-expr/repeat-expr-in-static.rs
new file mode 100644 (file)
index 0000000..0b89537
--- /dev/null
@@ -0,0 +1,8 @@
+// run-pass
+
+static FOO: [isize; 4] = [32; 4];
+static BAR: [isize; 4] = [32, 32, 32, 32];
+
+pub fn main() {
+    assert_eq!(FOO, BAR);
+}
diff --git a/src/test/ui/repeat-expr/repeat-to-run-dtor-twice.rs b/src/test/ui/repeat-expr/repeat-to-run-dtor-twice.rs
new file mode 100644 (file)
index 0000000..0cd8ece
--- /dev/null
@@ -0,0 +1,19 @@
+// Tests that one can't run a destructor twice with the repeated vector
+// literal syntax.
+
+struct Foo {
+    x: isize,
+
+}
+
+impl Drop for Foo {
+    fn drop(&mut self) {
+        println!("Goodbye!");
+    }
+}
+
+fn main() {
+    let a = Foo { x: 3 };
+    let _ = [ a; 5 ];
+    //~^ ERROR the trait bound `Foo: Copy` is not satisfied [E0277]
+}
diff --git a/src/test/ui/repeat-expr/repeat-to-run-dtor-twice.stderr b/src/test/ui/repeat-expr/repeat-to-run-dtor-twice.stderr
new file mode 100644 (file)
index 0000000..36b9361
--- /dev/null
@@ -0,0 +1,15 @@
+error[E0277]: the trait bound `Foo: Copy` is not satisfied
+  --> $DIR/repeat-to-run-dtor-twice.rs:17:15
+   |
+LL |     let _ = [ a; 5 ];
+   |               ^ the trait `Copy` is not implemented for `Foo`
+   |
+   = note: the `Copy` trait is required because this value will be copied for each element of the array
+help: consider annotating `Foo` with `#[derive(Copy)]`
+   |
+LL | #[derive(Copy)]
+   |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/repeat-expr/repeat_count.rs b/src/test/ui/repeat-expr/repeat_count.rs
new file mode 100644 (file)
index 0000000..96abff4
--- /dev/null
@@ -0,0 +1,34 @@
+// Regression test for issue #3645
+
+fn main() {
+    let n = 1;
+    let a = [0; n];
+    //~^ ERROR attempt to use a non-constant value in a constant [E0435]
+    let b = [0; ()];
+    //~^ ERROR mismatched types
+    //~| expected `usize`, found `()`
+    let c = [0; true];
+    //~^ ERROR mismatched types
+    //~| expected `usize`, found `bool`
+    let d = [0; 0.5];
+    //~^ ERROR mismatched types
+    //~| expected `usize`, found floating-point number
+    let e = [0; "foo"];
+    //~^ ERROR mismatched types
+    //~| expected `usize`, found `&str`
+    let f = [0; -4_isize];
+    //~^ ERROR mismatched types
+    //~| expected `usize`, found `isize`
+    let f = [0_usize; -1_isize];
+    //~^ ERROR mismatched types
+    //~| expected `usize`, found `isize`
+    let f = [0; 4u8];
+    //~^ ERROR mismatched types
+    //~| expected `usize`, found `u8`
+    struct G {
+        g: (),
+    }
+    let g = [0; G { g: () }];
+    //~^ ERROR mismatched types
+    //~| expected `usize`, found struct `G`
+}
diff --git a/src/test/ui/repeat-expr/repeat_count.stderr b/src/test/ui/repeat-expr/repeat_count.stderr
new file mode 100644 (file)
index 0000000..59bcd95
--- /dev/null
@@ -0,0 +1,69 @@
+error[E0435]: attempt to use a non-constant value in a constant
+  --> $DIR/repeat_count.rs:5:17
+   |
+LL |     let n = 1;
+   |     ----- help: consider using `const` instead of `let`: `const n`
+LL |     let a = [0; n];
+   |                 ^ non-constant value
+
+error[E0308]: mismatched types
+  --> $DIR/repeat_count.rs:7:17
+   |
+LL |     let b = [0; ()];
+   |                 ^^ expected `usize`, found `()`
+
+error[E0308]: mismatched types
+  --> $DIR/repeat_count.rs:10:17
+   |
+LL |     let c = [0; true];
+   |                 ^^^^ expected `usize`, found `bool`
+
+error[E0308]: mismatched types
+  --> $DIR/repeat_count.rs:13:17
+   |
+LL |     let d = [0; 0.5];
+   |                 ^^^ expected `usize`, found floating-point number
+
+error[E0308]: mismatched types
+  --> $DIR/repeat_count.rs:16:17
+   |
+LL |     let e = [0; "foo"];
+   |                 ^^^^^ expected `usize`, found `&str`
+
+error[E0308]: mismatched types
+  --> $DIR/repeat_count.rs:19:17
+   |
+LL |     let f = [0; -4_isize];
+   |                 ^^^^^^^^ expected `usize`, found `isize`
+   |
+   = note: `-4_isize` cannot fit into type `usize`
+
+error[E0308]: mismatched types
+  --> $DIR/repeat_count.rs:22:23
+   |
+LL |     let f = [0_usize; -1_isize];
+   |                       ^^^^^^^^ expected `usize`, found `isize`
+   |
+   = note: `-1_isize` cannot fit into type `usize`
+
+error[E0308]: mismatched types
+  --> $DIR/repeat_count.rs:25:17
+   |
+LL |     let f = [0; 4u8];
+   |                 ^^^ expected `usize`, found `u8`
+   |
+help: change the type of the numeric literal from `u8` to `usize`
+   |
+LL |     let f = [0; 4usize];
+   |                  ~~~~~
+
+error[E0308]: mismatched types
+  --> $DIR/repeat_count.rs:31:17
+   |
+LL |     let g = [0; G { g: () }];
+   |                 ^^^^^^^^^^^ expected `usize`, found struct `G`
+
+error: aborting due to 9 previous errors
+
+Some errors have detailed explanations: E0308, E0435.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/repeat-to-run-dtor-twice.rs b/src/test/ui/repeat-to-run-dtor-twice.rs
deleted file mode 100644 (file)
index 0cd8ece..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-// Tests that one can't run a destructor twice with the repeated vector
-// literal syntax.
-
-struct Foo {
-    x: isize,
-
-}
-
-impl Drop for Foo {
-    fn drop(&mut self) {
-        println!("Goodbye!");
-    }
-}
-
-fn main() {
-    let a = Foo { x: 3 };
-    let _ = [ a; 5 ];
-    //~^ ERROR the trait bound `Foo: Copy` is not satisfied [E0277]
-}
diff --git a/src/test/ui/repeat-to-run-dtor-twice.stderr b/src/test/ui/repeat-to-run-dtor-twice.stderr
deleted file mode 100644 (file)
index 9044137..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-error[E0277]: the trait bound `Foo: Copy` is not satisfied
-  --> $DIR/repeat-to-run-dtor-twice.rs:17:13
-   |
-LL |     let _ = [ a; 5 ];
-   |             ^^^^^^^^ the trait `Copy` is not implemented for `Foo`
-   |
-   = note: the `Copy` trait is required because the repeated element will be copied
-help: consider annotating `Foo` with `#[derive(Copy)]`
-   |
-LL | #[derive(Copy)]
-   |
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/repeat_count.rs b/src/test/ui/repeat_count.rs
deleted file mode 100644 (file)
index 96abff4..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-// Regression test for issue #3645
-
-fn main() {
-    let n = 1;
-    let a = [0; n];
-    //~^ ERROR attempt to use a non-constant value in a constant [E0435]
-    let b = [0; ()];
-    //~^ ERROR mismatched types
-    //~| expected `usize`, found `()`
-    let c = [0; true];
-    //~^ ERROR mismatched types
-    //~| expected `usize`, found `bool`
-    let d = [0; 0.5];
-    //~^ ERROR mismatched types
-    //~| expected `usize`, found floating-point number
-    let e = [0; "foo"];
-    //~^ ERROR mismatched types
-    //~| expected `usize`, found `&str`
-    let f = [0; -4_isize];
-    //~^ ERROR mismatched types
-    //~| expected `usize`, found `isize`
-    let f = [0_usize; -1_isize];
-    //~^ ERROR mismatched types
-    //~| expected `usize`, found `isize`
-    let f = [0; 4u8];
-    //~^ ERROR mismatched types
-    //~| expected `usize`, found `u8`
-    struct G {
-        g: (),
-    }
-    let g = [0; G { g: () }];
-    //~^ ERROR mismatched types
-    //~| expected `usize`, found struct `G`
-}
diff --git a/src/test/ui/repeat_count.stderr b/src/test/ui/repeat_count.stderr
deleted file mode 100644 (file)
index 59bcd95..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-error[E0435]: attempt to use a non-constant value in a constant
-  --> $DIR/repeat_count.rs:5:17
-   |
-LL |     let n = 1;
-   |     ----- help: consider using `const` instead of `let`: `const n`
-LL |     let a = [0; n];
-   |                 ^ non-constant value
-
-error[E0308]: mismatched types
-  --> $DIR/repeat_count.rs:7:17
-   |
-LL |     let b = [0; ()];
-   |                 ^^ expected `usize`, found `()`
-
-error[E0308]: mismatched types
-  --> $DIR/repeat_count.rs:10:17
-   |
-LL |     let c = [0; true];
-   |                 ^^^^ expected `usize`, found `bool`
-
-error[E0308]: mismatched types
-  --> $DIR/repeat_count.rs:13:17
-   |
-LL |     let d = [0; 0.5];
-   |                 ^^^ expected `usize`, found floating-point number
-
-error[E0308]: mismatched types
-  --> $DIR/repeat_count.rs:16:17
-   |
-LL |     let e = [0; "foo"];
-   |                 ^^^^^ expected `usize`, found `&str`
-
-error[E0308]: mismatched types
-  --> $DIR/repeat_count.rs:19:17
-   |
-LL |     let f = [0; -4_isize];
-   |                 ^^^^^^^^ expected `usize`, found `isize`
-   |
-   = note: `-4_isize` cannot fit into type `usize`
-
-error[E0308]: mismatched types
-  --> $DIR/repeat_count.rs:22:23
-   |
-LL |     let f = [0_usize; -1_isize];
-   |                       ^^^^^^^^ expected `usize`, found `isize`
-   |
-   = note: `-1_isize` cannot fit into type `usize`
-
-error[E0308]: mismatched types
-  --> $DIR/repeat_count.rs:25:17
-   |
-LL |     let f = [0; 4u8];
-   |                 ^^^ expected `usize`, found `u8`
-   |
-help: change the type of the numeric literal from `u8` to `usize`
-   |
-LL |     let f = [0; 4usize];
-   |                  ~~~~~
-
-error[E0308]: mismatched types
-  --> $DIR/repeat_count.rs:31:17
-   |
-LL |     let g = [0; G { g: () }];
-   |                 ^^^^^^^^^^^ expected `usize`, found struct `G`
-
-error: aborting due to 9 previous errors
-
-Some errors have detailed explanations: E0308, E0435.
-For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/resolve/issue-26545.rs b/src/test/ui/resolve/issue-26545.rs
new file mode 100644 (file)
index 0000000..5652ee7
--- /dev/null
@@ -0,0 +1,12 @@
+mod foo {
+    pub struct B(pub ());
+}
+
+mod baz {
+    fn foo() {
+        B(());
+        //~^ ERROR cannot find function, tuple struct or tuple variant `B` in this scope [E0425]
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/resolve/issue-26545.stderr b/src/test/ui/resolve/issue-26545.stderr
new file mode 100644 (file)
index 0000000..d3c8669
--- /dev/null
@@ -0,0 +1,14 @@
+error[E0425]: cannot find function, tuple struct or tuple variant `B` in this scope
+  --> $DIR/issue-26545.rs:7:9
+   |
+LL |         B(());
+   |         ^ not found in this scope
+   |
+help: consider importing this tuple struct
+   |
+LL |     use foo::B;
+   |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0425`.
diff --git a/src/test/ui/resolve/issue-73427.rs b/src/test/ui/resolve/issue-73427.rs
new file mode 100644 (file)
index 0000000..3c62782
--- /dev/null
@@ -0,0 +1,44 @@
+enum A {
+    StructWithFields { x: () },
+    TupleWithFields(()),
+    Struct {},
+    Tuple(),
+    Unit,
+}
+
+enum B {
+    StructWithFields { x: () },
+    TupleWithFields(()),
+}
+
+enum C {
+    StructWithFields { x: () },
+    TupleWithFields(()),
+    Unit,
+}
+
+enum D {
+    TupleWithFields(()),
+    Unit,
+}
+
+fn main() {
+    // Only variants without fields are suggested (and others mentioned in a note) where an enum
+    // is used rather than a variant.
+
+    A.foo();
+    //~^ ERROR expected value, found enum `A`
+    B.foo();
+    //~^ ERROR expected value, found enum `B`
+    C.foo();
+    //~^ ERROR expected value, found enum `C`
+    D.foo();
+    //~^ ERROR expected value, found enum `D`
+
+    // Only tuple variants are suggested in calls or tuple struct pattern matching.
+
+    let x = A(3);
+    //~^ ERROR expected function, tuple struct or tuple variant, found enum `A`
+    if let A(3) = x { }
+    //~^ ERROR expected tuple struct or tuple variant, found enum `A`
+}
diff --git a/src/test/ui/resolve/issue-73427.stderr b/src/test/ui/resolve/issue-73427.stderr
new file mode 100644 (file)
index 0000000..59bb98a
--- /dev/null
@@ -0,0 +1,156 @@
+error[E0423]: expected value, found enum `A`
+  --> $DIR/issue-73427.rs:29:5
+   |
+LL |     A.foo();
+   |     ^
+   |
+note: the enum is defined here
+  --> $DIR/issue-73427.rs:1:1
+   |
+LL | / enum A {
+LL | |     StructWithFields { x: () },
+LL | |     TupleWithFields(()),
+LL | |     Struct {},
+LL | |     Tuple(),
+LL | |     Unit,
+LL | | }
+   | |_^
+help: you might have meant to use one of the following enum variants
+   |
+LL |     (A::Struct {}).foo();
+   |     ~~~~~~~~~~~~~~
+LL |     (A::Tuple()).foo();
+   |     ~~~~~~~~~~~~
+LL |     A::Unit.foo();
+   |     ~~~~~~~
+help: the following enum variants are available
+   |
+LL |     (A::StructWithFields { /* fields */ }).foo();
+   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL |     (A::TupleWithFields(/* fields */)).foo();
+   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error[E0423]: expected value, found enum `B`
+  --> $DIR/issue-73427.rs:31:5
+   |
+LL |     B.foo();
+   |     ^
+   |
+note: the enum is defined here
+  --> $DIR/issue-73427.rs:9:1
+   |
+LL | / enum B {
+LL | |     StructWithFields { x: () },
+LL | |     TupleWithFields(()),
+LL | | }
+   | |_^
+help: the following enum variants are available
+   |
+LL |     (B::StructWithFields { /* fields */ }).foo();
+   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL |     (B::TupleWithFields(/* fields */)).foo();
+   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error[E0423]: expected value, found enum `C`
+  --> $DIR/issue-73427.rs:33:5
+   |
+LL |     C.foo();
+   |     ^
+   |
+note: the enum is defined here
+  --> $DIR/issue-73427.rs:14:1
+   |
+LL | / enum C {
+LL | |     StructWithFields { x: () },
+LL | |     TupleWithFields(()),
+LL | |     Unit,
+LL | | }
+   | |_^
+help: you might have meant to use the following enum variant
+   |
+LL |     C::Unit.foo();
+   |     ~~~~~~~
+help: the following enum variants are available
+   |
+LL |     (C::StructWithFields { /* fields */ }).foo();
+   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL |     (C::TupleWithFields(/* fields */)).foo();
+   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error[E0423]: expected value, found enum `D`
+  --> $DIR/issue-73427.rs:35:5
+   |
+LL |     D.foo();
+   |     ^
+   |
+note: the enum is defined here
+  --> $DIR/issue-73427.rs:20:1
+   |
+LL | / enum D {
+LL | |     TupleWithFields(()),
+LL | |     Unit,
+LL | | }
+   | |_^
+help: you might have meant to use the following enum variant
+   |
+LL |     D::Unit.foo();
+   |     ~~~~~~~
+help: the following enum variant is available
+   |
+LL |     (D::TupleWithFields(/* fields */)).foo();
+   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error[E0423]: expected function, tuple struct or tuple variant, found enum `A`
+  --> $DIR/issue-73427.rs:40:13
+   |
+LL |     let x = A(3);
+   |             ^
+   |
+   = help: you might have meant to construct one of the enum's non-tuple variants
+note: the enum is defined here
+  --> $DIR/issue-73427.rs:1:1
+   |
+LL | / enum A {
+LL | |     StructWithFields { x: () },
+LL | |     TupleWithFields(()),
+LL | |     Struct {},
+LL | |     Tuple(),
+LL | |     Unit,
+LL | | }
+   | |_^
+help: try to construct one of the enum's variants
+   |
+LL |     let x = A::Tuple(3);
+   |             ~~~~~~~~
+LL |     let x = A::TupleWithFields(3);
+   |             ~~~~~~~~~~~~~~~~~~
+
+error[E0532]: expected tuple struct or tuple variant, found enum `A`
+  --> $DIR/issue-73427.rs:42:12
+   |
+LL |     if let A(3) = x { }
+   |            ^
+   |
+   = help: you might have meant to match against one of the enum's non-tuple variants
+note: the enum is defined here
+  --> $DIR/issue-73427.rs:1:1
+   |
+LL | / enum A {
+LL | |     StructWithFields { x: () },
+LL | |     TupleWithFields(()),
+LL | |     Struct {},
+LL | |     Tuple(),
+LL | |     Unit,
+LL | | }
+   | |_^
+help: try to match against one of the enum's variants
+   |
+LL |     if let A::Tuple(3) = x { }
+   |            ~~~~~~~~
+LL |     if let A::TupleWithFields(3) = x { }
+   |            ~~~~~~~~~~~~~~~~~~
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0423, E0532.
+For more information about an error, try `rustc --explain E0423`.
index b9202f556d12b63f64af42975e994977eb50034b..989d2d4523099c4ba2066f1fd82e3caa866e3645 100644 (file)
@@ -2,9 +2,9 @@
 
 enum E { A, B, c }
 
-mod m {
+pub mod m {
     const CONST1: usize = 10;
-    const Const2: usize = 20;
+    pub const Const2: usize = 20;
 }
 
 fn main() {
@@ -22,15 +22,14 @@ fn main() {
         //~| ERROR variable `B` is bound inconsistently
         //~| ERROR mismatched types
         //~| ERROR variable `c` is not bound in all patterns
-        //~| HELP consider making the path in the pattern qualified: `?::A`
+        //~| HELP if you meant to match on unit variant `E::A`, use the full path in the pattern
     }
 
     let z = (10, 20);
     match z {
         (CONST1, _) | (_, Const2) => ()
         //~^ ERROR variable `CONST1` is not bound in all patterns
-        //~| HELP consider making the path in the pattern qualified: `?::CONST1`
         //~| ERROR variable `Const2` is not bound in all patterns
-        //~| HELP consider making the path in the pattern qualified: `?::Const2`
+        //~| HELP if you meant to match on constant `m::Const2`, use the full path in the pattern
     }
 }
index 70e9c2e5bf598e5621378721dfa3a29e90e31d1d..9de191f7d327ac40294239a30b81795d05f134b3 100644 (file)
@@ -23,11 +23,10 @@ LL |         (A, B) | (ref B, c) | (c, A) => ()
    |          |       pattern doesn't bind `A`
    |          variable not in all patterns
    |
-help: if you meant to match on a variant or a `const` item, consider making the path in the pattern qualified: `?::A`
-  --> $DIR/resolve-inconsistent-names.rs:19:10
+help: if you meant to match on unit variant `E::A`, use the full path in the pattern
    |
-LL |         (A, B) | (ref B, c) | (c, A) => ()
-   |          ^
+LL |         (E::A, B) | (ref B, c) | (c, A) => ()
+   |          ~~~~
 
 error[E0408]: variable `B` is not bound in all patterns
   --> $DIR/resolve-inconsistent-names.rs:19:31
@@ -63,11 +62,11 @@ LL |         (CONST1, _) | (_, Const2) => ()
    |          |
    |          variable not in all patterns
    |
-help: if you meant to match on a variant or a `const` item, consider making the path in the pattern qualified: `?::CONST1`
-  --> $DIR/resolve-inconsistent-names.rs:30:10
+note: you might have meant to match on constant `m::CONST1`, which exists but is inaccessible
+  --> $DIR/resolve-inconsistent-names.rs:6:5
    |
-LL |         (CONST1, _) | (_, Const2) => ()
-   |          ^^^^^^
+LL |     const CONST1: usize = 10;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ not accessible
 
 error[E0408]: variable `Const2` is not bound in all patterns
   --> $DIR/resolve-inconsistent-names.rs:30:9
@@ -77,11 +76,10 @@ LL |         (CONST1, _) | (_, Const2) => ()
    |         |
    |         pattern doesn't bind `Const2`
    |
-help: if you meant to match on a variant or a `const` item, consider making the path in the pattern qualified: `?::Const2`
-  --> $DIR/resolve-inconsistent-names.rs:30:27
+help: if you meant to match on constant `m::Const2`, use the full path in the pattern
    |
-LL |         (CONST1, _) | (_, Const2) => ()
-   |                           ^^^^^^
+LL |         (CONST1, _) | (_, m::Const2) => ()
+   |                           ~~~~~~~~~
 
 error[E0308]: mismatched types
   --> $DIR/resolve-inconsistent-names.rs:19:19
index 1f387a042e66672698a5d0f4e44d691f69a45686..950ffd6c89bd31ed2757c2d17d1a95b7ba628562 100644 (file)
@@ -1,8 +1,6 @@
 error[E0310]: the parameter type `U` may not live long enough
   --> $DIR/dont-infer-static.rs:8:10
    |
-LL | struct Foo<U> {
-   |            - help: consider adding an explicit lifetime bound...: `U: 'static`
 LL |     bar: Bar<U>
    |          ^^^^^^ ...so that the type `U` will meet its required lifetime bounds...
    |
@@ -11,6 +9,10 @@ note: ...that is required by this bound
    |
 LL | struct Bar<T: 'static> {
    |               ^^^^^^^
+help: consider adding an explicit lifetime bound...
+   |
+LL | struct Foo<U: 'static> {
+   |             +++++++++
 
 error: aborting due to previous error
 
index 553a3e71c169a093b8635f2b1b83625298551517..2c660b285009723961eadea6d1dc5f120a019de9 100644 (file)
@@ -1,27 +1,35 @@
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/regions-enum-not-wf.rs:17:18
    |
-LL | enum Ref1<'a, T> {
-   |               - help: consider adding an explicit lifetime bound...: `T: 'a`
 LL |     Ref1Variant1(RequireOutlives<'a, T>),
    |                  ^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | enum Ref1<'a, T: 'a> {
+   |                ++++
 
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/regions-enum-not-wf.rs:22:25
    |
-LL | enum Ref2<'a, T> {
-   |               - help: consider adding an explicit lifetime bound...: `T: 'a`
-LL |     Ref2Variant1,
 LL |     Ref2Variant2(isize, RequireOutlives<'a, T>),
    |                         ^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | enum Ref2<'a, T: 'a> {
+   |                ++++
 
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/regions-enum-not-wf.rs:35:23
    |
-LL | enum RefDouble<'a, 'b, T> {
-   |                        - help: consider adding an explicit lifetime bound...: `T: 'b`
 LL |     RefDoubleVariant1(&'a RequireOutlives<'b, T>),
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | enum RefDouble<'a, 'b, T: 'b> {
+   |                         ++++
 
 error: aborting due to 3 previous errors
 
index f886126299120aebbccf8d98a5a11b2c1e84212a..34ff1362cf32336d3d2dd1f441cbc848c6784129 100644 (file)
@@ -1,16 +1,17 @@
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/regions-struct-not-wf.rs:13:16
    |
-LL | impl<'a, T> Trait<'a, T> for usize {
-   |          - help: consider adding an explicit lifetime bound...: `T: 'a`
 LL |     type Out = &'a T;
    |                ^^^^^ ...so that the reference type `&'a T` does not outlive the data it points at
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | impl<'a, T: 'a> Trait<'a, T> for usize {
+   |           ++++
 
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/regions-struct-not-wf.rs:21:16
    |
-LL | impl<'a, T> Trait<'a, T> for u32 {
-   |          - help: consider adding an explicit lifetime bound...: `T: 'a`
 LL |     type Out = RefOk<'a, T>;
    |                ^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds...
    |
@@ -19,6 +20,10 @@ note: ...that is required by this bound
    |
 LL | struct RefOk<'a, T:'a> {
    |                    ^^
+help: consider adding an explicit lifetime bound...
+   |
+LL | impl<'a, T: 'a> Trait<'a, T> for u32 {
+   |           ++++
 
 error[E0491]: in type `&'a &'b T`, reference has a longer lifetime than the data it references
   --> $DIR/regions-struct-not-wf.rs:25:16
index 961968186de24a520918bcee881ed1344de12c46..dd5099317667307c38ebaac6edae56e645610fd4 100644 (file)
@@ -3,7 +3,7 @@
 pub struct Int(i32);
 
 impl const std::ops::Add for i32 { //~ ERROR type annotations needed
-    //~^ ERROR only traits defined in the current crate can be implemented for arbitrary types
+    //~^ ERROR only traits defined in the current crate can be implemented for primitive types
     type Output = Self;
 
     fn add(self, rhs: Self) -> Self {
index 154a6a35a44efdcb25233065f4ef9811b0e9596d..9fd82196e79c11836cdd70352ced3100d967f50b 100644 (file)
@@ -1,4 +1,4 @@
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for primitive types
   --> $DIR/const-and-non-const-impl.rs:5:1
    |
 LL | impl const std::ops::Add for i32 {
index 79273a1dcbf887a4c78a9956dd050f94583203c0..0ef7b8b09f11fd8db36d0d868e38834da722fb42 100644 (file)
@@ -7,7 +7,7 @@ LL |     sse2();
    = note: can only be called if the required target features are available
 
 error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:24:5
+  --> $DIR/safe-calls.rs:26:5
    |
 LL |     avx_bmi2();
    |     ^^^^^^^^^^ call to function with `#[target_feature]`
@@ -15,7 +15,7 @@ LL |     avx_bmi2();
    = note: can only be called if the required target features are available
 
 error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:25:5
+  --> $DIR/safe-calls.rs:29:5
    |
 LL |     Quux.avx_bmi2();
    |     ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
@@ -23,7 +23,7 @@ LL |     Quux.avx_bmi2();
    = note: can only be called if the required target features are available
 
 error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:30:5
+  --> $DIR/safe-calls.rs:36:5
    |
 LL |     avx_bmi2();
    |     ^^^^^^^^^^ call to function with `#[target_feature]`
@@ -31,7 +31,7 @@ LL |     avx_bmi2();
    = note: can only be called if the required target features are available
 
 error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:31:5
+  --> $DIR/safe-calls.rs:39:5
    |
 LL |     Quux.avx_bmi2();
    |     ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
@@ -39,7 +39,7 @@ LL |     Quux.avx_bmi2();
    = note: can only be called if the required target features are available
 
 error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:36:5
+  --> $DIR/safe-calls.rs:46:5
    |
 LL |     sse2();
    |     ^^^^^^ call to function with `#[target_feature]`
@@ -47,7 +47,7 @@ LL |     sse2();
    = note: can only be called if the required target features are available
 
 error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:37:5
+  --> $DIR/safe-calls.rs:49:5
    |
 LL |     avx_bmi2();
    |     ^^^^^^^^^^ call to function with `#[target_feature]`
@@ -55,7 +55,7 @@ LL |     avx_bmi2();
    = note: can only be called if the required target features are available
 
 error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:38:5
+  --> $DIR/safe-calls.rs:52:5
    |
 LL |     Quux.avx_bmi2();
    |     ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
@@ -63,7 +63,7 @@ LL |     Quux.avx_bmi2();
    = note: can only be called if the required target features are available
 
 error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:44:5
+  --> $DIR/safe-calls.rs:60:5
    |
 LL |     sse2();
    |     ^^^^^^ call to function with `#[target_feature]`
@@ -71,7 +71,7 @@ LL |     sse2();
    = note: can only be called if the required target features are available
 
 error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:47:18
+  --> $DIR/safe-calls.rs:65:18
    |
 LL | const name: () = sse2();
    |                  ^^^^^^ call to function with `#[target_feature]`
index de0b89f46ba3fbd8a643a2009af9dc28f08da45e..cebc6f947840459fce5f103c60c5b1f5a4d5883e 100644 (file)
@@ -20,30 +20,50 @@ fn avx_bmi2(&self) {}
 }
 
 fn foo() {
-    sse2();              //~ ERROR call to function with `#[target_feature]` is unsafe
-    avx_bmi2();          //~ ERROR call to function with `#[target_feature]` is unsafe
-    Quux.avx_bmi2();     //~ ERROR call to function with `#[target_feature]` is unsafe
+    sse2();
+    //[mir]~^ ERROR call to function with `#[target_feature]` is unsafe
+    //[thir]~^^ ERROR call to function `sse2` with `#[target_feature]` is unsafe
+    avx_bmi2();
+    //[mir]~^ ERROR call to function with `#[target_feature]` is unsafe
+    //[thir]~^^ ERROR call to function `avx_bmi2` with `#[target_feature]` is unsafe
+    Quux.avx_bmi2();
+    //[mir]~^ ERROR call to function with `#[target_feature]` is unsafe
+    //[thir]~^^ ERROR call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe
 }
 
 #[target_feature(enable = "sse2")]
 fn bar() {
-    avx_bmi2();          //~ ERROR call to function with `#[target_feature]` is unsafe
-    Quux.avx_bmi2();     //~ ERROR call to function with `#[target_feature]` is unsafe
+    avx_bmi2();
+    //[mir]~^ ERROR call to function with `#[target_feature]` is unsafe
+    //[thir]~^^ ERROR call to function `avx_bmi2` with `#[target_feature]` is unsafe
+    Quux.avx_bmi2();
+    //[mir]~^ ERROR call to function with `#[target_feature]` is unsafe
+    //[thir]~^^ ERROR call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe
 }
 
 #[target_feature(enable = "avx")]
 fn baz() {
-    sse2();              //~ ERROR call to function with `#[target_feature]` is unsafe
-    avx_bmi2();          //~ ERROR call to function with `#[target_feature]` is unsafe
-    Quux.avx_bmi2();     //~ ERROR call to function with `#[target_feature]` is unsafe
+    sse2();
+    //[mir]~^ ERROR call to function with `#[target_feature]` is unsafe
+    //[thir]~^^ ERROR call to function `sse2` with `#[target_feature]` is unsafe
+    avx_bmi2();
+    //[mir]~^ ERROR call to function with `#[target_feature]` is unsafe
+    //[thir]~^^ ERROR call to function `avx_bmi2` with `#[target_feature]` is unsafe
+    Quux.avx_bmi2();
+    //[mir]~^ ERROR call to function with `#[target_feature]` is unsafe
+    //[thir]~^^ ERROR call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe
 }
 
 #[target_feature(enable = "avx")]
 #[target_feature(enable = "bmi2")]
 fn qux() {
-    sse2();              //~ ERROR call to function with `#[target_feature]` is unsafe
+    sse2();
+    //[mir]~^ ERROR call to function with `#[target_feature]` is unsafe
+    //[thir]~^^ ERROR call to function `sse2` with `#[target_feature]` is unsafe
 }
 
-const name: () = sse2(); //~ ERROR call to function with `#[target_feature]` is unsafe
+const name: () = sse2();
+//[mir]~^ ERROR call to function with `#[target_feature]` is unsafe
+//[thir]~^^ ERROR call to function `sse2` with `#[target_feature]` is unsafe
 
 fn main() {}
index 79273a1dcbf887a4c78a9956dd050f94583203c0..c75ac6e8b9ae0c9561a60837bd4c03f3de2a10b2 100644 (file)
@@ -1,4 +1,4 @@
-error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
+error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block
   --> $DIR/safe-calls.rs:23:5
    |
 LL |     sse2();
@@ -6,72 +6,72 @@ LL |     sse2();
    |
    = note: can only be called if the required target features are available
 
-error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:24:5
+error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
+  --> $DIR/safe-calls.rs:26:5
    |
 LL |     avx_bmi2();
    |     ^^^^^^^^^^ call to function with `#[target_feature]`
    |
    = note: can only be called if the required target features are available
 
-error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:25:5
+error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
+  --> $DIR/safe-calls.rs:29:5
    |
 LL |     Quux.avx_bmi2();
    |     ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
    |
    = note: can only be called if the required target features are available
 
-error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:30:5
+error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
+  --> $DIR/safe-calls.rs:36:5
    |
 LL |     avx_bmi2();
    |     ^^^^^^^^^^ call to function with `#[target_feature]`
    |
    = note: can only be called if the required target features are available
 
-error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:31:5
+error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
+  --> $DIR/safe-calls.rs:39:5
    |
 LL |     Quux.avx_bmi2();
    |     ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
    |
    = note: can only be called if the required target features are available
 
-error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:36:5
+error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block
+  --> $DIR/safe-calls.rs:46:5
    |
 LL |     sse2();
    |     ^^^^^^ call to function with `#[target_feature]`
    |
    = note: can only be called if the required target features are available
 
-error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:37:5
+error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
+  --> $DIR/safe-calls.rs:49:5
    |
 LL |     avx_bmi2();
    |     ^^^^^^^^^^ call to function with `#[target_feature]`
    |
    = note: can only be called if the required target features are available
 
-error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:38:5
+error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
+  --> $DIR/safe-calls.rs:52:5
    |
 LL |     Quux.avx_bmi2();
    |     ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
    |
    = note: can only be called if the required target features are available
 
-error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:44:5
+error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block
+  --> $DIR/safe-calls.rs:60:5
    |
 LL |     sse2();
    |     ^^^^^^ call to function with `#[target_feature]`
    |
    = note: can only be called if the required target features are available
 
-error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:47:18
+error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block
+  --> $DIR/safe-calls.rs:65:18
    |
 LL | const name: () = sse2();
    |                  ^^^^^^ call to function with `#[target_feature]`
diff --git a/src/test/ui/save-analysis/issue-37323.rs b/src/test/ui/save-analysis/issue-37323.rs
new file mode 100644 (file)
index 0000000..55f5c5a
--- /dev/null
@@ -0,0 +1,20 @@
+// check-pass
+// compile-flags: -Zsave-analysis
+
+#![feature(rustc_attrs)]
+#![allow(warnings)]
+
+#[derive(Debug)]
+struct Point {
+}
+
+struct NestedA<'a, 'b> {
+    x: &'a NestedB<'b>
+}
+
+struct NestedB<'a> {
+    x: &'a i32,
+}
+
+fn main() {
+}
index b06ebf70477378344d4afc6c50ebca9dada1940f..057146e7cb0ad63ad2aeb38c2949c96b00c24f0a 100644 (file)
@@ -6,6 +6,11 @@ LL |     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 |     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.rs:14:69
@@ -15,6 +20,11 @@ LL |     fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self,
    |                    |          |
    |                    |          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 |     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.rs:21:58
index 1934207527b9cd9e56c5e066b9b8db08dd6d8d14..2e26c703b657366bd3b7e9200d1aa0d49f5947ce 100644 (file)
@@ -7,6 +7,11 @@ LL |     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 |     fn ref_self<'a>(&'a self, f: &'a u32) -> &u32 {
+   |                ++++  ++           ++
 
 error: lifetime may not live long enough
   --> $DIR/lt-ref-self.rs:23:9
@@ -17,6 +22,11 @@ LL |     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 |     fn ref_Self<'a>(self: &'a Self, f: &'a u32) -> &u32 {
+   |                ++++        ++           ++
 
 error: lifetime may not live long enough
   --> $DIR/lt-ref-self.rs:29:9
@@ -27,6 +37,11 @@ LL |     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 |     fn box_ref_Self<'a>(self: Box<&'a Self>, f: &'a u32) -> &u32 {
+   |                    ++++            ++            ++
 
 error: lifetime may not live long enough
   --> $DIR/lt-ref-self.rs:35:9
@@ -37,6 +52,11 @@ LL |     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 |     fn pin_ref_Self<'a>(self: Pin<&'a Self>, f: &'a u32) -> &u32 {
+   |                    ++++            ++            ++
 
 error: lifetime may not live long enough
   --> $DIR/lt-ref-self.rs:41:9
@@ -47,6 +67,11 @@ LL |     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 |     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.rs:47:9
@@ -57,6 +82,11 @@ LL |     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 |     fn box_pin_Self<'a>(self: Box<Pin<&'a Self>>, f: &'a u32) -> &u32 {
+   |                    ++++                ++             ++
 
 error: aborting due to 6 previous errors
 
index f1f4d341b2bd8ac45b464f39bffde6380271ae99..fd4ecae3cfe323ee1c96b60b2c79a33af9aff5df 100644 (file)
@@ -7,6 +7,11 @@ LL |     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 |     fn ref_self<'a>(&'a mut self, f: &'a u32) -> &u32 {
+   |                ++++  ++               ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-mut-self.rs:23:9
@@ -17,6 +22,11 @@ LL |     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 |     fn ref_Self<'a>(self: &'a mut Self, f: &'a u32) -> &u32 {
+   |                ++++        ++               ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-mut-self.rs:29:9
@@ -27,6 +37,11 @@ LL |     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 |     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.rs:35:9
@@ -37,6 +52,11 @@ LL |     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 |     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.rs:41:9
@@ -47,6 +67,11 @@ LL |     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 |     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.rs:47:9
@@ -57,6 +82,11 @@ LL |     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 |     fn box_pin_ref_Self<'a>(self: Box<Pin<&'a mut Self>>, f: &'a u32) -> &u32 {
+   |                        ++++                ++                 ++
 
 error: aborting due to 6 previous errors
 
index de7eb02d7a7fe38e82f341d056cf512d08ffa806..ede790c0611431fdb3f2d35e939f6fd17f392c8f 100644 (file)
@@ -7,6 +7,11 @@ LL |     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 |     fn ref_Struct<'a>(self: &'a mut Struct, f: &'a u32) -> &u32 {
+   |                  ++++        ++                 ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-mut-struct.rs:21:9
@@ -17,6 +22,11 @@ LL |     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 |     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.rs:27:9
@@ -27,6 +37,11 @@ LL |     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 |     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.rs:33:9
@@ -37,6 +52,11 @@ LL |     fn box_box_ref_Struct(self: Box<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 |     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.rs:39:9
@@ -47,6 +67,11 @@ LL |     fn box_pin_ref_Struct(self: Box<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 |     fn box_pin_ref_Struct<'a>(self: Box<Pin<&'a mut Struct>>, f: &'a u32) -> &u32 {
+   |                          ++++                ++                   ++
 
 error: aborting due to 5 previous errors
 
index f2b7b0ad019570965bfae7026292e79d121ac51c..c0efc35fa6c8e97161b8bcde0cf87f8d778a98fb 100644 (file)
@@ -7,6 +7,11 @@ LL |     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 |     fn ref_self<'a>(&'a self, f: &'a u32) -> &u32 {
+   |                ++++  ++           ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-self.rs:33:9
@@ -17,6 +22,11 @@ LL |     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 |     fn ref_Self<'a>(self: &'a Self, f: &'a u32) -> &u32 {
+   |                ++++        ++           ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-self.rs:39:9
@@ -27,6 +37,11 @@ LL |     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 |     fn box_ref_Self<'a>(self: Box<&'a Self>, f: &'a u32) -> &u32 {
+   |                    ++++            ++            ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-self.rs:45:9
@@ -37,6 +52,11 @@ LL |     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 |     fn pin_ref_Self<'a>(self: Pin<&'a Self>, f: &'a u32) -> &u32 {
+   |                    ++++            ++            ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-self.rs:51:9
@@ -47,6 +67,11 @@ LL |     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 |     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.rs:57:9
@@ -57,6 +82,11 @@ LL |     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 |     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.rs:63:9
@@ -67,6 +97,11 @@ LL |     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 |     fn wrap_ref_Self_Self<'a>(self: Wrap<&'a Self, Self>, f: &'a u8) -> &u8 {
+   |                          ++++             ++                  ++
 
 error: aborting due to 7 previous errors
 
index 70453b0ddfc71ab2b8b951ee5420a5711680e387..226923f59ff37bfcaa0fb173d11182828e08048c 100644 (file)
@@ -7,6 +7,11 @@ LL |     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 |     fn ref_Struct<'a>(self: &'a Struct, f: &'a u32) -> &u32 {
+   |                  ++++        ++             ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-struct.rs:21:9
@@ -17,6 +22,11 @@ LL |     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 |     fn box_ref_Struct<'a>(self: Box<&'a Struct>, f: &'a u32) -> &u32 {
+   |                      ++++            ++              ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-struct.rs:27:9
@@ -27,6 +37,11 @@ LL |     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 |     fn pin_ref_Struct<'a>(self: Pin<&'a Struct>, f: &'a u32) -> &u32 {
+   |                      ++++            ++              ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-struct.rs:33:9
@@ -37,6 +52,11 @@ LL |     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 |     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.rs:39:9
@@ -47,6 +67,11 @@ LL |     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 |     fn box_pin_Struct<'a>(self: Box<Pin<&'a Struct>>, f: &'a u32) -> &u32 {
+   |                      ++++                ++               ++
 
 error: aborting due to 5 previous errors
 
index 445df90d395ee3f956ce6636a857843068cc8dea..25c35fd5479f933ce4db6a3563e32ce0a152045e 100644 (file)
@@ -1,3 +1,13 @@
+error[E0408]: variable `d` is not bound in all patterns
+  --> $DIR/issue-39698.rs:10:37
+   |
+LL |         T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); }
+   |                  -          -       ^^^^^^^^   ^^^^^^^^ pattern doesn't bind `d`
+   |                  |          |       |
+   |                  |          |       pattern doesn't bind `d`
+   |                  |          variable not in all patterns
+   |                  variable not in all patterns
+
 error[E0408]: variable `a` is not bound in all patterns
   --> $DIR/issue-39698.rs:10:23
    |
@@ -28,16 +38,6 @@ LL |         T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}
    |         |             pattern doesn't bind `c`
    |         pattern doesn't bind `c`
 
-error[E0408]: variable `d` is not bound in all patterns
-  --> $DIR/issue-39698.rs:10:37
-   |
-LL |         T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); }
-   |                  -          -       ^^^^^^^^   ^^^^^^^^ pattern doesn't bind `d`
-   |                  |          |       |
-   |                  |          |       pattern doesn't bind `d`
-   |                  |          variable not in all patterns
-   |                  variable not in all patterns
-
 error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0408`.
index 79d9506619e17fbde574c674fe89201921fd4980..ef07a89315f4088ddd653b649a5e0d8cf1f99fd3 100644 (file)
@@ -2,7 +2,7 @@ warning: unnecessary lifetime parameter `'a`
   --> $DIR/static-lifetime-bound.rs:1:6
    |
 LL | fn f<'a: 'static>(_: &'a i32) {}
-   |      ^^^^^^^^^^^
+   |      ^^
    |
    = help: you can use the `'static` lifetime directly, in place of `'a`
 
diff --git a/src/test/ui/statics/issue-17233.rs b/src/test/ui/statics/issue-17233.rs
new file mode 100644 (file)
index 0000000..54a12fd
--- /dev/null
@@ -0,0 +1,17 @@
+// run-pass
+
+const X1: &'static [u8] = &[b'1'];
+const X2: &'static [u8] = b"1";
+const X3: &'static [u8; 1] = &[b'1'];
+const X4: &'static [u8; 1] = b"1";
+
+static Y1: u8 = X1[0];
+static Y2: u8 = X2[0];
+static Y3: u8 = X3[0];
+static Y4: u8 = X4[0];
+
+fn main() {
+    assert_eq!(Y1, Y2);
+    assert_eq!(Y1, Y3);
+    assert_eq!(Y1, Y4);
+}
diff --git a/src/test/ui/structs-enums/multiple-reprs.rs b/src/test/ui/structs-enums/multiple-reprs.rs
new file mode 100644 (file)
index 0000000..4be503a
--- /dev/null
@@ -0,0 +1,82 @@
+// run-pass
+
+#![allow(dead_code)]
+
+use std::mem::{size_of, align_of};
+use std::os::raw::c_int;
+
+// The two enums that follow are designed so that bugs trigger layout optimization.
+// Specifically, if either of the following reprs used here is not detected by the compiler,
+// then the sizes will be wrong.
+
+#[repr(C, u8)]
+enum E1 {
+    A(u8, u16, u8),
+    B(u8, u16, u8)
+}
+
+#[repr(u8, C)]
+enum E2 {
+    A(u8, u16, u8),
+    B(u8, u16, u8)
+}
+
+// Check that repr(int) and repr(C) are in fact different from the above
+
+#[repr(u8)]
+enum E3 {
+    A(u8, u16, u8),
+    B(u8, u16, u8)
+}
+
+#[repr(u16)]
+enum E4 {
+    A(u8, u16, u8),
+    B(u8, u16, u8)
+}
+
+#[repr(u32)]
+enum E5 {
+    A(u8, u16, u8),
+    B(u8, u16, u8)
+}
+
+#[repr(u64)]
+enum E6 {
+    A(u8, u16, u8),
+    B(u8, u16, u8)
+}
+
+#[repr(C)]
+enum E7 {
+    A(u8, u16, u8),
+    B(u8, u16, u8)
+}
+
+// From pr 37429
+
+#[repr(C,packed)]
+pub struct p0f_api_query {
+    pub magic: u32,
+    pub addr_type: u8,
+    pub addr: [u8; 16],
+}
+
+pub fn main() {
+    assert_eq!(size_of::<E1>(), 8);
+    assert_eq!(size_of::<E2>(), 8);
+    assert_eq!(size_of::<E3>(), 6);
+    assert_eq!(size_of::<E4>(), 8);
+    assert_eq!(size_of::<E5>(), align_size(10, align_of::<u32>()));
+    assert_eq!(size_of::<E6>(), align_size(14, align_of::<u64>()));
+    assert_eq!(size_of::<E7>(), align_size(6 + size_of::<c_int>(), align_of::<c_int>()));
+    assert_eq!(size_of::<p0f_api_query>(), 21);
+}
+
+fn align_size(size: usize, align: usize) -> usize {
+    if size % align != 0 {
+        size + (align - (size % align))
+    } else {
+        size
+    }
+}
diff --git a/src/test/ui/suggest-using-chars.rs b/src/test/ui/suggest-using-chars.rs
deleted file mode 100644 (file)
index 9573288..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-pub fn main() {
-    let _ = "foo".iter(); //~ ERROR no method named `iter` found for reference `&'static str` in the current scope
-    let _ = "foo".foo(); //~ ERROR no method named `foo` found for reference `&'static str` in the current scope
-    let _ = String::from("bar").iter(); //~ ERROR no method named `iter` found for struct `String` in the current scope
-    let _ = (&String::from("bar")).iter(); //~ ERROR no method named `iter` found for reference `&String` in the current scope
-    let _ = 0.iter(); //~ ERROR no method named `iter` found for type `{integer}` in the current scope
-}
diff --git a/src/test/ui/suggest-using-chars.stderr b/src/test/ui/suggest-using-chars.stderr
deleted file mode 100644 (file)
index 99bcfb0..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-error[E0599]: no method named `iter` found for reference `&'static str` in the current scope
-  --> $DIR/suggest-using-chars.rs:2:19
-   |
-LL |     let _ = "foo".iter();
-   |                   ^^^^ method not found in `&'static str`
-   |
-help: because of the in-memory representation of `&str`, to obtain an `Iterator` over each of its codepoint use method `chars`
-   |
-LL |     let _ = "foo".chars();
-   |                   ~~~~~
-
-error[E0599]: no method named `foo` found for reference `&'static str` in the current scope
-  --> $DIR/suggest-using-chars.rs:3:19
-   |
-LL |     let _ = "foo".foo();
-   |                   ^^^ method not found in `&'static str`
-
-error[E0599]: no method named `iter` found for struct `String` in the current scope
-  --> $DIR/suggest-using-chars.rs:4:33
-   |
-LL |     let _ = String::from("bar").iter();
-   |                                 ^^^^ method not found in `String`
-   |
-help: because of the in-memory representation of `&str`, to obtain an `Iterator` over each of its codepoint use method `chars`
-   |
-LL |     let _ = String::from("bar").chars();
-   |                                 ~~~~~
-
-error[E0599]: no method named `iter` found for reference `&String` in the current scope
-  --> $DIR/suggest-using-chars.rs:5:36
-   |
-LL |     let _ = (&String::from("bar")).iter();
-   |                                    ^^^^ method not found in `&String`
-   |
-help: because of the in-memory representation of `&str`, to obtain an `Iterator` over each of its codepoint use method `chars`
-   |
-LL |     let _ = (&String::from("bar")).chars();
-   |                                    ~~~~~
-
-error[E0599]: no method named `iter` found for type `{integer}` in the current scope
-  --> $DIR/suggest-using-chars.rs:6:15
-   |
-LL |     let _ = 0.iter();
-   |               ^^^^ method not found in `{integer}`
-
-error: aborting due to 5 previous errors
-
-For more information about this error, try `rustc --explain E0599`.
index 31fdd2b67e2944ba0a56675e9248539ad96362c9..17a019c69849f0174b014633b8da9dc65e765497 100644 (file)
@@ -35,7 +35,7 @@ fn test_one_bound_where<X>(x: X) where X: Sized + std::fmt::Debug {
 }
 
 #[allow(dead_code)]
-fn test_many_bounds_where<X>(x: X) where X: Sized, X: Sized, X: std::fmt::Debug {
+fn test_many_bounds_where<X>(x: X) where X: Sized + std::fmt::Debug, X: Sized {
     println!("{:?}", x);
     //~^ ERROR doesn't implement
 }
index 04f233a1e87af52a3c548d87efc186359fe912fb..e5e19444d2435c3a5796c9f194ffdb65d679d96b 100644 (file)
@@ -65,10 +65,10 @@ LL |     println!("{:?}", x);
    |                      ^ `X` cannot be formatted using `{:?}` because it doesn't implement `Debug`
    |
    = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: consider further restricting type parameter `X`
+help: consider further restricting this bound
    |
-LL | fn test_many_bounds_where<X>(x: X) where X: Sized, X: Sized, X: std::fmt::Debug {
-   |                                                            ++++++++++++++++++++
+LL | fn test_many_bounds_where<X>(x: X) where X: Sized + std::fmt::Debug, X: Sized {
+   |                                                   +++++++++++++++++
 
 error[E0277]: the size for values of type `Self` cannot be known at compilation time
   --> $DIR/bound-suggestions.rs:44:46
diff --git a/src/test/ui/suggestions/field-has-method.rs b/src/test/ui/suggestions/field-has-method.rs
new file mode 100644 (file)
index 0000000..9800001
--- /dev/null
@@ -0,0 +1,23 @@
+struct Kind;
+
+struct Ty {
+    kind: Kind,
+}
+
+impl Ty {
+    fn kind(&self) -> Kind {
+        todo!()
+    }
+}
+
+struct InferOk<T> {
+    value: T,
+    predicates: Vec<()>,
+}
+
+fn foo(i: InferOk<Ty>) {
+    let k = i.kind();
+    //~^ no method named `kind` found for struct `InferOk` in the current scope
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/field-has-method.stderr b/src/test/ui/suggestions/field-has-method.stderr
new file mode 100644 (file)
index 0000000..3a57436
--- /dev/null
@@ -0,0 +1,17 @@
+error[E0599]: no method named `kind` found for struct `InferOk` in the current scope
+  --> $DIR/field-has-method.rs:19:15
+   |
+LL | struct InferOk<T> {
+   | ----------------- method `kind` not found for this
+...
+LL |     let k = i.kind();
+   |               ^^^^ method not found in `InferOk<Ty>`
+   |
+help: one of the expressions' fields has a method of the same name
+   |
+LL |     let k = i.value.kind();
+   |               ++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.
index 5a17c108ccc132a7db44d0f90605e2a27a5d009f..cd3741356f4d0f042c1524320ff168d4012e5f62 100644 (file)
@@ -8,16 +8,12 @@ impl Bar for Qux {}
 
 fn foo() -> impl Bar {
     //~^ ERROR the trait bound `(): Bar` is not satisfied
-    //~| ERROR the trait bound `(): Bar` is not satisfied
-    //~| HELP the following other types implement trait `Bar`:
     5;
     //~^ HELP remove this semicolon
 }
 
 fn bar() -> impl Bar {
     //~^ ERROR the trait bound `(): Bar` is not satisfied
-    //~| ERROR the trait bound `(): Bar` is not satisfied
-    //~| HELP the following other types implement trait `Bar`:
     //~| HELP the following other types implement trait `Bar`:
     "";
 }
index 43f8b7c66f07a19c9b4a104a4c6135ef0cda95c4..e74c2c4214fe2d6977de70aaa2532bea39542a19 100644 (file)
@@ -3,31 +3,14 @@ error[E0277]: the trait bound `(): Bar` is not satisfied
    |
 LL | fn foo() -> impl Bar {
    |             ^^^^^^^^ the trait `Bar` is not implemented for `()`
-...
+LL |
 LL |     5;
    |     -- help: remove this semicolon
    |     |
    |     this expression has type `{integer}`, which implements `Bar`
 
 error[E0277]: the trait bound `(): Bar` is not satisfied
-  --> $DIR/impl-trait-return-trailing-semicolon.rs:9:22
-   |
-LL |   fn foo() -> impl Bar {
-   |  ______________________^
-LL | |
-LL | |
-LL | |
-LL | |     5;
-LL | |
-LL | | }
-   | |_^ the trait `Bar` is not implemented for `()`
-   |
-   = help: the following other types implement trait `Bar`:
-             Qux
-             i32
-
-error[E0277]: the trait bound `(): Bar` is not satisfied
-  --> $DIR/impl-trait-return-trailing-semicolon.rs:17:13
+  --> $DIR/impl-trait-return-trailing-semicolon.rs:15:13
    |
 LL | fn bar() -> impl Bar {
    |             ^^^^^^^^ the trait `Bar` is not implemented for `()`
@@ -36,23 +19,6 @@ LL | fn bar() -> impl Bar {
              Qux
              i32
 
-error[E0277]: the trait bound `(): Bar` is not satisfied
-  --> $DIR/impl-trait-return-trailing-semicolon.rs:17:22
-   |
-LL |   fn bar() -> impl Bar {
-   |  ______________________^
-LL | |
-LL | |
-LL | |
-LL | |
-LL | |     "";
-LL | | }
-   | |_^ the trait `Bar` is not implemented for `()`
-   |
-   = help: the following other types implement trait `Bar`:
-             Qux
-             i32
-
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
index 6255df06efb6ade307d7a8930812506c0f0dc2ab..8ec7b7bf496581e19e3436cef18e3172f91f76d6 100644 (file)
@@ -8,7 +8,7 @@ LL |     foo.hello();
 help: the following trait defines an item `hello`, perhaps you need to restrict type parameter `impl Foo` with it:
    |
 LL | fn test(foo: impl Foo + Bar) {
-   |              ~~~~~~~~~~~~~~
+   |                       +++++
 
 error: aborting due to previous error
 
index d18c24e53d030ddfe9cd63570b9e0e90c1d107d0..fe5e2b5816fdfe7ce79a78919610f398e2801a12 100644 (file)
@@ -11,11 +11,14 @@ note: an implementation of `PartialEq<_>` might be missing for `S<T>`
    |
 LL | struct S<T>(T);
    | ^^^^^^^^^^^^^^^ must implement `PartialEq<_>`
-   = note: the trait `std::cmp::PartialEq` is not implemented for `S<T>`
 help: consider annotating `S<T>` with `#[derive(PartialEq)]`
    |
 LL | #[derive(PartialEq)]
    |
+help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
+   |
+LL | pub fn foo<T>(s: S<T>, t: S<T>) where S<T>: PartialEq {
+   |                                 +++++++++++++++++++++
 
 error: aborting due to previous error
 
index eda29f876d8fcbb27316f5f40f7a3f7bc0f77f4c..0a4aaa61bc784cfc3b441d853e8b6c377831d8aa 100644 (file)
@@ -7,8 +7,8 @@ LL |     x.method()
    = help: items from traits can only be used if the type parameter is bounded by the trait
 help: the following trait defines an item `method`, perhaps you need to restrict type parameter `T` with it:
    |
-LL | fn call_method<T: Foo + std::fmt::Debug>(x: &T) {
-   |                ~~~~~~~~
+LL | fn call_method<T: std::fmt::Debug + Foo>(x: &T) {
+   |                                   +++++
 
 error[E0599]: no method named `method` found for type parameter `T` in the current scope
   --> $DIR/issue-21673.rs:10:7
@@ -20,7 +20,7 @@ LL |     x.method()
 help: the following trait defines an item `method`, perhaps you need to restrict type parameter `T` with it:
    |
 LL | fn call_method_2<T: Foo>(x: T) {
-   |                  ~~~~~~
+   |                   +++++
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/suggestions/issue-53692.rs b/src/test/ui/suggestions/issue-53692.rs
new file mode 100644 (file)
index 0000000..30f344e
--- /dev/null
@@ -0,0 +1,17 @@
+fn main() {
+        let items = vec![1, 2, 3];
+        let ref_items: &[i32] = &items;
+        let items_clone: Vec<i32> = ref_items.clone();
+//~^ ERROR mismatched types
+
+        // in that case no suggestion will be triggered
+        let items_clone_2:Vec<i32> = items.clone();
+
+        let s = "hi";
+        let string: String = s.clone();
+//~^ ERROR mismatched types
+
+        // in that case no suggestion will be triggered
+        let s2 = "hi";
+        let string_2: String = s2.to_string();
+}
diff --git a/src/test/ui/suggestions/issue-53692.stderr b/src/test/ui/suggestions/issue-53692.stderr
new file mode 100644 (file)
index 0000000..09c78da
--- /dev/null
@@ -0,0 +1,26 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-53692.rs:4:37
+   |
+LL |         let items_clone: Vec<i32> = ref_items.clone();
+   |                          --------   ^^^^^^^^^^^^^^^^^
+   |                          |          |
+   |                          |          expected struct `Vec`, found `&[i32]`
+   |                          |          help: try using a conversion method: `ref_items.to_vec()`
+   |                          expected due to this
+   |
+   = note: expected struct `Vec<i32>`
+           found reference `&[i32]`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-53692.rs:11:30
+   |
+LL |         let string: String = s.clone();
+   |                     ------   ^^^^^^^^^
+   |                     |        |
+   |                     |        expected struct `String`, found `&str`
+   |                     |        help: try using a conversion method: `s.to_string()`
+   |                     expected due to this
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
index 7ca7380a7befdd7ed1d3928a81f0548a3de06365..a601b5866f43e1689ae49fc9589c2cee9329b88f 100644 (file)
@@ -1,14 +1,12 @@
 // Don't suggest removing a semicolon if the last statement isn't an expression with semicolon
 // (#81098)
 fn wat() -> impl core::fmt::Display { //~ ERROR: `()` doesn't implement `std::fmt::Display`
-    //~^ ERROR: `()` doesn't implement `std::fmt::Display`
     fn why() {}
 }
 
 // Do it if the last statement is an expression with semicolon
 // (#54771)
 fn ok() -> impl core::fmt::Display { //~ ERROR: `()` doesn't implement `std::fmt::Display`
-    //~^ ERROR: `()` doesn't implement `std::fmt::Display`
     1;
 }
 
index 8665f2e70a85c597659af38f7907634701f529ff..4dc47a20282438dc48e4d9ecb3603c4a1aea425d 100644 (file)
@@ -8,24 +8,10 @@ LL | fn wat() -> impl core::fmt::Display {
    = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
 
 error[E0277]: `()` doesn't implement `std::fmt::Display`
-  --> $DIR/issue-81098.rs:3:37
-   |
-LL |   fn wat() -> impl core::fmt::Display {
-   |  _____________________________________^
-LL | |
-LL | |     fn why() {}
-LL | | }
-   | |_^ `()` cannot be formatted with the default formatter
-   |
-   = help: the trait `std::fmt::Display` is not implemented for `()`
-   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
-
-error[E0277]: `()` doesn't implement `std::fmt::Display`
-  --> $DIR/issue-81098.rs:10:12
+  --> $DIR/issue-81098.rs:9:12
    |
 LL | fn ok() -> impl core::fmt::Display {
    |            ^^^^^^^^^^^^^^^^^^^^^^^ `()` cannot be formatted with the default formatter
-LL |
 LL |     1;
    |     -- help: remove this semicolon
    |     |
@@ -34,19 +20,6 @@ LL |     1;
    = help: the trait `std::fmt::Display` is not implemented for `()`
    = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
 
-error[E0277]: `()` doesn't implement `std::fmt::Display`
-  --> $DIR/issue-81098.rs:10:36
-   |
-LL |   fn ok() -> impl core::fmt::Display {
-   |  ____________________________________^
-LL | |
-LL | |     1;
-LL | | }
-   | |_^ `()` cannot be formatted with the default formatter
-   |
-   = help: the trait `std::fmt::Display` is not implemented for `()`
-   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
-
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
index 536494c73445ceeaf3a6113d0bbda805afd51626..0212c2d712cb35014746a94f5dfd360780b3fdd8 100644 (file)
@@ -12,6 +12,18 @@ note: the parameter type `T` must be valid for the anonymous lifetime defined he
    |
 LL | fn func<T: Test>(foo: &Foo, t: T) {
    |                        ^^^
+note: ...so that the type `T` will meet its required lifetime bounds
+  --> $DIR/missing-lifetimes-in-signature-2.rs:20:5
+   |
+LL | /     foo.bar(move |_| {
+LL | |
+LL | |         t.test();
+LL | |     });
+   | |______^
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn func<T: Test + 'a>(foo: &Foo, t: T) {
+   |                 ++++
 
 error: aborting due to previous error
 
index adb928aa8a3766e73cf79d6fba51de548f4afffb..5d195e5ff32f76eabfe1a4834151edba0b2d8ade 100644 (file)
@@ -1,8 +1,6 @@
 error[E0311]: the parameter type `T` may not live long enough
   --> $DIR/missing-lifetimes-in-signature-2.rs:20:9
    |
-LL | fn func<T: Test>(foo: &Foo, t: T) {
-   |         -- help: consider adding an explicit lifetime bound...: `T: 'a +`
 LL |     foo.bar(move |_| {
    |         ^^^
    |
@@ -21,6 +19,10 @@ note: ...that is required by this bound
    |
 LL |         F: 'a,
    |            ^^
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn func<T: Test + 'a>(foo: &Foo, t: T) {
+   |                 ++++
 
 error: aborting due to previous error
 
index 0ae629676fec7dfe4525a2fe36ab9403484a6e55..24eac64d334da81934e311cbb4b0fb74eaa795b3 100644 (file)
@@ -1,5 +1,5 @@
 error[E0261]: use of undeclared lifetime name `'a`
-  --> $DIR/missing-lifetimes-in-signature.rs:38:11
+  --> $DIR/missing-lifetimes-in-signature.rs:37:11
    |
 LL | fn baz<G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
    |        -  ^^ undeclared lifetime
@@ -24,7 +24,7 @@ LL | fn foo<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
    |                                                   ++++
 
 error[E0311]: the parameter type `G` may not live long enough
-  --> $DIR/missing-lifetimes-in-signature.rs:32:5
+  --> $DIR/missing-lifetimes-in-signature.rs:31:5
    |
 LL | /     move || {
 LL | |         *dest = g.get();
@@ -36,9 +36,20 @@ note: the parameter type `G` must be valid for the anonymous lifetime defined he
    |
 LL | fn bar<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
    |                          ^^^^^^
+note: ...so that the type `G` will meet its required lifetime bounds
+  --> $DIR/missing-lifetimes-in-signature.rs:31:5
+   |
+LL | /     move || {
+LL | |         *dest = g.get();
+LL | |     }
+   | |_____^
+help: consider adding an explicit lifetime bound...
+   |
+LL |     G: Get<T> + 'a,
+   |               ++++
 
 error[E0311]: the parameter type `G` may not live long enough
-  --> $DIR/missing-lifetimes-in-signature.rs:55:5
+  --> $DIR/missing-lifetimes-in-signature.rs:53:5
    |
 LL | /     move || {
 LL | |         *dest = g.get();
@@ -46,13 +57,24 @@ LL | |     }
    | |_____^
    |
 note: the parameter type `G` must be valid for the anonymous lifetime defined here...
-  --> $DIR/missing-lifetimes-in-signature.rs:49:34
+  --> $DIR/missing-lifetimes-in-signature.rs:48:34
    |
 LL | fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
    |                                  ^^^^^^
+note: ...so that the type `G` will meet its required lifetime bounds
+  --> $DIR/missing-lifetimes-in-signature.rs:53:5
+   |
+LL | /     move || {
+LL | |         *dest = g.get();
+LL | |     }
+   | |_____^
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn qux<'a, G: 'a + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+   |                  ++++
 
 error[E0311]: the parameter type `G` may not live long enough
-  --> $DIR/missing-lifetimes-in-signature.rs:65:9
+  --> $DIR/missing-lifetimes-in-signature.rs:62:9
    |
 LL | /         move || {
 LL | |             *dest = g.get();
@@ -60,13 +82,24 @@ LL | |         }
    | |_________^
    |
 note: the parameter type `G` must be valid for the anonymous lifetime defined here...
-  --> $DIR/missing-lifetimes-in-signature.rs:62:47
+  --> $DIR/missing-lifetimes-in-signature.rs:60:47
    |
 LL |     fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
    |                                               ^^^^^^
+note: ...so that the type `G` will meet its required lifetime bounds
+  --> $DIR/missing-lifetimes-in-signature.rs:62:9
+   |
+LL | /         move || {
+LL | |             *dest = g.get();
+LL | |         }
+   | |_________^
+help: consider adding an explicit lifetime bound...
+   |
+LL |     fn qux<'b, G: Get<T> + 'b + 'c, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
+   |                               ++++
 
 error[E0311]: the parameter type `G` may not live long enough
-  --> $DIR/missing-lifetimes-in-signature.rs:77:5
+  --> $DIR/missing-lifetimes-in-signature.rs:74:5
    |
 LL | /     move || {
 LL | |         *dest = g.get();
@@ -74,13 +107,24 @@ LL | |     }
    | |_____^
    |
 note: the parameter type `G` must be valid for the anonymous lifetime defined here...
-  --> $DIR/missing-lifetimes-in-signature.rs:72:34
+  --> $DIR/missing-lifetimes-in-signature.rs:69:34
    |
 LL | fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a
    |                                  ^^^^^^
+note: ...so that the type `G` will meet its required lifetime bounds
+  --> $DIR/missing-lifetimes-in-signature.rs:74:5
+   |
+LL | /     move || {
+LL | |         *dest = g.get();
+LL | |     }
+   | |_____^
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn bat<'a, G: 'a + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a
+   |                  ++++
 
 error[E0621]: explicit lifetime required in the type of `dest`
-  --> $DIR/missing-lifetimes-in-signature.rs:77:5
+  --> $DIR/missing-lifetimes-in-signature.rs:74:5
    |
 LL |   fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a
    |                                    ------ help: add explicit lifetime `'a` to the type of `dest`: `&'a mut T`
@@ -91,14 +135,17 @@ LL | |     }
    | |_____^ lifetime `'a` required
 
 error[E0309]: the parameter type `G` may not live long enough
-  --> $DIR/missing-lifetimes-in-signature.rs:89:5
+  --> $DIR/missing-lifetimes-in-signature.rs:85:5
    |
 LL | /     move || {
 LL | |         *dest = g.get();
 LL | |     }
-   | |_____^
+   | |_____^ ...so that the type `G` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
    |
-   = help: consider adding an explicit lifetime bound `G: 'a`...
+LL |     G: Get<T> + 'a,
+   |               ++++
 
 error: aborting due to 8 previous errors
 
index 647b343fe06947c43727e39ec7b84c87a1ad5e73..0a3e6b481632d883826e4a6e620a5042f3219ca6 100644 (file)
@@ -28,7 +28,6 @@ fn bar<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
 where
     G: Get<T>,
 {
-    //~^ ERROR the parameter type `G` may not live long enough
     move || {
         *dest = g.get();
     }
@@ -51,7 +50,6 @@ fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
 where
     G: Get<T>,
 {
-    //~^ ERROR the parameter type `G` may not live long enough
     move || {
         *dest = g.get();
     }
@@ -61,7 +59,6 @@ fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
 impl<'a> Foo {
     fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
         //~^ ERROR the parameter type `G` may not live long enough
-        //~| ERROR the parameter type `G` may not live long enough
         move || {
             *dest = g.get();
         }
@@ -85,7 +82,6 @@ fn bak<'a, G, T>(g: G, dest: &'a mut T) -> impl FnOnce() + 'a
 where
     G: Get<T>,
 {
-    //~^ ERROR the parameter type `G` may not live long enough
     move || {
         *dest = g.get();
     }
index 6d538dfd609a80b47df0c180df5646e31308b387..ae9a020a099f49c1ba175f597a63656493878ba2 100644 (file)
@@ -1,5 +1,5 @@
 error[E0261]: use of undeclared lifetime name `'a`
-  --> $DIR/missing-lifetimes-in-signature.rs:38:11
+  --> $DIR/missing-lifetimes-in-signature.rs:37:11
    |
 LL | fn baz<G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
    |        -  ^^ undeclared lifetime
@@ -34,172 +34,63 @@ note: the parameter type `G` must be valid for the anonymous lifetime defined he
    |
 LL | fn bar<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
    |                          ^^^^^^
-note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:32:5: 34:6]` will meet its required lifetime bounds
+note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:31:5: 33:6]` will meet its required lifetime bounds
   --> $DIR/missing-lifetimes-in-signature.rs:26:37
    |
 LL | fn bar<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
    |                                     ^^^^^^^^^^^^^^^^^^
 help: consider introducing an explicit lifetime bound
    |
-LL | fn bar<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a
-   |        ~~~~~                                                   ++++
-
-error[E0311]: the parameter type `G` may not live long enough
-  --> $DIR/missing-lifetimes-in-signature.rs:30:1
-   |
-LL | / {
-LL | |
-LL | |     move || {
-LL | |         *dest = g.get();
-LL | |     }
-LL | | }
-   | |_^
-   |
-note: the parameter type `G` must be valid for the anonymous lifetime defined here...
-  --> $DIR/missing-lifetimes-in-signature.rs:26:26
-   |
-LL | fn bar<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
-   |                          ^^^^^^
-note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:32:5: 34:6]` will meet its required lifetime bounds
-  --> $DIR/missing-lifetimes-in-signature.rs:30:1
-   |
-LL | / {
-LL | |
-LL | |     move || {
-LL | |         *dest = g.get();
-LL | |     }
-LL | | }
-   | |_^
-help: consider introducing an explicit lifetime bound
-   |
-LL ~ fn bar<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+LL ~ fn bar<'a, G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a
 LL |
 LL | where
-LL |     G: Get<T>,
-LL | {
-LL |
- ...
+LL ~     G: Get<T> + 'a,
+   |
 
 error[E0311]: the parameter type `G` may not live long enough
-  --> $DIR/missing-lifetimes-in-signature.rs:49:45
+  --> $DIR/missing-lifetimes-in-signature.rs:48:45
    |
 LL | fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
    |                                             ^^^^^^^^^^^^^^^^^^
    |
 note: the parameter type `G` must be valid for the anonymous lifetime defined here...
-  --> $DIR/missing-lifetimes-in-signature.rs:49:34
+  --> $DIR/missing-lifetimes-in-signature.rs:48:34
    |
 LL | fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
    |                                  ^^^^^^
-note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:55:5: 57:6]` will meet its required lifetime bounds
-  --> $DIR/missing-lifetimes-in-signature.rs:49:45
+note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:53:5: 55:6]` will meet its required lifetime bounds
+  --> $DIR/missing-lifetimes-in-signature.rs:48:45
    |
 LL | fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
    |                                             ^^^^^^^^^^^^^^^^^^
 help: consider introducing an explicit lifetime bound
    |
-LL | fn qux<'b, 'a, G: 'b + 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'b
-   |        +++     ~~~~~~~                                                  ++++
-
-error[E0311]: the parameter type `G` may not live long enough
-  --> $DIR/missing-lifetimes-in-signature.rs:53:1
-   |
-LL | / {
-LL | |
-LL | |     move || {
-LL | |         *dest = g.get();
-LL | |     }
-LL | | }
-   | |_^
-   |
-note: the parameter type `G` must be valid for the anonymous lifetime defined here...
-  --> $DIR/missing-lifetimes-in-signature.rs:49:34
-   |
-LL | fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
-   |                                  ^^^^^^
-note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:55:5: 57:6]` will meet its required lifetime bounds
-  --> $DIR/missing-lifetimes-in-signature.rs:53:1
-   |
-LL | / {
-LL | |
-LL | |     move || {
-LL | |         *dest = g.get();
-LL | |     }
-LL | | }
-   | |_^
-help: consider introducing an explicit lifetime bound
-   |
-LL ~ fn qux<'b, 'a, G: 'b + 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
-LL |
-LL | where
-LL |     G: Get<T>,
-LL | {
-LL |
- ...
+LL | fn qux<'b, 'a, G: 'a + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'b
+   |        +++           ++++                                               ++++
 
 error[E0311]: the parameter type `G` may not live long enough
-  --> $DIR/missing-lifetimes-in-signature.rs:62:58
+  --> $DIR/missing-lifetimes-in-signature.rs:60:58
    |
 LL |     fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
    |                                                          ^^^^^^^^^^^^^^^^^^
    |
 note: the parameter type `G` must be valid for the anonymous lifetime defined here...
-  --> $DIR/missing-lifetimes-in-signature.rs:62:47
+  --> $DIR/missing-lifetimes-in-signature.rs:60:47
    |
 LL |     fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
    |                                               ^^^^^^
-note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:65:9: 67:10]` will meet its required lifetime bounds
-  --> $DIR/missing-lifetimes-in-signature.rs:62:58
+note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:62:9: 64:10]` will meet its required lifetime bounds
+  --> $DIR/missing-lifetimes-in-signature.rs:60:58
    |
 LL |     fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
    |                                                          ^^^^^^^^^^^^^^^^^^
 help: consider introducing an explicit lifetime bound
    |
-LL |     fn qux<'c, 'b, G: 'c + Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'c {
-   |            +++     ~~~~~~~                                                           ++++
-
-error[E0311]: the parameter type `G` may not live long enough
-  --> $DIR/missing-lifetimes-in-signature.rs:62:77
-   |
-LL |       fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
-   |  _____________________________________________________________________________^
-LL | |
-LL | |
-LL | |         move || {
-LL | |             *dest = g.get();
-LL | |         }
-LL | |     }
-   | |_____^
-   |
-note: the parameter type `G` must be valid for the anonymous lifetime defined here...
-  --> $DIR/missing-lifetimes-in-signature.rs:62:47
-   |
-LL |     fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
-   |                                               ^^^^^^
-note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:65:9: 67:10]` will meet its required lifetime bounds
-  --> $DIR/missing-lifetimes-in-signature.rs:62:77
-   |
-LL |       fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
-   |  _____________________________________________________________________________^
-LL | |
-LL | |
-LL | |         move || {
-LL | |             *dest = g.get();
-LL | |         }
-LL | |     }
-   | |_____^
-help: consider introducing an explicit lifetime bound
-   |
-LL ~     fn qux<'c, 'b, G: 'c + Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
-LL |
-LL |
-LL |         move || {
-LL |             *dest = g.get();
-LL |         }
- ...
+LL |     fn qux<'c, 'b, G: Get<T> + 'b + 'c, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'c {
+   |            +++                    ++++                                               ++++
 
 error[E0621]: explicit lifetime required in the type of `dest`
-  --> $DIR/missing-lifetimes-in-signature.rs:72:45
+  --> $DIR/missing-lifetimes-in-signature.rs:69:45
    |
 LL | fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a
    |                                  ------     ^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'a` required
@@ -207,28 +98,17 @@ LL | fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a
    |                                  help: add explicit lifetime `'a` to the type of `dest`: `&'a mut T`
 
 error[E0309]: the parameter type `G` may not live long enough
-  --> $DIR/missing-lifetimes-in-signature.rs:83:44
+  --> $DIR/missing-lifetimes-in-signature.rs:80:44
    |
 LL | fn bak<'a, G, T>(g: G, dest: &'a mut T) -> impl FnOnce() + 'a
-   |            -                               ^^^^^^^^^^^^^^^^^^ ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:89:5: 91:6]` will meet its required lifetime bounds
-   |            |
-   |            help: consider adding an explicit lifetime bound...: `G: 'a`
-
-error[E0309]: the parameter type `G` may not live long enough
-  --> $DIR/missing-lifetimes-in-signature.rs:87:1
+   |                                            ^^^^^^^^^^^^^^^^^^ ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:85:5: 87:6]` will meet its required lifetime bounds
    |
-LL |   fn bak<'a, G, T>(g: G, dest: &'a mut T) -> impl FnOnce() + 'a
-   |              - help: consider adding an explicit lifetime bound...: `G: 'a`
-...
-LL | / {
-LL | |
-LL | |     move || {
-LL | |         *dest = g.get();
-LL | |     }
-LL | | }
-   | |_^ ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:89:5: 91:6]` will meet its required lifetime bounds
+help: consider adding an explicit lifetime bound...
+   |
+LL |     G: Get<T> + 'a,
+   |               ++++
 
-error: aborting due to 11 previous errors
+error: aborting due to 7 previous errors
 
 Some errors have detailed explanations: E0261, E0309, E0621, E0700.
 For more information about an error, try `rustc --explain E0261`.
index 3ed3827b97da3b0b38c2c78a45d214e95ce1fd46..6c65e4f0175428e10640dac31ffcac1d78bb3785 100644 (file)
@@ -9,10 +9,14 @@ LL | |             remaining: self.0.iter(),
 LL | |         }
    | |_________^ returning this value requires that `'1` must outlive `'static`
    |
-help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as a bound
+help: to declare that the `impl Trait` captures data from argument `self`, you can add an explicit `'_` lifetime bound
    |
 LL |     fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> + '_ {
    |                                                          ++++
+help: to declare that the trait object captures data from argument `self`, you can add an explicit `'_` lifetime bound
+   |
+LL |     fn iter(&self) -> impl Iterator<Item = Box<dyn Foo + '_>> {
+   |                                                        ++++
 
 error: lifetime may not live long enough
   --> $DIR/trait-object-nested-in-impl-trait.rs:39:9
@@ -24,6 +28,11 @@ LL | |             current: None,
 LL | |             remaining: self.0.iter(),
 LL | |         }
    | |_________^ returning this value requires that `'1` must outlive `'static`
+   |
+help: to declare that the trait object captures data from argument `self`, you can add an explicit `'_` lifetime bound
+   |
+LL |     fn iter(&self) -> impl Iterator<Item = Box<dyn Foo + '_>> + '_ {
+   |                                                        ++++
 
 error: lifetime may not live long enough
   --> $DIR/trait-object-nested-in-impl-trait.rs:50:9
@@ -35,6 +44,11 @@ LL | |             current: None,
 LL | |             remaining: self.0.iter(),
 LL | |         }
    | |_________^ returning this value requires that `'a` must outlive `'static`
+   |
+help: to declare that the trait object captures data from argument `self`, you can add an explicit `'a` lifetime bound
+   |
+LL |     fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo + 'a>> + 'a {
+   |                                                               ++++
 
 error: lifetime may not live long enough
   --> $DIR/trait-object-nested-in-impl-trait.rs:61:9
@@ -47,10 +61,14 @@ LL | |             remaining: self.0.iter(),
 LL | |         }
    | |_________^ returning this value requires that `'a` must outlive `'static`
    |
-help: to allow this `impl Trait` to capture borrowed data with lifetime `'a`, add `'a` as a bound
+help: to declare that the `impl Trait` captures data from argument `self`, you can add an explicit `'a` lifetime bound
    |
 LL |     fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> + 'a {
    |                                                                 ++++
+help: to declare that the trait object captures data from argument `self`, you can add an explicit `'a` lifetime bound
+   |
+LL |     fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo + 'a>> {
+   |                                                               ++++
 
 error: aborting due to 4 previous errors
 
index 551a7c5060fc743e9b677ab3a67d63e0954e3fa0..01c2de7986419bed90a66cdce1f833ae9c503c4f 100644 (file)
@@ -85,8 +85,8 @@ LL | fn is_send<T: Send>(val: T) {}
    |               ^^^^ required by this bound in `is_send`
 help: consider further restricting this bound
    |
-LL | fn use_bound_and_where<S: Sync>(val: S) where S: std::fmt::Debug + std::marker::Send {
-   |                                                                  +++++++++++++++++++
+LL | fn use_bound_and_where<S: Sync + std::marker::Send>(val: S) where S: std::fmt::Debug {
+   |                                +++++++++++++++++++
 
 error[E0277]: `S` cannot be sent between threads safely
   --> $DIR/restrict-type-argument.rs:28:13
index f4eb9813c1ac77f3fe19621fecfe149db2659b95..cf912f4aac201284d87fd333382496edb3dfcdd3 100644 (file)
@@ -2,9 +2,12 @@ error[E0310]: the parameter type `impl Debug` may not live long enough
   --> $DIR/suggest-impl-trait-lifetime.rs:7:5
    |
 LL |     bar(d);
-   |     ^^^^^^
+   |     ^^^^^^ ...so that the type `impl Debug` will meet its required lifetime bounds
    |
-   = help: consider adding an explicit lifetime bound `impl Debug: 'static`...
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn foo(d: impl Debug + 'static) {
+   |                      +++++++++
 
 error: aborting due to previous error
 
index e4a247993c29b67df00219f1961e5f1bb888acfe..4a99c3a14d7bbc9c7146e4fa36553e7e3c51f4fc 100644 (file)
@@ -1,9 +1,6 @@
 error[E0310]: the parameter type `impl Debug` may not live long enough
   --> $DIR/suggest-impl-trait-lifetime.rs:7:5
    |
-LL | fn foo(d: impl Debug) {
-   |           ---------- help: consider adding an explicit lifetime bound...: `impl Debug + 'static`
-LL |
 LL |     bar(d);
    |     ^^^ ...so that the type `impl Debug` will meet its required lifetime bounds...
    |
@@ -12,6 +9,10 @@ note: ...that is required by this bound
    |
 LL | fn bar(d: impl Debug + 'static) {
    |                        ^^^^^^^
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn foo(d: impl Debug + 'static) {
+   |                      +++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/suggestions/suggest-using-chars.rs b/src/test/ui/suggestions/suggest-using-chars.rs
new file mode 100644 (file)
index 0000000..9573288
--- /dev/null
@@ -0,0 +1,7 @@
+pub fn main() {
+    let _ = "foo".iter(); //~ ERROR no method named `iter` found for reference `&'static str` in the current scope
+    let _ = "foo".foo(); //~ ERROR no method named `foo` found for reference `&'static str` in the current scope
+    let _ = String::from("bar").iter(); //~ ERROR no method named `iter` found for struct `String` in the current scope
+    let _ = (&String::from("bar")).iter(); //~ ERROR no method named `iter` found for reference `&String` in the current scope
+    let _ = 0.iter(); //~ ERROR no method named `iter` found for type `{integer}` in the current scope
+}
diff --git a/src/test/ui/suggestions/suggest-using-chars.stderr b/src/test/ui/suggestions/suggest-using-chars.stderr
new file mode 100644 (file)
index 0000000..99bcfb0
--- /dev/null
@@ -0,0 +1,48 @@
+error[E0599]: no method named `iter` found for reference `&'static str` in the current scope
+  --> $DIR/suggest-using-chars.rs:2:19
+   |
+LL |     let _ = "foo".iter();
+   |                   ^^^^ method not found in `&'static str`
+   |
+help: because of the in-memory representation of `&str`, to obtain an `Iterator` over each of its codepoint use method `chars`
+   |
+LL |     let _ = "foo".chars();
+   |                   ~~~~~
+
+error[E0599]: no method named `foo` found for reference `&'static str` in the current scope
+  --> $DIR/suggest-using-chars.rs:3:19
+   |
+LL |     let _ = "foo".foo();
+   |                   ^^^ method not found in `&'static str`
+
+error[E0599]: no method named `iter` found for struct `String` in the current scope
+  --> $DIR/suggest-using-chars.rs:4:33
+   |
+LL |     let _ = String::from("bar").iter();
+   |                                 ^^^^ method not found in `String`
+   |
+help: because of the in-memory representation of `&str`, to obtain an `Iterator` over each of its codepoint use method `chars`
+   |
+LL |     let _ = String::from("bar").chars();
+   |                                 ~~~~~
+
+error[E0599]: no method named `iter` found for reference `&String` in the current scope
+  --> $DIR/suggest-using-chars.rs:5:36
+   |
+LL |     let _ = (&String::from("bar")).iter();
+   |                                    ^^^^ method not found in `&String`
+   |
+help: because of the in-memory representation of `&str`, to obtain an `Iterator` over each of its codepoint use method `chars`
+   |
+LL |     let _ = (&String::from("bar")).chars();
+   |                                    ~~~~~
+
+error[E0599]: no method named `iter` found for type `{integer}` in the current scope
+  --> $DIR/suggest-using-chars.rs:6:15
+   |
+LL |     let _ = 0.iter();
+   |               ^^^^ method not found in `{integer}`
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/ui/symbol-names/x86-stdcall.rs b/src/test/ui/symbol-names/x86-stdcall.rs
new file mode 100644 (file)
index 0000000..9948488
--- /dev/null
@@ -0,0 +1,13 @@
+// build-pass
+// only-x86-windows
+#![crate_type = "cdylib"]
+#![feature(abi_vectorcall)]
+
+#[no_mangle]
+extern "stdcall" fn foo(_: bool) {}
+
+#[no_mangle]
+extern "fastcall" fn bar(_: u8) {}
+
+#[no_mangle]
+extern "vectorcall" fn baz(_: u16) {}
diff --git a/src/test/ui/threads-sendsync/issue-29488.rs b/src/test/ui/threads-sendsync/issue-29488.rs
new file mode 100644 (file)
index 0000000..3c9a6a8
--- /dev/null
@@ -0,0 +1,23 @@
+// run-pass
+// ignore-emscripten no threads support
+
+use std::thread;
+
+struct Foo;
+
+impl Drop for Foo {
+    fn drop(&mut self) {
+        println!("test2");
+    }
+}
+
+thread_local!(static FOO: Foo = Foo);
+
+fn main() {
+    // Off the main thread due to #28129, be sure to initialize FOO first before
+    // calling `println!`
+    thread::spawn(|| {
+        FOO.with(|_| {});
+        println!("test1");
+    }).join().unwrap();
+}
index 8dc0e75f1af22467dc3f416b3f48439d5b07f228..1e21a6b37a991eff5e7c01dda28a5c6b04f47fb0 100644 (file)
@@ -1,5 +1,5 @@
 error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
-  --> $DIR/issue-43733.rs:19:5
+  --> $DIR/issue-43733.rs:21:5
    |
 LL |     __KEY.get(Default::default)
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
@@ -7,7 +7,7 @@ LL |     __KEY.get(Default::default)
    = note: consult the function's documentation for information on how to avoid undefined behavior
 
 error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
-  --> $DIR/issue-43733.rs:22:42
+  --> $DIR/issue-43733.rs:26:42
    |
 LL | static FOO: std::thread::LocalKey<Foo> = std::thread::LocalKey::new(__getit);
    |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
index 9926ed09bb4a84088a35e520f0bcd0124fef0a4b..0ac6f588fb1d9976f9bd7b84fdb776d0f6be3f97 100644 (file)
@@ -1,5 +1,7 @@
 // revisions: mir thir
 // [thir]compile-flags: -Z thir-unsafeck
+// normalize-stderr-test: "__FastLocalKeyInner::<T>::get" -> "$$LOCALKEYINNER::<T>::get"
+// normalize-stderr-test: "__OsLocalKeyInner::<T>::get" -> "$$LOCALKEYINNER::<T>::get"
 
 #![feature(thread_local)]
 #![feature(cfg_target_thread_local, thread_local_internals)]
 static __KEY: std::thread::__OsLocalKeyInner<Foo> = std::thread::__OsLocalKeyInner::new();
 
 fn __getit(_: Option<&mut Option<RefCell<String>>>) -> std::option::Option<&'static Foo> {
-    __KEY.get(Default::default) //~ ERROR call to unsafe function is unsafe
+    __KEY.get(Default::default)
+    //[mir]~^ ERROR call to unsafe function is unsafe
+    //[thir]~^^ ERROR call to unsafe function `__
 }
 
 static FOO: std::thread::LocalKey<Foo> = std::thread::LocalKey::new(__getit);
-//~^ ERROR call to unsafe function is unsafe
+//[mir]~^ ERROR call to unsafe function is unsafe
+//[thir]~^^ ERROR call to unsafe function `LocalKey::<T>::new`
 
 fn main() {
     FOO.with(|foo| println!("{}", foo.borrow()));
index 8dc0e75f1af22467dc3f416b3f48439d5b07f228..ea7ff4080486dce986548b72c56054486c6b10f3 100644 (file)
@@ -1,13 +1,13 @@
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
-  --> $DIR/issue-43733.rs:19:5
+error[E0133]: call to unsafe function `$LOCALKEYINNER::<T>::get` is unsafe and requires unsafe function or block
+  --> $DIR/issue-43733.rs:21:5
    |
 LL |     __KEY.get(Default::default)
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
    |
    = note: consult the function's documentation for information on how to avoid undefined behavior
 
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
-  --> $DIR/issue-43733.rs:22:42
+error[E0133]: call to unsafe function `LocalKey::<T>::new` is unsafe and requires unsafe function or block
+  --> $DIR/issue-43733.rs:26:42
    |
 LL | static FOO: std::thread::LocalKey<Foo> = std::thread::LocalKey::new(__getit);
    |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
diff --git a/src/test/ui/traits/do-not-mention-type-params-by-name-in-suggestion-issue-96292.rs b/src/test/ui/traits/do-not-mention-type-params-by-name-in-suggestion-issue-96292.rs
new file mode 100644 (file)
index 0000000..9a444be
--- /dev/null
@@ -0,0 +1,20 @@
+struct Thing<X>(X);
+
+trait Method<T> {
+    fn method(self, _: i32) -> T;
+}
+
+impl<X> Method<i32> for Thing<X> {
+    fn method(self, _: i32) -> i32 { 0 }
+}
+
+impl<X> Method<u32> for Thing<X> {
+    fn method(self, _: i32) -> u32 { 0 }
+}
+
+fn main() {
+    let thing = Thing(true);
+    thing.method(42);
+    //~^ ERROR type annotations needed
+    //~| ERROR type annotations needed
+}
diff --git a/src/test/ui/traits/do-not-mention-type-params-by-name-in-suggestion-issue-96292.stderr b/src/test/ui/traits/do-not-mention-type-params-by-name-in-suggestion-issue-96292.stderr
new file mode 100644 (file)
index 0000000..0e52420
--- /dev/null
@@ -0,0 +1,37 @@
+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`
+
+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
+   |
+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
+   |
+LL |     <Thing<_> as Method<i32>>::method(thing, 42);
+   |     ++++++++++++++++++++++++++++++++++     ~
+LL |     <Thing<_> as Method<u32>>::method(thing, 42);
+   |     ++++++++++++++++++++++++++++++++++     ~
+
+error: aborting due to 2 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/issue-32963.rs b/src/test/ui/traits/issue-32963.rs
new file mode 100644 (file)
index 0000000..58055cd
--- /dev/null
@@ -0,0 +1,12 @@
+use std::mem;
+
+trait Misc {}
+
+fn size_of_copy<T: Copy+?Sized>() -> usize { mem::size_of::<T>() }
+
+fn main() {
+    size_of_copy::<dyn Misc + Copy>();
+    //~^ ERROR only auto traits can be used as additional traits in a trait object
+    //~| ERROR only auto traits can be used as additional traits in a trait object
+    //~| ERROR the trait bound `dyn Misc: Copy` is not satisfied
+}
diff --git a/src/test/ui/traits/issue-32963.stderr b/src/test/ui/traits/issue-32963.stderr
new file mode 100644 (file)
index 0000000..5e7762b
--- /dev/null
@@ -0,0 +1,38 @@
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/issue-32963.rs:8:31
+   |
+LL |     size_of_copy::<dyn Misc + Copy>();
+   |                        ----   ^^^^ additional non-auto trait
+   |                        |
+   |                        first non-auto trait
+   |
+   = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Misc + Copy {}`
+   = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/issue-32963.rs:8:31
+   |
+LL |     size_of_copy::<dyn Misc + Copy>();
+   |                        ----   ^^^^ additional non-auto trait
+   |                        |
+   |                        first non-auto trait
+   |
+   = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Misc + Copy {}`
+   = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
+
+error[E0277]: the trait bound `dyn Misc: Copy` is not satisfied
+  --> $DIR/issue-32963.rs:8:5
+   |
+LL |     size_of_copy::<dyn Misc + Copy>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `dyn Misc`
+   |
+note: required by a bound in `size_of_copy`
+  --> $DIR/issue-32963.rs:5:20
+   |
+LL | fn size_of_copy<T: Copy+?Sized>() -> usize { mem::size_of::<T>() }
+   |                    ^^^^ required by this bound in `size_of_copy`
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0225, E0277.
+For more information about an error, try `rustc --explain E0225`.
diff --git a/src/test/ui/traits/issue-4107.rs b/src/test/ui/traits/issue-4107.rs
new file mode 100644 (file)
index 0000000..98433e8
--- /dev/null
@@ -0,0 +1,26 @@
+// run-pass
+#![allow(dead_code)]
+
+pub fn main() {
+    let _id: &Mat2<f64> = &Matrix::identity(1.0);
+}
+
+pub trait Index<Index,Result> { fn get(&self, _: Index) -> Result { panic!() } }
+pub trait Dimensional<T>: Index<usize, T> { }
+
+pub struct Mat2<T> { x: T }
+pub struct Vec2<T> { x: T }
+
+impl<T> Dimensional<Vec2<T>> for Mat2<T> { }
+impl<T> Index<usize, Vec2<T>> for Mat2<T> { }
+
+impl<T> Dimensional<T> for Vec2<T> { }
+impl<T> Index<usize, T> for Vec2<T> { }
+
+pub trait Matrix<T,V>: Dimensional<V> {
+    fn identity(t:T) -> Self;
+}
+
+impl<T> Matrix<T, Vec2<T>> for Mat2<T> {
+    fn identity(t:T) -> Mat2<T> { Mat2{ x: t } }
+}
diff --git a/src/test/ui/traits/issue-43132.rs b/src/test/ui/traits/issue-43132.rs
new file mode 100644 (file)
index 0000000..c886f4b
--- /dev/null
@@ -0,0 +1,65 @@
+// run-pass
+#![allow(unused)]
+
+fn main() {
+}
+
+fn foo() {
+    let b = mk::<
+        Forward<(Box<dyn Future<Error = u32>>,)>,
+    >();
+    b.map_err(|_| ()).join();
+}
+
+fn mk<T>() -> T {
+    loop {}
+}
+
+impl<I: Future<Error = E>, E> Future for (I,) {
+    type Error = E;
+}
+
+struct Forward<T: Future> {
+    _a: T,
+}
+
+impl<T: Future> Future for Forward<T>
+where
+    T::Error: From<u32>,
+{
+    type Error = T::Error;
+}
+
+trait Future {
+    type Error;
+
+    fn map_err<F, E>(self, _: F) -> (Self, F)
+    where
+        F: FnOnce(Self::Error) -> E,
+        Self: Sized,
+    {
+        loop {}
+    }
+
+    fn join(self) -> (MaybeDone<Self>, ())
+    where
+        Self: Sized,
+    {
+        loop {}
+    }
+}
+
+impl<S: ?Sized + Future> Future for Box<S> {
+    type Error = S::Error;
+}
+
+enum MaybeDone<A: Future> {
+    _Done(A::Error),
+}
+
+impl<U, A: Future, F> Future for (A, F)
+where
+    F: FnOnce(A::Error) -> U,
+{
+    type Error = U;
+}
index cb1128fe5c66912dd68d1478195b7a58d0010a64..35d41c6266761680735097ff32e80c8418f3ad32 100644 (file)
@@ -7,8 +7,8 @@ LL |     t.foo()
    = help: items from traits can only be used if the type parameter is bounded by the trait
 help: the following trait defines an item `foo`, perhaps you need to restrict type parameter `T` with it:
    |
-LL | fn do_stuff<T: Foo + Bar>(t : T) {
-   |             ~~~~~~~~
+LL | fn do_stuff<T : Bar + Foo>(t : T) {
+   |                     +++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/traits/issue-71036.rs b/src/test/ui/traits/issue-71036.rs
new file mode 100644 (file)
index 0000000..3d2df6f
--- /dev/null
@@ -0,0 +1,17 @@
+#![feature(unsize, dispatch_from_dyn)]
+
+use std::marker::Unsize;
+use std::ops::DispatchFromDyn;
+
+#[allow(unused)]
+struct Foo<'a, T: ?Sized> {
+    _inner: &'a &'a T,
+}
+
+impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Foo<'a, U>> for Foo<'a, T> {}
+//~^ ERROR the trait bound `&'a T: Unsize<&'a U>` is not satisfied
+//~| NOTE the trait `Unsize<&'a U>` is not implemented for `&'a T`
+//~| NOTE all implementations of `Unsize` are provided automatically by the compiler
+//~| NOTE required because of the requirements on the impl
+
+fn main() {}
diff --git a/src/test/ui/traits/issue-71036.stderr b/src/test/ui/traits/issue-71036.stderr
new file mode 100644 (file)
index 0000000..db1f694
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0277]: the trait bound `&'a T: Unsize<&'a U>` is not satisfied
+  --> $DIR/issue-71036.rs:11:1
+   |
+LL | impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Foo<'a, U>> for Foo<'a, T> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Unsize<&'a U>` is not implemented for `&'a T`
+   |
+   = note: all implementations of `Unsize` are provided automatically by the compiler, see <https://doc.rust-lang.org/stable/std/marker/trait.Unsize.html> for more information
+   = note: required because of the requirements on the impl of `DispatchFromDyn<&'a &'a U>` for `&'a &'a T`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
index 413225d45a62ce6d6cd8d24a7e97c0c3296afb0e..63c1cb3791edf4144f239cff2393d5918eb86f16 100644 (file)
@@ -37,13 +37,13 @@ LL |     opts.get(opt.as_ref());
 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
 
 error[E0283]: type annotations needed
index d7d4790539604cfe93ab894a0ac2d305d5ec0e64..0a58ad4b663eb3ee4174c802dbd289308bae4bfa 100644 (file)
@@ -8,7 +8,7 @@ LL |     t.clone();
 help: the following trait defines an item `clone`, perhaps you need to restrict type parameter `T` with it:
    |
 LL | fn foo<T: Clone>(t: T) {
-   |        ~~~~~~~~
+   |           +++++
 
 error: aborting due to previous error
 
index 049fffe165ab58a2fbdff5ebbc47766ddeb9adff..3ae6bf130cc7e8b9cb95dad9ca88685183f1a6ba 100644 (file)
@@ -6,10 +6,10 @@ LL |     a * b
    |     |
    |     &T
    |
-help: consider further restricting this bound
+help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
    |
-LL | fn foo<T: MyMul<f64, f64> + std::ops::Mul<Output = f64>>(a: &T, b: f64) -> f64 {
-   |                           +++++++++++++++++++++++++++++
+LL | fn foo<T: MyMul<f64, f64>>(a: &T, b: f64) -> f64 where &T: Mul<f64> {
+   |                                                  ++++++++++++++++++
 
 error: aborting due to previous error
 
index 1a4105231dc7501664eee87d446a7e2ac920c0bd..1dbf3ebdf827cea0f6d3d28958194a40fa600213 100644 (file)
@@ -31,7 +31,9 @@ LL | | }
    | |_- this function returns a `Result`
    |
    = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `Result<u64, String>`
-   = help: the trait `FromResidual<Result<Infallible, E>>` is implemented for `Result<T, F>`
+   = help: the following other types implement trait `FromResidual<R>`:
+             <Result<T, F> as FromResidual<Result<Infallible, E>>>
+             <Result<T, F> as FromResidual<Yeet<E>>>
 
 error[E0277]: the `?` operator can only be used on `Result`s in a function that returns `Result`
   --> $DIR/bad-interconversion.rs:17:31
@@ -44,7 +46,9 @@ LL | | }
    | |_- this function returns a `Result`
    |
    = help: the trait `FromResidual<ControlFlow<{integer}, Infallible>>` is not implemented for `Result<u64, String>`
-   = help: the trait `FromResidual<Result<Infallible, E>>` is implemented for `Result<T, F>`
+   = help: the following other types implement trait `FromResidual<R>`:
+             <Result<T, F> as FromResidual<Result<Infallible, E>>>
+             <Result<T, F> as FromResidual<Yeet<E>>>
 
 error[E0277]: the `?` operator can only be used on `Option`s, not `Result`s, in a function that returns `Option`
   --> $DIR/bad-interconversion.rs:22:22
@@ -57,7 +61,9 @@ LL | | }
    | |_- this function returns an `Option`
    |
    = help: the trait `FromResidual<Result<Infallible, &str>>` is not implemented for `Option<u16>`
-   = help: the trait `FromResidual` is implemented for `Option<T>`
+   = help: the following other types implement trait `FromResidual<R>`:
+             <Option<T> as FromResidual<Yeet<()>>>
+             <Option<T> as FromResidual>
 
 error[E0277]: the `?` operator can only be used on `Option`s in a function that returns `Option`
   --> $DIR/bad-interconversion.rs:27:33
@@ -70,7 +76,9 @@ LL | | }
    | |_- this function returns an `Option`
    |
    = help: the trait `FromResidual<ControlFlow<{integer}, Infallible>>` is not implemented for `Option<u64>`
-   = help: the trait `FromResidual` is implemented for `Option<T>`
+   = help: the following other types implement trait `FromResidual<R>`:
+             <Option<T> as FromResidual<Yeet<()>>>
+             <Option<T> as FromResidual>
 
 error[E0277]: the `?` operator can only be used on `ControlFlow`s in a function that returns `ControlFlow`
   --> $DIR/bad-interconversion.rs:32:39
index b0e4de8cb4bf59223fe8add972f19d2d8c543b01..ae5c3ad628281c3968e19bcbf79b15b1a32f23f0 100644 (file)
@@ -10,7 +10,9 @@ LL | | }
    | |_- this function returns a `Result`
    |
    = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `Result<(), ()>`
-   = help: the trait `FromResidual<Result<Infallible, E>>` is implemented for `Result<T, F>`
+   = help: the following other types implement trait `FromResidual<R>`:
+             <Result<T, F> as FromResidual<Result<Infallible, E>>>
+             <Result<T, F> as FromResidual<Yeet<E>>>
 
 error[E0277]: the `?` operator can only be used on `Option`s, not `Result`s, in a function that returns `Option`
   --> $DIR/option-to-result.rs:11:6
@@ -24,7 +26,9 @@ LL | | }
    | |_- this function returns an `Option`
    |
    = help: the trait `FromResidual<Result<Infallible, i32>>` is not implemented for `Option<i32>`
-   = help: the trait `FromResidual` is implemented for `Option<T>`
+   = help: the following other types implement trait `FromResidual<R>`:
+             <Option<T> as FromResidual<Yeet<()>>>
+             <Option<T> as FromResidual>
 
 error: aborting due to 2 previous errors
 
index 7b2a9a16f900b258ff5a1e80f9cb4dc203a5f721..ba85a7cada2329668ec3bebd3a3f3bb3a4fb05ba 100644 (file)
@@ -10,7 +10,9 @@ LL | | }
    | |_- this function returns a `Result`
    |
    = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `Result<u32, ()>`
-   = help: the trait `FromResidual<Result<Infallible, E>>` is implemented for `Result<T, F>`
+   = help: the following other types implement trait `FromResidual<R>`:
+             <Result<T, F> as FromResidual<Result<Infallible, E>>>
+             <Result<T, F> as FromResidual<Yeet<E>>>
 
 error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
   --> $DIR/try-on-option.rs:11:6
diff --git a/src/test/ui/try-trait/yeet-for-option.rs b/src/test/ui/try-trait/yeet-for-option.rs
new file mode 100644 (file)
index 0000000..753fbc1
--- /dev/null
@@ -0,0 +1,11 @@
+// run-pass
+
+#![feature(yeet_expr)]
+
+fn always_yeet() -> Option<String> {
+    do yeet;
+}
+
+fn main() {
+    assert_eq!(always_yeet(), None);
+}
diff --git a/src/test/ui/try-trait/yeet-for-result.rs b/src/test/ui/try-trait/yeet-for-result.rs
new file mode 100644 (file)
index 0000000..b7b1137
--- /dev/null
@@ -0,0 +1,11 @@
+// run-pass
+
+#![feature(yeet_expr)]
+
+fn always_yeet() -> Result<i32, String> {
+    do yeet "hello";
+}
+
+fn main() {
+    assert_eq!(always_yeet(), Err("hello".to_string()));
+}
index d87ef2ec79c1a26bd14f122938098e1605769ab1..920eef11da4b993dcdf66fb168602371b8145781 100644 (file)
@@ -2,7 +2,7 @@ warning: unnecessary lifetime parameter `'a`
   --> $DIR/bounds-are-checked.rs:8:6
    |
 LL | fn f<'a: 'static>(t: &'a str) -> X<'a> {
-   |      ^^^^^^^^^^^
+   |      ^^
    |
    = help: you can use the `'static` lifetime directly, in place of `'a`
 
index a3b410c2cfb8c4946c53b40be46e6e828b4bf979..593fb8af32f30400a1ce4f9bf9ed41a335b876a2 100644 (file)
@@ -19,10 +19,13 @@ LL | type WrongGeneric<T> = impl 'static;
 error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/generic_type_does_not_live_long_enough.rs:18:5
    |
-LL | fn wrong_generic<T>(t: T) -> WrongGeneric<T> {
-   |                  - help: consider adding an explicit lifetime bound...: `T: 'static`
 LL |     t
    |     ^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn wrong_generic<T: 'static>(t: T) -> WrongGeneric<T> {
+   |                   +++++++++
 
 error: aborting due to 3 previous errors
 
index db771d211322c8f53776a358d3e67c210c140468..593fb8af32f30400a1ce4f9bf9ed41a335b876a2 100644 (file)
@@ -20,9 +20,12 @@ error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/generic_type_does_not_live_long_enough.rs:18:5
    |
 LL |     t
-   |     ^
+   |     ^ ...so that the type `T` will meet its required lifetime bounds
    |
-   = help: consider adding an explicit lifetime bound `T: 'static`...
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn wrong_generic<T: 'static>(t: T) -> WrongGeneric<T> {
+   |                   +++++++++
 
 error: aborting due to 3 previous errors
 
index a46047d91743d899d83ca79db0bc1e75553de94d..5b3d7375de0e3ef1b21a700b7d8ea81b778a1134 100644 (file)
@@ -10,5 +10,5 @@ extern crate std;
 trait Animal { }
 
 fn main() {
-        pub type ServeFut = /*impl Trait*/;
+        type ServeFut = /*impl Trait*/;
     }
index 314e5362a8f2c1182da25d4652fb7e17d7e38312..82248971692ce4e5ab2e41abfebceda7000e205d 100644 (file)
@@ -11,7 +11,6 @@ impl Foo<()> for () { }
 
 fn foo() -> impl Foo<FooX> {
     //~^ ERROR: the trait bound `(): Foo<FooX>` is not satisfied
-    //~| ERROR: the trait bound `(): Foo<FooX>` is not satisfied
     // FIXME(type-alias-impl-trait): We could probably make this work.
     ()
 }
index 0df2b57d373b6435c796feff2b7817c768578861..f98da9f7f920a60cad1430f09feac794a34b77ae 100644 (file)
@@ -6,20 +6,6 @@ LL | fn foo() -> impl Foo<FooX> {
    |
    = help: the trait `Foo<()>` is implemented for `()`
 
-error[E0277]: the trait bound `(): Foo<FooX>` is not satisfied
-  --> $DIR/nested-tait-inference.rs:12:28
-   |
-LL |   fn foo() -> impl Foo<FooX> {
-   |  ____________________________^
-LL | |
-LL | |
-LL | |     // FIXME(type-alias-impl-trait): We could probably make this work.
-LL | |     ()
-LL | | }
-   | |_^ the trait `Foo<FooX>` is not implemented for `()`
-   |
-   = help: the trait `Foo<()>` is implemented for `()`
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0277`.
index 4dc30d9257bedcce07144604a146198d6fc49e78..0d7f5bad25f11bda3617c3e07facf5c3974c85c5 100644 (file)
@@ -12,7 +12,6 @@ impl Foo<u32> for () {}
 
 fn foo() -> impl Foo<FooX> {
     //~^ ERROR: the trait bound `(): Foo<FooX>` is not satisfied
-    //~| ERROR: the trait bound `(): Foo<FooX>` is not satisfied
     ()
 }
 
index 264e8024fac3a445fab636c6745c74568ee01a47..54f571ad3e37e616fed91f8bfedfac8d47978e60 100644 (file)
@@ -8,21 +8,6 @@ LL | fn foo() -> impl Foo<FooX> {
              <() as Foo<()>>
              <() as Foo<u32>>
 
-error[E0277]: the trait bound `(): Foo<FooX>` is not satisfied
-  --> $DIR/nested-tait-inference2.rs:13:28
-   |
-LL |   fn foo() -> impl Foo<FooX> {
-   |  ____________________________^
-LL | |
-LL | |
-LL | |     ()
-LL | | }
-   | |_^ the trait `Foo<FooX>` is not implemented for `()`
-   |
-   = help: the following other types implement trait `Foo<A>`:
-             <() as Foo<()>>
-             <() as Foo<u32>>
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0277`.
index 59b8692dd4d1a5851c920bf5205316fe884772e8..2b58cd4180bd337dbe1587faa416e5a971f7601b 100644 (file)
@@ -8,8 +8,8 @@ LL |     let z = x + y;
    |
 help: consider restricting type parameter `T`
    |
-LL | fn foo<T: std::ops::Add<Output = T>>(x: T, y: T) {
-   |         +++++++++++++++++++++++++++
+LL | fn foo<T: std::ops::Add>(x: T, y: T) {
+   |         +++++++++++++++
 
 error[E0368]: binary assignment operation `+=` cannot be applied to type `T`
   --> $DIR/missing_trait_impl.rs:9:5
@@ -32,8 +32,8 @@ LL |     let y = -x;
    |
 help: consider restricting type parameter `T`
    |
-LL | fn baz<T: std::ops::Neg<Output = T>>(x: T) {
-   |         +++++++++++++++++++++++++++
+LL | fn baz<T: std::ops::Neg>(x: T) {
+   |         +++++++++++++++
 
 error[E0600]: cannot apply unary operator `!` to type `T`
   --> $DIR/missing_trait_impl.rs:14:13
@@ -43,8 +43,8 @@ LL |     let y = !x;
    |
 help: consider restricting type parameter `T`
    |
-LL | fn baz<T: std::ops::Not<Output = T>>(x: T) {
-   |         +++++++++++++++++++++++++++
+LL | fn baz<T: std::ops::Not>(x: T) {
+   |         +++++++++++++++
 
 error[E0614]: type `T` cannot be dereferenced
   --> $DIR/missing_trait_impl.rs:15:13
diff --git a/src/test/ui/typeck/issue-87181/empty-tuple-method.rs b/src/test/ui/typeck/issue-87181/empty-tuple-method.rs
new file mode 100644 (file)
index 0000000..1875d82
--- /dev/null
@@ -0,0 +1,14 @@
+struct Bar<T> {
+    bar: T
+}
+
+struct Foo();
+impl Foo {
+    fn foo() { }
+}
+
+fn main() {
+    let thing = Bar { bar: Foo };
+    thing.bar.foo();
+    //~^ ERROR no method named `foo` found for fn item `fn() -> Foo {Foo}` in the current scope [E0599]
+}
diff --git a/src/test/ui/typeck/issue-87181/empty-tuple-method.stderr b/src/test/ui/typeck/issue-87181/empty-tuple-method.stderr
new file mode 100644 (file)
index 0000000..6ed70b3
--- /dev/null
@@ -0,0 +1,16 @@
+error[E0599]: no method named `foo` found for fn item `fn() -> Foo {Foo}` in the current scope
+  --> $DIR/empty-tuple-method.rs:12:15
+   |
+LL |     thing.bar.foo();
+   |     --------- ^^^ method not found in `fn() -> Foo {Foo}`
+   |     |
+   |     this is the constructor of a struct
+   |
+help: call the constructor
+   |
+LL |     (thing.bar)().foo();
+   |     +         +++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/ui/typeck/issue-87181/enum-variant.rs b/src/test/ui/typeck/issue-87181/enum-variant.rs
new file mode 100644 (file)
index 0000000..3b926b9
--- /dev/null
@@ -0,0 +1,16 @@
+struct Bar<T> {
+    bar: T
+}
+
+enum Foo{
+    Tup()
+}
+impl Foo {
+    fn foo() { }
+}
+
+fn main() {
+    let thing = Bar { bar: Foo::Tup };
+    thing.bar.foo();
+    //~^ ERROR no method named `foo` found for fn item `fn() -> Foo {Foo::Tup}` in the current scope [E0599]
+}
diff --git a/src/test/ui/typeck/issue-87181/enum-variant.stderr b/src/test/ui/typeck/issue-87181/enum-variant.stderr
new file mode 100644 (file)
index 0000000..a3a8186
--- /dev/null
@@ -0,0 +1,16 @@
+error[E0599]: no method named `foo` found for fn item `fn() -> Foo {Foo::Tup}` in the current scope
+  --> $DIR/enum-variant.rs:14:15
+   |
+LL |     thing.bar.foo();
+   |     --------- ^^^ method not found in `fn() -> Foo {Foo::Tup}`
+   |     |
+   |     this is the constructor of an enum variant
+   |
+help: call the constructor
+   |
+LL |     (thing.bar)().foo();
+   |     +         +++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/ui/typeck/issue-87181/tuple-field.rs b/src/test/ui/typeck/issue-87181/tuple-field.rs
new file mode 100644 (file)
index 0000000..00e3b46
--- /dev/null
@@ -0,0 +1,14 @@
+struct Bar<T> {
+    bar: T
+}
+
+struct Foo(char, u16);
+impl Foo {
+    fn foo() { }
+}
+
+fn main() {
+    let thing = Bar { bar: Foo };
+    thing.bar.0;
+    //~^ ERROR no field `0` on type `fn(char, u16) -> Foo {Foo}` [E0609]
+}
diff --git a/src/test/ui/typeck/issue-87181/tuple-field.stderr b/src/test/ui/typeck/issue-87181/tuple-field.stderr
new file mode 100644 (file)
index 0000000..4d22ada
--- /dev/null
@@ -0,0 +1,16 @@
+error[E0609]: no field `0` on type `fn(char, u16) -> Foo {Foo}`
+  --> $DIR/tuple-field.rs:12:15
+   |
+LL |     thing.bar.0;
+   |     --------- ^
+   |     |
+   |     this is the constructor of a struct
+   |
+help: call the constructor
+   |
+LL |     (thing.bar)(_, _).0;
+   |     +         +++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0609`.
diff --git a/src/test/ui/typeck/issue-87181/tuple-method.rs b/src/test/ui/typeck/issue-87181/tuple-method.rs
new file mode 100644 (file)
index 0000000..e88f642
--- /dev/null
@@ -0,0 +1,14 @@
+struct Bar<T> {
+    bar: T
+}
+
+struct Foo(u8, i32);
+impl Foo {
+    fn foo() { }
+}
+
+fn main() {
+    let thing = Bar { bar: Foo };
+    thing.bar.foo();
+    //~^ ERROR no method named `foo` found for fn item `fn(u8, i32) -> Foo {Foo}` in the current scope [E0599]
+}
diff --git a/src/test/ui/typeck/issue-87181/tuple-method.stderr b/src/test/ui/typeck/issue-87181/tuple-method.stderr
new file mode 100644 (file)
index 0000000..1e392e1
--- /dev/null
@@ -0,0 +1,16 @@
+error[E0599]: no method named `foo` found for fn item `fn(u8, i32) -> Foo {Foo}` in the current scope
+  --> $DIR/tuple-method.rs:12:15
+   |
+LL |     thing.bar.foo();
+   |     --------- ^^^ method not found in `fn(u8, i32) -> Foo {Foo}`
+   |     |
+   |     this is the constructor of a struct
+   |
+help: call the constructor
+   |
+LL |     (thing.bar)(_, _).foo();
+   |     +         +++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/ui/typeck/remove-extra-argument.fixed b/src/test/ui/typeck/remove-extra-argument.fixed
new file mode 100644 (file)
index 0000000..a9338c7
--- /dev/null
@@ -0,0 +1,9 @@
+// run-rustfix
+// Check that the HELP suggestion is `l(vec![])` instead of `l($crate::vec::Vec::new())`
+fn l(_a: Vec<u8>) {}
+
+fn main() {
+    l(vec![])
+    //~^ ERROR this function takes 1 argument but 2 arguments were supplied
+    //~| HELP remove the extra argument
+}
diff --git a/src/test/ui/typeck/remove-extra-argument.rs b/src/test/ui/typeck/remove-extra-argument.rs
new file mode 100644 (file)
index 0000000..659cb8b
--- /dev/null
@@ -0,0 +1,9 @@
+// run-rustfix
+// Check that the HELP suggestion is `l(vec![])` instead of `l($crate::vec::Vec::new())`
+fn l(_a: Vec<u8>) {}
+
+fn main() {
+    l(vec![], vec![])
+    //~^ ERROR this function takes 1 argument but 2 arguments were supplied
+    //~| HELP remove the extra argument
+}
diff --git a/src/test/ui/typeck/remove-extra-argument.stderr b/src/test/ui/typeck/remove-extra-argument.stderr
new file mode 100644 (file)
index 0000000..8152977
--- /dev/null
@@ -0,0 +1,19 @@
+error[E0061]: this function takes 1 argument but 2 arguments were supplied
+  --> $DIR/remove-extra-argument.rs:6:5
+   |
+LL |     l(vec![], vec![])
+   |     ^         ------ argument unexpected
+   |
+note: function defined here
+  --> $DIR/remove-extra-argument.rs:3:4
+   |
+LL | fn l(_a: Vec<u8>) {}
+   |    ^ -----------
+help: remove the extra argument
+   |
+LL |     l(vec![])
+   |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0061`.
index cf5c15df7051cee43b705213b501dd19fdea6d8d..fc3778b796745283c6a11c7928efc1f232047b06 100644 (file)
@@ -26,7 +26,7 @@ error[E0321]: cross-crate traits with a default impl, like `DefaultedTrait`, can
 LL | impl DefaultedTrait for Box<C> { }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait for type in another crate
 
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0117]: only traits defined in the current crate can be implemented for types defined outside of the crate
   --> $DIR/typeck-default-trait-impl-cross-crate-coherence.rs:22:1
    |
 LL | impl DefaultedTrait for lib::Something<C> { }
index ca0876be58df9909d111e16ac6cea7d8272bb3f4..22fedb22d66c6b9b2fe96046bbd9706889062493 100644 (file)
@@ -57,7 +57,7 @@ unsafe fn test12(x: *const usize) -> *const *const _ {
 
 impl Clone for Test9 {
     fn clone(&self) -> _ { Test9 }
-    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
 
     fn clone_from(&mut self, other: _) { *self = Test9; }
     //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
@@ -113,7 +113,7 @@ fn fn_test10(&self, _x : _) { }
 
     impl Clone for FnTest9 {
         fn clone(&self) -> _ { FnTest9 }
-        //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
+        //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
 
         fn clone_from(&mut self, other: _) { *self = FnTest9; }
         //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
index c07b96f9a977ae325e2a2cc527f7719ff949d7a3..3ea317dfb1a5d329a07c14569935f854b1a32861 100644 (file)
@@ -545,14 +545,16 @@ help: use type parameters instead
 LL |     fn test10<T>(&self, _x : T) { }
    |              +++             ~
 
-error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/typeck_type_placeholder_item.rs:59:24
    |
 LL |     fn clone(&self) -> _ { Test9 }
-   |                        ^
-   |                        |
-   |                        not allowed in type signatures
-   |                        help: replace with the correct return type: `Test9`
+   |                        ^ not allowed in type signatures
+   |
+help: try replacing `_` with the type in the corresponding trait method signature
+   |
+LL |     fn clone(&self) -> Test9 { Test9 }
+   |                        ~~~~~
 
 error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/typeck_type_placeholder_item.rs:62:37
@@ -560,10 +562,10 @@ error[E0121]: the placeholder `_` is not allowed within types on item signatures
 LL |     fn clone_from(&mut self, other: _) { *self = Test9; }
    |                                     ^ not allowed in type signatures
    |
-help: use type parameters instead
+help: try replacing `_` with the type in the corresponding trait method signature
    |
-LL |     fn clone_from<T>(&mut self, other: T) { *self = Test9; }
-   |                  +++                   ~
+LL |     fn clone_from(&mut self, other: &Test9) { *self = Test9; }
+   |                                     ~~~~~~
 
 error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/typeck_type_placeholder_item.rs:107:31
@@ -585,14 +587,16 @@ help: use type parameters instead
 LL |         fn fn_test10<T>(&self, _x : T) { }
    |                     +++             ~
 
-error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/typeck_type_placeholder_item.rs:115:28
    |
 LL |         fn clone(&self) -> _ { FnTest9 }
-   |                            ^
-   |                            |
-   |                            not allowed in type signatures
-   |                            help: replace with the correct return type: `FnTest9`
+   |                            ^ not allowed in type signatures
+   |
+help: try replacing `_` with the type in the corresponding trait method signature
+   |
+LL |         fn clone(&self) -> FnTest9 { FnTest9 }
+   |                            ~~~~~~~
 
 error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/typeck_type_placeholder_item.rs:118:41
@@ -600,10 +604,10 @@ error[E0121]: the placeholder `_` is not allowed within types on item signatures
 LL |         fn clone_from(&mut self, other: _) { *self = FnTest9; }
    |                                         ^ not allowed in type signatures
    |
-help: use type parameters instead
+help: try replacing `_` with the type in the corresponding trait method signature
    |
-LL |         fn clone_from<T>(&mut self, other: T) { *self = FnTest9; }
-   |                      +++                   ~
+LL |         fn clone_from(&mut self, other: &FnTest9) { *self = FnTest9; }
+   |                                         ~~~~~~~~
 
 error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated types
   --> $DIR/typeck_type_placeholder_item.rs:201:14
index 0b6d94e71f0c7ba5a296ce7c4ad1623b607c4a2f..e9883903674ad47e1f3a2d657b5dd69ab0509f11 100644 (file)
@@ -2,9 +2,9 @@ error[E0599]: no method named `call` found for closure `[closure@$DIR/unboxed-cl
   --> $DIR/unboxed-closures-static-call-wrong-trait.rs:7:10
    |
 LL |     mut_.call((0, ));
-   |          ^^^^ method not found in `[closure@$DIR/unboxed-closures-static-call-wrong-trait.rs:6:26: 6:31]`
-   |
-   = note: `mut_` is a function, perhaps you wish to call it
+   |     ---- ^^^^ method not found in `[closure@$DIR/unboxed-closures-static-call-wrong-trait.rs:6:26: 6:31]`
+   |     |
+   |     this is a function, perhaps you wish to call it
 
 error: aborting due to previous error
 
index 53d45f6a8f22b98da018b6f2e3fee0278758a770..0ffb77cf02164355c14f61d30aeeefcf98b4d8c7 100644 (file)
@@ -6,6 +6,11 @@ LL | fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T>> {
 LL |     //                      ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to `'static`
 LL |     Box::new(items.iter())
    |     ^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static`
+   |
+help: to declare that the trait object captures data from argument `items`, you can add an explicit `'_` lifetime bound
+   |
+LL | fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T> + '_> {
+   |                                                   ++++
 
 error: aborting due to previous error
 
index 8e10242cb1331ae08dbb46b8cbff7f69b8d9351c..a4dece320ec268ac7fb904c514acab3b220b5476 100644 (file)
@@ -6,6 +6,11 @@ LL | fn foo(x: &mut Vec<&'_ u8>, y: &'_ u8) { x.push(y); }
    |                    |           |
    |                    |           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
+   |
+LL | fn foo<'a>(x: &mut Vec<&'a u8>, y: &'a u8) { x.push(y); }
+   |       ++++              ~~          ~~
 
 error: aborting due to previous error
 
index 163c101772c47c3ba871a369db550f90489c1c34..fd58e1b1ebe37908ac070d9c28c6168a85027ee4 100644 (file)
@@ -12,7 +12,7 @@ LL | #![deny(unsafe_op_in_unsafe_fn)]
    = note: consult the function's documentation for information on how to avoid undefined behavior
 
 error: dereference of raw pointer is unsafe and requires unsafe block (error E0133)
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:14:5
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:15:5
    |
 LL |     *PTR;
    |     ^^^^ dereference of raw pointer
@@ -20,7 +20,7 @@ LL |     *PTR;
    = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
 
 error: use of mutable static is unsafe and requires unsafe block (error E0133)
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:16:5
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:17:5
    |
 LL |     VOID = ();
    |     ^^^^^^^^^ use of mutable static
@@ -28,7 +28,7 @@ LL |     VOID = ();
    = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
 
 error: unnecessary `unsafe` block
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:19:5
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:20:5
    |
 LL |     unsafe {}
    |     ^^^^^^ unnecessary `unsafe` block
@@ -40,13 +40,13 @@ LL | #![deny(unused_unsafe)]
    |         ^^^^^^^^^^^^^
 
 error: call to unsafe function is unsafe and requires unsafe block (error E0133)
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:27:5
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:28:5
    |
 LL |     unsf();
    |     ^^^^^^ call to unsafe function
    |
 note: the lint level is defined here
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:25:8
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:26:8
    |
 LL | #[deny(warnings)]
    |        ^^^^^^^^
@@ -54,7 +54,7 @@ LL | #[deny(warnings)]
    = note: consult the function's documentation for information on how to avoid undefined behavior
 
 error: dereference of raw pointer is unsafe and requires unsafe block (error E0133)
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:29:5
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:31:5
    |
 LL |     *PTR;
    |     ^^^^ dereference of raw pointer
@@ -62,7 +62,7 @@ LL |     *PTR;
    = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
 
 error: use of mutable static is unsafe and requires unsafe block (error E0133)
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:31:5
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:33:5
    |
 LL |     VOID = ();
    |     ^^^^^^^^^ use of mutable static
@@ -70,19 +70,19 @@ LL |     VOID = ();
    = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
 
 error: unnecessary `unsafe` block
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:33:5
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:35:5
    |
 LL |     unsafe {}
    |     ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:47:5
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:49:5
    |
 LL |     unsafe { unsafe { unsf() } }
    |     ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:58:5
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:60:5
    |
 LL | unsafe fn allow_level() {
    | ----------------------- because it's nested under this `unsafe` fn
@@ -92,13 +92,13 @@ LL |     unsafe { unsf() }
    |
    = note: this `unsafe` block does contain unsafe operations, but those are already allowed in an `unsafe fn`
 note: the lint level is defined here
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:51:9
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:53:9
    |
 LL | #[allow(unsafe_op_in_unsafe_fn)]
    |         ^^^^^^^^^^^^^^^^^^^^^^
 
 error: unnecessary `unsafe` block
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:70:9
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:72:9
    |
 LL | unsafe fn nested_allow_level() {
    | ------------------------------ because it's nested under this `unsafe` fn
@@ -108,13 +108,13 @@ LL |         unsafe { unsf() }
    |
    = note: this `unsafe` block does contain unsafe operations, but those are already allowed in an `unsafe fn`
 note: the lint level is defined here
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:63:13
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:65:13
    |
 LL |     #[allow(unsafe_op_in_unsafe_fn)]
    |             ^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0133]: call to unsafe function is unsafe and requires unsafe block
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:76:5
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:78:5
    |
 LL |     unsf();
    |     ^^^^^^ call to unsafe function
@@ -122,7 +122,7 @@ LL |     unsf();
    = note: consult the function's documentation for information on how to avoid undefined behavior
 
 error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:80:9
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:83:9
    |
 LL |         unsf();
    |         ^^^^^^ call to unsafe function
index 7ca714b85c216a940a79733a24c4229792ce3705..30b072340341bbfa2c9b2032bd997ecf2cfee49a 100644 (file)
@@ -10,7 +10,8 @@ unsafe fn unsf() {}
 
 unsafe fn deny_level() {
     unsf();
-    //~^ ERROR call to unsafe function is unsafe and requires unsafe block
+    //[mir]~^ ERROR call to unsafe function is unsafe and requires unsafe block
+    //[thir]~^^ ERROR call to unsafe function `unsf` is unsafe and requires unsafe block
     *PTR;
     //~^ ERROR dereference of raw pointer is unsafe and requires unsafe block
     VOID = ();
@@ -25,7 +26,8 @@ unsafe fn deny_level() {
 #[deny(warnings)]
 unsafe fn warning_level() {
     unsf();
-    //~^ ERROR call to unsafe function is unsafe and requires unsafe block
+    //[mir]~^ ERROR call to unsafe function is unsafe and requires unsafe block
+    //[thir]~^^ ERROR call to unsafe function `unsf` is unsafe and requires unsafe block
     *PTR;
     //~^ ERROR dereference of raw pointer is unsafe and requires unsafe block
     VOID = ();
@@ -74,10 +76,12 @@ unsafe fn nested_allow_level() {
 
 fn main() {
     unsf();
-    //~^ ERROR call to unsafe function is unsafe and requires unsafe block
+    //[mir]~^ ERROR call to unsafe function is unsafe and requires unsafe block
+    //[thir]~^^ ERROR call to unsafe function `unsf` is unsafe and requires unsafe block
     #[allow(unsafe_op_in_unsafe_fn)]
     {
         unsf();
-        //~^ ERROR call to unsafe function is unsafe and requires unsafe function or block
+        //[mir]~^ ERROR call to unsafe function is unsafe and requires unsafe function or block
+        //[thir]~^^ ERROR call to unsafe function `unsf` is unsafe and requires unsafe function or block
     }
 }
index ad87690bb52f04869ef5792a29286931ebdafb8e..2ba6a72930df802455becb8a2e37820f13ddb862 100644 (file)
@@ -1,4 +1,4 @@
-error: call to unsafe function is unsafe and requires unsafe block (error E0133)
+error: call to unsafe function `unsf` is unsafe and requires unsafe block (error E0133)
   --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:12:5
    |
 LL |     unsf();
@@ -12,7 +12,7 @@ LL | #![deny(unsafe_op_in_unsafe_fn)]
    = note: consult the function's documentation for information on how to avoid undefined behavior
 
 error: dereference of raw pointer is unsafe and requires unsafe block (error E0133)
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:14:5
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:15:5
    |
 LL |     *PTR;
    |     ^^^^ dereference of raw pointer
@@ -20,7 +20,7 @@ LL |     *PTR;
    = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
 
 error: use of mutable static is unsafe and requires unsafe block (error E0133)
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:16:5
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:17:5
    |
 LL |     VOID = ();
    |     ^^^^ use of mutable static
@@ -28,7 +28,7 @@ LL |     VOID = ();
    = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
 
 error: unnecessary `unsafe` block
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:19:5
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:20:5
    |
 LL |     unsafe {}
    |     ^^^^^^ unnecessary `unsafe` block
@@ -39,14 +39,14 @@ note: the lint level is defined here
 LL | #![deny(unused_unsafe)]
    |         ^^^^^^^^^^^^^
 
-error: call to unsafe function is unsafe and requires unsafe block (error E0133)
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:27:5
+error: call to unsafe function `unsf` is unsafe and requires unsafe block (error E0133)
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:28:5
    |
 LL |     unsf();
    |     ^^^^^^ call to unsafe function
    |
 note: the lint level is defined here
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:25:8
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:26:8
    |
 LL | #[deny(warnings)]
    |        ^^^^^^^^
@@ -54,7 +54,7 @@ LL | #[deny(warnings)]
    = note: consult the function's documentation for information on how to avoid undefined behavior
 
 error: dereference of raw pointer is unsafe and requires unsafe block (error E0133)
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:29:5
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:31:5
    |
 LL |     *PTR;
    |     ^^^^ dereference of raw pointer
@@ -62,7 +62,7 @@ LL |     *PTR;
    = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
 
 error: use of mutable static is unsafe and requires unsafe block (error E0133)
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:31:5
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:33:5
    |
 LL |     VOID = ();
    |     ^^^^ use of mutable static
@@ -70,13 +70,13 @@ LL |     VOID = ();
    = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
 
 error: unnecessary `unsafe` block
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:33:5
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:35:5
    |
 LL |     unsafe {}
    |     ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:47:14
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:49:14
    |
 LL |     unsafe { unsafe { unsf() } }
    |     ------   ^^^^^^ unnecessary `unsafe` block
@@ -84,7 +84,7 @@ LL |     unsafe { unsafe { unsf() } }
    |     because it's nested under this `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:58:5
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:60:5
    |
 LL | unsafe fn allow_level() {
    | ----------------------- because it's nested under this `unsafe` fn
@@ -93,7 +93,7 @@ LL |     unsafe { unsf() }
    |     ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:70:9
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:72:9
    |
 LL | unsafe fn nested_allow_level() {
    | ------------------------------ because it's nested under this `unsafe` fn
@@ -101,16 +101,16 @@ LL | unsafe fn nested_allow_level() {
 LL |         unsafe { unsf() }
    |         ^^^^^^ unnecessary `unsafe` block
 
-error[E0133]: call to unsafe function is unsafe and requires unsafe block
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:76:5
+error[E0133]: call to unsafe function `unsf` is unsafe and requires unsafe block
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:78:5
    |
 LL |     unsf();
    |     ^^^^^^ call to unsafe function
    |
    = note: consult the function's documentation for information on how to avoid undefined behavior
 
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:80:9
+error[E0133]: call to unsafe function `unsf` is unsafe and requires unsafe function or block
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:83:9
    |
 LL |         unsf();
    |         ^^^^^^ call to unsafe function
index 3031be720f02e8dbdd4514b290ee7052013f73ae..1a77adf4459d08f1e9dbcc3b56ba920a6d4a47d6 100644 (file)
@@ -1,4 +1,4 @@
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+error[E0133]: call to unsafe function `dummy` is unsafe and requires unsafe function or block
   --> $DIR/unsafe-const-fn.rs:10:18
    |
 LL | const VAL: u32 = dummy(0xFFFF);
index df12e4415165ccc5cb7674ffef0a70bc5a55e0d2..55072dcc6c314e1f1a3bb382c4ece9282074d5d7 100644 (file)
@@ -4,5 +4,7 @@
 unsafe fn f() { return; }
 
 fn main() {
-    f(); //~ ERROR call to unsafe function is unsafe
+    f();
+    //[mir]~^ ERROR call to unsafe function is unsafe
+    //[thir]~^^ ERROR call to unsafe function `f` is unsafe
 }
index 1d6fa4cbf407d9357793be3e4901c35fa23a9d6f..206dbd90a7521e55cbfd7e85cd8cc6b373caa66a 100644 (file)
@@ -1,4 +1,4 @@
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+error[E0133]: call to unsafe function `f` is unsafe and requires unsafe function or block
   --> $DIR/unsafe-fn-called-from-safe.rs:7:5
    |
 LL |     f();
index 2af0786617bccba4ea753432eee66ee822f3af07..9517598c7ce57e20a2987f0bc7c92ea7ce3e2ffc 100644 (file)
@@ -5,5 +5,7 @@
 
 fn main() {
     let x = f;
-    x();    //~ ERROR call to unsafe function is unsafe
+    x();
+    //[mir]~^ ERROR call to unsafe function is unsafe
+    //[thir]~^^ ERROR call to unsafe function `f` is unsafe
 }
index b08a7109dda57566934650b12c64157305f6a3fb..e81dd3b2b4186e83fc7cf56da3d8996b56dfd928 100644 (file)
@@ -1,4 +1,4 @@
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+error[E0133]: call to unsafe function `f` is unsafe and requires unsafe function or block
   --> $DIR/unsafe-fn-used-as-value.rs:8:5
    |
 LL |     x();
diff --git a/src/test/ui/unused-crate-deps/deny-attr.rs b/src/test/ui/unused-crate-deps/deny-attr.rs
new file mode 100644 (file)
index 0000000..e9ab18f
--- /dev/null
@@ -0,0 +1,9 @@
+// Check for unused crate dep, no path
+
+// edition:2018
+// aux-crate:bar=bar.rs
+
+#![deny(unused_crate_dependencies)]
+//~^ ERROR external crate `bar` unused in
+
+fn main() {}
diff --git a/src/test/ui/unused-crate-deps/deny-attr.stderr b/src/test/ui/unused-crate-deps/deny-attr.stderr
new file mode 100644 (file)
index 0000000..93694f6
--- /dev/null
@@ -0,0 +1,14 @@
+error: external crate `bar` unused in `deny_attr`: remove the dependency or add `use bar as _;`
+  --> $DIR/deny-attr.rs:6:1
+   |
+LL | #![deny(unused_crate_dependencies)]
+   | ^
+   |
+note: the lint level is defined here
+  --> $DIR/deny-attr.rs:6:9
+   |
+LL | #![deny(unused_crate_dependencies)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/unused-crate-deps/deny-cmdline-json-silent.rs b/src/test/ui/unused-crate-deps/deny-cmdline-json-silent.rs
new file mode 100644 (file)
index 0000000..fd9a61d
--- /dev/null
@@ -0,0 +1,8 @@
+// Check for unused crate dep, json event, deny but we're not reporting that in exit status
+
+// edition:2018
+// check-pass
+// compile-flags: -Dunused-crate-dependencies -Zunstable-options --json unused-externs-silent --error-format=json
+// aux-crate:bar=bar.rs
+
+fn main() {}
diff --git a/src/test/ui/unused-crate-deps/deny-cmdline-json-silent.stderr b/src/test/ui/unused-crate-deps/deny-cmdline-json-silent.stderr
new file mode 100644 (file)
index 0000000..595619f
--- /dev/null
@@ -0,0 +1 @@
+{"lint_level":"deny","unused_extern_names":["bar"]}
diff --git a/src/test/ui/unused-crate-deps/deny-cmdline-json.rs b/src/test/ui/unused-crate-deps/deny-cmdline-json.rs
new file mode 100644 (file)
index 0000000..2b369de
--- /dev/null
@@ -0,0 +1,7 @@
+// Check for unused crate dep, json event, deny, expect compile failure
+
+// edition:2018
+// compile-flags: -Dunused-crate-dependencies  -Zunstable-options --json unused-externs --error-format=json
+// aux-crate:bar=bar.rs
+
+fn main() {}
diff --git a/src/test/ui/unused-crate-deps/deny-cmdline-json.stderr b/src/test/ui/unused-crate-deps/deny-cmdline-json.stderr
new file mode 100644 (file)
index 0000000..595619f
--- /dev/null
@@ -0,0 +1 @@
+{"lint_level":"deny","unused_extern_names":["bar"]}
diff --git a/src/test/ui/unused-crate-deps/deny-cmdline.rs b/src/test/ui/unused-crate-deps/deny-cmdline.rs
new file mode 100644 (file)
index 0000000..69e28b3
--- /dev/null
@@ -0,0 +1,8 @@
+// Check for unused crate dep, deny, expect failure
+
+// edition:2018
+// compile-flags: -Dunused-crate-dependencies
+// aux-crate:bar=bar.rs
+
+fn main() {}
+//~^ ERROR external crate `bar` unused in
diff --git a/src/test/ui/unused-crate-deps/deny-cmdline.stderr b/src/test/ui/unused-crate-deps/deny-cmdline.stderr
new file mode 100644 (file)
index 0000000..0951dc6
--- /dev/null
@@ -0,0 +1,10 @@
+error: external crate `bar` unused in `deny_cmdline`: remove the dependency or add `use bar as _;`
+  --> $DIR/deny-cmdline.rs:7:1
+   |
+LL | fn main() {}
+   | ^
+   |
+   = note: requested on the command line with `-D unused-crate-dependencies`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/unused-crate-deps/warn-cmdline-json.rs b/src/test/ui/unused-crate-deps/warn-cmdline-json.rs
new file mode 100644 (file)
index 0000000..4826c00
--- /dev/null
@@ -0,0 +1,8 @@
+// Check for unused crate dep, warn, json event, expect pass
+
+// edition:2018
+// check-pass
+// compile-flags: -Wunused-crate-dependencies -Zunstable-options --json unused-externs --error-format=json
+// aux-crate:bar=bar.rs
+
+fn main() {}
diff --git a/src/test/ui/unused-crate-deps/warn-cmdline-json.stderr b/src/test/ui/unused-crate-deps/warn-cmdline-json.stderr
new file mode 100644 (file)
index 0000000..98dbd76
--- /dev/null
@@ -0,0 +1 @@
+{"lint_level":"warn","unused_extern_names":["bar"]}
index a02b3230689e8d2f25460b932e941f4a258bed82..42acd30a0ff6a5caf5d784dd275c4e6c251809c0 100644 (file)
@@ -164,6 +164,12 @@ fn monkey_barrel() {
     assert_eq!(val, ());
 }
 
+fn bathroom_stall() {
+    let mut i = 1;
+    matches!(2, _|_|_|_|_|_ if (i+=1) != (i+=1));
+    assert_eq!(i, 13);
+}
+
 pub fn main() {
     strange();
     funny();
@@ -183,4 +189,5 @@ pub fn main() {
     i_yield();
     match_nested_if();
     monkey_barrel();
+    bathroom_stall();
 }
index 3f324190b7b6bcd1fff6b40646c5feb5c361342f..b9d4857a3efde0d57ab0c92a8657a27e86377e9b 100644 (file)
@@ -1,10 +1,13 @@
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/wf-impl-associated-type-region.rs:10:16
    |
-LL | impl<'a, T> Foo<'a> for T {
-   |          - help: consider adding an explicit lifetime bound...: `T: 'a`
 LL |     type Bar = &'a T;
    |                ^^^^^ ...so that the reference type `&'a T` does not outlive the data it points at
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | impl<'a, T: 'a> Foo<'a> for T {
+   |           ++++
 
 error: aborting due to previous error
 
index 44cacf4ef4dfe5d75fadd5041c0f93ed50af7178..73fbb9ca670b021cfb77b75010ea08c39b4a9353 100644 (file)
@@ -1,20 +1,24 @@
 error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/wf-in-fn-type-static.rs:13:8
    |
-LL | struct Foo<T> {
-   |            - help: consider adding an explicit lifetime bound...: `T: 'static`
-LL |     // needs T: 'static
 LL |     x: fn() -> &'static T
    |        ^^^^^^^^^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | struct Foo<T: 'static> {
+   |             +++++++++
 
 error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/wf-in-fn-type-static.rs:18:8
    |
-LL | struct Bar<T> {
-   |            - help: consider adding an explicit lifetime bound...: `T: 'static`
-LL |     // needs T: Copy
 LL |     x: fn(&'static T)
    |        ^^^^^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | struct Bar<T: 'static> {
+   |             +++++++++
 
 error: aborting due to 2 previous errors
 
index c50a6bb6e4d878939e0c963e3a3306dcf5d556c6..c3ad42dd5d5ac0b878d73dbafb76c8daf45230d6 100644 (file)
@@ -1,11 +1,13 @@
 error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/wf-in-obj-type-static.rs:14:8
    |
-LL | struct Foo<T> {
-   |            - help: consider adding an explicit lifetime bound...: `T: 'static`
-LL |     // needs T: 'static
 LL |     x: dyn Object<&'static T>
    |        ^^^^^^^^^^^^^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | struct Foo<T: 'static> {
+   |             +++++++++
 
 error: aborting due to previous error
 
index 68c1e9091d753d653d07e8c165a4be0ab1b125ec..4d4d8b2ab4d463e1d12e783828a001e6a1873c56 100644 (file)
@@ -1,18 +1,24 @@
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/wf-outlives-ty-in-fn-or-trait.rs:9:16
    |
-LL | impl<'a, T> Trait<'a, T> for usize {
-   |          - help: consider adding an explicit lifetime bound...: `T: 'a`
 LL |     type Out = &'a fn(T);
    |                ^^^^^^^^^ ...so that the reference type `&'a fn(T)` does not outlive the data it points at
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | impl<'a, T: 'a> Trait<'a, T> for usize {
+   |           ++++
 
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/wf-outlives-ty-in-fn-or-trait.rs:19:16
    |
-LL | impl<'a, T> Trait<'a, T> for u32 {
-   |          - help: consider adding an explicit lifetime bound...: `T: 'a`
 LL |     type Out = &'a dyn Baz<T>;
    |                ^^^^^^^^^^^^^^ ...so that the reference type `&'a (dyn Baz<T> + 'a)` does not outlive the data it points at
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | impl<'a, T: 'a> Trait<'a, T> for u32 {
+   |           ++++
 
 error: aborting due to 2 previous errors
 
index edffc4ada3d77799e5a04eeafd9b2f843d29fc23..f63f23ff1f1a12ede8585bbd1bbf0c536e50293d 160000 (submodule)
@@ -1 +1 @@
-Subproject commit edffc4ada3d77799e5a04eeafd9b2f843d29fc23
+Subproject commit f63f23ff1f1a12ede8585bbd1bbf0c536e50293d
index 85f952375491f213556d9f3fa606e8ad17edf044..2bf7f868905458be690ecf5d3d39e80fcd404470 100644 (file)
@@ -82,7 +82,7 @@ fn check<'tcx>(
 
         if rust_cc > self.limit.limit() {
             let fn_span = match kind {
-                FnKind::ItemFn(ident, _, _, _) | FnKind::Method(ident, _, _) => ident.span,
+                FnKind::ItemFn(ident, _, _) | FnKind::Method(ident, _) => ident.span,
                 FnKind::Closure => {
                     let header_span = body_span.with_hi(decl.output.span().lo());
                     let pos = snippet_opt(cx, header_span).and_then(|snip| {
index 1f4353fa4f72bd73a6028f80c49e71d1b552230e..346d03ca5568f0aaf7c3593a45f721999a758ea3 100644 (file)
@@ -260,7 +260,7 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
                     }
                     // The `module_name_repetitions` lint should only trigger if the item has the module in its
                     // name. Having the same name is accepted.
-                    if item.vis.node.is_pub() && item_camel.len() > mod_camel.len() {
+                    if cx.tcx.visibility(item.def_id).is_public() && item_camel.len() > mod_camel.len() {
                         let matching = count_match_start(mod_camel, &item_camel);
                         let rmatching = count_match_end(mod_camel, &item_camel);
                         let nchars = mod_camel.chars().count();
index b0f50b5c144bbe45a6487cee425aa3501258169f..173d41b4b05060b7794a9cbac5432ace09c817c0 100644 (file)
@@ -78,7 +78,10 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
             if !attrs.iter().any(|a| a.has_name(sym::non_exhaustive));
             then {
                 let (lint, msg) = if let ItemKind::Struct(ref v, ..) = item.kind {
-                    if v.fields().iter().any(|f| !f.vis.node.is_pub()) {
+                    if v.fields().iter().any(|f| {
+                        let def_id = cx.tcx.hir().local_def_id(f.hir_id);
+                        !cx.tcx.visibility(def_id).is_public()
+                    }) {
                         // skip structs with private fields
                         return;
                     }
index 0709580c8adfdd2ad66a15af13efcf76ebc98d94..5462d913fb4414bf554e3c73d1bd5f0697493413 100644 (file)
@@ -108,7 +108,7 @@ fn check_needless_must_use(
                 diag.span_suggestion(
                     attr.span,
                     "remove the attribute",
-                    "".into(),
+                    "",
                     Applicability::MachineApplicable,
                 );
             },
index 830e3b32cfa2fac80d26726df67d353a835ea145..565a1c871d7580458b633285ea8a84aa913e0410 100644 (file)
@@ -17,8 +17,8 @@ pub(super) fn check_fn<'tcx>(
     hir_id: hir::HirId,
 ) {
     let unsafety = match kind {
-        intravisit::FnKind::ItemFn(_, _, hir::FnHeader { unsafety, .. }, _) => unsafety,
-        intravisit::FnKind::Method(_, sig, _) => sig.header.unsafety,
+        intravisit::FnKind::ItemFn(_, _, hir::FnHeader { unsafety, .. }) => unsafety,
+        intravisit::FnKind::Method(_, sig) => sig.header.unsafety,
         intravisit::FnKind::Closure => return,
     };
 
index 3af960491ed01d5872a0df98cba836829cadd303..5c8d8b8e7552c9e15f23b53a60f891a94357bf8a 100644 (file)
@@ -26,9 +26,8 @@ pub(super) fn check_fn(
                     header: hir::FnHeader { abi: Abi::Rust, .. },
                     ..
                 },
-                _,
             )
-            | intravisit::FnKind::ItemFn(_, _, hir::FnHeader { abi: Abi::Rust, .. }, _) => check_arg_number(
+            | intravisit::FnKind::ItemFn(_, _, hir::FnHeader { abi: Abi::Rust, .. }) => check_arg_number(
                 cx,
                 decl,
                 span.with_hi(decl.output.span().hi()),
index b09c23f31e97049cbf539d9143593d794d65a9c2..662a561f171e91c49450f05d4818ff68ce973531 100644 (file)
@@ -8,7 +8,7 @@
 use rustc_hir::{
     BareFnTy, BodyId, FnDecl, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, ImplItem,
     ImplItemKind, Item, ItemKind, LangItem, Lifetime, LifetimeName, ParamName, PolyTraitRef, TraitBoundModifier,
-    TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WhereClause, WherePredicate,
+    TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -130,7 +130,7 @@ fn check_fn_inner<'tcx>(
     span: Span,
     report_extra_lifetimes: bool,
 ) {
-    if span.from_expansion() || has_where_lifetimes(cx, &generics.where_clause) {
+    if span.from_expansion() || has_where_lifetimes(cx, generics) {
         return;
     }
 
@@ -139,28 +139,35 @@ fn check_fn_inner<'tcx>(
         .iter()
         .filter(|param| matches!(param.kind, GenericParamKind::Type { .. }));
     for typ in types {
-        for bound in typ.bounds {
-            let mut visitor = RefVisitor::new(cx);
-            walk_param_bound(&mut visitor, bound);
-            if visitor.lts.iter().any(|lt| matches!(lt, RefLt::Named(_))) {
-                return;
+        for pred in generics.bounds_for_param(cx.tcx.hir().local_def_id(typ.hir_id)) {
+            if pred.in_where_clause {
+                // has_where_lifetimes checked that this predicate contains no lifetime.
+                continue;
             }
-            if let GenericBound::Trait(ref trait_ref, _) = *bound {
-                let params = &trait_ref
-                    .trait_ref
-                    .path
-                    .segments
-                    .last()
-                    .expect("a path must have at least one segment")
-                    .args;
-                if let Some(params) = *params {
-                    let lifetimes = params.args.iter().filter_map(|arg| match arg {
-                        GenericArg::Lifetime(lt) => Some(lt),
-                        _ => None,
-                    });
-                    for bound in lifetimes {
-                        if bound.name != LifetimeName::Static && !bound.is_elided() {
-                            return;
+
+            for bound in pred.bounds {
+                let mut visitor = RefVisitor::new(cx);
+                walk_param_bound(&mut visitor, bound);
+                if visitor.lts.iter().any(|lt| matches!(lt, RefLt::Named(_))) {
+                    return;
+                }
+                if let GenericBound::Trait(ref trait_ref, _) = *bound {
+                    let params = &trait_ref
+                        .trait_ref
+                        .path
+                        .segments
+                        .last()
+                        .expect("a path must have at least one segment")
+                        .args;
+                    if let Some(params) = *params {
+                        let lifetimes = params.args.iter().filter_map(|arg| match arg {
+                            GenericArg::Lifetime(lt) => Some(lt),
+                            _ => None,
+                        });
+                        for bound in lifetimes {
+                            if bound.name != LifetimeName::Static && !bound.is_elided() {
+                                return;
+                            }
                         }
                     }
                 }
@@ -322,9 +329,7 @@ fn allowed_lts_from(named_generics: &[GenericParam<'_>]) -> FxHashSet<RefLt> {
     let mut allowed_lts = FxHashSet::default();
     for par in named_generics.iter() {
         if let GenericParamKind::Lifetime { .. } = par.kind {
-            if par.bounds.is_empty() {
-                allowed_lts.insert(RefLt::Named(par.name.ident().name));
-            }
+            allowed_lts.insert(RefLt::Named(par.name.ident().name));
         }
     }
     allowed_lts.insert(RefLt::Unnamed);
@@ -445,8 +450,8 @@ fn visit_ty(&mut self, ty: &'tcx Ty<'_>) {
 
 /// Are any lifetimes mentioned in the `where` clause? If so, we don't try to
 /// reason about elision.
-fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, where_clause: &'tcx WhereClause<'_>) -> bool {
-    for predicate in where_clause.predicates {
+fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, generics: &'tcx Generics<'_>) -> bool {
+    for predicate in generics.predicates {
         match *predicate {
             WherePredicate::RegionPredicate(..) => return true,
             WherePredicate::BoundPredicate(ref pred) => {
index 777ec9b75bc24705494bf68c10fe2be018f83401..aa3552001f469e4aa6ba2720117baa72c3e2bd32 100644 (file)
@@ -193,7 +193,7 @@ fn find_sugg_for_if_let<'tcx>(
         PatKind::TupleStruct(ref qpath, [sub_pat], _) => {
             if let PatKind::Wild = sub_pat.kind {
                 let res = cx.typeck_results().qpath_res(qpath, check_pat.hir_id);
-                let Some(id) = res.opt_def_id().and_then(|ctor_id| cx.tcx.parent(ctor_id)) else { return };
+                let Some(id) = res.opt_def_id().map(|ctor_id| cx.tcx.parent(ctor_id)) else { return };
                 let lang_items = cx.tcx.lang_items();
                 if Some(id) == lang_items.result_ok_variant() {
                     ("is_ok()", try_get_generic_ty(op_ty, 0).unwrap_or(op_ty))
index eec232e6d0989dd731c44b47902780d8f66a6076..b88ec0963f2b55da8cd2f4567e8b91d9f3f58e45 100644 (file)
@@ -42,7 +42,7 @@ pub(crate) trait BindInsteadOfMap {
 
     fn no_op_msg(cx: &LateContext<'_>) -> Option<String> {
         let variant_id = cx.tcx.lang_items().require(Self::VARIANT_LANG_ITEM).ok()?;
-        let item_id = cx.tcx.parent(variant_id)?;
+        let item_id = cx.tcx.parent(variant_id);
         Some(format!(
             "using `{}.{}({})`, which is a no-op",
             cx.tcx.item_name(item_id),
@@ -53,7 +53,7 @@ fn no_op_msg(cx: &LateContext<'_>) -> Option<String> {
 
     fn lint_msg(cx: &LateContext<'_>) -> Option<String> {
         let variant_id = cx.tcx.lang_items().require(Self::VARIANT_LANG_ITEM).ok()?;
-        let item_id = cx.tcx.parent(variant_id)?;
+        let item_id = cx.tcx.parent(variant_id);
         Some(format!(
             "using `{}.{}(|x| {}(y))`, which is more succinctly expressed as `{}(|x| y)`",
             cx.tcx.item_name(item_id),
@@ -145,7 +145,7 @@ fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg:
         if_chain! {
             if let Some(adt) = cx.typeck_results().expr_ty(recv).ty_adt_def();
             if let Ok(vid) = cx.tcx.lang_items().require(Self::VARIANT_LANG_ITEM);
-            if Some(adt.did()) == cx.tcx.parent(vid);
+            if adt.did() == cx.tcx.parent(vid);
             then {} else { return false; }
         }
 
@@ -182,7 +182,7 @@ fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg:
     fn is_variant(cx: &LateContext<'_>, res: Res) -> bool {
         if let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Fn), id) = res {
             if let Ok(variant_id) = cx.tcx.lang_items().require(Self::VARIANT_LANG_ITEM) {
-                return cx.tcx.parent(id) == Some(variant_id);
+                return cx.tcx.parent(id) == variant_id;
             }
         }
         false
index 2cf2c5641bf10654e37c51cfb31171ce62bce223..f7b79f0839ba8c17ffbfd08172c16df143491df8 100644 (file)
@@ -19,7 +19,7 @@ pub(super) fn check(
     if_chain! {
         if let Some(args) = method_chain_args(info.chain, chain_methods);
         if let hir::ExprKind::Call(fun, [arg_char]) = info.other.kind;
-        if let Some(id) = path_def_id(cx, fun).and_then(|ctor_id| cx.tcx.parent(ctor_id));
+        if let Some(id) = path_def_id(cx, fun).map(|ctor_id| cx.tcx.parent(ctor_id));
         if Some(id) == cx.tcx.lang_items().option_some_variant();
         then {
             let mut applicability = Applicability::MachineApplicable;
index 2a5ab6e625c111ae0bec3d204db34d7f5c6653f0..76bc9466ed81800e23cdf94f4f8b771a2cc1a895 100644 (file)
@@ -75,7 +75,7 @@ pub(super) fn check<'tcx>(
             let arg_snippet = snippet(cx, span, "..");
             let body = cx.tcx.hir().body(id);
                 if let Some((func, [arg_char])) = reduce_unit_expression(&body.value);
-                if let Some(id) = path_def_id(cx, func).and_then(|ctor_id| cx.tcx.parent(ctor_id));
+                if let Some(id) = path_def_id(cx, func).map(|ctor_id| cx.tcx.parent(ctor_id));
                 if Some(id) == cx.tcx.lang_items().option_some_variant();
                 then {
                     let func_snippet = snippet(cx, arg_char.span, "..");
index 5816a95dcebffe63aa2a9410940e4c372a83260d..a20377f320b23b2dca9b7c2e30f48b249956876f 100644 (file)
@@ -114,7 +114,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'_>) {
             hir::ItemKind::Fn(..) => {
                 // ignore main()
                 if it.ident.name == sym::main {
-                    let at_root = cx.tcx.local_parent(it.def_id) == Some(CRATE_DEF_ID);
+                    let at_root = cx.tcx.local_parent(it.def_id) == CRATE_DEF_ID;
                     if at_root {
                         return;
                     }
index d29d07da7b0ffdcc8aa85a28443b6d8f1623357f..4034079a90c0d097cbece091e56c388c3068c229 100644 (file)
@@ -85,7 +85,7 @@ fn check_fn(
         }
 
         match kind {
-            FnKind::ItemFn(.., header, _) => {
+            FnKind::ItemFn(.., header) => {
                 let attrs = cx.tcx.hir().attrs(hir_id);
                 if header.abi != Abi::Rust || requires_exact_signature(attrs) {
                     return;
@@ -241,7 +241,7 @@ fn check_fn(
                                                 |x| Cow::from(format!("change `{}` to", x)),
                                             )
                                             .as_ref(),
-                                        suggestion.into(),
+                                        suggestion,
                                         Applicability::Unspecified,
                                     );
                                 }
@@ -271,7 +271,7 @@ fn check_fn(
                                                 |x| Cow::from(format!("change `{}` to", x))
                                             )
                                             .as_ref(),
-                                        suggestion.into(),
+                                        suggestion,
                                         Applicability::Unspecified,
                                     );
                                 }
index 9419056be14325a39b7912c51dfbbdcbe9604fc2..96c00c205ff2e9401e0589e1a9786fb47c2c2356 100644 (file)
@@ -68,7 +68,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
             ..
         }) = item.kind
         {
-            for assoc_item in items {
+            for assoc_item in *items {
                 if assoc_item.kind == (hir::AssocItemKind::Fn { has_self: false }) {
                     let impl_item = cx.tcx.hir().impl_item(assoc_item.id);
                     if in_external_macro(cx.sess(), impl_item.span) {
index e827cdaae8728922580a9f4e7d9fbc7cafd5b3b6..1469cb434c00c07dfeb0190d14c5527bf5e96c25 100644 (file)
@@ -42,7 +42,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
             if let Some(eq_trait) = cx.tcx.lang_items().eq_trait();
             if trait_ref.path.res.def_id() == eq_trait;
             then {
-                for impl_item in impl_items {
+                for impl_item in *impl_items {
                     if impl_item.ident.name == sym::ne {
                         span_lint_hir(
                             cx,
index d59249d7f13d32343bcb237ae44bb5afd860e0a1..9af3059a37f93c9f7137de24778a71a0cada764a 100644 (file)
@@ -251,7 +251,7 @@ fn check_fn(
         }
 
         match kind {
-            FnKind::ItemFn(.., header, _) => {
+            FnKind::ItemFn(.., header) => {
                 if header.abi != Abi::Rust {
                     return;
                 }
index 2cee3c14d7f30f89db58dc7797d8090d4fe6d3a1..e2e2400f8e267ae8e398778ed0de72ba17b1bdbb 100644 (file)
@@ -1,8 +1,10 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use rustc_errors::Applicability;
-use rustc_hir::{Item, ItemKind, VisibilityKind};
+use rustc_hir::{Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::def_id::CRATE_DEF_ID;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -41,7 +43,7 @@ pub struct RedundantPubCrate {
 
 impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
-        if let VisibilityKind::Crate { .. } = item.vis.node {
+        if cx.tcx.visibility(item.def_id) == ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id()) {
             if !cx.access_levels.is_exported(item.def_id) && self.is_exported.last() == Some(&false) {
                 let span = item.span.with_hi(item.ident.span.hi());
                 let descr = cx.tcx.def_kind(item.def_id).descr(item.def_id.to_def_id());
@@ -52,7 +54,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
                     &format!("pub(crate) {} inside private module", descr),
                     |diag| {
                         diag.span_suggestion(
-                            item.vis.span,
+                            item.vis_span,
                             "consider using",
                             "pub".to_string(),
                             Applicability::MachineApplicable,
index 79f104eac0be24c9e5b55e719021af891613471a..91e5e1e8b289288ae9c2e8d653f28484bfd8db36 100644 (file)
@@ -111,7 +111,7 @@ fn check_fn(
     ) {
         if_chain! {
             // We are only interested in methods, not in functions or associated functions.
-            if matches!(kind, FnKind::Method(_, _, _));
+            if matches!(kind, FnKind::Method(_, _));
             if let Some(fn_def) = cx.tcx.hir().opt_local_def_id(hir_id);
             if let Some(impl_def) = cx.tcx.impl_of_method(fn_def.to_def_id());
             // We don't want this method to be te implementation of a trait because the
index 398e2c200de3ca777db90fcf9295a8c06217f6a8..fc1c2af9257bf98484d807b775a7a2da416a56e2 100644 (file)
@@ -36,7 +36,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
                 if did == visit_did {
                     let mut seen_str = None;
                     let mut seen_string = None;
-                    for item in items {
+                    for item in *items {
                         match item.ident.as_str() {
                             "visit_str" => seen_str = Some(item.span),
                             "visit_string" => seen_string = Some(item.span),
index 43e0132a7ec7b1a5f48397d9760e367a1e7a7f93..3d1b2ee925bcebfd9d5511895d51e7ebf1f8c987 100644 (file)
@@ -8,8 +8,7 @@
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::{
-    GenericBound, Generics, Item, ItemKind, Node, ParamName, Path, PathSegment, QPath, TraitItem, Ty, TyKind,
-    WherePredicate,
+    GenericBound, Generics, Item, ItemKind, Node, Path, PathSegment, QPath, TraitItem, Ty, TyKind, WherePredicate,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
@@ -90,10 +89,9 @@ fn check_generics(&mut self, cx: &LateContext<'tcx>, gen: &'tcx Generics<'_>) {
     }
 
     fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'tcx>) {
-        let Generics { where_clause, .. } = &item.generics;
         let mut self_bounds_map = FxHashMap::default();
 
-        for predicate in where_clause.predicates {
+        for predicate in item.generics.predicates {
             if_chain! {
                 if let WherePredicate::BoundPredicate(ref bound_predicate) = predicate;
                 if !bound_predicate.span.from_expansion();
@@ -166,7 +164,7 @@ impl Eq for SpanlessTy<'_, '_> {}
         }
         let mut map: UnhashMap<SpanlessTy<'_, '_>, Vec<&GenericBound<'_>>> = UnhashMap::default();
         let mut applicability = Applicability::MaybeIncorrect;
-        for bound in gen.where_clause.predicates {
+        for bound in gen.predicates {
             if_chain! {
                 if let WherePredicate::BoundPredicate(ref p) = bound;
                 if p.bounds.len() as u64 <= self.max_trait_bounds;
@@ -216,34 +214,23 @@ impl Eq for SpanlessTy<'_, '_> {}
 }
 
 fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
-    if gen.span.from_expansion() || gen.params.is_empty() || gen.where_clause.predicates.is_empty() {
+    if gen.span.from_expansion() || gen.params.is_empty() || gen.predicates.is_empty() {
         return;
     }
 
-    let mut map = FxHashMap::default();
-    for param in gen.params {
-        if let ParamName::Plain(ref ident) = param.name {
-            let res = param
-                .bounds
-                .iter()
-                .filter_map(get_trait_info_from_bound)
-                .collect::<Vec<_>>();
-            map.insert(*ident, res);
-        }
-    }
-
-    for predicate in gen.where_clause.predicates {
+    let mut map = FxHashMap::<_, Vec<_>>::default();
+    for predicate in gen.predicates {
         if_chain! {
             if let WherePredicate::BoundPredicate(ref bound_predicate) = predicate;
             if !bound_predicate.span.from_expansion();
             if let TyKind::Path(QPath::Resolved(_, Path { segments, .. })) = bound_predicate.bounded_ty.kind;
             if let Some(segment) = segments.first();
-            if let Some(trait_resolutions_direct) = map.get(&segment.ident);
             then {
-                for (res_where, _,  _) in bound_predicate.bounds.iter().filter_map(get_trait_info_from_bound) {
-                    if let Some((_, _, span_direct)) = trait_resolutions_direct
+                for (res_where, _, span_where) in bound_predicate.bounds.iter().filter_map(get_trait_info_from_bound) {
+                    let trait_resolutions_direct = map.entry(segment.ident).or_default();
+                    if let Some((_, span_direct)) = trait_resolutions_direct
                                                 .iter()
-                                                .find(|(res_direct, _, _)| *res_direct == res_where) {
+                                                .find(|(res_direct, _)| *res_direct == res_where) {
                         span_lint_and_help(
                             cx,
                             TRAIT_DUPLICATION_IN_BOUNDS,
@@ -253,6 +240,9 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
                             "consider removing this trait bound",
                         );
                     }
+                    else {
+                        trait_resolutions_direct.push((res_where, span_where))
+                    }
                 }
             }
         }
index 7c06906293b167f373356698b2d9af026c33e581..f35f44eda5679fb34f365965dac7433983875010 100644 (file)
@@ -104,8 +104,10 @@ fn get_bounds_if_impl_trait<'tcx>(cx: &LateContext<'tcx>, qpath: &QPath<'_>, id:
         if let Some(Node::GenericParam(generic_param)) = cx.tcx.hir().get_if_local(did);
         if let GenericParamKind::Type { synthetic, .. } = generic_param.kind;
         if synthetic;
+        if let Some(generics) = cx.tcx.hir().get_generics(id.owner);
+        if let Some(pred) = generics.bounds_for_param(did.expect_local()).next();
         then {
-            Some(generic_param.bounds)
+            Some(pred.bounds)
         } else {
             None
         }
index 2b89398ecd6ad1ea3ed6be1359814d43aa0be47c..41333bb2addf7bbf70dfffc8a4fff632993348a3 100644 (file)
@@ -67,7 +67,7 @@ fn check_fn(
         span: Span,
         hir_id: HirId,
     ) {
-        if let FnKind::ItemFn(_, _, FnHeader { asyncness, .. }, _) = &fn_kind {
+        if let FnKind::ItemFn(_, _, FnHeader { asyncness, .. }) = &fn_kind {
             if matches!(asyncness, IsAsync::Async) {
                 let mut visitor = AsyncFnVisitor { cx, found_await: false };
                 walk_fn(&mut visitor, fn_kind, fn_decl, body.id(), span, hir_id);
index a04288e0a413ecd8f6733eda276ba321d1b146d8..37b114a0cfbc2239b4d539789daf80d638bba804 100644 (file)
@@ -4,6 +4,7 @@
 use rustc_ast::ast::{Attribute, InlineAsmTemplatePiece};
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::ty;
 use rustc_session::Session;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 
@@ -45,14 +46,16 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<
             return;
         }
         println!("impl item `{}`", item.ident.name);
-        match item.vis.node {
-            hir::VisibilityKind::Public => println!("public"),
-            hir::VisibilityKind::Crate(_) => println!("visible crate wide"),
-            hir::VisibilityKind::Restricted { path, .. } => println!(
-                "visible in module `{}`",
-                rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_path(path, false))
-            ),
-            hir::VisibilityKind::Inherited => println!("visibility inherited from outer item"),
+        match cx.tcx.visibility(item.def_id) {
+            ty::Visibility::Public => println!("public"),
+            ty::Visibility::Restricted(def_id) => {
+                if def_id.is_top_level_module() {
+                    println!("visible crate wide")
+                } else {
+                    println!("visible in module `{}`", cx.tcx.def_path_str(def_id))
+                }
+            },
+            ty::Visibility::Invisible => println!("invisible"),
         }
         match item.kind {
             hir::ImplItemKind::Const(_, body_id) => {
@@ -360,14 +363,16 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) {
 fn print_item(cx: &LateContext<'_>, item: &hir::Item<'_>) {
     let did = item.def_id;
     println!("item `{}`", item.ident.name);
-    match item.vis.node {
-        hir::VisibilityKind::Public => println!("public"),
-        hir::VisibilityKind::Crate(_) => println!("visible crate wide"),
-        hir::VisibilityKind::Restricted { path, .. } => println!(
-            "visible in module `{}`",
-            rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_path(path, false))
-        ),
-        hir::VisibilityKind::Inherited => println!("visibility inherited from outer item"),
+    match cx.tcx.visibility(item.def_id) {
+        ty::Visibility::Public => println!("public"),
+        ty::Visibility::Restricted(def_id) => {
+            if def_id.is_top_level_module() {
+                println!("visible crate wide")
+            } else {
+                println!("visible in module `{}`", cx.tcx.def_path_str(def_id))
+            }
+        },
+        ty::Visibility::Invisible => println!("invisible"),
     }
     match item.kind {
         hir::ItemKind::ExternCrate(ref _renamed_from) => {
index 832da66a53695c55287ddda2eb3dc1343cab1b0a..2f74eaf3cf5c319a9fff3f2bc0e06d06e24da1e3 100644 (file)
@@ -8,6 +8,7 @@
     Item, ItemKind, PathSegment, UseKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::symbol::kw;
 use rustc_span::{sym, BytePos};
@@ -115,7 +116,8 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
         if is_test_module_or_function(cx.tcx, item) {
             self.test_modules_deep = self.test_modules_deep.saturating_add(1);
         }
-        if item.vis.node.is_pub() || item.vis.node.is_pub_restricted() {
+        let module = cx.tcx.parent_module_from_def_id(item.def_id);
+        if cx.tcx.visibility(item.def_id) != ty::Visibility::Restricted(module.to_def_id()) {
             return;
         }
         if_chain! {
index a275bac4ce63dc5436ea18d4677f8c219c50488c..7d46952d9718b5cbcdf149de40a1a9206d1afa25 100644 (file)
@@ -235,7 +235,7 @@ pub fn is_lang_ctor(cx: &LateContext<'_>, qpath: &QPath<'_>, lang_item: LangItem
     if let QPath::Resolved(_, path) = qpath {
         if let Res::Def(DefKind::Ctor(..), ctor_id) = path.res {
             if let Ok(item_id) = cx.tcx.lang_items().require(lang_item) {
-                return cx.tcx.parent(ctor_id) == Some(item_id);
+                return cx.tcx.parent(ctor_id) == item_id;
             }
         }
     }
@@ -1690,7 +1690,7 @@ pub fn if_sequence<'tcx>(mut expr: &'tcx Expr<'tcx>) -> (Vec<&'tcx Expr<'tcx>>,
 
 /// Checks if the given function kind is an async function.
 pub fn is_async_fn(kind: FnKind<'_>) -> bool {
-    matches!(kind, FnKind::ItemFn(_, _, header, _) if header.asyncness == IsAsync::Async)
+    matches!(kind, FnKind::ItemFn(_, _, header) if header.asyncness == IsAsync::Async)
 }
 
 /// Peels away all the compiler generated code surrounding the body of an async function,
index 1fc9979f3dd7de45db66a7dd5eb6fd8a48506841..794d2e1026f8c7013de5515b02b2610ddace3365 100644 (file)
@@ -214,6 +214,7 @@ pub fn ast(cx: &EarlyContext<'_>, expr: &ast::Expr, default: &'a str) -> Self {
             | ast::ExprKind::Path(..)
             | ast::ExprKind::Repeat(..)
             | ast::ExprKind::Ret(..)
+            | ast::ExprKind::Yeet(..)
             | ast::ExprKind::Struct(..)
             | ast::ExprKind::Try(..)
             | ast::ExprKind::TryBlock(..)
index ebdb8e749520fed2bd95045043b76e60f5829543..9143fb2c208a05604d86a10e3fdb59f569b7b3b6 100644 (file)
@@ -6,12 +6,6 @@ LL | fn unused_lt<'a>(x: u8) {}
    |
    = note: `-D clippy::extra-unused-lifetimes` implied by `-D warnings`
 
-error: this lifetime isn't used in the function definition
-  --> $DIR/extra_unused_lifetimes.rs:16:25
-   |
-LL | fn unused_lt_transitive<'a, 'b: 'a>(x: &'b u8) {
-   |                         ^^
-
 error: this lifetime isn't used in the function definition
   --> $DIR/extra_unused_lifetimes.rs:41:10
    |
@@ -24,5 +18,5 @@ error: this lifetime isn't used in the function definition
 LL |         fn unused_lt<'a>(x: u8) {}
    |                      ^^
 
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
index ffa152427a97740c108221fccfbfad53096500aa..a488bc01fffa289257f8cd7032c32eacf32ab3f3 100644 (file)
@@ -108,12 +108,6 @@ error: explicit lifetimes given in parameter types where they could be elided (o
 LL |         fn baz<'a>(&'a self) -> impl Foo + 'a {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:307:5
-   |
-LL |     fn impl_trait_elidable_nested_named_lifetimes<'a>(i: &'a i32, f: impl for<'b> Fn(&'b i32) -> &'b i32) -> &'a i32 {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
   --> $DIR/needless_lifetimes.rs:310:5
    |
@@ -192,5 +186,5 @@ error: explicit lifetimes given in parameter types where they could be elided (o
 LL |         fn lifetime_elsewhere_provided<'a>(self: Box<Self>, here: &'a ()) -> &'a () {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 32 previous errors
+error: aborting due to 31 previous errors
 
index 1bf6e6d011e5c125a2be7e7f64c5c3c54cbc15e5..2cb368c6881887cd6042740739bdfcbeb2c58fcd 100644 (file)
@@ -198,11 +198,8 @@ pub struct Config {
     /// The rust-demangler executable.
     pub rust_demangler_path: Option<PathBuf>,
 
-    /// The Python executable to use for LLDB.
-    pub lldb_python: String,
-
-    /// The Python executable to use for htmldocck.
-    pub docck_python: String,
+    /// The Python executable to use for LLDB and htmldocck.
+    pub python: String,
 
     /// The jsondocck executable.
     pub jsondocck_path: Option<String>,
index 858a576dcb4745a1ac37b8fbead9445259ef244a..e6f058569dbd8cf816823a087cf6c3b646fc9a1f 100644 (file)
@@ -157,6 +157,8 @@ pub struct TestProps {
     pub should_ice: bool,
     // If true, the stderr is expected to be different across bit-widths.
     pub stderr_per_bitwidth: bool,
+    // The MIR opt to unit test, if any
+    pub mir_unit_test: Option<String>,
 }
 
 mod directives {
@@ -189,6 +191,7 @@ mod directives {
     pub const STDERR_PER_BITWIDTH: &'static str = "stderr-per-bitwidth";
     pub const INCREMENTAL: &'static str = "incremental";
     pub const KNOWN_BUG: &'static str = "known-bug";
+    pub const MIR_UNIT_TEST: &'static str = "unit-test";
     // This isn't a real directive, just one that is probably mistyped often
     pub const INCORRECT_COMPILER_FLAGS: &'static str = "compiler-flags";
 }
@@ -232,6 +235,7 @@ pub fn new() -> Self {
             assembly_output: None,
             should_ice: false,
             stderr_per_bitwidth: false,
+            mir_unit_test: None,
         }
     }
 
@@ -392,6 +396,9 @@ fn load_from(&mut self, testfile: &Path, cfg: Option<&str>, config: &Config) {
                 config.set_name_directive(ln, STDERR_PER_BITWIDTH, &mut self.stderr_per_bitwidth);
                 config.set_name_directive(ln, INCREMENTAL, &mut self.incremental);
                 config.set_name_directive(ln, KNOWN_BUG, &mut self.known_bug);
+                config.set_name_value_directive(ln, MIR_UNIT_TEST, &mut self.mir_unit_test, |s| {
+                    s.trim().to_string()
+                });
             });
         }
 
index 5b144a1020f4c3e0f9baeb51299b3875c8e0a0af..a8fd4880f078250191547ae4c743c12e35f6630f 100644 (file)
@@ -43,8 +43,7 @@ fn config() -> Config {
         "--compile-lib-path=",
         "--run-lib-path=",
         "--rustc-path=",
-        "--lldb-python=",
-        "--docck-python=",
+        "--python=",
         "--jsondocck-path=",
         "--src-base=",
         "--build-base=",
index a5ff779a4abfb5fda511554d944830ef90229128..10726b9842080be4c5e34f9f07f1394c121e7d2e 100644 (file)
@@ -23,6 +23,14 @@ struct ArtifactNotification {
     artifact: PathBuf,
 }
 
+#[derive(Deserialize)]
+struct UnusedExternNotification {
+    #[allow(dead_code)]
+    lint_level: String,
+    #[allow(dead_code)]
+    unused_extern_names: Vec<String>,
+}
+
 #[derive(Deserialize, Clone)]
 struct DiagnosticSpan {
     file_name: String,
@@ -113,6 +121,9 @@ pub fn extract_rendered(output: &str) -> String {
                 } else if serde_json::from_str::<ArtifactNotification>(line).is_ok() {
                     // Ignore the notification.
                     None
+                } else if serde_json::from_str::<UnusedExternNotification>(line).is_ok() {
+                    // Ignore the notification.
+                    None
                 } else {
                     print!(
                         "failed to decode compiler output as json: line: {}\noutput: {}",
index 8c1f28f14076887dcb110c0064beca87a8350c2b..3d11ea21acf9fccbb126c324ef6e8b10fe1248c8 100644 (file)
@@ -61,8 +61,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
         .reqopt("", "rustc-path", "path to rustc to use for compiling", "PATH")
         .optopt("", "rustdoc-path", "path to rustdoc to use for compiling", "PATH")
         .optopt("", "rust-demangler-path", "path to rust-demangler to use in tests", "PATH")
-        .reqopt("", "lldb-python", "path to python to use for doc tests", "PATH")
-        .reqopt("", "docck-python", "path to python to use for doc tests", "PATH")
+        .reqopt("", "python", "path to python to use for doc tests", "PATH")
         .optopt("", "jsondocck-path", "path to jsondocck to use for doc tests", "PATH")
         .optopt("", "valgrind-path", "path to Valgrind executable for Valgrind tests", "PROGRAM")
         .optflag("", "force-valgrind", "fail if Valgrind tests cannot be run under Valgrind")
@@ -222,8 +221,7 @@ fn make_absolute(path: PathBuf) -> PathBuf {
         rustc_path: opt_path(matches, "rustc-path"),
         rustdoc_path: matches.opt_str("rustdoc-path").map(PathBuf::from),
         rust_demangler_path: matches.opt_str("rust-demangler-path").map(PathBuf::from),
-        lldb_python: matches.opt_str("lldb-python").unwrap(),
-        docck_python: matches.opt_str("docck-python").unwrap(),
+        python: matches.opt_str("python").unwrap(),
         jsondocck_path: matches.opt_str("jsondocck-path"),
         valgrind_path: matches.opt_str("valgrind-path"),
         force_valgrind: matches.opt_present("force-valgrind"),
@@ -667,6 +665,40 @@ fn stamp(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> Path
     output_base_dir(config, testpaths, revision).join("stamp")
 }
 
+fn files_related_to_test(
+    config: &Config,
+    testpaths: &TestPaths,
+    props: &EarlyProps,
+    revision: Option<&str>,
+) -> Vec<PathBuf> {
+    let mut related = vec![];
+
+    if testpaths.file.is_dir() {
+        // run-make tests use their individual directory
+        for entry in WalkDir::new(&testpaths.file) {
+            let path = entry.unwrap().into_path();
+            if path.is_file() {
+                related.push(path);
+            }
+        }
+    } else {
+        related.push(testpaths.file.clone());
+    }
+
+    for aux in &props.aux {
+        let path = testpaths.file.parent().unwrap().join("auxiliary").join(aux);
+        related.push(path);
+    }
+
+    // UI test files.
+    for extension in UI_EXTENSIONS {
+        let path = expected_output_path(testpaths, revision, &config.compare_mode, extension);
+        related.push(path);
+    }
+
+    related
+}
+
 fn is_up_to_date(
     config: &Config,
     testpaths: &TestPaths,
@@ -688,20 +720,10 @@ fn is_up_to_date(
 
     // Check timestamps.
     let mut inputs = inputs.clone();
-    // Use `add_dir` to account for run-make tests, which use their individual directory
-    inputs.add_dir(&testpaths.file);
-
-    for aux in &props.aux {
-        let path = testpaths.file.parent().unwrap().join("auxiliary").join(aux);
+    for path in files_related_to_test(config, testpaths, props, revision) {
         inputs.add_path(&path);
     }
 
-    // UI test files.
-    for extension in UI_EXTENSIONS {
-        let path = &expected_output_path(testpaths, revision, &config.compare_mode, extension);
-        inputs.add_path(path);
-    }
-
     inputs < Stamp::from_path(&stamp_name)
 }
 
index 6b27d1ecbf550038f2846a3d1e2c4c289d1f27ff..6d94fe3ebb9cb53b76480ba6561e31dd203fe075 100644 (file)
@@ -179,7 +179,7 @@ pub fn compute_stamp_hash(config: &Config) -> String {
         }
 
         Some(Debugger::Lldb) => {
-            config.lldb_python.hash(&mut hash);
+            config.python.hash(&mut hash);
             config.lldb_python_dir.hash(&mut hash);
             env::var_os("PATH").hash(&mut hash);
             env::var_os("PYTHONPATH").hash(&mut hash);
@@ -1141,7 +1141,7 @@ fn run_lldb(
         // Prepare the lldb_batchmode which executes the debugger script
         let lldb_script_path = rust_src_root.join("src/etc/lldb_batchmode.py");
         self.cmd2procres(
-            Command::new(&self.config.lldb_python)
+            Command::new(&self.config.python)
                 .arg(&lldb_script_path)
                 .arg(test_executable)
                 .arg(debugger_script)
@@ -1856,10 +1856,14 @@ fn make_compile_args(
                 rustc.args(&[
                     "-Copt-level=1",
                     "-Zdump-mir=all",
-                    "-Zmir-opt-level=4",
                     "-Zvalidate-mir",
                     "-Zdump-mir-exclude-pass-number",
                 ]);
+                if let Some(pass) = &self.props.mir_unit_test {
+                    rustc.args(&["-Zmir-opt-level=0", &format!("-Zmir-enable-passes=+{}", pass)]);
+                } else {
+                    rustc.arg("-Zmir-opt-level=4");
+                }
 
                 let mir_dump_dir = self.get_mir_dump_dir();
                 let _ = fs::remove_dir_all(&mir_dump_dir);
@@ -2256,7 +2260,7 @@ fn run_rustdoc_test(&self) {
             self.check_rustdoc_test_option(proc_res);
         } else {
             let root = self.config.find_rust_src_root().unwrap();
-            let mut cmd = Command::new(&self.config.docck_python);
+            let mut cmd = Command::new(&self.config.python);
             cmd.arg(root.join("src/etc/htmldocck.py")).arg(&out_dir).arg(&self.testpaths.file);
             if self.config.bless {
                 cmd.arg("--bless");
@@ -2457,7 +2461,7 @@ fn run_rustdoc_json_test(&self) {
         let mut json_out = out_dir.join(self.testpaths.file.file_stem().unwrap());
         json_out.set_extension("json");
         let res = self.cmd2procres(
-            Command::new(&self.config.docck_python)
+            Command::new(&self.config.python)
                 .arg(root.join("src/etc/check_missing_items.py"))
                 .arg(&json_out),
         );
@@ -2852,7 +2856,7 @@ fn run_rmake_test(&self) {
             .stdout(Stdio::piped())
             .stderr(Stdio::piped())
             .env("TARGET", &self.config.target)
-            .env("PYTHON", &self.config.docck_python)
+            .env("PYTHON", &self.config.python)
             .env("S", src_root)
             .env("RUST_BUILD_STAGE", &self.config.stage_id)
             .env("RUSTC", cwd.join(&self.config.rustc_path))
index edd4858846003dc96020a0de07a1499e3224e633..a71a0083937671d79e16bfac4c7b8cab9c8ab9bb 160000 (submodule)
@@ -1 +1 @@
-Subproject commit edd4858846003dc96020a0de07a1499e3224e633
+Subproject commit a71a0083937671d79e16bfac4c7b8cab9c8ab9bb
index 24cf957627d5ede1b395f92ff871fd7a281d49a4..5dce1ff0212e467271c9e895478670c74d847ee9 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 24cf957627d5ede1b395f92ff871fd7a281d49a4
+Subproject commit 5dce1ff0212e467271c9e895478670c74d847ee9
index 841c0f2b9395e1db1564020d74ac52f27b481eec..d75884567afee2db06aa351e2b051883e8d08f11 100644 (file)
@@ -138,7 +138,6 @@ async function main(argv) {
     try {
         // This is more convenient that setting fields one by one.
         let args = [
-            "--no-screenshot-comparison",
             "--variable", "DOC_PATH", opts["doc_folder"],
         ];
         if (opts["debug"]) {
index 1736233835529a260525228f3dab6411be275fc5..98d0f5dc656c17ac0cd4359630e5aba742d9b121 100644 (file)
@@ -85,8 +85,11 @@ function extractFunction(content, functionName) {
 }
 
 // Stupid function extractor for array.
-function extractArrayVariable(content, arrayName) {
-    var splitter = "var " + arrayName;
+function extractArrayVariable(content, arrayName, kind) {
+    if (typeof kind === "undefined") {
+        kind = "let ";
+    }
+    var splitter = kind + arrayName;
     while (true) {
         var start = content.indexOf(splitter);
         if (start === -1) {
@@ -126,12 +129,18 @@ function extractArrayVariable(content, arrayName) {
         }
         content = content.slice(start + 1);
     }
+    if (kind === "let ") {
+        return extractArrayVariable(content, arrayName, "const ");
+    }
     return null;
 }
 
 // Stupid function extractor for variable.
-function extractVariable(content, varName) {
-    var splitter = "var " + varName;
+function extractVariable(content, varName, kind) {
+    if (typeof kind === "undefined") {
+        kind = "let ";
+    }
+    var splitter = kind + varName;
     while (true) {
         var start = content.indexOf(splitter);
         if (start === -1) {
@@ -162,6 +171,9 @@ function extractVariable(content, varName) {
         }
         content = content.slice(start + 1);
     }
+    if (kind === "let ") {
+        return extractVariable(content, varName, "const ");
+    }
     return null;
 }
 
index 4f333cd27cefe5c9a70d1a7e883819f126dcf8de..e4cc93026f10bb552b89514ce87d5098d87352ed 100644 (file)
@@ -2,7 +2,7 @@
 use std::cmp::min;
 
 use itertools::Itertools;
-use rustc_ast::token::{DelimToken, LitKind};
+use rustc_ast::token::{Delimiter, LitKind};
 use rustc_ast::{ast, ptr};
 use rustc_span::{BytePos, Span};
 
@@ -225,6 +225,10 @@ pub(crate) fn format_expr(
         ast::ExprKind::Ret(Some(ref expr)) => {
             rewrite_unary_prefix(context, "return ", &**expr, shape)
         }
+        ast::ExprKind::Yeet(None) => Some("do yeet".to_owned()),
+        ast::ExprKind::Yeet(Some(ref expr)) => {
+            rewrite_unary_prefix(context, "do yeet ", &**expr, shape)
+        }
         ast::ExprKind::Box(ref expr) => rewrite_unary_prefix(context, "box ", &**expr, shape),
         ast::ExprKind::AddrOf(borrow_kind, mutability, ref expr) => {
             rewrite_expr_addrof(context, borrow_kind, mutability, expr, shape)
@@ -412,7 +416,7 @@ pub(crate) fn rewrite_array<'a, T: 'a + IntoOverflowableItem<'a>>(
     context: &'a RewriteContext<'_>,
     shape: Shape,
     force_separator_tactic: Option<SeparatorTactic>,
-    delim_token: Option<DelimToken>,
+    delim_token: Option<Delimiter>,
 ) -> Option<String> {
     overflow::rewrite_with_square_brackets(
         context,
@@ -1325,7 +1329,7 @@ pub(crate) fn can_be_overflowed_expr(
         }
         ast::ExprKind::MacCall(ref mac) => {
             match (
-                rustc_ast::ast::MacDelimiter::from_token(mac.args.delim()),
+                rustc_ast::ast::MacDelimiter::from_token(mac.args.delim().unwrap()),
                 context.config.overflow_delimited_expr(),
             ) {
                 (Some(ast::MacDelimiter::Bracket), true)
index 664f152e8be1d3ba2e7586b1acdbc6afcdcc42af..26c429eb94ff3b1d0bb2677c9a1dbf7c8cd10b28 100644 (file)
@@ -12,7 +12,7 @@
 use std::collections::HashMap;
 use std::panic::{catch_unwind, AssertUnwindSafe};
 
-use rustc_ast::token::{BinOpToken, DelimToken, Token, TokenKind};
+use rustc_ast::token::{BinOpToken, Delimiter, Token, TokenKind};
 use rustc_ast::tokenstream::{Cursor, Spacing, TokenStream, TokenTree};
 use rustc_ast::{ast, ptr};
 use rustc_ast_pretty::pprust;
@@ -203,7 +203,7 @@ fn rewrite_macro_inner(
     let is_forced_bracket = FORCED_BRACKET_MACROS.contains(&&macro_name[..]);
 
     let style = if is_forced_bracket && !is_nested_macro {
-        DelimToken::Bracket
+        Delimiter::Bracket
     } else {
         original_style
     };
@@ -212,15 +212,15 @@ fn rewrite_macro_inner(
     let has_comment = contains_comment(context.snippet(mac.span()));
     if ts.is_empty() && !has_comment {
         return match style {
-            DelimToken::Paren if position == MacroPosition::Item => {
+            Delimiter::Parenthesis if position == MacroPosition::Item => {
                 Some(format!("{}();", macro_name))
             }
-            DelimToken::Bracket if position == MacroPosition::Item => {
+            Delimiter::Bracket if position == MacroPosition::Item => {
                 Some(format!("{}[];", macro_name))
             }
-            DelimToken::Paren => Some(format!("{}()", macro_name)),
-            DelimToken::Bracket => Some(format!("{}[]", macro_name)),
-            DelimToken::Brace => Some(format!("{} {{}}", macro_name)),
+            Delimiter::Parenthesis => Some(format!("{}()", macro_name)),
+            Delimiter::Bracket => Some(format!("{}[]", macro_name)),
+            Delimiter::Brace => Some(format!("{} {{}}", macro_name)),
             _ => unreachable!(),
         };
     }
@@ -260,7 +260,7 @@ fn rewrite_macro_inner(
     }
 
     match style {
-        DelimToken::Paren => {
+        Delimiter::Parenthesis => {
             // Handle special case: `vec!(expr; expr)`
             if vec_with_semi {
                 handle_vec_semi(context, shape, arg_vec, macro_name, style)
@@ -286,7 +286,7 @@ fn rewrite_macro_inner(
                 })
             }
         }
-        DelimToken::Bracket => {
+        Delimiter::Bracket => {
             // Handle special case: `vec![expr; expr]`
             if vec_with_semi {
                 handle_vec_semi(context, shape, arg_vec, macro_name, style)
@@ -323,7 +323,7 @@ fn rewrite_macro_inner(
                 Some(format!("{}{}", rewrite, comma))
             }
         }
-        DelimToken::Brace => {
+        Delimiter::Brace => {
             // For macro invocations with braces, always put a space between
             // the `macro_name!` and `{ /* macro_body */ }` but skip modifying
             // anything in between the braces (for now).
@@ -342,11 +342,11 @@ fn handle_vec_semi(
     shape: Shape,
     arg_vec: Vec<MacroArg>,
     macro_name: String,
-    delim_token: DelimToken,
+    delim_token: Delimiter,
 ) -> Option<String> {
     let (left, right) = match delim_token {
-        DelimToken::Paren => ("(", ")"),
-        DelimToken::Bracket => ("[", "]"),
+        Delimiter::Parenthesis => ("(", ")"),
+        Delimiter::Bracket => ("[", "]"),
         _ => unreachable!(),
     };
 
@@ -528,7 +528,7 @@ enum MacroArgKind {
     /// e.g., `$($foo: expr),*`
     Repeat(
         /// `()`, `[]` or `{}`.
-        DelimToken,
+        Delimiter,
         /// Inner arguments inside delimiters.
         Vec<ParsedMacroArg>,
         /// Something after the closing delimiter and the repeat token, if available.
@@ -537,7 +537,7 @@ enum MacroArgKind {
         Token,
     ),
     /// e.g., `[derive(Debug)]`
-    Delimited(DelimToken, Vec<ParsedMacroArg>),
+    Delimited(Delimiter, Vec<ParsedMacroArg>),
     /// A possible separator. e.g., `,` or `;`.
     Separator(String, String),
     /// Other random stuff that does not fit to other kinds.
@@ -547,22 +547,22 @@ enum MacroArgKind {
 
 fn delim_token_to_str(
     context: &RewriteContext<'_>,
-    delim_token: DelimToken,
+    delim_token: Delimiter,
     shape: Shape,
     use_multiple_lines: bool,
     inner_is_empty: bool,
 ) -> (String, String) {
     let (lhs, rhs) = match delim_token {
-        DelimToken::Paren => ("(", ")"),
-        DelimToken::Bracket => ("[", "]"),
-        DelimToken::Brace => {
+        Delimiter::Parenthesis => ("(", ")"),
+        Delimiter::Bracket => ("[", "]"),
+        Delimiter::Brace => {
             if inner_is_empty || use_multiple_lines {
                 ("{", "}")
             } else {
                 ("{ ", " }")
             }
         }
-        DelimToken::NoDelim => ("", ""),
+        Delimiter::Invisible => unreachable!(),
     };
     if use_multiple_lines {
         let indent_str = shape.indent.to_string_with_newline(context.config);
@@ -583,8 +583,8 @@ impl MacroArgKind {
     fn starts_with_brace(&self) -> bool {
         matches!(
             *self,
-            MacroArgKind::Repeat(DelimToken::Brace, _, _, _)
-                | MacroArgKind::Delimited(DelimToken::Brace, _)
+            MacroArgKind::Repeat(Delimiter::Brace, _, _, _)
+                | MacroArgKind::Delimited(Delimiter::Brace, _)
         )
     }
 
@@ -753,7 +753,7 @@ fn add_meta_variable(&mut self, iter: &mut Cursor) -> Option<()> {
         }
     }
 
-    fn add_delimited(&mut self, inner: Vec<ParsedMacroArg>, delim: DelimToken) {
+    fn add_delimited(&mut self, inner: Vec<ParsedMacroArg>, delim: Delimiter) {
         self.result.push(ParsedMacroArg {
             kind: MacroArgKind::Delimited(delim, inner),
         });
@@ -763,7 +763,7 @@ fn add_delimited(&mut self, inner: Vec<ParsedMacroArg>, delim: DelimToken) {
     fn add_repeat(
         &mut self,
         inner: Vec<ParsedMacroArg>,
-        delim: DelimToken,
+        delim: Delimiter,
         iter: &mut Cursor,
     ) -> Option<()> {
         let mut buffer = String::new();
@@ -1083,18 +1083,18 @@ pub(crate) fn convert_try_mac(
     }
 }
 
-pub(crate) fn macro_style(mac: &ast::MacCall, context: &RewriteContext<'_>) -> DelimToken {
+pub(crate) fn macro_style(mac: &ast::MacCall, context: &RewriteContext<'_>) -> Delimiter {
     let snippet = context.snippet(mac.span());
     let paren_pos = snippet.find_uncommented("(").unwrap_or(usize::max_value());
     let bracket_pos = snippet.find_uncommented("[").unwrap_or(usize::max_value());
     let brace_pos = snippet.find_uncommented("{").unwrap_or(usize::max_value());
 
     if paren_pos < bracket_pos && paren_pos < brace_pos {
-        DelimToken::Paren
+        Delimiter::Parenthesis
     } else if bracket_pos < brace_pos {
-        DelimToken::Bracket
+        Delimiter::Bracket
     } else {
-        DelimToken::Brace
+        Delimiter::Brace
     }
 }
 
@@ -1174,7 +1174,7 @@ struct Macro {
 // rather than clone them, if we can make the borrowing work out.
 struct MacroBranch {
     span: Span,
-    args_paren_kind: DelimToken,
+    args_paren_kind: Delimiter,
     args: TokenStream,
     body: Span,
     whole_body: Span,
@@ -1188,7 +1188,7 @@ fn rewrite(
         multi_branch_style: bool,
     ) -> Option<String> {
         // Only attempt to format function-like macros.
-        if self.args_paren_kind != DelimToken::Paren {
+        if self.args_paren_kind != Delimiter::Parenthesis {
             // FIXME(#1539): implement for non-sugared macros.
             return None;
         }
@@ -1350,18 +1350,18 @@ fn rewrite_macro_with_items(
     items: &[MacroArg],
     macro_name: &str,
     shape: Shape,
-    style: DelimToken,
+    style: Delimiter,
     position: MacroPosition,
     span: Span,
 ) -> Option<String> {
     let (opener, closer) = match style {
-        DelimToken::Paren => ("(", ")"),
-        DelimToken::Bracket => ("[", "]"),
-        DelimToken::Brace => (" {", "}"),
+        Delimiter::Parenthesis => ("(", ")"),
+        Delimiter::Bracket => ("[", "]"),
+        Delimiter::Brace => (" {", "}"),
         _ => return None,
     };
     let trailing_semicolon = match style {
-        DelimToken::Paren | DelimToken::Bracket if position == MacroPosition::Item => ";",
+        Delimiter::Parenthesis | Delimiter::Bracket if position == MacroPosition::Item => ";",
         _ => "",
     };
 
index 80aed998d7377d83c16925e2d0fe55ef5fa2f943..f115e7d0261826b9bfd30b91a8fd776ce6fab1be 100644 (file)
@@ -3,7 +3,7 @@
 use std::cmp::min;
 
 use itertools::Itertools;
-use rustc_ast::token::DelimToken;
+use rustc_ast::token::Delimiter;
 use rustc_ast::{ast, ptr};
 use rustc_span::Span;
 
@@ -297,11 +297,11 @@ pub(crate) fn rewrite_with_square_brackets<'a, T: 'a + IntoOverflowableItem<'a>>
     shape: Shape,
     span: Span,
     force_separator_tactic: Option<SeparatorTactic>,
-    delim_token: Option<DelimToken>,
+    delim_token: Option<Delimiter>,
 ) -> Option<String> {
     let (lhs, rhs) = match delim_token {
-        Some(DelimToken::Paren) => ("(", ")"),
-        Some(DelimToken::Brace) => ("{", "}"),
+        Some(Delimiter::Parenthesis) => ("(", ")"),
+        Some(Delimiter::Brace) => ("{", "}"),
         _ => ("[", "]"),
     };
     Context::new(
index 306b6bb745ee6d0221571f17ccc32fdad0986336..09b3e32df312d5b026be722102e2e20e526ad1a8 100644 (file)
@@ -1,7 +1,7 @@
 use std::panic::{catch_unwind, AssertUnwindSafe};
 
 use rustc_ast::ast;
-use rustc_ast::token::{DelimToken, TokenKind};
+use rustc_ast::token::{Delimiter, TokenKind};
 use rustc_parse::parser::ForceCollect;
 use rustc_span::symbol::kw;
 
@@ -47,11 +47,11 @@ fn parse_cfg_if_inner<'a>(
                 .map_err(|_| "Failed to parse attributes")?;
         }
 
-        if !parser.eat(&TokenKind::OpenDelim(DelimToken::Brace)) {
+        if !parser.eat(&TokenKind::OpenDelim(Delimiter::Brace)) {
             return Err("Expected an opening brace");
         }
 
-        while parser.token != TokenKind::CloseDelim(DelimToken::Brace)
+        while parser.token != TokenKind::CloseDelim(Delimiter::Brace)
             && parser.token.kind != TokenKind::Eof
         {
             let item = match parser.parse_item(ForceCollect::No) {
@@ -70,7 +70,7 @@ fn parse_cfg_if_inner<'a>(
             }
         }
 
-        if !parser.eat(&TokenKind::CloseDelim(DelimToken::Brace)) {
+        if !parser.eat(&TokenKind::CloseDelim(Delimiter::Brace)) {
             return Err("Expected a closing brace");
         }
 
index 3728f3a19b44fc40ceccb60342ed4f5d99aeee75..d4dbf21f8cab7fffa14ca8abd08530c78f50bd88 100644 (file)
@@ -1,4 +1,4 @@
-use rustc_ast::token::{DelimToken, TokenKind};
+use rustc_ast::token::{Delimiter, TokenKind};
 use rustc_ast::tokenstream::TokenStream;
 use rustc_ast::{ast, ptr};
 use rustc_parse::parser::{ForceCollect, Parser};
@@ -81,7 +81,7 @@ fn check_keyword<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option<MacroArg> {
             && parser.look_ahead(1, |t| {
                 t.kind == TokenKind::Eof
                     || t.kind == TokenKind::Comma
-                    || t.kind == TokenKind::CloseDelim(DelimToken::NoDelim)
+                    || t.kind == TokenKind::CloseDelim(Delimiter::Invisible)
             })
         {
             parser.bump();
@@ -97,7 +97,7 @@ fn check_keyword<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option<MacroArg> {
 pub(crate) fn parse_macro_args(
     context: &RewriteContext<'_>,
     tokens: TokenStream,
-    style: DelimToken,
+    style: Delimiter,
     forced_bracket: bool,
 ) -> Option<ParsedMacroArgs> {
     let mut parser = build_parser(context, tokens);
@@ -105,7 +105,7 @@ pub(crate) fn parse_macro_args(
     let mut vec_with_semi = false;
     let mut trailing_comma = false;
 
-    if DelimToken::Brace != style {
+    if Delimiter::Brace != style {
         loop {
             if let Some(arg) = check_keyword(&mut parser) {
                 args.push(arg);
index 35512e78fa6e29988e58eee9bd427f7eeb4c96a5..ed418fb1fece6afcf6464d67cb2d020a646eb5e7 100644 (file)
@@ -512,6 +512,7 @@ pub(crate) fn is_block_expr(context: &RewriteContext<'_>, expr: &ast::Expr, repr
         | ast::ExprKind::Range(..)
         | ast::ExprKind::Repeat(..)
         | ast::ExprKind::Ret(..)
+        | ast::ExprKind::Yeet(..)
         | ast::ExprKind::Tup(..)
         | ast::ExprKind::Type(..)
         | ast::ExprKind::Yield(None)
index 1621eb406b10f35514e24ae78cdc466fbd92d662..f04fb2e0446c2f06e870a702d19e59ff8215560d 100644 (file)
@@ -1,7 +1,7 @@
 use std::cell::{Cell, RefCell};
 use std::rc::Rc;
 
-use rustc_ast::{ast, token::DelimToken, visit, AstLike};
+use rustc_ast::{ast, token::Delimiter, visit, AstLike};
 use rustc_data_structures::sync::Lrc;
 use rustc_span::{symbol, BytePos, Pos, Span};
 
@@ -689,7 +689,7 @@ fn visit_mac(&mut self, mac: &ast::MacCall, ident: Option<symbol::Ident>, pos: M
         // with whitespace between the delimiters and trailing semi (i.e. `foo!(abc)     ;`)
         // are formatted correctly.
         let (span, rewrite) = match macro_style(mac, &self.get_context()) {
-            DelimToken::Bracket | DelimToken::Paren if MacroPosition::Item == pos => {
+            Delimiter::Bracket | Delimiter::Parenthesis if MacroPosition::Item == pos => {
                 let search_span = mk_sp(mac.span().hi(), self.snippet_provider.end_pos());
                 let hi = self.snippet_provider.span_before(search_span, ";");
                 let target_span = mk_sp(mac.span().lo(), hi + BytePos(1));
index 3f776b70b14c771fdb1b36008b3850d50d478769..4bf932563aadc6bf3fd73a1c77a1567960c7ef48 100644 (file)
     "rand_chacha",
     "rand_core",
     "rand_hc",
-    "rand_pcg",
     "rand_xorshift",
     "rand_xoshiro",
     "redox_syscall",
index 63a8909c6627ab6b7fa97f1f6c7252b826b6828d..6b715f727b2234a2c4295dbf71b1b362a5dd8740 100644 (file)
@@ -7,8 +7,8 @@
 
 const ENTRY_LIMIT: usize = 1000;
 // FIXME: The following limits should be reduced eventually.
-const ROOT_ENTRY_LIMIT: usize = 986;
-const ISSUES_ENTRY_LIMIT: usize = 2310;
+const ROOT_ENTRY_LIMIT: usize = 977;
+const ISSUES_ENTRY_LIMIT: usize = 2278;
 
 fn check_entries(path: &Path, bad: &mut bool) {
     let dirs = walkdir::WalkDir::new(&path.join("test/ui"))