]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #96195 - sunfishcode:sunfishcode/handle-or-error-type, r=joshtriplett
authorbors <bors@rust-lang.org>
Wed, 27 Apr 2022 03:42:59 +0000 (03:42 +0000)
committerbors <bors@rust-lang.org>
Wed, 27 Apr 2022 03:42:59 +0000 (03:42 +0000)
 Define a dedicated error type for `HandleOrNull` and `HandleOrInvalid`.

Define `NullHandleError` and `InvalidHandleError` types, that implement std::error::Error, and use them as the error types in `HandleOrNull` and `HandleOrInvalid`,

This addresses [this concern](https://github.com/rust-lang/rust/issues/87074#issuecomment-1080031167).

This is the same as #95387.

r? `@joshtriplett`

817 files changed:
Cargo.lock
compiler/rustc_ast/src/attr/mod.rs
compiler/rustc_ast/src/tokenstream.rs
compiler/rustc_ast/src/util/comments.rs
compiler/rustc_ast/src/visit.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_passes/src/ast_validation.rs
compiler/rustc_ast_passes/src/node_count.rs
compiler/rustc_borrowck/src/constraints/graph.rs
compiler/rustc_borrowck/src/constraints/mod.rs
compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
compiler/rustc_borrowck/src/diagnostics/mod.rs
compiler/rustc_borrowck/src/diagnostics/region_errors.rs
compiler/rustc_borrowck/src/region_infer/dump_mir.rs
compiler/rustc_borrowck/src/region_infer/mod.rs
compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
compiler/rustc_borrowck/src/type_check/free_region_relations.rs
compiler/rustc_borrowck/src/type_check/input_output.rs
compiler/rustc_borrowck/src/type_check/mod.rs
compiler/rustc_borrowck/src/type_check/relate_tys.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/asm.rs
compiler/rustc_codegen_llvm/src/asm.rs
compiler/rustc_codegen_llvm/src/back/lto.rs
compiler/rustc_codegen_llvm/src/back/write.rs
compiler/rustc_codegen_llvm/src/debuginfo/metadata.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/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/lib.rs
compiler/rustc_const_eval/src/const_eval/mod.rs
compiler/rustc_const_eval/src/interpret/eval_context.rs
compiler/rustc_const_eval/src/interpret/machine.rs
compiler/rustc_const_eval/src/interpret/memory.rs
compiler/rustc_const_eval/src/interpret/place.rs
compiler/rustc_const_eval/src/interpret/validity.rs
compiler/rustc_const_eval/src/transform/validate.rs
compiler/rustc_data_structures/src/stable_hasher.rs
compiler/rustc_error_messages/src/lib.rs
compiler/rustc_errors/src/diagnostic.rs
compiler/rustc_errors/src/diagnostic_builder.rs
compiler/rustc_errors/src/json.rs
compiler/rustc_errors/src/lib.rs
compiler/rustc_expand/src/proc_macro.rs
compiler/rustc_hir/src/def.rs
compiler/rustc_hir/src/definitions.rs
compiler/rustc_hir/src/hir.rs
compiler/rustc_hir/src/hir_id.rs
compiler/rustc_hir/src/intravisit.rs
compiler/rustc_hir_pretty/src/lib.rs
compiler/rustc_incremental/src/assert_dep_graph.rs
compiler/rustc_infer/src/infer/combine.rs
compiler/rustc_infer/src/infer/equate.rs
compiler/rustc_infer/src/infer/error_reporting/mod.rs
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
compiler/rustc_interface/src/tests.rs
compiler/rustc_lint/Cargo.toml
compiler/rustc_lint/src/builtin.rs
compiler/rustc_lint/src/context.rs
compiler/rustc_lint/src/nonstandard_style.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/session_diagnostic.rs
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_metadata/src/rmeta/table.rs
compiler/rustc_middle/src/dep_graph/dep_node.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/interpret/pointer.rs
compiler/rustc_middle/src/mir/mod.rs
compiler/rustc_middle/src/mir/patch.rs
compiler/rustc_middle/src/mir/pretty.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.rs
compiler/rustc_middle/src/ty/context.rs
compiler/rustc_middle/src/ty/layout.rs
compiler/rustc_middle/src/ty/list.rs
compiler/rustc_middle/src/ty/mod.rs
compiler/rustc_middle/src/ty/print/pretty.rs
compiler/rustc_middle/src/ty/query.rs
compiler/rustc_middle/src/ty/relate.rs
compiler/rustc_middle/src/ty/structural_impls.rs
compiler/rustc_mir_build/src/build/expr/into.rs
compiler/rustc_mir_build/src/build/mod.rs
compiler/rustc_mir_build/src/check_unsafety.rs
compiler/rustc_mir_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/pass_manager.rs
compiler/rustc_monomorphize/src/partitioning/default.rs
compiler/rustc_parse/src/parser/attr_wrapper.rs
compiler/rustc_parse/src/parser/diagnostics.rs
compiler/rustc_parse/src/parser/mod.rs
compiler/rustc_parse/src/parser/nonterminal.rs
compiler/rustc_passes/src/dead.rs
compiler/rustc_passes/src/entry.rs
compiler/rustc_passes/src/hir_id_validator.rs
compiler/rustc_passes/src/hir_stats.rs
compiler/rustc_passes/src/reachable.rs
compiler/rustc_passes/src/stability.rs
compiler/rustc_privacy/src/lib.rs
compiler/rustc_query_impl/src/profiling_support.rs
compiler/rustc_resolve/src/build_reduced_graph.rs
compiler/rustc_resolve/src/diagnostics.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_save_analysis/src/dump_visitor.rs
compiler/rustc_save_analysis/src/lib.rs
compiler/rustc_serialize/src/serialize.rs
compiler/rustc_session/src/config.rs
compiler/rustc_session/src/options.rs
compiler/rustc_session/src/search_paths.rs
compiler/rustc_session/src/utils.rs
compiler/rustc_span/src/def_id.rs
compiler/rustc_span/src/lib.rs
compiler/rustc_span/src/profiling.rs [new file with mode: 0644]
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/asm/mod.rs
compiler/rustc_target/src/asm/x86.rs
compiler/rustc_target/src/spec/mod.rs
compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
compiler/rustc_typeck/src/astconv/errors.rs
compiler/rustc_typeck/src/astconv/mod.rs
compiler/rustc_typeck/src/check/expr.rs
compiler/rustc_typeck/src/check/fn_ctxt/checks.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_unused.rs
compiler/rustc_typeck/src/coherence/orphan.rs
compiler/rustc_typeck/src/collect.rs
compiler/rustc_typeck/src/errors.rs
compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs
config.toml.example
library/alloc/src/borrow.rs
library/alloc/src/collections/linked_list.rs
library/alloc/src/collections/vec_deque/mod.rs
library/alloc/src/collections/vec_deque/tests.rs
library/alloc/src/macros.rs
library/core/src/internal_macros.rs
library/core/src/intrinsics.rs
library/core/src/iter/traits/collect.rs
library/core/src/num/f32.rs
library/core/src/num/f64.rs
library/core/src/panic/unwind_safe.rs
library/core/src/slice/iter.rs
library/core/src/slice/mod.rs
library/core/tests/lib.rs
library/core/tests/num/ops.rs
library/core/tests/slice.rs
library/proc_macro/Cargo.toml
library/proc_macro/src/quote.rs
library/std/src/lib.rs
library/std/src/net/parser.rs
library/std/src/os/unix/process.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/futex.rs
library/std/src/sys/unix/locks/mod.rs
library/std/src/sys/unix/os.rs
library/std/src/sys/unix/process/process_common.rs
library/std/src/sys/unix/weak.rs
library/std/src/sys/wasm/atomics/condvar.rs [deleted file]
library/std/src/sys/wasm/atomics/futex.rs
library/std/src/sys/wasm/atomics/mutex.rs [deleted file]
library/std/src/sys/wasm/atomics/rwlock.rs [deleted file]
library/std/src/sys/wasm/atomics/thread.rs
library/std/src/sys/wasm/mod.rs
library/std/src/sys/windows/args.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/process.rs
library/std/src/sys/windows/process/tests.rs
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/doc.rs
src/bootstrap/flags.rs
src/bootstrap/tarball.rs
src/bootstrap/test.rs
src/doc/book
src/doc/embedded-book
src/doc/rust-by-example
src/doc/rustc-dev-guide
src/doc/unstable-book/src/compiler-flags/extern-location.md [deleted file]
src/librustdoc/Cargo.toml
src/librustdoc/clean/mod.rs
src/librustdoc/clean/types.rs
src/librustdoc/clean/types/tests.rs [new file with mode: 0644]
src/librustdoc/core.rs
src/librustdoc/doctest.rs
src/librustdoc/formats/cache.rs
src/librustdoc/html/format.rs
src/librustdoc/html/markdown.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/search.js
src/librustdoc/html/static/js/settings.js
src/librustdoc/html/static_files.rs
src/librustdoc/json/conversions.rs
src/librustdoc/lib.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/librustdoc/visit_lib.rs
src/llvm-project
src/test/assembly/nvptx-kernel-abi/nvptx-kernel-args-abi-v7.rs [new file with mode: 0644]
src/test/codegen/asm-clobber_abi.rs
src/test/codegen/panic-in-drop-abort.rs
src/test/codegen/set-discriminant-invalid.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.opt1.EarlyOtherwiseBranch.diff
src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff
src/test/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff
src/test/mir-opt/early_otherwise_branch.rs
src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff
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/if_condition_int.dont_opt_bool.SimplifyComparisonIntegral.diff
src/test/mir-opt/if_condition_int.dont_opt_floats.SimplifyComparisonIntegral.diff
src/test/mir-opt/if_condition_int.dont_remove_comparison.SimplifyComparisonIntegral.diff
src/test/mir-opt/if_condition_int.opt_char.SimplifyComparisonIntegral.diff
src/test/mir-opt/if_condition_int.opt_i8.SimplifyComparisonIntegral.diff
src/test/mir-opt/if_condition_int.opt_multiple_ifs.SimplifyComparisonIntegral.diff
src/test/mir-opt/if_condition_int.opt_negative.SimplifyComparisonIntegral.diff
src/test/mir-opt/if_condition_int.opt_u32.SimplifyComparisonIntegral.diff
src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir
src/test/mir-opt/inline/inline_diverging.h.Inline.diff
src/test/mir-opt/issue_72181_1.main.mir_map.0.mir
src/test/mir-opt/lower_slice_len.rs
src/test/mir-opt/nll/named_lifetimes_basic.use_x.nll.0.mir
src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir
src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir
src/test/mir-opt/nrvo-simple.rs
src/test/mir-opt/nrvo_simple.nrvo.RenameReturnPlace.diff
src/test/mir-opt/storage_ranges.main.nll.0.mir
src/test/pretty/hir-pretty-loop.pp
src/test/pretty/issue-4264.pp
src/test/run-make-fulldeps/reproducible-build/linker.rs
src/test/run-make-fulldeps/symbol-visibility/Makefile
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/rustdoc-js-std/filter-crate.js
src/test/rustdoc-js-std/parser-errors.js [new file with mode: 0644]
src/test/rustdoc-js-std/parser-filter.js [new file with mode: 0644]
src/test/rustdoc-js-std/parser-generics.js [new file with mode: 0644]
src/test/rustdoc-js-std/parser-ident.js [new file with mode: 0644]
src/test/rustdoc-js-std/parser-literal.js [new file with mode: 0644]
src/test/rustdoc-js-std/parser-paths.js [new file with mode: 0644]
src/test/rustdoc-js-std/parser-quote.js [new file with mode: 0644]
src/test/rustdoc-js-std/parser-returned.js [new file with mode: 0644]
src/test/rustdoc-js-std/parser-separators.js [new file with mode: 0644]
src/test/rustdoc-js-std/parser-weird-queries.js [new file with mode: 0644]
src/test/rustdoc-js-std/quoted.js
src/test/rustdoc-js-std/struct-vec.js
src/test/rustdoc-js-std/typed-query.js
src/test/rustdoc-js-std/vec-new.js
src/test/rustdoc-js/doc-alias-filter.js
src/test/rustdoc-js/doc-alias.js
src/test/rustdoc-js/generics.js
src/test/rustdoc-js/generics.rs
src/test/rustdoc-ui/intra-doc/email-address-localhost.rs
src/test/rustdoc-ui/intra-doc/email-address-localhost.stderr [deleted file]
src/test/rustdoc-ui/issue-91713.stdout
src/test/rustdoc/early-unindent.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/rustdoc/where.SWhere_Simd_item-decl.html [new file with mode: 0644]
src/test/rustdoc/where.SWhere_TraitWhere_item-decl.html [new file with mode: 0644]
src/test/rustdoc/where.rs
src/test/ui-fulldeps/issue-15149.rs
src/test/ui/asm/x86_64/bad-reg.rs
src/test/ui/asm/x86_64/bad-reg.stderr
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/issues/issue-67893.rs
src/test/ui/async-await/issues/issue-67893.stderr
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/closures/coerce-unsafe-closure-to-unsafe-fn-ptr.thir.stderr
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/const-generics/issues/issue-87493.stderr
src/test/ui/consts/const-eval/ub-enum.32bit.stderr
src/test/ui/consts/const-eval/ub-enum.64bit.stderr
src/test/ui/consts/const-eval/ub-enum.rs
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-for.stderr
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/E0107.rs
src/test/ui/error-codes/E0107.stderr
src/test/ui/error-codes/E0117.stderr
src/test/ui/error-codes/E0133.thir.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/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-93161.rs
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/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/hrtb/issue-30786.migrate.stderr
src/test/ui/hrtb/issue-30786.nll.stderr
src/test/ui/impl-trait/issues/issue-88236-2.nll.stderr
src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr
src/test/ui/impl-trait/type_parameters_captured.nll.stderr
src/test/ui/intrinsics/unchecked_math_unsafe.thir.stderr
src/test/ui/issues/issue-16922.nll.stderr
src/test/ui/issues/issue-1866.rs [deleted file]
src/test/ui/issues/issue-1866.stderr [deleted file]
src/test/ui/issues/issue-20343.rs [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-3080.thir.stderr
src/test/ui/issues/issue-35668.stderr
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-53692.rs [deleted file]
src/test/ui/issues/issue-53692.stderr [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-80512-param-reordering-with-defaults.rs [deleted file]
src/test/ui/issues/issue-80512-param-reordering-with-defaults.stderr [deleted file]
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/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-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/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/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/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/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/raw/raw-str-unbalanced.rs
src/test/ui/parser/raw/raw-str-unbalanced.stderr
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-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.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/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/rfc1623.base.stderr
src/test/ui/rfc1623.nll.stderr
src/test/ui/rfc1623.rs
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/statics/uninhabited-static.rs
src/test/ui/statics/uninhabited-static.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/invalid-bin-op.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/lifetimes/missing-lifetimes-in-signature-2.nll.stderr
src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.nll.stderr
src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.nll.stderr
src/test/ui/suggestions/pattern-struct-with-slice-vec-field.rs [new file with mode: 0644]
src/test/ui/suggestions/pattern-struct-with-slice-vec-field.stderr [new file with mode: 0644]
src/test/ui/suggestions/suggest-impl-trait-lifetime.nll.stderr
src/test/ui/suggestions/use-type-argument-instead-of-assoc-type.stderr
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/issue-43132.rs [new file with mode: 0644]
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/resolution-in-overloaded-op.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/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/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/uninhabited/privately-uninhabited-mir-call.rs [new file with mode: 0644]
src/test/ui/uninhabited/privately-uninhabited-mir-call.stderr [new file with mode: 0644]
src/test/ui/unsafe/issue-45087-unreachable-unsafe.mir.stderr
src/test/ui/unsafe/issue-45087-unreachable-unsafe.rs
src/test/ui/unsafe/issue-45087-unreachable-unsafe.thir.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/extern-loc-bad-loctype.rs [deleted file]
src/test/ui/unused-crate-deps/extern-loc-bad-loctype.stderr [deleted file]
src/test/ui/unused-crate-deps/extern-loc-defl-json.rs [deleted file]
src/test/ui/unused-crate-deps/extern-loc-defl-json.stderr [deleted file]
src/test/ui/unused-crate-deps/extern-loc-json-bad-json.rs [deleted file]
src/test/ui/unused-crate-deps/extern-loc-json-bad-json.stderr [deleted file]
src/test/ui/unused-crate-deps/extern-loc-json-json.rs [deleted file]
src/test/ui/unused-crate-deps/extern-loc-json-json.stderr [deleted file]
src/test/ui/unused-crate-deps/extern-loc-json.rs [deleted file]
src/test/ui/unused-crate-deps/extern-loc-json.stderr [deleted file]
src/test/ui/unused-crate-deps/extern-loc-missing-loc.rs [deleted file]
src/test/ui/unused-crate-deps/extern-loc-missing-loc.stderr [deleted file]
src/test/ui/unused-crate-deps/extern-loc-missing-loctype.rs [deleted file]
src/test/ui/unused-crate-deps/extern-loc-missing-loctype.stderr [deleted file]
src/test/ui/unused-crate-deps/extern-loc-raw-json.rs [deleted file]
src/test/ui/unused-crate-deps/extern-loc-raw-json.stderr [deleted file]
src/test/ui/unused-crate-deps/extern-loc-raw-missing-loc.rs [deleted file]
src/test/ui/unused-crate-deps/extern-loc-raw-missing-loc.stderr [deleted file]
src/test/ui/unused-crate-deps/extern-loc-raw.rs [deleted file]
src/test/ui/unused-crate-deps/extern-loc-raw.stderr [deleted file]
src/test/ui/unused-crate-deps/libfib.stderr
src/test/ui/unused-crate-deps/unused-aliases.stderr
src/test/ui/unused-crate-deps/warn-attr.stderr
src/test/ui/unused-crate-deps/warn-cmdline-static.stderr
src/test/ui/unused-crate-deps/warn-cmdline.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/not_unsafe_ptr_arg_deref.rs
src/tools/clippy/clippy_lints/src/functions/too_many_arguments.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/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/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/compiletest/src/common.rs
src/tools/compiletest/src/header.rs
src/tools/compiletest/src/header/tests.rs
src/tools/compiletest/src/main.rs
src/tools/compiletest/src/runtest.rs
src/tools/miri
src/tools/rustdoc-js/tester.js
src/tools/tidy/src/deps.rs
src/tools/tidy/src/ui_tests.rs

index e908520ef692adde2c470abf2255db71d86c7704..30175ae3561ab7b3ff6b9630855f1bc3b2e0759a 100644 (file)
@@ -337,6 +337,7 @@ dependencies = [
  "humantime 2.0.1",
  "ignore",
  "im-rc",
+ "indexmap",
  "itertools",
  "jobserver",
  "lazy_static",
@@ -358,6 +359,7 @@ dependencies = [
  "serde_ignored",
  "serde_json",
  "shell-escape",
+ "snapbox",
  "strip-ansi-escapes",
  "tar",
  "tempfile",
@@ -794,6 +796,32 @@ dependencies = [
  "winapi",
 ]
 
+[[package]]
+name = "concolor"
+version = "0.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "015267563b1df20adccdd00cb05257b1dfbea70a04928e9cf88ffb850c1a40af"
+dependencies = [
+ "atty",
+ "bitflags",
+ "concolor-query",
+]
+
+[[package]]
+name = "concolor-query"
+version = "0.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d6417fe6fc03a8b533fd2177742eeb39a90c7233eedec7bac96d4d6b69a09449"
+
+[[package]]
+name = "content_inspector"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b7bda66e858c683005a53a9a60c69a4aca7eeaa45d124526e389f7aec8e62f38"
+dependencies = [
+ "memchr",
+]
+
 [[package]]
 name = "core"
 version = "0.0.0"
@@ -1088,6 +1116,12 @@ dependencies = [
  "rustc-std-workspace-core",
 ]
 
+[[package]]
+name = "dunce"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "453440c271cf5577fd2a40e4942540cb7d0d2f85e27c8d07dd0023c925a67541"
+
 [[package]]
 name = "either"
 version = "1.6.0"
@@ -2417,6 +2451,12 @@ dependencies = [
  "version_check",
 ]
 
+[[package]]
+name = "normalize-line-endings"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be"
+
 [[package]]
 name = "ntapi"
 version = "0.3.6"
@@ -2491,9 +2531,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"
@@ -2894,6 +2934,7 @@ dependencies = [
 name = "proc_macro"
 version = "0.0.0"
 dependencies = [
+ "core",
  "std",
 ]
 
@@ -3934,7 +3975,6 @@ dependencies = [
  "rustc_infer",
  "rustc_middle",
  "rustc_parse_format",
- "rustc_serialize",
  "rustc_session",
  "rustc_span",
  "rustc_target",
@@ -4496,6 +4536,7 @@ dependencies = [
  "expect-test",
  "itertools",
  "minifier",
+ "once_cell",
  "pulldown-cmark",
  "rayon",
  "regex",
@@ -4790,6 +4831,12 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "similar"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2e24979f63a11545f5f2c60141afe249d4f19f84581ea2138065e400941d83d3"
+
 [[package]]
 name = "siphasher"
 version = "0.3.3"
@@ -4824,6 +4871,30 @@ version = "1.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "da73c8f77aebc0e40c300b93f0a5f1bece7a248a36eee287d4e095f35c7b7d6e"
 
+[[package]]
+name = "snapbox"
+version = "0.2.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c1f212b806d6f56d19838e36a0aaa7e79a0bc9ca177e873fb87651ad92f983e2"
+dependencies = [
+ "concolor",
+ "content_inspector",
+ "dunce",
+ "filetime",
+ "normalize-line-endings",
+ "similar",
+ "snapbox-macros",
+ "tempfile",
+ "walkdir",
+ "yansi",
+]
+
+[[package]]
+name = "snapbox-macros"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c01dea7e04cbb27ef4c86e9922184608185f7cd95c1763bc30d727cda4a5e930"
+
 [[package]]
 name = "socket2"
 version = "0.4.1"
@@ -5668,9 +5739,9 @@ dependencies = [
 
 [[package]]
 name = "walkdir"
-version = "2.3.1"
+version = "2.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d"
+checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
 dependencies = [
  "same-file",
  "winapi",
@@ -5781,6 +5852,12 @@ dependencies = [
  "linked-hash-map",
 ]
 
+[[package]]
+name = "yansi"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
+
 [[package]]
 name = "yansi-term"
 version = "0.1.2"
index 80caf37d7099d67ddea64e0912cc44be3099483e..9a6d12faa605d62bcdf7540aeb1adf28a9dbb8b1 100644 (file)
@@ -9,6 +9,7 @@
 use crate::tokenstream::{AttrAnnotatedTokenStream, AttrAnnotatedTokenTree};
 use crate::tokenstream::{DelimSpan, Spacing, TokenTree, TreeAndSpacing};
 use crate::tokenstream::{LazyTokenStream, TokenStream};
+use crate::util::comments;
 
 use rustc_index::bit_set::GrowableBitSet;
 use rustc_span::source_map::BytePos;
@@ -262,6 +263,10 @@ pub fn doc_str(&self) -> Option<Symbol> {
         }
     }
 
+    pub fn may_have_doc_links(&self) -> bool {
+        self.doc_str().map_or(false, |s| comments::may_have_doc_links(s.as_str()))
+    }
+
     pub fn get_normal_item(&self) -> &AttrItem {
         match self.kind {
             AttrKind::Normal(ref item, _) => item,
index affb4289cb1b5a4f229a79cdaba90b1d7008f7c3..d609fa6720502c5ca1b679ad2cd0b0c99c813be7 100644 (file)
@@ -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()),
@@ -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 8730aeb0f3bffdf182cef918a75c06a4a44bd391..b4fff0022e29547e2cd17c2994ac09f528258456 100644 (file)
@@ -24,6 +24,14 @@ pub struct Comment {
     pub pos: BytePos,
 }
 
+/// A fast conservative estimate on whether the string can contain documentation links.
+/// A pair of square brackets `[]` must exist in the string, but we only search for the
+/// opening bracket because brackets always go in pairs in practice.
+#[inline]
+pub fn may_have_doc_links(s: &str) -> bool {
+    s.contains('[')
+}
+
 /// Makes a doc string more presentable to users.
 /// Used by rustdoc and perhaps other tools, but not by rustc.
 pub fn beautify_doc_string(data: Symbol, kind: CommentKind) -> Symbol {
index d925c6dd3549aa5da8b01d7a80858bd1dccaf8d1..e08ba73e0ae31a866a3ac2c445db63c44bb600b6 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) => {
index 5eab21bf79a90c9a95b57a41534df927793c3832..0f90239f4c8b39aa07822c2eed1c893bc733e997 100644 (file)
@@ -290,18 +290,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..29353d47b87e89ad36a2fed4666141b447332117 100644 (file)
@@ -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;
@@ -230,15 +230,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 +251,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 +260,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());
@@ -527,12 +527,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 +585,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 +593,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 +655,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 +667,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 +682,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();
@@ -773,7 +715,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 +793,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,
         }
     }
@@ -1016,8 +958,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 +986,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,
index 9cb205074e7eaf6b9a81413042c3127e991a14bd..b15f299b5f2cb9e5da02d6131f0a44d80d18a9c0 100644 (file)
@@ -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};
 
@@ -1530,7 +1530,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))
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 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 cb9e0234c49ffa5a5a7edc3e653817563f93ee5e..c19a39c393f799f3c926d4ac3aa8e5c6f0c447d1 100644 (file)
@@ -156,6 +156,7 @@ fn next(&mut self) -> Option<Self::Item> {
                 sup: self.static_region,
                 sub: next_static_idx.into(),
                 locations: Locations::All(DUMMY_SP),
+                span: DUMMY_SP,
                 category: ConstraintCategory::Internal,
                 variance_info: VarianceDiagInfo::default(),
             })
@@ -189,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),
         }
@@ -224,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 d41143ee763ad835709be88e3966595533913df5..14f0e5f620aeeab90d15b10d259eb735b64e5eb2 100644 (file)
@@ -2,6 +2,7 @@
 use rustc_index::vec::IndexVec;
 use rustc_middle::mir::ConstraintCategory;
 use rustc_middle::ty::{RegionVid, VarianceDiagInfo};
+use rustc_span::Span;
 use std::fmt;
 use std::ops::Index;
 
@@ -87,6 +88,12 @@ pub struct OutlivesConstraint<'tcx> {
     /// Where did this constraint arise?
     pub locations: Locations,
 
+    /// The `Span` associated with the creation of this constraint.
+    /// This should be used in preference to obtaining the span from
+    /// `locations`, since the `locations` may give a poor span
+    /// in some cases (e.g. converting a constraint from a promoted).
+    pub span: Span,
+
     /// What caused this constraint?
     pub category: ConstraintCategory,
 
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..b81360fd6aab401b8bc2c0c597b5235bb9c451ad 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);
 
@@ -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 5fd9ecf4513661c4301705d5d0db35c7950a122d..b5ee4a5edce7d6e3ef60a36a91a8124699c137ac 100644 (file)
@@ -1,16 +1,17 @@
 //! 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_param_with_region, 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 +167,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
@@ -647,82 +651,47 @@ 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;
-                            }
-                        }
-                    }
-
-                    found
-                };
+                .map(|r| self.infcx.tcx.return_type_impl_or_dyn_traits(r.def_id))
+                .unwrap_or_default();
 
-                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())),
+            );
         }
     }
 }
index 97233b930c395f839abe07d86a4b64640fc5ded7..fe5193102f958de004aa6b1fbcbd59fa9d00bfab 100644 (file)
@@ -74,14 +74,18 @@ fn for_each_constraint(
         let mut constraints: Vec<_> = self.constraints.outlives().iter().collect();
         constraints.sort_by_key(|c| (c.sup, c.sub));
         for constraint in &constraints {
-            let OutlivesConstraint { sup, sub, locations, category, variance_info: _ } = constraint;
+            let OutlivesConstraint { sup, sub, locations, category, span, variance_info: _ } =
+                constraint;
             let (name, arg) = match locations {
                 Locations::All(span) => {
                     ("All", tcx.sess.source_map().span_to_embeddable_string(*span))
                 }
                 Locations::Single(loc) => ("Single", format!("{:?}", loc)),
             };
-            with_msg(&format!("{:?}: {:?} due to {:?} at {}({})", sup, sub, category, name, arg))?;
+            with_msg(&format!(
+                "{:?}: {:?} due to {:?} at {}({}) ({:?}",
+                sup, sub, category, name, arg, span
+            ))?;
         }
 
         Ok(())
index dabf61715ce58fb78bb4239dd40ab501932c061e..cf03f34a4ec5fbb03b2a76e6e8434ea49dbdc832 100644 (file)
@@ -1733,7 +1733,7 @@ fn check_member_constraints(
 
     crate fn retrieve_closure_constraint_info(
         &self,
-        body: &Body<'tcx>,
+        _body: &Body<'tcx>,
         constraint: &OutlivesConstraint<'tcx>,
     ) -> BlameConstraint<'tcx> {
         let loc = match constraint.locations {
@@ -1760,7 +1760,7 @@ fn check_member_constraints(
             .unwrap_or(BlameConstraint {
                 category: constraint.category,
                 from_closure: false,
-                cause: ObligationCause::dummy_with_span(body.source_info(loc).span),
+                cause: ObligationCause::dummy_with_span(constraint.span),
                 variance_info: constraint.variance_info,
             })
     }
@@ -1869,6 +1869,7 @@ fn check_member_constraints(
                     sup: r,
                     sub: constraint.min_choice,
                     locations: Locations::All(p_c.definition_span),
+                    span: p_c.definition_span,
                     category: ConstraintCategory::OpaqueType,
                     variance_info: ty::VarianceDiagInfo::default(),
                 };
@@ -2017,7 +2018,7 @@ fn check_member_constraints(
                         category: constraint.category,
                         from_closure: false,
                         cause: ObligationCause::new(
-                            constraint.locations.span(body),
+                            constraint.span,
                             CRATE_HIR_ID,
                             cause_code.clone(),
                         ),
index 5022cb98b821d0786565e1a81cbc76e60d0f6396..21190a850b7b1eb33d8129fa3c85022ca4c3e112 100644 (file)
@@ -8,7 +8,7 @@
 use rustc_middle::ty::subst::GenericArgKind;
 use rustc_middle::ty::TypeFoldable;
 use rustc_middle::ty::{self, TyCtxt};
-use rustc_span::DUMMY_SP;
+use rustc_span::{Span, DUMMY_SP};
 
 use crate::{
     constraints::OutlivesConstraint,
@@ -26,6 +26,7 @@
     implicit_region_bound: Option<ty::Region<'tcx>>,
     param_env: ty::ParamEnv<'tcx>,
     locations: Locations,
+    span: Span,
     category: ConstraintCategory,
     constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
 }
@@ -38,6 +39,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
         implicit_region_bound: Option<ty::Region<'tcx>>,
         param_env: ty::ParamEnv<'tcx>,
         locations: Locations,
+        span: Span,
         category: ConstraintCategory,
         constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
     ) -> Self {
@@ -49,6 +51,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
             implicit_region_bound,
             param_env,
             locations,
+            span,
             category,
             constraints,
         }
@@ -153,6 +156,7 @@ fn add_outlives(&mut self, sup: ty::RegionVid, sub: ty::RegionVid) {
         self.constraints.outlives_constraints.push(OutlivesConstraint {
             locations: self.locations,
             category: self.category,
+            span: self.span,
             sub,
             sup,
             variance_info: ty::VarianceDiagInfo::default(),
index f8439d2e163559f5c51faa2364f18c15b2dc1aed..f08f2e1b12da6439fc574adcafe272119e481c33 100644 (file)
@@ -316,6 +316,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
                 self.implicit_region_bound,
                 self.param_env,
                 Locations::All(DUMMY_SP),
+                DUMMY_SP,
                 ConstraintCategory::Internal,
                 &mut self.constraints,
             )
index 83c8ecba1f17aa78d86d2af0a8a8c76dbc69bf06..e6f996491a41b7031b2420d00fc2e9b4266c52e8 100644 (file)
@@ -235,6 +235,7 @@ pub(crate) fn normalize_and_add_constraints(&mut self, t: Ty<'tcx>) -> Fallible<
                 Some(self.implicit_region_bound),
                 self.param_env,
                 Locations::All(DUMMY_SP),
+                DUMMY_SP,
                 ConstraintCategory::Internal,
                 &mut self.borrowck_context.constraints,
             )
index ece801716b2dbacc6715dc87e2d37113304fce63..6dcdd46816e0dbea5a284ec8a88ffa306cbde90a 100644 (file)
@@ -1141,6 +1141,7 @@ fn push_region_constraints(
             Some(self.implicit_region_bound),
             self.param_env,
             locations,
+            locations.span(self.body),
             category,
             &mut self.borrowck_context.constraints,
         )
@@ -2401,6 +2402,7 @@ fn add_reborrow_constraint(
                                 sup: ref_region.to_region_vid(),
                                 sub: borrow_region.to_region_vid(),
                                 locations: location.to_locations(),
+                                span: location.to_locations().span(body),
                                 category,
                                 variance_info: ty::VarianceDiagInfo::default(),
                             });
index f0106630797d33d91f4cf771d22759a272c80d77..f98d2c3128c524ed7f27c20ce13719c7284009db 100644 (file)
@@ -116,6 +116,7 @@ fn push_outlives(
                 sup,
                 sub,
                 locations: self.locations,
+                span: self.locations.span(self.type_checker.body),
                 category: self.category,
                 variance_info: info,
             },
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 2af050f0c7533282bd965bf3628936e1a9e682f4..2e8cd934eb2986fb22f6633618722ec912ab8f44 100644 (file)
@@ -589,6 +589,7 @@ fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister {
             | InlineAsmRegClass::X86(X86InlineAsmRegClass::ymm_reg) => "x",
             InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => "v",
             InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => unimplemented!(),
+            InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg0) => unimplemented!(),
             InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => unimplemented!(),
             InlineAsmRegClass::X86(
                 X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg,
@@ -654,6 +655,7 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl
         | InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => cx.type_f32(),
         InlineAsmRegClass::X86(X86InlineAsmRegClass::x87_reg) => unimplemented!(),
         InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => cx.type_i16(),
+        InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg0) => cx.type_i16(),
         InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => cx.type_i32(),
         InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
             bug!("LLVM backend does not support SPIR-V")
@@ -784,6 +786,7 @@ fn modifier_to_gcc(arch: InlineAsmArch, reg: InlineAsmRegClass, modifier: Option
             _ => unreachable!(),
         },
         InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => None,
+        InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg0) => None,
         InlineAsmRegClass::X86(X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg) => {
             unreachable!("clobber-only")
         }
index dff3200791825adac4ad57ce0ebf272891d0affd..e994001f96fd9b47cd6fa2e3c550c9ee1351b04d 100644 (file)
@@ -602,7 +602,9 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) ->
             InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => "v",
             InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => "^Yk",
             InlineAsmRegClass::X86(
-                X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg,
+                X86InlineAsmRegClass::x87_reg
+                | X86InlineAsmRegClass::mmx_reg
+                | X86InlineAsmRegClass::kreg0,
             ) => unreachable!("clobber-only"),
             InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => "r",
             InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::reg) => "r",
@@ -687,7 +689,11 @@ fn modifier_to_llvm(
             _ => unreachable!(),
         },
         InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => None,
-        InlineAsmRegClass::X86(X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg) => {
+        InlineAsmRegClass::X86(
+            X86InlineAsmRegClass::x87_reg
+            | X86InlineAsmRegClass::mmx_reg
+            | X86InlineAsmRegClass::kreg0,
+        ) => {
             unreachable!("clobber-only")
         }
         InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => None,
@@ -757,7 +763,11 @@ fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &'
         | InlineAsmRegClass::X86(X86InlineAsmRegClass::ymm_reg)
         | InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => cx.type_f32(),
         InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => cx.type_i16(),
-        InlineAsmRegClass::X86(X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg) => {
+        InlineAsmRegClass::X86(
+            X86InlineAsmRegClass::x87_reg
+            | X86InlineAsmRegClass::mmx_reg
+            | X86InlineAsmRegClass::kreg0,
+        ) => {
             unreachable!("clobber-only")
         }
         InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => cx.type_i32(),
index 7a747a9cdee4ead49b6894f5dc730a0ac94e729e..5c63bd8c1bd8dcff95494050e9da3d96f4ec49bf 100644 (file)
@@ -16,7 +16,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 +55,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
@@ -625,7 +625,7 @@ pub(crate) fn run_pass_manager(
             if thin {
                 llvm::LLVMRustPassManagerBuilderPopulateThinLTOPassManager(b, pm);
             } else {
-                llvm::LLVMPassManagerBuilderPopulateLTOPassManager(
+                llvm::LLVMRustPassManagerBuilderPopulateLTOPassManager(
                     b, pm, /* Internalize = */ False, /* RunInliner = */ True,
                 );
             }
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 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 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 cf32d558d4a5190bd495cc15d7b894ece75fe712..743f6c0e5703db5c5f6293f47e68f434b418c555 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;
@@ -987,7 +988,7 @@ fn is_illegal_instruction(_status: &ExitStatus) -> bool {
 
         // On MSVC packed debug information is produced by the linker itself so
         // there's no need to do anything else here.
-        SplitDebuginfo::Packed if sess.target.is_like_msvc => {}
+        SplitDebuginfo::Packed if sess.target.is_like_windows => {}
 
         // ... and otherwise we're processing a `*.dwp` packed dwarf file.
         //
@@ -1655,6 +1656,73 @@ 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);
+    }
+
+    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 +1863,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);
 
index 2c15ed831670ceefe65dd6eb93bd93c12f5373ca..6e13e0d0e43b1fd42d4b0a888db5584ab2e6a3c3 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};
@@ -1518,6 +1519,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 +1550,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::Staticlib | CrateType::ProcMacro | CrateType::Rlib | CrateType::Dylib => {
+            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::symbol_name_for_instance_in_crate(tcx, symbol, cnum),
+                info.kind,
+            ));
+        }
+    });
+
     symbols
 }
 
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 765bd877db1697dfde390b89604cd455e83b4a29..3a416c8a2b54b47ef327359a5dca32165ef69fc9 100644 (file)
@@ -1,15 +1,13 @@
 use std::collections::hash_map::Entry::*;
 
 use rustc_ast::expand::allocator::ALLOCATOR_METHODS;
-use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir as hir;
-use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE};
 use rustc_hir::Node;
-use rustc_index::vec::IndexVec;
 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};
@@ -42,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() {
@@ -105,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
@@ -143,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
     }
@@ -157,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() {
@@ -167,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() {
@@ -181,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,
+                },
+            ));
         }
     }
 
@@ -194,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,
+                },
+            )
         }));
     }
 
@@ -212,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() {
@@ -245,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 }) => {
@@ -254,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
@@ -277,17 +347,6 @@ fn upstream_monomorphizations_provider(
 
     let mut instances: DefIdMap<FxHashMap<_, _>> = Default::default();
 
-    let cnum_stable_ids: IndexVec<CrateNum, Fingerprint> = {
-        let mut cnum_stable_ids = IndexVec::from_elem_n(Fingerprint::ZERO, cnums.len() + 1);
-
-        for &cnum in cnums.iter() {
-            cnum_stable_ids[cnum] =
-                tcx.def_path_hash(DefId { krate: cnum, index: CRATE_DEF_INDEX }).0;
-        }
-
-        cnum_stable_ids
-    };
-
     let drop_in_place_fn_def_id = tcx.lang_items().drop_in_place_fn();
 
     for &cnum in cnums.iter() {
@@ -316,7 +375,7 @@ fn upstream_monomorphizations_provider(
                     // If there are multiple monomorphizations available,
                     // we select one deterministically.
                     let other_cnum = *e.get();
-                    if cnum_stable_ids[other_cnum] > cnum_stable_ids[cnum] {
+                    if tcx.stable_crate_id(other_cnum) > tcx.stable_crate_id(cnum) {
                         e.insert(cnum);
                     }
                 }
index d5d21775f0abc4ac33c861153f8d168c5f7a7a04..98dc5fe8d642436b74d797beb345f53c72bbcbdc 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)]
index 7933afb50e8ce70d9dbf52cf506c98f3c2d3ed23..019c9c179d8e1b88d59a7d5ffa1117ee039e1127 100644 (file)
@@ -801,6 +801,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 +840,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 5273b6cc83725521dbd49caedf2806dcaf2ed5c8..d4308002209309adee767c8bb1f369bfe44f89a0 100644 (file)
@@ -28,6 +28,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 +142,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 80270f825630f079c58ec55ea4b8560b1de8ccd7..68f9bee593f65ea0f8b04da55f60ef657b0670f8 100644 (file)
@@ -38,7 +38,7 @@ pub(crate) fn const_caller_location(
     if intern_const_alloc_recursive(&mut ecx, InternKind::Constant, &loc_place).is_err() {
         bug!("intern_const_alloc_recursive should not error in this case")
     }
-    ConstValue::Scalar(Scalar::from_pointer(loc_place.ptr.into_pointer_or_addr().unwrap(), &tcx))
+    ConstValue::Scalar(Scalar::from_maybe_pointer(loc_place.ptr, &tcx))
 }
 
 /// Convert an evaluated constant to a type level constant
index f0fff602fe4cfbf8a647c415035898a04eaa8e6f..827959113b90734ce321673ab5c56bbc359469d7 100644 (file)
@@ -679,7 +679,7 @@ pub fn push_stack_frame(
         return_place: Option<&PlaceTy<'tcx, M::PointerTag>>,
         return_to_block: StackPopCleanup,
     ) -> InterpResult<'tcx> {
-        debug!("body: {:#?}", body);
+        trace!("body: {:#?}", body);
         // first push a stack frame so we have access to the local substs
         let pre_frame = Frame {
             body,
@@ -836,7 +836,7 @@ pub(super) fn pop_stack_frame(&mut self, unwinding: bool) -> InterpResult<'tcx>
             return Ok(());
         }
 
-        debug!("locals: {:#?}", frame.locals);
+        trace!("locals: {:#?}", frame.locals);
 
         // Cleanup: deallocate all locals that are backed by an allocation.
         for local in &frame.locals {
index ddfbcbdd22e162495e2621d8ab67184c11ed4d68..7721485771b3b0a121ea08e321b326889869d982 100644 (file)
@@ -88,6 +88,10 @@ pub trait Machine<'mir, 'tcx>: Sized {
     /// Pointers are "tagged" with provenance information; typically the `AllocId` they belong to.
     type PointerTag: Provenance + Eq + Hash + 'static;
 
+    /// When getting the AllocId of a pointer, some extra data is also obtained from the tag
+    /// that is passed to memory access hooks so they can do things with it.
+    type TagExtra: Copy + 'static;
+
     /// Machines can define extra (non-instance) things that represent values of function pointers.
     /// For example, Miri uses this to return a function pointer from `dlsym`
     /// that can later be called to execute the right thing.
@@ -122,6 +126,8 @@ pub trait Machine<'mir, 'tcx>: Sized {
 
     /// Whether, when checking alignment, we should `force_int` and thus support
     /// custom alignment logic based on whatever the integer address happens to be.
+    ///
+    /// Requires PointerTag::OFFSET_IS_ADDR to be true.
     fn force_int_for_alignment_check(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
 
     /// Whether to enforce the validity invariant
@@ -285,11 +291,14 @@ fn ptr_from_addr(
         addr: u64,
     ) -> Pointer<Option<Self::PointerTag>>;
 
-    /// Convert a pointer with provenance into an allocation-offset pair.
+    /// Convert a pointer with provenance into an allocation-offset pair
+    /// and extra provenance info.
+    ///
+    /// The returned `AllocId` must be the same as `ptr.provenance.get_alloc_id()`.
     fn ptr_get_alloc(
         ecx: &InterpCx<'mir, 'tcx, Self>,
         ptr: Pointer<Self::PointerTag>,
-    ) -> (AllocId, Size);
+    ) -> (AllocId, Size, Self::TagExtra);
 
     /// Called to initialize the "extra" state of an allocation and make the pointers
     /// it contains (in relocations) tagged.  The way we construct allocations is
@@ -321,7 +330,7 @@ fn memory_read(
         _tcx: TyCtxt<'tcx>,
         _machine: &Self,
         _alloc_extra: &Self::AllocExtra,
-        _tag: Self::PointerTag,
+        _tag: (AllocId, Self::TagExtra),
         _range: AllocRange,
     ) -> InterpResult<'tcx> {
         Ok(())
@@ -333,7 +342,7 @@ fn memory_written(
         _tcx: TyCtxt<'tcx>,
         _machine: &mut Self,
         _alloc_extra: &mut Self::AllocExtra,
-        _tag: Self::PointerTag,
+        _tag: (AllocId, Self::TagExtra),
         _range: AllocRange,
     ) -> InterpResult<'tcx> {
         Ok(())
@@ -345,7 +354,7 @@ fn memory_deallocated(
         _tcx: TyCtxt<'tcx>,
         _machine: &mut Self,
         _alloc_extra: &mut Self::AllocExtra,
-        _tag: Self::PointerTag,
+        _tag: (AllocId, Self::TagExtra),
         _range: AllocRange,
     ) -> InterpResult<'tcx> {
         Ok(())
@@ -397,6 +406,8 @@ fn after_stack_pop(
 // (CTFE and ConstProp) use the same instance.  Here, we share that code.
 pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
     type PointerTag = AllocId;
+    type TagExtra = ();
+
     type ExtraFnVal = !;
 
     type MemoryMap =
@@ -474,9 +485,12 @@ fn ptr_from_addr(_ecx: &InterpCx<$mir, $tcx, Self>, addr: u64) -> Pointer<Option
     }
 
     #[inline(always)]
-    fn ptr_get_alloc(_ecx: &InterpCx<$mir, $tcx, Self>, ptr: Pointer<AllocId>) -> (AllocId, Size) {
+    fn ptr_get_alloc(
+        _ecx: &InterpCx<$mir, $tcx, Self>,
+        ptr: Pointer<AllocId>,
+    ) -> (AllocId, Size, Self::TagExtra) {
         // We know `offset` is relative to the allocation, so we can use `into_parts`.
         let (alloc_id, offset) = ptr.into_parts();
-        (alloc_id, offset)
+        (alloc_id, offset, ())
     }
 }
index a165fa23f30acf5e40af7a2a4d4171ba84ada542..b1d7ab6a098beccc7954322739b348f6551678d1 100644 (file)
@@ -158,8 +158,7 @@ pub fn global_base_pointer(
         &self,
         ptr: Pointer<AllocId>,
     ) -> InterpResult<'tcx, Pointer<M::PointerTag>> {
-        // We know `offset` is relative to the allocation, so we can use `into_parts`.
-        let (alloc_id, offset) = ptr.into_parts();
+        let alloc_id = ptr.provenance;
         // We need to handle `extern static`.
         match self.tcx.get_global_alloc(alloc_id) {
             Some(GlobalAlloc::Static(def_id)) if self.tcx.is_thread_local_static(def_id) => {
@@ -171,7 +170,7 @@ pub fn global_base_pointer(
             _ => {}
         }
         // And we need to get the tag.
-        Ok(M::tag_alloc_base_pointer(self, Pointer::new(alloc_id, offset)))
+        Ok(M::tag_alloc_base_pointer(self, ptr))
     }
 
     pub fn create_fn_alloc_ptr(
@@ -238,7 +237,7 @@ pub fn reallocate_ptr(
         new_align: Align,
         kind: MemoryKind<M::MemoryKind>,
     ) -> InterpResult<'tcx, Pointer<M::PointerTag>> {
-        let (alloc_id, offset, ptr) = self.ptr_get_alloc_id(ptr)?;
+        let (alloc_id, offset, _tag) = self.ptr_get_alloc_id(ptr)?;
         if offset.bytes() != 0 {
             throw_ub_format!(
                 "reallocating {:?} which does not point to the beginning of an object",
@@ -255,14 +254,14 @@ pub fn reallocate_ptr(
         };
         // This will also call the access hooks.
         self.mem_copy(
-            ptr.into(),
+            ptr,
             Align::ONE,
             new_ptr.into(),
             Align::ONE,
             old_size.min(new_size),
             /*nonoverlapping*/ true,
         )?;
-        self.deallocate_ptr(ptr.into(), old_size_and_align, kind)?;
+        self.deallocate_ptr(ptr, old_size_and_align, kind)?;
 
         Ok(new_ptr)
     }
@@ -274,7 +273,7 @@ pub fn deallocate_ptr(
         old_size_and_align: Option<(Size, Align)>,
         kind: MemoryKind<M::MemoryKind>,
     ) -> InterpResult<'tcx> {
-        let (alloc_id, offset, ptr) = self.ptr_get_alloc_id(ptr)?;
+        let (alloc_id, offset, tag) = self.ptr_get_alloc_id(ptr)?;
         trace!("deallocating: {}", alloc_id);
 
         if offset.bytes() != 0 {
@@ -330,7 +329,7 @@ pub fn deallocate_ptr(
             *self.tcx,
             &mut self.machine,
             &mut alloc.extra,
-            ptr.provenance,
+            (alloc_id, tag),
             alloc_range(Size::ZERO, size),
         )?;
 
@@ -350,17 +349,17 @@ fn get_ptr_access(
         ptr: Pointer<Option<M::PointerTag>>,
         size: Size,
         align: Align,
-    ) -> InterpResult<'tcx, Option<(AllocId, Size, Pointer<M::PointerTag>)>> {
+    ) -> InterpResult<'tcx, Option<(AllocId, Size, M::TagExtra)>> {
         let align = M::enforce_alignment(&self).then_some(align);
         self.check_and_deref_ptr(
             ptr,
             size,
             align,
             CheckInAllocMsg::MemoryAccessTest,
-            |alloc_id, offset, ptr| {
+            |alloc_id, offset, tag| {
                 let (size, align) =
                     self.get_alloc_size_and_align(alloc_id, AllocCheck::Dereferenceable)?;
-                Ok((size, align, (alloc_id, offset, ptr)))
+                Ok((size, align, (alloc_id, offset, tag)))
             },
         )
     }
@@ -401,11 +400,7 @@ fn check_and_deref_ptr<T>(
         size: Size,
         align: Option<Align>,
         msg: CheckInAllocMsg,
-        alloc_size: impl FnOnce(
-            AllocId,
-            Size,
-            Pointer<M::PointerTag>,
-        ) -> InterpResult<'tcx, (Size, Align, T)>,
+        alloc_size: impl FnOnce(AllocId, Size, M::TagExtra) -> InterpResult<'tcx, (Size, Align, T)>,
     ) -> InterpResult<'tcx, Option<T>> {
         fn check_offset_align(offset: u64, align: Align) -> InterpResult<'static> {
             if offset % align.bytes() == 0 {
@@ -433,8 +428,8 @@ fn check_offset_align(offset: u64, align: Align) -> InterpResult<'static> {
                 }
                 None
             }
-            Ok((alloc_id, offset, ptr)) => {
-                let (alloc_size, alloc_align, ret_val) = alloc_size(alloc_id, offset, ptr)?;
+            Ok((alloc_id, offset, tag)) => {
+                let (alloc_size, alloc_align, ret_val) = alloc_size(alloc_id, offset, tag)?;
                 // Test bounds. This also ensures non-null.
                 // It is sufficient to check this for the end pointer. Also check for overflow!
                 if offset.checked_add(size, &self.tcx).map_or(true, |end| end > alloc_size) {
@@ -450,10 +445,8 @@ fn check_offset_align(offset: u64, align: Align) -> InterpResult<'static> {
                 // we want the error to be about the bounds.
                 if let Some(align) = align {
                     if M::force_int_for_alignment_check(self) {
-                        let addr = Scalar::from_pointer(ptr, &self.tcx)
-                            .to_machine_usize(&self.tcx)
-                            .expect("ptr-to-int cast for align check should never fail");
-                        check_offset_align(addr, align)?;
+                        // `force_int_for_alignment_check` can only be true if `OFFSET_IS_ADDR` is true.
+                        check_offset_align(ptr.addr().bytes(), align)?;
                     } else {
                         // Check allocation alignment and offset alignment.
                         if alloc_align.bytes() < align.bytes() {
@@ -569,14 +562,14 @@ pub fn get_ptr_alloc<'a>(
             size,
             align,
             CheckInAllocMsg::MemoryAccessTest,
-            |alloc_id, offset, ptr| {
+            |alloc_id, offset, tag| {
                 let alloc = self.get_alloc_raw(alloc_id)?;
-                Ok((alloc.size(), alloc.align, (alloc_id, offset, ptr, alloc)))
+                Ok((alloc.size(), alloc.align, (alloc_id, offset, tag, alloc)))
             },
         )?;
-        if let Some((alloc_id, offset, ptr, alloc)) = ptr_and_alloc {
+        if let Some((alloc_id, offset, tag, alloc)) = ptr_and_alloc {
             let range = alloc_range(offset, size);
-            M::memory_read(*self.tcx, &self.machine, &alloc.extra, ptr.provenance, range)?;
+            M::memory_read(*self.tcx, &self.machine, &alloc.extra, (alloc_id, tag), range)?;
             Ok(Some(AllocRef { alloc, range, tcx: *self.tcx, alloc_id }))
         } else {
             // Even in this branch we have to be sure that we actually access the allocation, in
@@ -631,13 +624,13 @@ pub fn get_ptr_alloc_mut<'a>(
         align: Align,
     ) -> InterpResult<'tcx, Option<AllocRefMut<'a, 'tcx, M::PointerTag, M::AllocExtra>>> {
         let parts = self.get_ptr_access(ptr, size, align)?;
-        if let Some((alloc_id, offset, ptr)) = parts {
+        if let Some((alloc_id, offset, tag)) = parts {
             let tcx = *self.tcx;
             // FIXME: can we somehow avoid looking up the allocation twice here?
             // We cannot call `get_raw_mut` inside `check_and_deref_ptr` as that would duplicate `&mut self`.
             let (alloc, machine) = self.get_alloc_raw_mut(alloc_id)?;
             let range = alloc_range(offset, size);
-            M::memory_written(tcx, machine, &mut alloc.extra, ptr.provenance, range)?;
+            M::memory_written(tcx, machine, &mut alloc.extra, (alloc_id, tag), range)?;
             Ok(Some(AllocRefMut { alloc, range, tcx, alloc_id }))
         } else {
             Ok(None)
@@ -732,7 +725,7 @@ pub fn get_ptr_fn(
         ptr: Pointer<Option<M::PointerTag>>,
     ) -> InterpResult<'tcx, FnVal<'tcx, M::ExtraFnVal>> {
         trace!("get_fn({:?})", ptr);
-        let (alloc_id, offset, _ptr) = self.ptr_get_alloc_id(ptr)?;
+        let (alloc_id, offset, _tag) = self.ptr_get_alloc_id(ptr)?;
         if offset.bytes() != 0 {
             throw_ub!(InvalidFunctionPointer(Pointer::new(alloc_id, offset)))
         }
@@ -877,9 +870,17 @@ pub fn write_scalar(
         range: AllocRange,
         val: ScalarMaybeUninit<Tag>,
     ) -> InterpResult<'tcx> {
+        let range = self.range.subrange(range);
+        debug!(
+            "write_scalar in {} at {:#x}, size {}: {:?}",
+            self.alloc_id,
+            range.start.bytes(),
+            range.size.bytes(),
+            val
+        );
         Ok(self
             .alloc
-            .write_scalar(&self.tcx, self.range.subrange(range), val)
+            .write_scalar(&self.tcx, range, val)
             .map_err(|e| e.to_interp_error(self.alloc_id))?)
     }
 
@@ -892,17 +893,29 @@ pub fn write_ptr_sized(
     }
 
     /// Mark the entire referenced range as uninitalized
-    pub fn write_uninit(&mut self) {
-        self.alloc.mark_init(self.range, false);
+    pub fn write_uninit(&mut self) -> InterpResult<'tcx> {
+        Ok(self
+            .alloc
+            .write_uninit(&self.tcx, self.range)
+            .map_err(|e| e.to_interp_error(self.alloc_id))?)
     }
 }
 
 impl<'tcx, 'a, Tag: Provenance, Extra> AllocRef<'a, 'tcx, Tag, Extra> {
     pub fn read_scalar(&self, range: AllocRange) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> {
-        Ok(self
+        let range = self.range.subrange(range);
+        let res = self
             .alloc
-            .read_scalar(&self.tcx, self.range.subrange(range))
-            .map_err(|e| e.to_interp_error(self.alloc_id))?)
+            .read_scalar(&self.tcx, range)
+            .map_err(|e| e.to_interp_error(self.alloc_id))?;
+        debug!(
+            "read_scalar in {} at {:#x}, size {}: {:?}",
+            self.alloc_id,
+            range.start.bytes(),
+            range.size.bytes(),
+            res
+        );
+        Ok(res)
     }
 
     pub fn read_ptr_sized(&self, offset: Size) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> {
@@ -1009,16 +1022,16 @@ pub fn mem_copy_repeatedly(
         // and once below to get the underlying `&[mut] Allocation`.
 
         // Source alloc preparations and access hooks.
-        let Some((src_alloc_id, src_offset, src)) = src_parts else {
+        let Some((src_alloc_id, src_offset, src_tag)) = src_parts else {
             // Zero-sized *source*, that means dst is also zero-sized and we have nothing to do.
             return Ok(());
         };
         let src_alloc = self.get_alloc_raw(src_alloc_id)?;
         let src_range = alloc_range(src_offset, size);
-        M::memory_read(*tcx, &self.machine, &src_alloc.extra, src.provenance, src_range)?;
+        M::memory_read(*tcx, &self.machine, &src_alloc.extra, (src_alloc_id, src_tag), src_range)?;
         // We need the `dest` ptr for the next operation, so we get it now.
         // We already did the source checks and called the hooks so we are good to return early.
-        let Some((dest_alloc_id, dest_offset, dest)) = dest_parts else {
+        let Some((dest_alloc_id, dest_offset, dest_tag)) = dest_parts else {
             // Zero-sized *destination*.
             return Ok(());
         };
@@ -1040,7 +1053,13 @@ pub fn mem_copy_repeatedly(
         // Destination alloc preparations and access hooks.
         let (dest_alloc, extra) = self.get_alloc_raw_mut(dest_alloc_id)?;
         let dest_range = alloc_range(dest_offset, size * num_copies);
-        M::memory_written(*tcx, extra, &mut dest_alloc.extra, dest.provenance, dest_range)?;
+        M::memory_written(
+            *tcx,
+            extra,
+            &mut dest_alloc.extra,
+            (dest_alloc_id, dest_tag),
+            dest_range,
+        )?;
         let dest_bytes = dest_alloc
             .get_bytes_mut_ptr(&tcx, dest_range)
             .map_err(|e| e.to_interp_error(dest_alloc_id))?
@@ -1053,8 +1072,10 @@ pub fn mem_copy_repeatedly(
             // This also avoids writing to the target bytes so that the backing allocation is never
             // touched if the bytes stay uninitialized for the whole interpreter execution. On contemporary
             // operating system this can avoid physically allocating the page.
-            dest_alloc.mark_init(dest_range, false); // `Size` multiplication
-            dest_alloc.mark_relocation_range(relocations);
+            dest_alloc
+                .write_uninit(&tcx, dest_range)
+                .map_err(|e| e.to_interp_error(dest_alloc_id))?;
+            // We can forget about the relocations, this is all not initialized anyway.
             return Ok(());
         }
 
@@ -1159,11 +1180,11 @@ pub fn scalar_may_be_null(&self, scalar: Scalar<M::PointerTag>) -> InterpResult<
     pub fn ptr_try_get_alloc_id(
         &self,
         ptr: Pointer<Option<M::PointerTag>>,
-    ) -> Result<(AllocId, Size, Pointer<M::PointerTag>), u64> {
+    ) -> Result<(AllocId, Size, M::TagExtra), u64> {
         match ptr.into_pointer_or_addr() {
             Ok(ptr) => {
-                let (alloc_id, offset) = M::ptr_get_alloc(self, ptr);
-                Ok((alloc_id, offset, ptr))
+                let (alloc_id, offset, extra) = M::ptr_get_alloc(self, ptr);
+                Ok((alloc_id, offset, extra))
             }
             Err(addr) => Err(addr.bytes()),
         }
@@ -1174,7 +1195,7 @@ pub fn ptr_try_get_alloc_id(
     pub fn ptr_get_alloc_id(
         &self,
         ptr: Pointer<Option<M::PointerTag>>,
-    ) -> InterpResult<'tcx, (AllocId, Size, Pointer<M::PointerTag>)> {
+    ) -> InterpResult<'tcx, (AllocId, Size, M::TagExtra)> {
         self.ptr_try_get_alloc_id(ptr).map_err(|offset| {
             err_ub!(DanglingIntPointer(offset, CheckInAllocMsg::InboundsTest)).into()
         })
index 31da4522a1fda38ff0554920315fa39c5111e597..e4660fe090ce5fb4900d9c350908103866906a1d 100644 (file)
@@ -823,7 +823,7 @@ pub fn write_uninit(&mut self, dest: &PlaceTy<'tcx, M::PointerTag>) -> InterpRes
             // Zero-sized access
             return Ok(());
         };
-        alloc.write_uninit();
+        alloc.write_uninit()?;
         Ok(())
     }
 
index 4a0aa41de739b3caa13f0ed80fa3170fc8c3d331..71d29be97d5ec38e99b544bee0532d2c58ad4400 100644 (file)
@@ -432,7 +432,7 @@ fn check_safe_pointer(
         if let Some(ref mut ref_tracking) = self.ref_tracking {
             // Proceed recursively even for ZST, no reason to skip them!
             // `!` is a ZST and we want to validate it.
-            if let Ok((alloc_id, _offset, _ptr)) = self.ecx.ptr_try_get_alloc_id(place.ptr) {
+            if let Ok((alloc_id, _offset, _tag)) = self.ecx.ptr_try_get_alloc_id(place.ptr) {
                 // Special handling for pointers to statics (irrespective of their type).
                 let alloc_kind = self.ecx.tcx.get_global_alloc(alloc_id);
                 if let Some(GlobalAlloc::Static(did)) = alloc_kind {
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 85ad0f2f7f5ce5aca99f2f8ddc601ce1f7f45f6b..25353290fd50c4943c018554102791388342163d 100644 (file)
@@ -207,9 +207,14 @@ pub trait ToStableHashKey<HCX> {
     fn to_stable_hash_key(&self, hcx: &HCX) -> Self::KeyType;
 }
 
-// Implement HashStable by just calling `Hash::hash()`. This works fine for
-// self-contained values that don't depend on the hashing context `CTX`.
-#[macro_export]
+/// Implement HashStable by just calling `Hash::hash()`.
+///
+/// **WARNING** This is only valid for types that *really* don't need any context for fingerprinting.
+/// But it is easy to misuse this macro (see [#96013](https://github.com/rust-lang/rust/issues/96013)
+/// for examples). Therefore this macro is not exported and should only be used in the limited cases
+/// here in this module.
+///
+/// Use `#[derive(HashStable_Generic)]` instead.
 macro_rules! impl_stable_hash_via_hash {
     ($t:ty) => {
         impl<CTX> $crate::stable_hasher::HashStable<CTX> for $t {
@@ -246,12 +251,14 @@ fn hash_stable(&self, _ctx: &mut CTX, _hasher: &mut StableHasher) {
 }
 
 impl<CTX> HashStable<CTX> for ::std::num::NonZeroU32 {
+    #[inline]
     fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
         self.get().hash_stable(ctx, hasher)
     }
 }
 
 impl<CTX> HashStable<CTX> for ::std::num::NonZeroUsize {
+    #[inline]
     fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
         self.get().hash_stable(ctx, hasher)
     }
@@ -272,12 +279,14 @@ fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
 }
 
 impl<CTX> HashStable<CTX> for ::std::cmp::Ordering {
+    #[inline]
     fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
         (*self as i8).hash_stable(ctx, hasher);
     }
 }
 
 impl<T1: HashStable<CTX>, CTX> HashStable<CTX> for (T1,) {
+    #[inline]
     fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
         let (ref _0,) = *self;
         _0.hash_stable(ctx, hasher);
index de0dd18cc6ec5402283997b1adcb2581aa34c343..e1e0ed7222d55fb39265197de0f449e32bf5d32d 100644 (file)
@@ -338,18 +338,12 @@ pub fn primary_spans(&self) -> &[Span] {
 
     /// Returns `true` if any of the primary spans are displayable.
     pub fn has_primary_spans(&self) -> bool {
-        self.primary_spans.iter().any(|sp| !sp.is_dummy())
+        !self.is_dummy()
     }
 
     /// Returns `true` if this contains only a dummy primary span with any hygienic context.
     pub fn is_dummy(&self) -> bool {
-        let mut is_dummy = true;
-        for span in &self.primary_spans {
-            if !span.is_dummy() {
-                is_dummy = false;
-            }
-        }
-        is_dummy
+        self.primary_spans.iter().all(|sp| sp.is_dummy())
     }
 
     /// Replaces all occurrences of one Span with another. Used to move `Span`s in areas that don't
index 9cd072c8b4cdf38af332c504b226cea1996edb3f..cd17726c78588dae3ac87503de5ba14dd192a8c1 100644 (file)
@@ -1,12 +1,11 @@
 use crate::snippet::Style;
 use crate::{
     CodeSuggestion, DiagnosticMessage, Level, MultiSpan, Substitution, SubstitutionPart,
-    SuggestionStyle, ToolMetadata,
+    SuggestionStyle,
 };
 use rustc_data_structures::stable_map::FxHashMap;
 use rustc_error_messages::FluentValue;
 use rustc_lint_defs::{Applicability, LintExpectationId};
-use rustc_serialize::json::Json;
 use rustc_span::edition::LATEST_STABLE_EDITION;
 use rustc_span::symbol::{Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
@@ -554,7 +553,6 @@ pub fn multipart_suggestion_with_style(
             msg: msg.into(),
             style,
             applicability,
-            tool_metadata: Default::default(),
         });
         self
     }
@@ -582,7 +580,6 @@ pub fn tool_only_multipart_suggestion(
             msg: msg.into(),
             style: SuggestionStyle::CompletelyHidden,
             applicability,
-            tool_metadata: Default::default(),
         });
         self
     }
@@ -637,7 +634,6 @@ pub fn span_suggestion_with_style(
             msg: msg.into(),
             style,
             applicability,
-            tool_metadata: Default::default(),
         });
         self
     }
@@ -680,7 +676,6 @@ pub fn span_suggestions(
             msg: msg.into(),
             style: SuggestionStyle::ShowCode,
             applicability,
-            tool_metadata: Default::default(),
         });
         self
     }
@@ -705,7 +700,6 @@ pub fn multipart_suggestions(
             msg: msg.into(),
             style: SuggestionStyle::ShowCode,
             applicability,
-            tool_metadata: Default::default(),
         });
         self
     }
@@ -774,23 +768,6 @@ pub fn tool_only_span_suggestion(
         self
     }
 
-    /// Adds a suggestion intended only for a tool. The intent is that the metadata encodes
-    /// the suggestion in a tool-specific way, as it may not even directly involve Rust code.
-    pub fn tool_only_suggestion_with_metadata(
-        &mut self,
-        msg: impl Into<DiagnosticMessage>,
-        applicability: Applicability,
-        tool_metadata: Json,
-    ) {
-        self.push_suggestion(CodeSuggestion {
-            substitutions: vec![],
-            msg: msg.into(),
-            style: SuggestionStyle::CompletelyHidden,
-            applicability,
-            tool_metadata: ToolMetadata::new(tool_metadata),
-        })
-    }
-
     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..d2180408477044b1e7e795874d2ab212ab415a13 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])*
index 0139007da4261222d7b565c72da23e59bca2b586..d680e7fab704763917a2361f2c67b2100b33e915 100644 (file)
@@ -14,7 +14,6 @@
 use crate::emitter::{Emitter, HumanReadableErrorType};
 use crate::registry::Registry;
 use crate::DiagnosticId;
-use crate::ToolMetadata;
 use crate::{
     CodeSuggestion, FluentBundle, LazyFallbackBundle, MultiSpan, SpanLabel, SubDiagnostic,
 };
@@ -30,7 +29,6 @@
 use std::vec;
 
 use rustc_serialize::json::{as_json, as_pretty_json};
-use rustc_serialize::{Encodable, Encoder};
 
 #[cfg(test)]
 mod tests;
@@ -205,8 +203,7 @@ fn should_show_explain(&self) -> bool {
 
 // The following data types are provided just for serialisation.
 
-// NOTE: this has a manual implementation of Encodable which needs to be updated in
-// parallel.
+#[derive(Encodable)]
 struct Diagnostic {
     /// The primary error message.
     message: String,
@@ -218,65 +215,6 @@ struct Diagnostic {
     children: Vec<Diagnostic>,
     /// The message as rustc would render it.
     rendered: Option<String>,
-    /// Extra tool metadata
-    tool_metadata: ToolMetadata,
-}
-
-macro_rules! encode_fields {
-    (
-        $enc:expr,                  // encoder
-        $idx:expr,                  // starting field index
-        $struct:expr,               // struct we're serializing
-        $struct_name:ident,         // struct name
-        [ $($name:ident),+$(,)? ],  // fields to encode
-        [ $($ignore:ident),+$(,)? ] // fields we're skipping
-    ) => {
-        {
-            // Pattern match to make sure all fields are accounted for
-            let $struct_name { $($name,)+ $($ignore: _,)+ } = $struct;
-            let mut idx = $idx;
-            $(
-                $enc.emit_struct_field(
-                    stringify!($name),
-                    idx == 0,
-                    |enc| $name.encode(enc),
-                )?;
-                idx += 1;
-            )+
-            idx
-        }
-    };
-}
-
-// Special-case encoder to skip tool_metadata if not set
-impl<E: Encoder> Encodable<E> for Diagnostic {
-    fn encode(&self, s: &mut E) -> Result<(), E::Error> {
-        s.emit_struct(false, |s| {
-            let mut idx = 0;
-
-            idx = encode_fields!(
-                s,
-                idx,
-                self,
-                Self,
-                [message, code, level, spans, children, rendered],
-                [tool_metadata]
-            );
-            if self.tool_metadata.is_set() {
-                idx = encode_fields!(
-                    s,
-                    idx,
-                    self,
-                    Self,
-                    [tool_metadata],
-                    [message, code, level, spans, children, rendered]
-                );
-            }
-
-            let _ = idx;
-            Ok(())
-        })
-    }
 }
 
 #[derive(Encodable)]
@@ -380,7 +318,6 @@ fn from_errors_diagnostic(diag: &crate::Diagnostic, je: &JsonEmitter) -> Diagnos
                 spans: DiagnosticSpan::from_suggestion(sugg, &args, je),
                 children: vec![],
                 rendered: None,
-                tool_metadata: sugg.tool_metadata.clone(),
             }
         });
 
@@ -428,7 +365,6 @@ fn flush(&mut self) -> io::Result<()> {
                 .chain(sugg)
                 .collect(),
             rendered: Some(output),
-            tool_metadata: ToolMetadata::default(),
         }
     }
 
@@ -449,7 +385,6 @@ fn from_sub_diagnostic(
                 .unwrap_or_else(|| DiagnosticSpan::from_multispan(&diag.span, args, je)),
             children: vec![],
             rendered: None,
-            tool_metadata: ToolMetadata::default(),
         }
     }
 }
index d7c5df7d8e26eed42b608e4cd20514555e3b67f5..4e6ab0edf6666377c97b16e433619dd6c785f2c2 100644 (file)
     LazyFallbackBundle, MultiSpan, SpanLabel, DEFAULT_LOCALE_RESOURCES,
 };
 pub use rustc_lint_defs::{pluralize, Applicability};
-use rustc_serialize::json::Json;
-use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 use rustc_span::source_map::SourceMap;
+use rustc_span::HashStableContext;
 use rustc_span::{Loc, Span};
 
 use std::borrow::Cow;
-use std::hash::{Hash, Hasher};
+use std::hash::Hash;
 use std::num::NonZeroUsize;
 use std::panic;
 use std::path::Path;
@@ -93,39 +92,6 @@ fn hide_inline(&self) -> bool {
     }
 }
 
-#[derive(Clone, Debug, PartialEq, Default)]
-pub struct ToolMetadata(pub Option<Json>);
-
-impl ToolMetadata {
-    fn new(json: Json) -> Self {
-        ToolMetadata(Some(json))
-    }
-
-    fn is_set(&self) -> bool {
-        self.0.is_some()
-    }
-}
-
-impl Hash for ToolMetadata {
-    fn hash<H: Hasher>(&self, _state: &mut H) {}
-}
-
-// Doesn't really need to round-trip
-impl<D: Decoder> Decodable<D> for ToolMetadata {
-    fn decode(_d: &mut D) -> Self {
-        ToolMetadata(None)
-    }
-}
-
-impl<S: Encoder> Encodable<S> for ToolMetadata {
-    fn encode(&self, e: &mut S) -> Result<(), S::Error> {
-        match &self.0 {
-            None => e.emit_unit(),
-            Some(json) => json.encode(e),
-        }
-    }
-}
-
 #[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
 pub struct CodeSuggestion {
     /// Each substitute can have multiple variants due to multiple
@@ -159,8 +125,6 @@ pub struct CodeSuggestion {
     /// which are useful for users but not useful for
     /// tools like rustfix
     pub applicability: Applicability,
-    /// Tool-specific metadata
-    pub tool_metadata: ToolMetadata,
 }
 
 #[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
@@ -1531,6 +1495,7 @@ pub fn add_elided_lifetime_in_path_suggestion(
 /// Useful type to use with `Result<>` indicate that an error has already
 /// been reported to the user, so no need to continue checking.
 #[derive(Clone, Copy, Debug, Encodable, Decodable, Hash, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(HashStable_Generic)]
 pub struct ErrorGuaranteed(());
 
 impl ErrorGuaranteed {
@@ -1540,5 +1505,3 @@ pub fn unchecked_claim_error_was_emitted() -> Self {
         ErrorGuaranteed(())
     }
 }
-
-rustc_data_structures::impl_stable_hash_via_hash!(ErrorGuaranteed);
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 53d60d280c001dcf3179d0488facd869e828a5dc..324e110005717ac6517f4f357e4b4dc7c08cc1a2 100644 (file)
@@ -1,4 +1,4 @@
-use crate::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use crate::def_id::DefId;
 use crate::hir;
 
 use rustc_ast as ast;
@@ -124,9 +124,7 @@ impl DefKind {
     pub fn descr(self, def_id: DefId) -> &'static str {
         match self {
             DefKind::Fn => "function",
-            DefKind::Mod if def_id.index == CRATE_DEF_INDEX && def_id.krate != LOCAL_CRATE => {
-                "crate"
-            }
+            DefKind::Mod if def_id.is_crate_root() && !def_id.is_local() => "crate",
             DefKind::Mod => "module",
             DefKind::Static(..) => "static",
             DefKind::Enum => "enum",
index 4908992085a6e12de70bf3f25fc513d71c4f0ff2..bce9ba12ac0c424045e391a05f420f714307d4f7 100644 (file)
@@ -353,11 +353,6 @@ pub fn new(stable_crate_id: StableCrateId, crate_span: Span) -> Definitions {
         }
     }
 
-    /// Retrieves the root definition.
-    pub fn get_root_def(&self) -> LocalDefId {
-        LocalDefId { local_def_index: CRATE_DEF_INDEX }
-    }
-
     /// Adds a definition with a parent definition.
     pub fn create_def(
         &mut self,
index b3de86662eb09dc71da34f0f7187bab0bf975458..2d01673b61d315a6412be74cbe8bfcd40bccd026 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};
@@ -2140,10 +2140,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 kind: ImplItemKind<'hir>,
     pub span: Span,
+    pub vis_span: Span,
 }
 
 impl ImplItem<'_> {
@@ -2645,34 +2645,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 +2721,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<'_> {
@@ -3002,7 +2979,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<'_> {
@@ -3210,7 +3187,6 @@ pub enum Node<'hir> {
 
     Lifetime(&'hir Lifetime),
     GenericParam(&'hir GenericParam<'hir>),
-    Visibility(&'hir Visibility<'hir>),
 
     Crate(&'hir Mod<'hir>),
 
@@ -3253,7 +3229,6 @@ pub fn ident(&self) -> Option<Ident> {
             | Node::Binding(..)
             | Node::Arm(..)
             | Node::Local(..)
-            | Node::Visibility(..)
             | Node::Crate(..)
             | Node::Ty(..)
             | Node::TraitRef(..)
@@ -3318,18 +3293,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 +3314,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.
@@ -3350,8 +3331,8 @@ mod size_asserts {
     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::Item<'static>, 160);
     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::ImplItem<'static>, 120);
+    rustc_data_structures::static_assert_size!(super::ForeignItem<'static>, 112);
 }
index 3b5e4dcf5e01188db28d3edfcab62cc43167b28f..346ac9e96440abfb1eae0ec9932bf40d5b6fdd91 100644 (file)
@@ -1,4 +1,4 @@
-use crate::def_id::{LocalDefId, CRATE_DEF_INDEX};
+use crate::def_id::{LocalDefId, CRATE_DEF_ID};
 use std::fmt;
 
 /// Uniquely identifies a node in the HIR of the current crate. It is
@@ -76,16 +76,14 @@ fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
     /// integers starting at zero, so a mapping that maps all or most nodes within
     /// an "item-like" to something else can be implemented by a `Vec` instead of a
     /// tree or hash map.
+    #[derive(HashStable_Generic)]
     pub struct ItemLocalId { .. }
 }
-rustc_data_structures::impl_stable_hash_via_hash!(ItemLocalId);
+
 impl ItemLocalId {
     /// Signal local id which should never be used.
     pub const INVALID: ItemLocalId = ItemLocalId::MAX;
 }
 
-/// The `HirId` corresponding to `CRATE_NODE_ID` and `CRATE_DEF_INDEX`.
-pub const CRATE_HIR_ID: HirId = HirId {
-    owner: LocalDefId { local_def_index: CRATE_DEF_INDEX },
-    local_id: ItemLocalId::from_u32(0),
-};
+/// The `HirId` corresponding to `CRATE_NODE_ID` and `CRATE_DEF_ID`.
+pub const CRATE_HIR_ID: HirId = HirId { owner: CRATE_DEF_ID, local_id: ItemLocalId::from_u32(0) };
index 8689e2c2afab36fd504eaf3c203bc09226bb8872..59bd46ae353b2f23611d087d0ba11de57ec68614 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,
         }
     }
@@ -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,
@@ -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 {
@@ -999,7 +994,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 +1020,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 +1032,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 +1076,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 +1243,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 27f07a479b1b0ea0d8f14f6b3cdd010fa614aa53..87ff94577836cfcccd89d382c2eb98bc252356b9 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(":");
@@ -473,7 +460,7 @@ 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
@@ -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,7 +626,6 @@ 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.word_nbsp("impl");
@@ -679,7 +662,6 @@ pub fn print_item(&mut self, item: &hir::Item<'_>) {
             }
             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");
@@ -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());
@@ -753,9 +735,8 @@ 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);
@@ -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,7 +783,6 @@ 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();
@@ -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();
@@ -2301,16 +2251,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 86229dbfad746a51b528e1de9fff6d256cf7baff..0ca0fe33614f826600589d69fd0edfcea9b14d9e 100644 (file)
@@ -567,11 +567,17 @@ fn relate_item_substs(
             // Avoid fetching the variance if we are in an invariant
             // context; no need, and it can induce dependency cycles
             // (e.g., #41849).
-            relate::relate_substs(self, None, a_subst, b_subst)
+            relate::relate_substs(self, a_subst, b_subst)
         } else {
             let tcx = self.tcx();
             let opt_variances = tcx.variances_of(item_def_id);
-            relate::relate_substs(self, Some((item_def_id, &opt_variances)), a_subst, b_subst)
+            relate::relate_substs_with_variances(
+                self,
+                item_def_id,
+                &opt_variances,
+                a_subst,
+                b_subst,
+            )
         }
     }
 
index 65c0eba4b3d5c791aa254269c389c3c26460e5f4..ef6d464d3c6f101bad711e81647aa88450a4857b 100644 (file)
@@ -53,7 +53,7 @@ fn relate_item_substs(
         // performing trait matching (which then performs equality
         // unification).
 
-        relate::relate_substs(self, None, a_subst, b_subst)
+        relate::relate_substs(self, a_subst, b_subst)
     }
 
     fn relate_with_variance<T: Relate<'tcx>>(
index f2dd4f5d5cbcae1273fa0d4d3a7bf5d91d9d7ca2..f9273cc50b70a2b6a44b6c1630afb6e618170035 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;
@@ -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
@@ -2606,11 +2606,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:
index df81aea6ef9ecfb1ceda0f93dd452fc701883633..79f852d8a95e739e0ed1c10a4c11ff4c5b2cf4f0 100644 (file)
@@ -15,6 +15,7 @@
 mod util;
 
 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..7d3ed2ed38a307b6ff8c1b01b7cd40c5f88a2ebc 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).unwrap(), 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 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 8ea47dda928f5f0cc8af8c4ab83299c95ee021e1..02f747eeccc3e1eb21f72d4f6395c4f0112bb58b 100644 (file)
@@ -18,7 +18,6 @@ rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_feature = { path = "../rustc_feature" }
 rustc_index = { path = "../rustc_index" }
 rustc_session = { path = "../rustc_session" }
-rustc_serialize = { path = "../rustc_serialize" }
 rustc_trait_selection = { path = "../rustc_trait_selection" }
 rustc_parse_format = { path = "../rustc_parse_format" }
 rustc_infer = { path = "../rustc_infer" }
index 77fe76af2de21ce7d777168524540788f5145347..68658e2616e9b76c697e1166374a1ebbbc09f05f 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);
@@ -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,
+            );
+        }
     }
 }
 
index 152c53dac7ff8d0790927205cf418116d336d06a..0ffa65b79b584a5070e06bc93b2bcd717a6f91cb 100644 (file)
@@ -33,8 +33,7 @@
 use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, print::Printer, subst::GenericArg, RegisteredTools, Ty, TyCtxt};
-use rustc_serialize::json::Json;
-use rustc_session::lint::{BuiltinLintDiagnostics, ExternDepSpec};
+use rustc_session::lint::BuiltinLintDiagnostics;
 use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintId};
 use rustc_session::Session;
 use rustc_span::lev_distance::find_best_match_for_name;
@@ -728,30 +727,6 @@ fn lookup_with_diagnostics(
                 BuiltinLintDiagnostics::LegacyDeriveHelpers(span) => {
                     db.span_label(span, "the attribute is introduced here");
                 }
-                BuiltinLintDiagnostics::ExternDepSpec(krate, loc) => {
-                    let json = match loc {
-                        ExternDepSpec::Json(json) => {
-                            db.help(&format!("remove unnecessary dependency `{}`", krate));
-                            json
-                        }
-                        ExternDepSpec::Raw(raw) => {
-                            db.help(&format!("remove unnecessary dependency `{}` at `{}`", krate, raw));
-                            db.span_suggestion_with_style(
-                                DUMMY_SP,
-                                "raw extern location",
-                                raw.clone(),
-                                Applicability::Unspecified,
-                                SuggestionStyle::CompletelyHidden,
-                            );
-                            Json::String(raw)
-                        }
-                    };
-                    db.tool_only_suggestion_with_metadata(
-                        "json extern location",
-                        Applicability::Unspecified,
-                        json
-                    );
-                }
                 BuiltinLintDiagnostics::ProcMacroBackCompat(note) => {
                     db.note(&note);
                 }
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 4debbf26be63b1063c7c9dc855f0153662416756..f590172af4f9ccf8c2b33e456b6be0fd4dec2ea6 100644 (file)
@@ -8,8 +8,8 @@
 use rustc_ast::{AttrId, Attribute};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
 use rustc_error_messages::MultiSpan;
+use rustc_hir::HashStableContext;
 use rustc_hir::HirId;
-use rustc_serialize::json::Json;
 use rustc_span::edition::Edition;
 use rustc_span::{sym, symbol::Ident, Span, Symbol};
 use rustc_target::spec::abi::Abi;
@@ -147,7 +147,7 @@ fn to_stable_hash_key(&self, _: &HCX) -> Self::KeyType {
 /// Setting for how to handle a lint.
 ///
 /// See: <https://doc.rust-lang.org/rustc/lints/levels.html>
-#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
+#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash, HashStable_Generic)]
 pub enum Level {
     /// The `allow` level will not issue any message.
     Allow,
@@ -175,8 +175,6 @@ pub enum Level {
     Forbid,
 }
 
-rustc_data_structures::impl_stable_hash_via_hash!(Level);
-
 impl Level {
     /// Converts a level to a lower-case string.
     pub fn as_str(self) -> &'static str {
@@ -403,13 +401,6 @@ fn to_stable_hash_key(&self, _: &HCX) -> &'static str {
     }
 }
 
-// Duplicated from rustc_session::config::ExternDepSpec to avoid cyclic dependency
-#[derive(PartialEq, Debug)]
-pub enum ExternDepSpec {
-    Json(Json),
-    Raw(String),
-}
-
 // This could be a closure, but then implementing derive trait
 // becomes hacky (and it gets allocated).
 #[derive(Debug)]
@@ -428,7 +419,6 @@ pub enum BuiltinLintDiagnostics {
     UnusedBuiltinAttribute { attr_name: Symbol, macro_name: String, invoc_span: Span },
     PatternsInFnsWithoutBody(Span, Ident),
     LegacyDeriveHelpers(Span),
-    ExternDepSpec(String, ExternDepSpec),
     ProcMacroBackCompat(String),
     OrPatternsBackCompat(Span, String),
     ReservedPrefix(Span),
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..850b80e42801bfe31074df388103e21e87a66317 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"
index 46f698f6f9b819ef793934c319031b6e2bab8372..ff7506979fc3445c9ed78c834ebad5b35246aa34 100644 (file)
 /// # extern crate rust_middle;
 /// # use rustc_middle::ty::Ty;
 /// #[derive(SessionDiagnostic)]
-/// #[error(code = "E0505", slug = "move-out-of-borrow-error")]
+/// #[error(code = "E0505", slug = "borrowck-move-out-of-borrow")]
 /// pub struct MoveOutOfBorrowError<'tcx> {
 ///     pub name: Ident,
 ///     pub ty: Ty<'tcx>,
 ///     #[primary_span]
-///     #[label = "cannot move out of borrow"]
+///     #[label]
 ///     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)>
+///     #[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)
 ///     expected,
 ///     actual,
 ///     span,
-///     other_span,
-///     opt_sugg: Some(suggestion, Applicability::MachineApplicable),
+///     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: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
     // Names for the diagnostic we build and the session we build it from.
     let diag = format_ident!("diag");
index 566d27212d08dcbfee7b44a6f50553222b1b69d5..e8cdae7fd25ceb742492882fac8360b08774931a 100644 (file)
 use rustc_hir::definitions::Definitions;
 use rustc_index::vec::IndexVec;
 use rustc_middle::ty::TyCtxt;
-use rustc_serialize::json::ToJson;
 use rustc_session::config::{self, CrateType, ExternLocation};
 use rustc_session::cstore::{CrateDepKind, CrateSource, ExternCrate};
 use rustc_session::cstore::{ExternCrateSource, MetadataLoaderDyn};
-use rustc_session::lint::{self, BuiltinLintDiagnostics, ExternDepSpec};
+use rustc_session::lint;
 use rustc_session::output::validate_crate_name;
 use rustc_session::search_paths::PathKind;
 use rustc_session::Session;
@@ -27,7 +26,6 @@
 use rustc_target::spec::{PanicStrategy, TargetTriple};
 
 use proc_macro::bridge::client::ProcMacro;
-use std::collections::BTreeMap;
 use std::ops::Fn;
 use std::path::Path;
 use std::{cmp, env};
@@ -909,6 +907,10 @@ 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;
@@ -920,20 +922,7 @@ fn report_unused_deps(&mut self, krate: &ast::Crate) {
                 continue;
             }
 
-            let diag = match self.sess.opts.extern_dep_specs.get(name) {
-                Some(loc) => BuiltinLintDiagnostics::ExternDepSpec(name.clone(), loc.into()),
-                None => {
-                    // If we don't have a specific location, provide a json encoding of the `--extern`
-                    // option.
-                    let meta: BTreeMap<String, String> =
-                        std::iter::once(("name".to_string(), name.to_string())).collect();
-                    BuiltinLintDiagnostics::ExternDepSpec(
-                        name.clone(),
-                        ExternDepSpec::Json(meta.to_json()),
-                    )
-                }
-            };
-            self.sess.parse_sess.buffer_lint_with_diagnostic(
+            self.sess.parse_sess.buffer_lint(
                     lint::builtin::UNUSED_CRATE_DEPENDENCIES,
                     span,
                     ast::CRATE_NODE_ID,
@@ -942,7 +931,6 @@ fn report_unused_deps(&mut self, krate: &ast::Crate) {
                         name,
                         self.local_crate_name,
                         name),
-                    diag,
                 );
         }
     }
index 611694a0d304201cb4fc3d734bee720fec66469c..1edb62e189f9768c3b8dbc16b8dfbee25621ccb4 100644 (file)
 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;
 use rustc_middle::ty::codec::TyDecoder;
 use rustc_middle::ty::fast_reject::SimplifiedType;
+use rustc_middle::ty::GeneratorDiagnosticData;
 use rustc_middle::ty::{self, Ty, TyCtxt, Visibility};
 use rustc_serialize::{opaque, Decodable, Decoder};
 use rustc_session::cstore::{
@@ -1428,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)))
     }
 
@@ -1725,6 +1726,28 @@ fn imported_source_files(self, sess: &Session) -> &'a [ImportedSourceFile] {
                 .collect()
         })
     }
+
+    fn get_generator_diagnostic_data(
+        self,
+        tcx: TyCtxt<'tcx>,
+        id: DefIndex,
+    ) -> Option<GeneratorDiagnosticData<'tcx>> {
+        self.root
+            .tables
+            .generator_diagnostic_data
+            .get(self, id)
+            .map(|param| param.decode((self, tcx)))
+            .map(|generator_data| GeneratorDiagnosticData {
+                generator_interior_types: generator_data.generator_interior_types,
+                hir_owner: generator_data.hir_owner,
+                nodes_types: generator_data.nodes_types,
+                adjustments: generator_data.adjustments,
+            })
+    }
+
+    fn get_may_have_doc_links(self, index: DefIndex) -> bool {
+        self.root.tables.may_have_doc_links.get(self, index).is_some()
+    }
 }
 
 impl CrateMetadata {
index 63bf929fb86393a7bc4b102dcd54dca606bb9865..da1dd6af65a5dd72a27ec00a1d00a5324882119f 100644 (file)
@@ -5,7 +5,7 @@
 
 use rustc_ast as ast;
 use rustc_hir::def::{CtorKind, DefKind, Res};
-use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LOCAL_CRATE};
 use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
 use rustc_middle::metadata::ModChild;
 use rustc_middle::middle::exported_symbols::ExportedSymbol;
@@ -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
                 }
@@ -246,6 +246,7 @@ fn into_args(self) -> (DefId, SimplifiedType) {
 
     crate_extern_paths => { cdata.source().paths().cloned().collect() }
     expn_that_defined => { cdata.get_expn_that_defined(def_id.index, tcx.sess) }
+    generator_diagnostic_data => { cdata.get_generator_diagnostic_data(tcx, def_id.index) }
 }
 
 pub(in crate::rmeta) fn provide(providers: &mut Providers) {
@@ -324,7 +325,7 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) {
                     continue;
                 }
 
-                bfs_queue.push_back(DefId { krate: cnum, index: CRATE_DEF_INDEX });
+                bfs_queue.push_back(cnum.as_def_id());
             }
 
             let mut add_child = |bfs_queue: &mut VecDeque<_>, child: &ModChild, parent: DefId| {
@@ -530,6 +531,18 @@ pub fn incoherent_impls_in_crate_untracked(
     ) -> impl Iterator<Item = DefId> + '_ {
         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)
+    }
 }
 
 impl CrateStore for CStore {
index 6a8d4e037544c6d8e77d1fe0aaa08c448b01e2f0..ed49eebd16d9ce0898712198e652cfc1ed2c7510 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;
@@ -977,6 +977,14 @@ fn should_encode_generics(def_kind: DefKind) -> bool {
 }
 
 impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
+    fn encode_attrs(&mut self, def_id: DefId) {
+        let attrs = self.tcx.get_attrs(def_id);
+        record!(self.tables.attributes[def_id] <- attrs);
+        if attrs.iter().any(|attr| attr.may_have_doc_links()) {
+            self.tables.may_have_doc_links.set(def_id.index, ());
+        }
+    }
+
     fn encode_def_ids(&mut self) {
         if self.is_proc_macro {
             return;
@@ -989,7 +997,7 @@ fn encode_def_ids(&mut self) {
             let Some(def_kind) = def_kind else { continue };
             self.tables.opt_def_kind.set(def_id.index, def_kind);
             record!(self.tables.def_span[def_id] <- tcx.def_span(def_id));
-            record!(self.tables.attributes[def_id] <- tcx.get_attrs(def_id));
+            self.encode_attrs(def_id);
             record!(self.tables.expn_that_defined[def_id] <- self.tcx.expn_that_defined(def_id));
             if should_encode_visibility(def_kind) {
                 record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id));
@@ -1556,16 +1564,17 @@ fn encode_info_for_generic_param(&mut self, def_id: DefId, kind: EntryKind, enco
     fn encode_info_for_closure(&mut self, hir_id: hir::HirId) {
         let def_id = self.tcx.hir().local_def_id(hir_id);
         debug!("EncodeContext::encode_info_for_closure({:?})", def_id);
-
         // NOTE(eddyb) `tcx.type_of(def_id)` isn't used because it's fully generic,
         // including on the signature, which is inferred in `typeck.
-        let ty = self.tcx.typeck(def_id).node_type(hir_id);
-
+        let typeck_result: &'tcx ty::TypeckResults<'tcx> = self.tcx.typeck(def_id);
+        let ty = typeck_result.node_type(hir_id);
         match ty.kind() {
             ty::Generator(..) => {
                 let data = self.tcx.generator_kind(def_id).unwrap();
+                let generator_diagnostic_data = typeck_result.get_generator_diagnostic_data();
                 record!(self.tables.kind[def_id.to_def_id()] <- EntryKind::Generator);
                 record!(self.tables.generator_kind[def_id.to_def_id()] <- data);
+                record!(self.tables.generator_diagnostic_data[def_id.to_def_id()]  <- generator_diagnostic_data);
             }
 
             ty::Closure(..) => {
@@ -1639,7 +1648,7 @@ fn encode_proc_macros(&mut self) -> Option<ProcMacroData> {
             let hir = tcx.hir();
 
             let proc_macro_decls_static = tcx.proc_macro_decls_static(()).unwrap().local_def_index;
-            let stability = tcx.lookup_stability(DefId::local(CRATE_DEF_INDEX));
+            let stability = tcx.lookup_stability(CRATE_DEF_ID);
             let macros =
                 self.lazy(tcx.resolutions(()).proc_macros.iter().map(|p| p.local_def_index));
             let spans = self.tcx.sess.parse_sess.proc_macro_quoted_spans();
@@ -1650,7 +1659,7 @@ fn encode_proc_macros(&mut self) -> Option<ProcMacroData> {
 
             self.tables.opt_def_kind.set(LOCAL_CRATE.as_def_id().index, DefKind::Mod);
             record!(self.tables.def_span[LOCAL_CRATE.as_def_id()] <- tcx.def_span(LOCAL_CRATE.as_def_id()));
-            record!(self.tables.attributes[LOCAL_CRATE.as_def_id()] <- tcx.get_attrs(LOCAL_CRATE.as_def_id()));
+            self.encode_attrs(LOCAL_CRATE.as_def_id());
             record!(self.tables.visibility[LOCAL_CRATE.as_def_id()] <- tcx.visibility(LOCAL_CRATE.as_def_id()));
             if let Some(stability) = stability {
                 record!(self.tables.lookup_stability[LOCAL_CRATE.as_def_id()] <- stability);
@@ -1691,7 +1700,7 @@ fn encode_proc_macros(&mut self) -> Option<ProcMacroData> {
                 let def_id = id.to_def_id();
                 self.tables.opt_def_kind.set(def_id.index, DefKind::Macro(macro_kind));
                 record!(self.tables.kind[def_id] <- EntryKind::ProcMacro(macro_kind));
-                record!(self.tables.attributes[def_id] <- attrs);
+                self.encode_attrs(def_id);
                 record!(self.tables.def_keys[def_id] <- def_key);
                 record!(self.tables.def_ident_span[def_id] <- span);
                 record!(self.tables.def_span[def_id] <- span);
@@ -1865,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 43ccfc64e0563978adf8f7c7b6dfd7a083ff3c2a..cdbed90e6b98e8623bf4a2a9e25f7998b64ea2a5 100644 (file)
 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;
 use rustc_middle::ty::query::Providers;
+use rustc_middle::ty::GeneratorDiagnosticData;
 use rustc_middle::ty::{self, ReprOptions, Ty};
 use rustc_serialize::opaque::Encoder;
 use rustc_session::config::SymbolManglingVersion;
@@ -219,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,
@@ -358,6 +359,8 @@ fn encode(&self, buf: &mut Encoder) -> LazyTables<'tcx> {
     def_keys: Table<DefIndex, Lazy<DefKey>>,
     def_path_hashes: Table<DefIndex, DefPathHash>,
     proc_macro_quoted_spans: Table<usize, Lazy<Span>>,
+    generator_diagnostic_data: Table<DefIndex, Lazy<GeneratorDiagnosticData<'tcx>>>,
+    may_have_doc_links: Table<DefIndex, ()>,
 }
 
 #[derive(Copy, Clone, MetadataEncodable, MetadataDecodable)]
index 7a23cba536a0a18bfdfbc69b4fb3cda5333aacad..53fc2efe00bb79c230515dd319c9246ddca47c99 100644 (file)
@@ -186,6 +186,20 @@ impl FixedSizeEncoding for Option<RawDefId> {
     }
 }
 
+impl FixedSizeEncoding for Option<()> {
+    type ByteArray = [u8; 1];
+
+    #[inline]
+    fn from_bytes(b: &[u8; 1]) -> Self {
+        (b[0] != 0).then(|| ())
+    }
+
+    #[inline]
+    fn write_to_bytes(self, b: &mut [u8; 1]) {
+        b[0] = self.is_some() as u8
+    }
+}
+
 // NOTE(eddyb) there could be an impl for `usize`, which would enable a more
 // generic `Lazy<T>` impl, but in the general case we might not need / want to
 // fit every `usize` in `u32`.
index d20be0a34d2d5f525f456c9c604d3426678e8d2f..8402ca3028cce500665ac2091c230f8cdf91183d 100644 (file)
@@ -60,7 +60,7 @@
 use crate::ty::TyCtxt;
 
 use rustc_data_structures::fingerprint::Fingerprint;
-use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{CrateNum, DefId, LocalDefId};
 use rustc_hir::definitions::DefPathHash;
 use rustc_hir::HirId;
 use rustc_query_system::dep_graph::FingerprintStyle;
@@ -366,7 +366,7 @@ fn fingerprint_style() -> FingerprintStyle {
 
     #[inline(always)]
     fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
-        let def_id = DefId { krate: *self, index: CRATE_DEF_INDEX };
+        let def_id = self.as_def_id();
         def_id.to_fingerprint(tcx)
     }
 
index d74759e31a2d907514c87232a8ed1344c4b4d75f..e0ed402283904a1bf99a1a9f0dbf7df8cf73bb6d 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)
@@ -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 fd6e241346db8e9aeddada8789c59fac6736f03d..758658c3d8c941c8f07081001c9493590f28b955 100644 (file)
@@ -11,7 +11,7 @@
 use rustc_feature::GateIssue;
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
-use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::{self, HirId};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_session::lint::builtin::{DEPRECATED, DEPRECATED_IN_FUTURE, SOFT_UNSTABLE};
@@ -370,8 +370,7 @@ pub fn eval_stability(
             };
         }
 
-        let is_staged_api =
-            self.lookup_stability(DefId { index: CRATE_DEF_INDEX, ..def_id }).is_some();
+        let is_staged_api = self.lookup_stability(def_id.krate.as_def_id()).is_some();
         if !is_staged_api {
             return EvalResult::Allow;
         }
index 438f356f072c6d863e093668d022327785efb3d9..c628406064fb63e4703bf503d75519a680c07534 100644 (file)
@@ -269,7 +269,7 @@ impl<Tag: Provenance, Extra> Allocation<Tag, Extra> {
     /// `get_bytes_with_uninit_and_ptr` instead,
     ///
     /// This function also guarantees that the resulting pointer will remain stable
-    /// even when new allocations are pushed to the `HashMap`. `copy_repeatedly` relies
+    /// even when new allocations are pushed to the `HashMap`. `mem_copy_repeatedly` relies
     /// on that.
     ///
     /// It is the caller's responsibility to check bounds and alignment beforehand.
@@ -429,8 +429,7 @@ pub fn write_scalar(
         let val = match val {
             ScalarMaybeUninit::Scalar(scalar) => scalar,
             ScalarMaybeUninit::Uninit => {
-                self.mark_init(range, false);
-                return Ok(());
+                return self.write_uninit(cx, range);
             }
         };
 
@@ -455,6 +454,13 @@ pub fn write_scalar(
 
         Ok(())
     }
+
+    /// Write "uninit" to the given memory range.
+    pub fn write_uninit(&mut self, cx: &impl HasDataLayout, range: AllocRange) -> AllocResult {
+        self.mark_init(range, false);
+        self.clear_relocations(cx, range)?;
+        return Ok(());
+    }
 }
 
 /// Relocations.
@@ -509,6 +515,9 @@ fn clear_relocations(&mut self, cx: &impl HasDataLayout, range: AllocRange) -> A
             if Tag::ERR_ON_PARTIAL_PTR_OVERWRITE {
                 return Err(AllocError::PartialPointerOverwrite(first));
             }
+            warn!(
+                "Partial pointer overwrite! De-initializing memory at offsets {first:?}..{start:?}."
+            );
             self.init_mask.set_range(first, start, false);
         }
         if last > end {
@@ -517,10 +526,15 @@ fn clear_relocations(&mut self, cx: &impl HasDataLayout, range: AllocRange) -> A
                     last - cx.data_layout().pointer_size,
                 ));
             }
+            warn!(
+                "Partial pointer overwrite! De-initializing memory at offsets {end:?}..{last:?}."
+            );
             self.init_mask.set_range(end, last, false);
         }
 
         // Forget all the relocations.
+        // Since relocations do not overlap, we know that removing until `last` (exclusive) is fine,
+        // i.e., this will not remove any other relocations just after the ones we care about.
         self.relocations.0.remove_range(first..last);
 
         Ok(())
@@ -561,8 +575,10 @@ fn deref(&self) -> &Self::Target {
 }
 
 /// A partial, owned list of relocations to transfer into another allocation.
+///
+/// Offsets are already adjusted to the destination allocation.
 pub struct AllocationRelocations<Tag> {
-    relative_relocations: Vec<(Size, Tag)>,
+    dest_relocations: Vec<(Size, Tag)>,
 }
 
 impl<Tag: Copy, Extra> Allocation<Tag, Extra> {
@@ -575,12 +591,17 @@ pub fn prepare_relocation_copy(
     ) -> AllocationRelocations<Tag> {
         let relocations = self.get_relocations(cx, src);
         if relocations.is_empty() {
-            return AllocationRelocations { relative_relocations: Vec::new() };
+            return AllocationRelocations { dest_relocations: Vec::new() };
         }
 
         let size = src.size;
         let mut new_relocations = Vec::with_capacity(relocations.len() * (count as usize));
 
+        // If `count` is large, this is rather wasteful -- we are allocating a big array here, which
+        // is mostly filled with redundant information since it's just N copies of the same `Tag`s
+        // at slightly adjusted offsets. The reason we do this is so that in `mark_relocation_range`
+        // we can use `insert_presorted`. That wouldn't work with an `Iterator` that just produces
+        // the right sequence of relocations for all N copies.
         for i in 0..count {
             new_relocations.extend(relocations.iter().map(|&(offset, reloc)| {
                 // compute offset for current repetition
@@ -593,14 +614,17 @@ pub fn prepare_relocation_copy(
             }));
         }
 
-        AllocationRelocations { relative_relocations: new_relocations }
+        AllocationRelocations { dest_relocations: new_relocations }
     }
 
     /// Applies a relocation copy.
     /// The affected range, as defined in the parameters to `prepare_relocation_copy` is expected
     /// to be clear of relocations.
+    ///
+    /// This is dangerous to use as it can violate internal `Allocation` invariants!
+    /// It only exists to support an efficient implementation of `mem_copy_repeatedly`.
     pub fn mark_relocation_range(&mut self, relocations: AllocationRelocations<Tag>) {
-        self.relocations.0.insert_presorted(relocations.relative_relocations);
+        self.relocations.0.insert_presorted(relocations.dest_relocations);
     }
 }
 
@@ -1056,7 +1080,7 @@ fn check_init(&self, range: AllocRange) -> AllocResult {
         })
     }
 
-    pub fn mark_init(&mut self, range: AllocRange, is_init: bool) {
+    fn mark_init(&mut self, range: AllocRange, is_init: bool) {
         if range.size.bytes() == 0 {
             return;
         }
@@ -1118,6 +1142,9 @@ pub fn compress_uninit_range(&self, range: AllocRange) -> InitMaskCompressed {
     }
 
     /// Applies multiple instances of the run-length encoding to the initialization mask.
+    ///
+    /// This is dangerous to use as it can violate internal `Allocation` invariants!
+    /// It only exists to support an efficient implementation of `mem_copy_repeatedly`.
     pub fn mark_compressed_init_range(
         &mut self,
         defined: &InitMaskCompressed,
index 813c0912f539679db80f57d1ec455580c0ccb1de..c71aea417eca0143279c565a813ed0da9203dabc 100644 (file)
@@ -163,6 +163,9 @@ pub struct Pointer<Tag = AllocId> {
 }
 
 static_assert_size!(Pointer, 16);
+// `Option<Tag>` pointers are also passed around quite a bit
+// (but not stored in permanent machine state).
+static_assert_size!(Pointer<Option<AllocId>>, 16);
 
 // We want the `Debug` output to be readable as it is used by `derive(Debug)` for
 // all the Miri types.
@@ -198,12 +201,26 @@ fn from(ptr: Pointer<Tag>) -> Self {
 }
 
 impl<Tag> Pointer<Option<Tag>> {
+    /// Convert this pointer that *might* have a tag into a pointer that *definitely* has a tag, or
+    /// an absolute address.
+    ///
+    /// This is rarely what you want; call `ptr_try_get_alloc_id` instead.
     pub fn into_pointer_or_addr(self) -> Result<Pointer<Tag>, Size> {
         match self.provenance {
             Some(tag) => Ok(Pointer::new(tag, self.offset)),
             None => Err(self.offset),
         }
     }
+
+    /// Returns the absolute address the pointer points to.
+    /// Only works if Tag::OFFSET_IS_ADDR is true!
+    pub fn addr(self) -> Size
+    where
+        Tag: Provenance,
+    {
+        assert!(Tag::OFFSET_IS_ADDR);
+        self.offset
+    }
 }
 
 impl<Tag> Pointer<Option<Tag>> {
index 49769b7ae3d89cdbf58dfb875d8e0eda79cbb882..883fc72cd56c1867c5ebe68c24b5e5ceb8565bda 100644 (file)
@@ -15,7 +15,7 @@
 
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def::{CtorKind, Namespace};
-use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
 use rustc_hir::{self, GeneratorKind};
 use rustc_hir::{self as hir, HirId};
 use rustc_session::Session;
@@ -166,7 +166,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`
@@ -385,7 +386,7 @@ pub fn new(
     pub fn new_cfg_only(basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>) -> Self {
         let mut body = Body {
             phase: MirPhase::Built,
-            source: MirSource::item(DefId::local(CRATE_DEF_INDEX)),
+            source: MirSource::item(CRATE_DEF_ID.to_def_id()),
             basic_blocks,
             source_scopes: IndexVec::new(),
             generator: None,
@@ -2330,7 +2331,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.
@@ -2577,8 +2581,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..ad74e356cf953048293cb043684337896dd7f978 100644 (file)
@@ -141,6 +141,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 +150,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 69dac03883940de4d24ea32afa0a04f5bc3b9255..b7f695da544f1db26a260a1c26d2e3a63cf42b64 100644 (file)
@@ -851,6 +851,7 @@ fn write_allocation_bytes<'tcx, Tag: Provenance, Extra>(
         }
         if let Some(&tag) = alloc.relocations().get(&i) {
             // Memory with a relocation must be defined
+            assert!(alloc.init_mask().is_range_initialized(i, i + ptr_size).is_ok());
             let j = i.bytes_usize();
             let offset = alloc
                 .inspect_with_uninit_and_ptr_outside_interpreter(j..j + ptr_size.bytes_usize());
index 999cb9f30b8aa642fbc8e17c80f6cc8c2fab0c97..d8586a8a77df62075ce2bc11a66afe43b6f1fdd6 100644 (file)
     // 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
     }
         eval_always
         desc { "computing the backend features for CLI flags" }
     }
+
+    query generator_diagnostic_data(key: DefId) -> Option<GeneratorDiagnosticData<'tcx>> {
+        storage(ArenaCacheSelector<'tcx>)
+        desc { |tcx| "looking up generator diagnostic data of `{}`", tcx.def_path_str(key) }
+        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 4b7c1d44cea29f6c6a531fd8519720e9e9eb836d..7af7eb4f5ecfd868ebf1408ac90aed3027c08b93 100644 (file)
@@ -44,10 +44,12 @@ pub struct ConstS<'tcx> {
 static_assert_size!(ConstS<'_>, 48);
 
 impl<'tcx> Const<'tcx> {
+    #[inline]
     pub fn ty(self) -> Ty<'tcx> {
         self.0.ty
     }
 
+    #[inline]
     pub fn val(self) -> ConstKind<'tcx> {
         self.0.val
     }
index 4e6be84ad7f8ff6f990a155de5be959c7d6d0772..30fe3ffa7e3c46c0b438269ebf430942b85397c8 100644 (file)
@@ -367,6 +367,16 @@ pub struct GeneratorInteriorTypeCause<'tcx> {
     pub expr: Option<hir::HirId>,
 }
 
+// This type holds diagnostic information on generators and async functions across crate boundaries
+// and is used to provide better error messages
+#[derive(TyEncodable, TyDecodable, Clone, Debug, HashStable)]
+pub struct GeneratorDiagnosticData<'tcx> {
+    pub generator_interior_types: ty::Binder<'tcx, Vec<GeneratorInteriorTypeCause<'tcx>>>,
+    pub hir_owner: DefId,
+    pub nodes_types: ItemLocalMap<Ty<'tcx>>,
+    pub adjustments: ItemLocalMap<Vec<ty::adjustment::Adjustment<'tcx>>>,
+}
+
 #[derive(TyEncodable, TyDecodable, Debug, HashStable)]
 pub struct TypeckResults<'tcx> {
     /// The `HirId::owner` all `ItemLocalId`s in this table are relative to.
@@ -623,6 +633,28 @@ pub fn node_types_mut(&mut self) -> LocalTableInContextMut<'_, Ty<'tcx>> {
         LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.node_types }
     }
 
+    pub fn get_generator_diagnostic_data(&self) -> GeneratorDiagnosticData<'tcx> {
+        let generator_interior_type = self.generator_interior_types.map_bound_ref(|vec| {
+            vec.iter()
+                .map(|item| {
+                    GeneratorInteriorTypeCause {
+                        ty: item.ty,
+                        span: item.span,
+                        scope_span: item.scope_span,
+                        yield_span: item.yield_span,
+                        expr: None, //FIXME: Passing expression over crate boundaries is impossible at the moment
+                    }
+                })
+                .collect::<Vec<_>>()
+        });
+        GeneratorDiagnosticData {
+            generator_interior_types: generator_interior_type,
+            hir_owner: self.hir_owner.to_def_id(),
+            nodes_types: self.node_types.clone(),
+            adjustments: self.adjustments.clone(),
+        }
+    }
+
     pub fn node_type(&self, id: hir::HirId) -> Ty<'tcx> {
         self.node_type_opt(id).unwrap_or_else(|| {
             bug!("node_type: no type for node `{}`", tls::with(|tcx| tcx.hir().node_to_string(id)))
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 c2accea11ba2aee2bb6604ba30d8b7e7e2f768ee..ec416722c214e6018bc9f566c7e2aa065292b4c4 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_INDEX};
+use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalDefIdMap};
 use rustc_hir::Node;
 use rustc_macros::HashStable;
 use rustc_query_system::ich::StableHashingContext;
@@ -67,8 +67,9 @@
 };
 pub use self::context::{
     tls, CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations,
-    CtxtInterners, DelaySpanBugEmitted, FreeRegionInfo, GeneratorInteriorTypeCause, GlobalCtxt,
-    Lift, OnDiskCache, TyCtxt, TypeckResults, UserType, UserTypeAnnotationIndex,
+    CtxtInterners, DelaySpanBugEmitted, FreeRegionInfo, GeneratorDiagnosticData,
+    GeneratorInteriorTypeCause, GlobalCtxt, Lift, OnDiskCache, TyCtxt, TypeckResults, UserType,
+    UserTypeAnnotationIndex,
 };
 pub use self::instance::{Instance, InstanceDef};
 pub use self::list::List;
@@ -130,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>,
@@ -316,22 +319,6 @@ fn parent(self, id: DefId) -> Option<DefId> {
 }
 
 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(DefId::local(CRATE_DEF_INDEX)),
-            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 {
@@ -1992,8 +1979,8 @@ pub fn provided_trait_methods(self, id: DefId) -> impl 'tcx + Iterator<Item = &'
     }
 
     fn opt_item_name(self, def_id: DefId) -> Option<Symbol> {
-        if def_id.index == CRATE_DEF_INDEX {
-            Some(self.crate_name(def_id.krate))
+        if let Some(cnum) = def_id.as_crate_root() {
+            Some(self.crate_name(cnum))
         } else {
             let def_key = self.def_key(def_id);
             match def_key.disambiguated_data.data {
index cac46ba25fe6bc3db7397e12a3e5bd7f5c07d4b0..38362a4cbb92529a8a164ba137096bd1cda4e70a 100644 (file)
@@ -6,7 +6,7 @@
 use rustc_data_structures::sso::SsoHashSet;
 use rustc_hir as hir;
 use rustc_hir::def::{self, CtorKind, DefKind, Namespace};
-use rustc_hir::def_id::{DefId, DefIdSet, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, DefIdSet, CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathData};
 use rustc_session::config::TrimmedDefPaths;
 use rustc_session::cstore::{ExternCrate, ExternCrateSource};
@@ -335,9 +335,7 @@ fn try_print_visible_def_path_recur(
 
         // If `def_id` is a direct or injected extern crate, return the
         // path to the crate followed by the path to the item within the crate.
-        if def_id.index == CRATE_DEF_INDEX {
-            let cnum = def_id.krate;
-
+        if let Some(cnum) = def_id.as_crate_root() {
             if cnum == LOCAL_CRATE {
                 return Ok((self.path_crate(cnum)?, true));
             }
@@ -2227,11 +2225,11 @@ fn name_by_region_index(index: usize) -> Symbol {
                     ty::BrNamed(_, _) => br.kind,
                     ty::BrAnon(i) => {
                         let name = region_map[&(i + 1)];
-                        ty::BrNamed(DefId::local(CRATE_DEF_INDEX), name)
+                        ty::BrNamed(CRATE_DEF_ID.to_def_id(), name)
                     }
                     ty::BrEnv => {
                         let name = region_map[&0];
-                        ty::BrNamed(DefId::local(CRATE_DEF_INDEX), name)
+                        ty::BrNamed(CRATE_DEF_ID.to_def_id(), name)
                     }
                 };
                 self.tcx.mk_region(ty::ReLateBound(
@@ -2257,7 +2255,7 @@ fn name_by_region_index(index: usize) -> Symbol {
                             }
                         };
                         do_continue(&mut self, name);
-                        ty::BrNamed(DefId::local(CRATE_DEF_INDEX), name)
+                        ty::BrNamed(CRATE_DEF_ID.to_def_id(), name)
                     }
                 };
                 tcx.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BoundRegion { var: br.var, kind }))
@@ -2697,7 +2695,7 @@ fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, N
     let mut seen_defs: DefIdSet = Default::default();
 
     for &cnum in tcx.crates(()).iter() {
-        let def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX };
+        let def_id = cnum.as_def_id();
 
         // Ignore crates that are not direct dependencies.
         match tcx.extern_crate(def_id) {
index 9e48c569c253a593f1bb0dd5dd1bd3003eb87578..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;
 use crate::ty::fast_reject::SimplifiedType;
 use crate::ty::subst::{GenericArg, SubstsRef};
 use crate::ty::util::AlwaysRequiresDrop;
+use crate::ty::GeneratorDiagnosticData;
 use crate::ty::{self, AdtSizedConstraint, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt};
+use rustc_ast as ast;
 use rustc_ast::expand::allocator::AllocatorKind;
+use rustc_attr as attr;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
 use rustc_data_structures::steal::Steal;
 use rustc_data_structures::svh::Svh;
 use rustc_session::cstore::{ExternCrate, ForeignModule, LinkagePreference, NativeLib};
 use rustc_session::utils::NativeLibKind;
 use rustc_session::Limits;
-use rustc_target::abi;
-use rustc_target::spec::PanicStrategy;
-
-use rustc_ast as ast;
-use rustc_attr as attr;
 use rustc_span::symbol::Symbol;
 use rustc_span::{Span, DUMMY_SP};
+use rustc_target::abi;
+use rustc_target::spec::PanicStrategy;
 use std::ops::Deref;
 use std::path::PathBuf;
 use std::sync::Arc;
index d9b55563996bab580d050db2d2d9d4d517e244ed..4c1160e21fec2bf715d8257f46082faba65f2916 100644 (file)
@@ -61,7 +61,7 @@ fn relate_item_substs(
 
         let tcx = self.tcx();
         let opt_variances = tcx.variances_of(item_def_id);
-        relate_substs(self, Some((item_def_id, opt_variances)), a_subst, b_subst)
+        relate_substs_with_variances(self, item_def_id, opt_variances, a_subst, b_subst)
     }
 
     /// Switch variance for the purpose of relating `a` and `b`.
@@ -135,29 +135,34 @@ pub fn relate_type_and_mut<'tcx, R: TypeRelation<'tcx>>(
     }
 }
 
+#[inline]
 pub fn relate_substs<'tcx, R: TypeRelation<'tcx>>(
     relation: &mut R,
-    variances: Option<(DefId, &[ty::Variance])>,
+    a_subst: SubstsRef<'tcx>,
+    b_subst: SubstsRef<'tcx>,
+) -> RelateResult<'tcx, SubstsRef<'tcx>> {
+    relation.tcx().mk_substs(iter::zip(a_subst, b_subst).map(|(a, b)| {
+        relation.relate_with_variance(ty::Invariant, ty::VarianceDiagInfo::default(), a, b)
+    }))
+}
+
+pub fn relate_substs_with_variances<'tcx, R: TypeRelation<'tcx>>(
+    relation: &mut R,
+    ty_def_id: DefId,
+    variances: &[ty::Variance],
     a_subst: SubstsRef<'tcx>,
     b_subst: SubstsRef<'tcx>,
 ) -> RelateResult<'tcx, SubstsRef<'tcx>> {
     let tcx = relation.tcx();
-    let mut cached_ty = None;
 
+    let mut cached_ty = None;
     let params = iter::zip(a_subst, b_subst).enumerate().map(|(i, (a, b))| {
-        let (variance, variance_info) = match variances {
-            Some((ty_def_id, variances)) => {
-                let variance = variances[i];
-                let variance_info = if variance == ty::Invariant {
-                    let ty = *cached_ty
-                        .get_or_insert_with(|| tcx.type_of(ty_def_id).subst(tcx, a_subst));
-                    ty::VarianceDiagInfo::Invariant { ty, param_index: i.try_into().unwrap() }
-                } else {
-                    ty::VarianceDiagInfo::default()
-                };
-                (variance, variance_info)
-            }
-            None => (ty::Invariant, ty::VarianceDiagInfo::default()),
+        let variance = variances[i];
+        let variance_info = if variance == ty::Invariant {
+            let ty = *cached_ty.get_or_insert_with(|| tcx.type_of(ty_def_id).subst(tcx, a_subst));
+            ty::VarianceDiagInfo::Invariant { ty, param_index: i.try_into().unwrap() }
+        } else {
+            ty::VarianceDiagInfo::default()
         };
         relation.relate_with_variance(variance, variance_info, a, b)
     });
@@ -318,7 +323,7 @@ fn relate<R: TypeRelation<'tcx>>(
         if a.def_id != b.def_id {
             Err(TypeError::Traits(expected_found(relation, a.def_id, b.def_id)))
         } else {
-            let substs = relate_substs(relation, None, a.substs, b.substs)?;
+            let substs = relate_substs(relation, a.substs, b.substs)?;
             Ok(ty::TraitRef { def_id: a.def_id, substs })
         }
     }
@@ -334,7 +339,7 @@ fn relate<R: TypeRelation<'tcx>>(
         if a.def_id != b.def_id {
             Err(TypeError::Traits(expected_found(relation, a.def_id, b.def_id)))
         } else {
-            let substs = relate_substs(relation, None, a.substs, b.substs)?;
+            let substs = relate_substs(relation, a.substs, b.substs)?;
             Ok(ty::ExistentialTraitRef { def_id: a.def_id, substs })
         }
     }
@@ -554,7 +559,7 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>(
         (&ty::Opaque(a_def_id, a_substs), &ty::Opaque(b_def_id, b_substs))
             if a_def_id == b_def_id =>
         {
-            let substs = relate_substs(relation, None, a_substs, b_substs)?;
+            let substs = relate_substs(relation, a_substs, b_substs)?;
             Ok(tcx.mk_opaque(a_def_id, substs))
         }
 
@@ -742,7 +747,7 @@ fn relate<R: TypeRelation<'tcx>>(
         a: ty::ClosureSubsts<'tcx>,
         b: ty::ClosureSubsts<'tcx>,
     ) -> RelateResult<'tcx, ty::ClosureSubsts<'tcx>> {
-        let substs = relate_substs(relation, None, a.substs, b.substs)?;
+        let substs = relate_substs(relation, a.substs, b.substs)?;
         Ok(ty::ClosureSubsts { substs })
     }
 }
@@ -753,7 +758,7 @@ fn relate<R: TypeRelation<'tcx>>(
         a: ty::GeneratorSubsts<'tcx>,
         b: ty::GeneratorSubsts<'tcx>,
     ) -> RelateResult<'tcx, ty::GeneratorSubsts<'tcx>> {
-        let substs = relate_substs(relation, None, a.substs, b.substs)?;
+        let substs = relate_substs(relation, a.substs, b.substs)?;
         Ok(ty::GeneratorSubsts { substs })
     }
 }
@@ -764,7 +769,7 @@ fn relate<R: TypeRelation<'tcx>>(
         a: SubstsRef<'tcx>,
         b: SubstsRef<'tcx>,
     ) -> RelateResult<'tcx, SubstsRef<'tcx>> {
-        relate_substs(relation, None, a, b)
+        relate_substs(relation, a, b)
     }
 }
 
index 5c7910db362d290c2257e04daf031bdebffb8436..4ef6ff1835ffd022ccddc0a098c3c2496aec2640 100644 (file)
@@ -10,7 +10,6 @@
 use rustc_data_structures::functor::IdFunctor;
 use rustc_hir as hir;
 use rustc_hir::def::Namespace;
-use rustc_hir::def_id::CRATE_DEF_INDEX;
 use rustc_index::vec::{Idx, IndexVec};
 
 use std::fmt;
@@ -71,7 +70,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match *self {
             ty::BrAnon(n) => write!(f, "BrAnon({:?})", n),
             ty::BrNamed(did, name) => {
-                if did.index == CRATE_DEF_INDEX {
+                if did.is_crate_root() {
                     write!(f, "BrNamed({})", name)
                 } else {
                     write!(f, "BrNamed({:?}, {})", did, name)
index a04ac33827424ab35fa1562077e3518c18103672..cee657e9da244fdc39f5358f463d5cf1f8fa024c 100644 (file)
@@ -255,10 +255,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         func: fun,
                         args,
                         cleanup: None,
-                        // FIXME(varkor): replace this with an uninhabitedness-based check.
-                        // This requires getting access to the current module to call
-                        // `tcx.is_ty_uninhabited_from`, which is currently tricky to do.
-                        destination: if expr.ty.is_never() {
+                        // The presence or absence of a return edge affects control-flow sensitive
+                        // MIR checks and ultimately whether code is accepted or not. We can only
+                        // omit the return edge if a return type is visibly uninhabited to a module
+                        // that makes the call.
+                        destination: if this.tcx.is_ty_uninhabited_from(
+                            this.parent_module,
+                            expr.ty,
+                            this.param_env,
+                        ) {
                             None
                         } else {
                             Some((destination, success))
index 901635dc488a7c42fa99f9c472a3b900fc0fd94d..3c51f7918627437bcd9b8f3d479941abed490f4c 100644 (file)
@@ -350,6 +350,7 @@ struct Builder<'a, 'tcx> {
 
     def_id: DefId,
     hir_id: hir::HirId,
+    parent_module: DefId,
     check_overflow: bool,
     fn_span: Span,
     arg_count: usize,
@@ -807,15 +808,17 @@ fn new(
         );
 
         let lint_level = LintLevel::Explicit(hir_id);
+        let param_env = tcx.param_env(def.did);
         let mut builder = Builder {
             thir,
             tcx,
             infcx,
             typeck_results: tcx.typeck_opt_const_arg(def),
             region_scope_tree: tcx.region_scope_tree(def.did),
-            param_env: tcx.param_env(def.did),
+            param_env,
             def_id: def.did.to_def_id(),
             hir_id,
+            parent_module: tcx.parent_module(hir_id).to_def_id(),
             check_overflow,
             cfg: CFG { basic_blocks: IndexVec::new() },
             fn_span: span,
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 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..7d81bb74cd60872d24cfa82090252d52816c6d56 100644 (file)
@@ -1,68 +1,89 @@
 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_temp(ty, self.local_decls[p_ref.local].source_info.span);
+
+                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 last 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 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 c4ffb19f87a91a6595a193c858b0c4fdbd47496b..bf99cd6e42426035d65d2cbc7a15529dc58b2e6b 100644 (file)
@@ -2,10 +2,10 @@
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir::def::DefKind;
-use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+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;
@@ -335,10 +335,10 @@ fn compute_codegen_unit_name(
     let mut cgu_def_id = None;
     // Walk backwards from the item we want to find the module for.
     loop {
-        if current_def_id.index == CRATE_DEF_INDEX {
+        if current_def_id.is_crate_root() {
             if cgu_def_id.is_none() {
                 // If we have not found a module yet, take the crate root.
-                cgu_def_id = Some(DefId { krate: def_id.krate, index: CRATE_DEF_INDEX });
+                cgu_def_id = Some(def_id.krate.as_def_id());
             }
             break;
         } else if tcx.def_kind(current_def_id) == DefKind::Mod {
@@ -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 5ee9c339bb7aa9067c5d24726f65110b2a78fd8b..02749088c3139e50e9745dee12243021de5a73ac 100644 (file)
@@ -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);
index ed2640451705b6080e89b48cfc58e9b69dd2bd47..acc0d7a6ee05efd86769c227f4e167aa887f9082 100644 (file)
@@ -431,10 +431,11 @@ fn tokens_to_string(tokens: &[TokenType]) -> String {
                 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.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 +509,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 +544,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 +552,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,
index cb6be8f412cf54cf7cd9d2ddb4deecae119f9f14..1686c5873e1833f4b5627fd627300aad055e950d 100644 (file)
@@ -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
@@ -238,73 +246,60 @@ struct TokenCursor {
 struct TokenCursorFrame {
     delim: token::DelimToken,
     span: DelimSpan,
-    open_delim: bool,
     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,
-        }
+        TokenCursorFrame { delim, span, 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 `NoDelim` open/close delims. To fix #67062 we will
+            // need to, whereupon the `delim != DelimToken::NoDelim` conditions below can be
+            // removed, as well as the loop.
+            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(sp, delim, tts.clone());
+                        self.stack.push(mem::replace(&mut self.frame, frame));
+                        if delim != DelimToken::NoDelim {
+                            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() {
+                let delim = self.frame.delim;
+                let span = self.frame.span;
                 self.frame = frame;
-                continue;
-            } 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));
+                if delim != DelimToken::NoDelim {
+                    return (Token::new(token::CloseDelim(delim), span.close), Spacing::Alone);
                 }
+                // No close delimiter to return; continue on to the next iteration.
+            } else {
+                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 +313,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,
             [
-                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()
@@ -338,12 +333,12 @@ fn inlined_next_desugared(&mut self) -> (Token, Spacing) {
                 delim_span,
                 token::NoDelim,
                 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 +346,7 @@ fn inlined_next_desugared(&mut self) -> (Token, Spacing) {
             ),
         ));
 
-        self.next()
+        self.next(/* desugar_doc_comments */ false)
     }
 }
 
@@ -436,9 +431,9 @@ 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;
+        // Note: because of the way `TokenCursor::inlined_next` is structured, the `span` and
+        // `delim` arguments here are never used.
+        let start_frame = TokenCursorFrame::new(DelimSpan::dummy(), token::NoDelim, tokens);
 
         let mut parser = Parser {
             sess,
@@ -476,33 +471,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),
@@ -697,7 +665,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.
@@ -1019,12 +987,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 +997,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(token::NoDelim) | token::CloseDelim(token::NoDelim)
+        ));
+        self.inlined_bump_with(next)
     }
 
     /// Look-ahead `dist` tokens of `self.token` and get access to that token there.
@@ -1069,7 +1047,7 @@ 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)
@@ -1217,24 +1195,28 @@ 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();
+                // 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;
 
-                // 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(_)))
-                {
+                // 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)
index b45bca3d2e024acf169d5a34411a32d9430b07d7..691bfdb01a43ebfef224e141869c992c1f0ce57a 100644 (file)
 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 {
@@ -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 261ea0b4deb4a18bb164838bfaee63e8110f1405..b661f6f9d729eaa31020189d6d53e01dfa971924 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>,
@@ -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);
     }
@@ -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 5a1373ad1a218dc94c0987cc3a6b2023ca0e4811..db083d0453bc05d7cc9a6924a3a3e3ca845eca8c 100644 (file)
@@ -1,21 +1,18 @@
 use rustc_ast::entry::EntryPointType;
 use rustc_errors::struct_span_err;
-use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::{ForeignItem, ImplItem, Item, ItemKind, Node, TraitItem, CRATE_HIR_ID};
-use rustc_middle::hir::map::Map;
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::{DefIdTree, TyCtxt};
 use rustc_session::config::{CrateType, EntryFnType};
 use rustc_session::parse::feature_err;
 use rustc_session::Session;
 use rustc_span::symbol::sym;
 use rustc_span::{Span, DUMMY_SP};
 
-struct EntryContext<'a, 'tcx> {
-    session: &'a Session,
-
-    map: Map<'tcx>,
+struct EntryContext<'tcx> {
+    tcx: TyCtxt<'tcx>,
 
     /// The function that has attribute named `main`.
     attr_main_fn: Option<(LocalDefId, Span)>,
@@ -28,10 +25,9 @@ struct EntryContext<'a, 'tcx> {
     non_main_fns: Vec<Span>,
 }
 
-impl<'a, 'tcx> ItemLikeVisitor<'tcx> for EntryContext<'a, 'tcx> {
+impl<'tcx> ItemLikeVisitor<'tcx> for EntryContext<'tcx> {
     fn visit_item(&mut self, item: &'tcx Item<'tcx>) {
-        let def_key = self.map.def_key(item.def_id);
-        let at_root = def_key.parent == Some(CRATE_DEF_INDEX);
+        let at_root = self.tcx.local_parent(item.def_id) == Some(CRATE_DEF_ID);
         find_item(item, self, at_root);
     }
 
@@ -60,13 +56,8 @@ fn entry_fn(tcx: TyCtxt<'_>, (): ()) -> Option<(DefId, EntryFnType)> {
         return None;
     }
 
-    let mut ctxt = EntryContext {
-        session: tcx.sess,
-        map: tcx.hir(),
-        attr_main_fn: None,
-        start_fn: None,
-        non_main_fns: Vec::new(),
-    };
+    let mut ctxt =
+        EntryContext { tcx, attr_main_fn: None, start_fn: None, non_main_fns: Vec::new() };
 
     tcx.hir().visit_all_item_likes(&mut ctxt);
 
@@ -75,11 +66,11 @@ fn entry_fn(tcx: TyCtxt<'_>, (): ()) -> Option<(DefId, EntryFnType)> {
 
 // Beware, this is duplicated in `librustc_builtin_macros/test_harness.rs`
 // (with `ast::Item`), so make sure to keep them in sync.
-fn entry_point_type(ctxt: &EntryContext<'_, '_>, item: &Item<'_>, at_root: bool) -> EntryPointType {
-    let attrs = ctxt.map.attrs(item.hir_id());
-    if ctxt.session.contains_name(attrs, sym::start) {
+fn entry_point_type(ctxt: &EntryContext<'_>, item: &Item<'_>, at_root: bool) -> EntryPointType {
+    let attrs = ctxt.tcx.hir().attrs(item.hir_id());
+    if ctxt.tcx.sess.contains_name(attrs, sym::start) {
         EntryPointType::Start
-    } else if ctxt.session.contains_name(attrs, sym::rustc_main) {
+    } else if ctxt.tcx.sess.contains_name(attrs, sym::rustc_main) {
         EntryPointType::MainAttr
     } else if item.ident.name == sym::main {
         if at_root {
@@ -98,16 +89,16 @@ fn throw_attr_err(sess: &Session, span: Span, attr: &str) {
         .emit();
 }
 
-fn find_item(item: &Item<'_>, ctxt: &mut EntryContext<'_, '_>, at_root: bool) {
+fn find_item(item: &Item<'_>, ctxt: &mut EntryContext<'_>, at_root: bool) {
     match entry_point_type(ctxt, item, at_root) {
         EntryPointType::None => (),
         _ if !matches!(item.kind, ItemKind::Fn(..)) => {
-            let attrs = ctxt.map.attrs(item.hir_id());
-            if let Some(attr) = ctxt.session.find_by_name(attrs, sym::start) {
-                throw_attr_err(&ctxt.session, attr.span, "start");
+            let attrs = ctxt.tcx.hir().attrs(item.hir_id());
+            if let Some(attr) = ctxt.tcx.sess.find_by_name(attrs, sym::start) {
+                throw_attr_err(&ctxt.tcx.sess, attr.span, "start");
             }
-            if let Some(attr) = ctxt.session.find_by_name(attrs, sym::rustc_main) {
-                throw_attr_err(&ctxt.session, attr.span, "rustc_main");
+            if let Some(attr) = ctxt.tcx.sess.find_by_name(attrs, sym::rustc_main) {
+                throw_attr_err(&ctxt.tcx.sess, attr.span, "rustc_main");
             }
         }
         EntryPointType::MainNamed => (),
@@ -119,7 +110,7 @@ fn find_item(item: &Item<'_>, ctxt: &mut EntryContext<'_, '_>, at_root: bool) {
                 ctxt.attr_main_fn = Some((item.def_id, item.span));
             } else {
                 struct_span_err!(
-                    ctxt.session,
+                    ctxt.tcx.sess,
                     item.span,
                     E0137,
                     "multiple functions with a `#[main]` attribute"
@@ -133,7 +124,7 @@ fn find_item(item: &Item<'_>, ctxt: &mut EntryContext<'_, '_>, at_root: bool) {
             if ctxt.start_fn.is_none() {
                 ctxt.start_fn = Some((item.def_id, item.span));
             } else {
-                struct_span_err!(ctxt.session, item.span, E0138, "multiple `start` functions")
+                struct_span_err!(ctxt.tcx.sess, item.span, E0138, "multiple `start` functions")
                     .span_label(ctxt.start_fn.unwrap().1, "previous `#[start]` function here")
                     .span_label(item.span, "multiple `start` functions")
                     .emit();
@@ -142,7 +133,7 @@ fn find_item(item: &Item<'_>, ctxt: &mut EntryContext<'_, '_>, at_root: bool) {
     }
 }
 
-fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) -> Option<(DefId, EntryFnType)> {
+fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) -> Option<(DefId, EntryFnType)> {
     if let Some((def_id, _)) = visitor.start_fn {
         Some((def_id.to_def_id(), EntryFnType::Start))
     } else if let Some((def_id, _)) = visitor.attr_main_fn {
@@ -177,7 +168,7 @@ fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) -> Option<(De
     }
 }
 
-fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) {
+fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) {
     let sp = tcx.def_span(CRATE_DEF_ID);
     if *tcx.sess.parse_sess.reached_eof.borrow() {
         // There's an unclosed brace that made the parser reach `Eof`, we shouldn't complain about
index 56755d68686e3d27b4c70df96de00d5ef82db02d..379a6827c8aac5d3d41075a5aa1998ee7d4cec24 100644 (file)
@@ -1,7 +1,7 @@
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::sync::Lock;
 use rustc_hir as hir;
-use rustc_hir::def_id::{LocalDefId, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
 use rustc_hir::intravisit;
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::{HirId, ItemLocalId};
@@ -89,7 +89,7 @@ fn check<F: FnOnce(&mut HirIdValidator<'a, 'hir>)>(&mut self, owner: LocalDefId,
         self.owner = Some(owner);
         walk(self);
 
-        if owner.local_def_index == CRATE_DEF_INDEX {
+        if owner == CRATE_DEF_ID {
             return;
         }
 
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 b520e5d04eab98650b09844bc56e0df77bb4302e..b65e334261325166abbe12c850b77872bc540356 100644 (file)
@@ -333,6 +333,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 01ba9e35c24dc65c22e1ba4d79e9ef381214cfbc..35a858cb86c3f1851f40e4b266c2571bf0fc5342 100644 (file)
@@ -6,7 +6,7 @@
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
 use rustc_hir::hir_id::CRATE_HIR_ID;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{FieldDef, Generics, HirId, Item, TraitRef, Ty, TyKind, Variant};
@@ -703,7 +703,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
                 let Some(cnum) = self.tcx.extern_mod_stmt_cnum(item.def_id) else {
                     return;
                 };
-                let def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX };
+                let def_id = cnum.as_def_id();
                 self.tcx.check_stability(def_id, Some(item.hir_id()), item.span, None);
             }
 
index 0ce97de413496db7146557dd8e4681183a3acbb6..5f9a03575575c6ad9767be7764e4ce6d82899083 100644 (file)
@@ -295,28 +295,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.
 ////////////////////////////////////////////////////////////////////////////////
@@ -682,7 +660,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 +1341,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 +1363,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 +1499,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 +1570,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;
             }
 
@@ -1655,7 +1634,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 +1661,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 +1749,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 +1811,6 @@ fn visit_def_id(
 
 struct PrivateItemsInPublicInterfacesVisitor<'tcx> {
     tcx: TyCtxt<'tcx>,
-    has_pub_restricted: bool,
     old_error_set_ancestry: LocalDefIdSet,
 }
 
@@ -1842,7 +1824,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 +1975,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 +2061,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 +2078,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 acccf43f06285f59b8421227b0373d47bbbfac26..b20aa7b53468aa0f329071cde63314849288ccc1 100644 (file)
@@ -1,7 +1,7 @@
 use measureme::{StringComponent, StringId};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::profiling::SelfProfiler;
-use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, LOCAL_CRATE};
 use rustc_hir::definitions::DefPathData;
 use rustc_middle::ty::{TyCtxt, WithOptConstParam};
 use rustc_query_system::query::QueryCache;
@@ -143,7 +143,7 @@ fn spec_to_self_profile_string(
         &self,
         builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
     ) -> StringId {
-        builder.def_id_to_string_id(DefId { krate: *self, index: CRATE_DEF_INDEX })
+        builder.def_id_to_string_id(self.as_def_id())
     }
 }
 
index 063b15e643d9c96f5f27bb1a6ba597e40bfe1f66..291b6645d9aa6d00a185cf9364e83f2908a46e22 100644 (file)
@@ -23,7 +23,7 @@
 use rustc_expand::base::SyntaxExtension;
 use rustc_expand::expand::AstFragment;
 use rustc_hir::def::{self, *};
-use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
 use rustc_metadata::creader::LoadedMacro;
 use rustc_middle::bug;
 use rustc_middle::metadata::ModChild;
@@ -140,8 +140,8 @@ pub fn expect_module(&mut self, def_id: DefId) -> Module<'a> {
                     let parent = def_key.parent.map(|index| {
                         self.get_nearest_non_block_module(DefId { index, krate: def_id.krate })
                     });
-                    let name = if def_id.index == CRATE_DEF_INDEX {
-                        self.cstore().crate_name(def_id.krate)
+                    let name = if let Some(cnum) = def_id.as_crate_root() {
+                        self.cstore().crate_name(cnum)
                     } else {
                         def_key.disambiguated_data.data.get_opt_name().expect("module without name")
                     };
@@ -250,7 +250,7 @@ fn try_resolve_visibility<'ast>(
         match vis.kind {
             ast::VisibilityKind::Public => Ok(ty::Visibility::Public),
             ast::VisibilityKind::Crate(..) => {
-                Ok(ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX)))
+                Ok(ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id()))
             }
             ast::VisibilityKind::Inherited => {
                 Ok(match self.parent_scope.module.kind {
@@ -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,
@@ -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) => {
@@ -758,7 +769,7 @@ fn build_reduced_graph_for_item(&mut self, item: &'b Item) {
                     let mut ctor_vis = if vis == ty::Visibility::Public
                         && self.r.session.contains_name(&item.attrs, sym::non_exhaustive)
                     {
-                        ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX))
+                        ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id())
                     } else {
                         vis
                     };
@@ -1107,7 +1118,7 @@ fn process_macro_use_imports(&mut self, item: &Item, module: Module<'a>) -> bool
                 root_span: span,
                 span,
                 module_path: Vec::new(),
-                vis: Cell::new(ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX))),
+                vis: Cell::new(ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id())),
                 used: Cell::new(false),
             })
         };
@@ -1243,7 +1254,7 @@ fn define_macro(&mut self, item: &ast::Item) -> MacroRulesScopeRef<'a> {
             let vis = if is_macro_export {
                 ty::Visibility::Public
             } else {
-                ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX))
+                ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id())
             };
             let binding = (res, vis, span, expansion).to_name_binding(self.r.arenas);
             self.r.set_binding_parent_module(binding, parent_scope.module);
@@ -1489,7 +1500,7 @@ fn visit_variant(&mut self, variant: &'b ast::Variant) {
         let ctor_vis = if vis == ty::Visibility::Public
             && self.r.session.contains_name(&variant.attrs, sym::non_exhaustive)
         {
-            ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX))
+            ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id())
         } else {
             vis
         };
index f3b8c1e266c5871a2ca30a56c286f8ba0b64064d..9bbecf104e55e897964cc1838e9e31bb3a39154a 100644 (file)
@@ -10,7 +10,7 @@
 use rustc_feature::BUILTIN_ATTRIBUTES;
 use rustc_hir::def::Namespace::{self, *};
 use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, NonMacroAttrKind, PerNS};
-use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_hir::PrimTy;
 use rustc_middle::bug;
 use rustc_middle::ty::DefIdTree;
@@ -1014,7 +1014,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
             }
@@ -1167,7 +1167,7 @@ fn early_lookup_typo_candidate(
                 }
                 Scope::ExternPrelude => {
                     suggestions.extend(this.extern_prelude.iter().filter_map(|(ident, _)| {
-                        let res = Res::Def(DefKind::Mod, DefId::local(CRATE_DEF_INDEX));
+                        let res = Res::Def(DefKind::Mod, CRATE_DEF_ID.to_def_id());
                         filter_fn(res).then_some(TypoSuggestion::typo_from_res(ident.name, res))
                     }));
                 }
index 9bc5d63ca179e0b580d1645dd5db690dcd7940e8..50055f8030c6841c362cd1cb7fae94fd24d53dd8 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_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_INDEX};
+use rustc_hir::def_id::{DefId, CRATE_DEF_ID};
 use rustc_hir::{PrimTy, TraitCandidate};
 use rustc_middle::ty::DefIdTree;
 use rustc_middle::{bug, span_bug};
@@ -835,7 +835,7 @@ fn visit_where_predicate(&mut self, p: &'ast WherePredicate) {
                         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)
                         }
                     },
                 );
@@ -1026,12 +1026,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 {
@@ -1496,7 +1496,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,
@@ -1580,7 +1580,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);
                             },
                         );
                     },
@@ -1696,7 +1696,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;
             }
@@ -2751,7 +2751,7 @@ fn resolve_qpath(
                 // trait to resolve.  In that case, we leave the `B`
                 // segment to be resolved by type-check.
                 return Ok(Some(PartialRes::with_unresolved_segments(
-                    Res::Def(DefKind::Mod, DefId::local(CRATE_DEF_INDEX)),
+                    Res::Def(DefKind::Mod, CRATE_DEF_ID.to_def_id()),
                     path.len(),
                 )));
             }
index 0bae141ce26c85759c179ef0617b68ddbb4c2e24..d77cc917e2f9a2035c05fd4d3b7b303c4c19db7c 100644 (file)
@@ -20,7 +20,7 @@
 use rustc_hir as hir;
 use rustc_hir::def::Namespace::{self, *};
 use rustc_hir::def::{self, CtorKind, CtorOf, DefKind};
-use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_hir::PrimTy;
 use rustc_session::parse::feature_err;
 use rustc_span::edition::Edition;
@@ -352,7 +352,7 @@ pub(crate) fn smart_resolve_report_errors(
                 }
             })
             .collect::<Vec<_>>();
-        let crate_def_id = DefId::local(CRATE_DEF_INDEX);
+        let crate_def_id = CRATE_DEF_ID.to_def_id();
         if candidates.is_empty() && is_expected(Res::Def(DefKind::Enum, crate_def_id)) {
             let mut enum_candidates: Vec<_> = self
                 .r
@@ -1332,10 +1332,8 @@ fn lookup_typo_candidate(
                             names.extend(extern_prelude.iter().flat_map(|(ident, _)| {
                                 self.r.crate_loader.maybe_process_path_extern(ident.name).and_then(
                                     |crate_id| {
-                                        let crate_mod = Res::Def(
-                                            DefKind::Mod,
-                                            DefId { krate: crate_id, index: CRATE_DEF_INDEX },
-                                        );
+                                        let crate_mod =
+                                            Res::Def(DefKind::Mod, crate_id.as_def_id());
 
                                         if filter_fn(crate_mod) {
                                             Some(TypoSuggestion::typo_from_res(
index d5f2e2db1e39b1851754fbbc0fed7d35c36b81fb..ce3069265d0206381b1c29dda43f0258a8af8428 100644 (file)
@@ -685,8 +685,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();
index eed54370e23310bcc61b3071b6915ab2bb5f6f68..cca1f1025866863465fae0b73fd465019ac6bfef 100644 (file)
@@ -38,7 +38,7 @@
 use rustc_hir::def::Namespace::*;
 use rustc_hir::def::{self, CtorOf, DefKind, PartialRes};
 use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefPathHash, LocalDefId};
-use rustc_hir::def_id::{CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_hir::definitions::{DefKey, DefPathData, Definitions};
 use rustc_hir::TraitCandidate;
 use rustc_index::vec::IndexVec;
@@ -796,7 +796,7 @@ fn is_extern_crate(&self) -> bool {
             NameBindingKind::Module(&ModuleData {
                 kind: ModuleKind::Def(DefKind::Mod, def_id, _),
                 ..
-            }) => def_id.index == CRATE_DEF_INDEX,
+            }) => def_id.is_crate_root(),
             _ => false,
         }
     }
@@ -934,6 +934,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)>,
@@ -1248,18 +1249,17 @@ pub fn new(
         );
 
         let definitions = Definitions::new(session.local_stable_crate_id(), krate.spans.inner_span);
-        let root = definitions.get_root_def();
 
         let mut visibilities = FxHashMap::default();
         visibilities.insert(CRATE_DEF_ID, ty::Visibility::Public);
 
         let mut def_id_to_node_id = IndexVec::default();
-        assert_eq!(def_id_to_node_id.push(CRATE_NODE_ID), root);
+        assert_eq!(def_id_to_node_id.push(CRATE_NODE_ID), CRATE_DEF_ID);
         let mut node_id_to_def_id = FxHashMap::default();
-        node_id_to_def_id.insert(CRATE_NODE_ID, root);
+        node_id_to_def_id.insert(CRATE_NODE_ID, CRATE_DEF_ID);
 
         let mut invocation_parents = FxHashMap::default();
-        invocation_parents.insert(LocalExpnId::ROOT, (root, ImplTraitContext::Existential));
+        invocation_parents.insert(LocalExpnId::ROOT, (CRATE_DEF_ID, ImplTraitContext::Existential));
 
         let mut extern_prelude: FxHashMap<Ident, ExternPreludeEntry<'_>> = session
             .opts
@@ -1314,6 +1314,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(),
@@ -1424,6 +1425,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;
@@ -1436,6 +1438,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,
@@ -1462,6 +1465,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(),
index 22d0a20395ec7d77b62a9811f14049940e55f1a2..6681ea9d299cf057c69b0090b03de10541a45f4a 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,7 +1135,7 @@ 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 =
@@ -1176,7 +1164,7 @@ 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);
@@ -1249,7 +1237,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,
@@ -1443,7 +1431,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..582186cbd1fe7221c30c5655bc4c9b7fe97b1421 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,
                 _ => {
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 5a447aa6237345f2e6c608666f90bf0fecc34a8f..925f6bfd93d3cdf90f80671e2087fe1354175e0e 100644 (file)
@@ -3,20 +3,18 @@
 
 pub use crate::options::*;
 
-use crate::lint;
 use crate::search_paths::SearchPath;
 use crate::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
 use crate::{early_error, early_warn, Session};
+use crate::{lint, HashStableContext};
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_data_structures::impl_stable_hash_via_hash;
 
+use rustc_data_structures::stable_hasher::ToStableHashKey;
 use rustc_target::abi::{Align, TargetDataLayout};
 use rustc_target::spec::{LinkerFlavor, SplitDebuginfo, Target, TargetTriple, TargetWarnings};
 use rustc_target::spec::{PanicStrategy, SanitizerSet, TARGETS};
 
-use rustc_serialize::json;
-
 use crate::parse::{CrateCheckConfig, CrateConfig};
 use rustc_feature::UnstableFeatures;
 use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST, LATEST_STABLE_EDITION};
@@ -80,7 +78,7 @@ pub enum CFProtection {
     Full,
 }
 
-#[derive(Clone, Copy, Debug, PartialEq, Hash)]
+#[derive(Clone, Copy, Debug, PartialEq, Hash, HashStable_Generic)]
 pub enum OptLevel {
     No,         // -O0
     Less,       // -O1
@@ -90,8 +88,6 @@ pub enum OptLevel {
     SizeMin,    // -Oz
 }
 
-impl_stable_hash_via_hash!(OptLevel);
-
 /// This is what the `LtoCli` values get mapped to after resolving defaults and
 /// and taking other command line options into account.
 ///
@@ -232,15 +228,13 @@ pub fn enabled(&self) -> bool {
     }
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable_Generic)]
 #[derive(Encodable, Decodable)]
 pub enum SymbolManglingVersion {
     Legacy,
     V0,
 }
 
-impl_stable_hash_via_hash!(SymbolManglingVersion);
-
 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
 pub enum DebugInfo {
     None,
@@ -279,7 +273,7 @@ fn from_str(s: &str) -> Result<Self, ()> {
     }
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, HashStable_Generic)]
 #[derive(Encodable, Decodable)]
 pub enum OutputType {
     Bitcode,
@@ -292,7 +286,13 @@ pub enum OutputType {
     DepInfo,
 }
 
-impl_stable_hash_via_hash!(OutputType);
+impl<HCX: HashStableContext> ToStableHashKey<HCX> for OutputType {
+    type KeyType = Self;
+
+    fn to_stable_hash_key(&self, _: &HCX) -> Self::KeyType {
+        *self
+    }
+}
 
 impl OutputType {
     fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
@@ -398,7 +398,7 @@ pub enum TrimmedDefPaths {
 /// *Do not* switch `BTreeMap` out for an unsorted container type! That would break
 /// dependency tracking for command-line arguments. Also only hash keys, since tracking
 /// should only depend on the output types, not the paths they're written to.
-#[derive(Clone, Debug, Hash)]
+#[derive(Clone, Debug, Hash, HashStable_Generic)]
 pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
 
 impl OutputTypes {
@@ -460,9 +460,6 @@ pub fn should_link(&self) -> bool {
 #[derive(Clone)]
 pub struct Externs(BTreeMap<String, ExternEntry>);
 
-#[derive(Clone)]
-pub struct ExternDepSpecs(BTreeMap<String, ExternDepSpec>);
-
 #[derive(Clone, Debug)]
 pub struct ExternEntry {
     pub location: ExternLocation,
@@ -477,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)]
@@ -494,27 +496,6 @@ pub enum ExternLocation {
     ExactPaths(BTreeSet<CanonicalizedPath>),
 }
 
-/// Supplied source location of a dependency - for example in a build specification
-/// file like Cargo.toml. We support several syntaxes: if it makes sense to reference
-/// a file and line, then the build system can specify that. On the other hand, it may
-/// make more sense to have an arbitrary raw string.
-#[derive(Clone, PartialEq)]
-pub enum ExternDepSpec {
-    /// Raw string
-    Raw(String),
-    /// Raw data in json format
-    Json(json::Json),
-}
-
-impl<'a> From<&'a ExternDepSpec> for rustc_lint_defs::ExternDepSpec {
-    fn from(from: &'a ExternDepSpec) -> Self {
-        match from {
-            ExternDepSpec::Raw(s) => rustc_lint_defs::ExternDepSpec::Raw(s.clone()),
-            ExternDepSpec::Json(json) => rustc_lint_defs::ExternDepSpec::Json(json.clone()),
-        }
-    }
-}
-
 impl Externs {
     /// Used for testing.
     pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs {
@@ -536,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>> {
@@ -547,25 +528,6 @@ pub fn files(&self) -> Option<impl Iterator<Item = &CanonicalizedPath>> {
     }
 }
 
-impl ExternDepSpecs {
-    pub fn new(data: BTreeMap<String, ExternDepSpec>) -> ExternDepSpecs {
-        ExternDepSpecs(data)
-    }
-
-    pub fn get(&self, key: &str) -> Option<&ExternDepSpec> {
-        self.0.get(key)
-    }
-}
-
-impl fmt::Display for ExternDepSpec {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self {
-            ExternDepSpec::Raw(raw) => fmt.write_str(raw),
-            ExternDepSpec::Json(json) => json::as_json(json).fmt(fmt),
-        }
-    }
-}
-
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 pub enum PrintRequest {
     FileNames,
@@ -630,7 +592,7 @@ pub fn source_name(&self) -> FileName {
     }
 }
 
-#[derive(Clone, Hash, Debug)]
+#[derive(Clone, Hash, Debug, HashStable_Generic)]
 pub struct OutputFilenames {
     pub out_directory: PathBuf,
     filestem: String,
@@ -639,8 +601,6 @@ pub struct OutputFilenames {
     pub outputs: OutputTypes,
 }
 
-impl_stable_hash_via_hash!(OutputFilenames);
-
 pub const RLINK_EXT: &str = "rlink";
 pub const RUST_CGU_EXT: &str = "rcgu";
 pub const DWARF_OBJECT_EXT: &str = "dwo";
@@ -785,7 +745,6 @@ fn default() -> Options {
             cg: Default::default(),
             error_format: ErrorOutputType::default(),
             externs: Externs(BTreeMap::new()),
-            extern_dep_specs: ExternDepSpecs(BTreeMap::new()),
             crate_name: None,
             libs: Vec::new(),
             unstable_features: UnstableFeatures::Disallow,
@@ -854,15 +813,14 @@ pub fn diagnostic_handler_flags(&self, can_emit_warnings: bool) -> HandlerFlags
 }
 
 // The type of entry function, so users can have their own entry functions
-#[derive(Copy, Clone, PartialEq, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Hash, Debug, HashStable_Generic)]
 pub enum EntryFnType {
     Main,
     Start,
 }
 
-impl_stable_hash_via_hash!(EntryFnType);
-
 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
+#[derive(HashStable_Generic)]
 pub enum CrateType {
     Executable,
     Dylib,
@@ -872,8 +830,6 @@ pub enum CrateType {
     ProcMacro,
 }
 
-impl_stable_hash_via_hash!(CrateType);
-
 impl CrateType {
     /// When generated, is this crate type an archive?
     pub fn is_archive(&self) -> bool {
@@ -1454,12 +1410,6 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
             "Specify where an external rust library is located",
             "NAME[=PATH]",
         ),
-        opt::multi_s(
-            "",
-            "extern-location",
-            "Location where an external crate dependency is specified",
-            "NAME=LOCATION",
-        ),
         opt::opt_s("", "sysroot", "Override the system root", "PATH"),
         opt::multi("Z", "", "Set internal debugging options", "FLAG"),
         opt::opt_s(
@@ -2186,6 +2136,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(
@@ -2207,6 +2158,7 @@ pub fn parse_externs(
                             );
                         }
                     }
+                    "nounused" => nounused_dep = true,
                     _ => early_error(error_format, &format!("unknown --extern option `{opt}`")),
                 }
             }
@@ -2215,74 +2167,14 @@ 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;
     }
     Externs(externs)
 }
 
-fn parse_extern_dep_specs(
-    matches: &getopts::Matches,
-    debugging_opts: &DebuggingOptions,
-    error_format: ErrorOutputType,
-) -> ExternDepSpecs {
-    let is_unstable_enabled = debugging_opts.unstable_options;
-    let mut map = BTreeMap::new();
-
-    for arg in matches.opt_strs("extern-location") {
-        if !is_unstable_enabled {
-            early_error(
-                error_format,
-                "`--extern-location` option is unstable: set `-Z unstable-options`",
-            );
-        }
-
-        let mut parts = arg.splitn(2, '=');
-        let name = parts.next().unwrap_or_else(|| {
-            early_error(error_format, "`--extern-location` value must not be empty")
-        });
-        let loc = parts.next().unwrap_or_else(|| {
-            early_error(
-                error_format,
-                &format!("`--extern-location`: specify location for extern crate `{name}`"),
-            )
-        });
-
-        let locparts: Vec<_> = loc.split(':').collect();
-        let spec = match &locparts[..] {
-            ["raw", ..] => {
-                // Don't want `:` split string
-                let raw = loc.splitn(2, ':').nth(1).unwrap_or_else(|| {
-                    early_error(error_format, "`--extern-location`: missing `raw` location")
-                });
-                ExternDepSpec::Raw(raw.to_string())
-            }
-            ["json", ..] => {
-                // Don't want `:` split string
-                let raw = loc.splitn(2, ':').nth(1).unwrap_or_else(|| {
-                    early_error(error_format, "`--extern-location`: missing `json` location")
-                });
-                let json = json::from_str(raw).unwrap_or_else(|_| {
-                    early_error(
-                        error_format,
-                        &format!("`--extern-location`: malformed json location `{raw}`"),
-                    )
-                });
-                ExternDepSpec::Json(json)
-            }
-            [bad, ..] => early_error(
-                error_format,
-                &format!("unknown location type `{bad}`: use `raw` or `json`"),
-            ),
-            [] => early_error(error_format, "missing location specification"),
-        };
-
-        map.insert(name.to_string(), spec);
-    }
-
-    ExternDepSpecs::new(map)
-}
-
 fn parse_remap_path_prefix(
     matches: &getopts::Matches,
     debugging_opts: &DebuggingOptions,
@@ -2525,7 +2417,6 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
     }
 
     let externs = parse_externs(matches, &debugging_opts, error_format);
-    let extern_dep_specs = parse_extern_dep_specs(matches, &debugging_opts, error_format);
 
     let crate_name = matches.opt_str("crate-name");
 
@@ -2601,7 +2492,6 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
         error_format,
         externs,
         unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
-        extern_dep_specs,
         crate_name,
         libs,
         debug_assertions,
index 4994f8eaeb2dcaae287369413334f0710c10c62b..96f50e57ac4d0efe779ec63c14fc44a3a1c1c2f0 100644 (file)
@@ -183,7 +183,6 @@ pub struct Options {
         borrowck_mode: BorrowckMode [UNTRACKED],
         cg: CodegenOptions [SUBSTRUCT],
         externs: Externs [UNTRACKED],
-        extern_dep_specs: ExternDepSpecs [UNTRACKED],
         crate_name: Option<String> [TRACKED],
         /// Indicates how the compiler should treat unstable features.
         unstable_features: UnstableFeatures [TRACKED],
@@ -369,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;
@@ -530,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;
@@ -1319,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 b6bde28233d243bc2ad86c0e5619111f3bc1d6d7..56a6b6f3b03efe6d18c98fd80ad69e1fa6c5af2c 100644 (file)
@@ -26,7 +26,7 @@ pub struct SearchPathFile {
     pub file_name_str: String,
 }
 
-#[derive(PartialEq, Clone, Copy, Debug, Hash, Eq, Encodable, Decodable)]
+#[derive(PartialEq, Clone, Copy, Debug, Hash, Eq, Encodable, Decodable, HashStable_Generic)]
 pub enum PathKind {
     Native,
     Crate,
@@ -36,8 +36,6 @@ pub enum PathKind {
     All,
 }
 
-rustc_data_structures::impl_stable_hash_via_hash!(PathKind);
-
 impl PathKind {
     pub fn matches(&self, kind: PathKind) -> bool {
         match (self, kind) {
index 9a286d94ab89da3aa65042e8d9b14fba2e268acd..8064c217457bb561bc66185b27d75822f0fbce1e 100644 (file)
@@ -18,6 +18,7 @@ pub fn time<R>(&self, what: &'static str, f: impl FnOnce() -> R) -> R {
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
+#[derive(HashStable_Generic)]
 pub enum NativeLibKind {
     /// Static library (e.g. `libfoo.a` on Linux or `foo.lib` on Windows/MSVC)
     Static {
@@ -57,9 +58,8 @@ pub fn has_modifiers(&self) -> bool {
     }
 }
 
-rustc_data_structures::impl_stable_hash_via_hash!(NativeLibKind);
-
 #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
+#[derive(HashStable_Generic)]
 pub struct NativeLib {
     pub name: String,
     pub new_name: Option<String>,
@@ -73,8 +73,6 @@ pub fn has_modifiers(&self) -> bool {
     }
 }
 
-rustc_data_structures::impl_stable_hash_via_hash!(NativeLib);
-
 /// A path that has been canonicalized along with its original, non-canonicalized form
 #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
 pub struct CanonicalizedPath {
index 6d1b36796d869fec88463521d022bc76dea66489..d5f806308cf41bbca3b16ea67cd7f1fe77278fd5 100644 (file)
@@ -283,8 +283,19 @@ pub fn expect_local(self) -> LocalDefId {
         self.as_local().unwrap_or_else(|| panic!("DefId::expect_local: `{:?}` isn't local", self))
     }
 
+    #[inline]
+    pub fn is_crate_root(self) -> bool {
+        self.index == CRATE_DEF_INDEX
+    }
+
+    #[inline]
+    pub fn as_crate_root(self) -> Option<CrateNum> {
+        if self.is_crate_root() { Some(self.krate) } else { None }
+    }
+
+    #[inline]
     pub fn is_top_level_module(self) -> bool {
-        self.is_local() && self.index == CRATE_DEF_INDEX
+        self.is_local() && self.is_crate_root()
     }
 }
 
@@ -357,7 +368,7 @@ pub fn to_def_id(self) -> DefId {
 
     #[inline]
     pub fn is_top_level_module(self) -> bool {
-        self.local_def_index == CRATE_DEF_INDEX
+        self == CRATE_DEF_ID
     }
 }
 
index b132c0a2132b724b0077f3019432112d4a1ba55e..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};
 
@@ -1130,6 +1132,7 @@ pub fn get_source(&self) -> Option<&Lrc<String>> {
 pub struct OffsetOverflowError;
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
+#[derive(HashStable_Generic)]
 pub enum SourceFileHashAlgorithm {
     Md5,
     Sha1,
@@ -1149,8 +1152,6 @@ fn from_str(s: &str) -> Result<SourceFileHashAlgorithm, ()> {
     }
 }
 
-rustc_data_structures::impl_stable_hash_via_hash!(SourceFileHashAlgorithm);
-
 /// The hash of the on-disk source file used for debug info.
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 #[derive(HashStable_Generic, Encodable, Decodable)]
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 d9bada295894f314be2b5c90268a155a19a0c3b7..e3ce8105a8b47a825ccb5499944993015f4bea92 100644 (file)
         keyword,
         kind,
         kreg,
+        kreg0,
         label,
         label_break_value,
         lang,
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 5bc4b566daf67f86a241082c544ba75b90a6444d..6bc807c7c4421649f89e81867da730d26a88b733 100644 (file)
@@ -893,7 +893,7 @@ macro_rules! clobbered_regs {
 
                     xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7,
 
-                    k1, k2, k3, k4, k5, k6, k7,
+                    k0, k1, k2, k3, k4, k5, k6, k7,
 
                     mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7,
                     st0, st1, st2, st3, st4, st5, st6, st7,
@@ -908,7 +908,7 @@ macro_rules! clobbered_regs {
                     zmm16, zmm17, zmm18, zmm19, zmm20, zmm21, zmm22, zmm23,
                     zmm24, zmm25, zmm26, zmm27, zmm28, zmm29, zmm30, zmm31,
 
-                    k1, k2, k3, k4, k5, k6, k7,
+                    k0, k1, k2, k3, k4, k5, k6, k7,
 
                     mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7,
                     st0, st1, st2, st3, st4, st5, st6, st7,
@@ -927,7 +927,7 @@ macro_rules! clobbered_regs {
                     zmm16, zmm17, zmm18, zmm19, zmm20, zmm21, zmm22, zmm23,
                     zmm24, zmm25, zmm26, zmm27, zmm28, zmm29, zmm30, zmm31,
 
-                    k1, k2, k3, k4, k5, k6, k7,
+                    k0, k1, k2, k3, k4, k5, k6, k7,
 
                     mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7,
                     st0, st1, st2, st3, st4, st5, st6, st7,
index 7c136a475486b63eb835a2e3bdac065f6204f54a..854674c7f2fa7c98804c4ce6cc28bc9d5c483a9b 100644 (file)
@@ -14,6 +14,7 @@
         ymm_reg,
         zmm_reg,
         kreg,
+        kreg0,
         mmx_reg,
         x87_reg,
     }
@@ -38,7 +39,7 @@ pub fn valid_modifiers(self, arch: super::InlineAsmArch) -> &'static [char] {
             }
             Self::reg_byte => &[],
             Self::xmm_reg | Self::ymm_reg | Self::zmm_reg => &['x', 'y', 'z'],
-            Self::kreg => &[],
+            Self::kreg | Self::kreg0 => &[],
             Self::mmx_reg | Self::x87_reg => &[],
         }
     }
@@ -77,7 +78,7 @@ pub fn suggest_modifier(
                 256 => Some(('y', "ymm0")),
                 _ => Some(('x', "xmm0")),
             },
-            Self::kreg => None,
+            Self::kreg | Self::kreg0 => None,
             Self::mmx_reg | Self::x87_reg => None,
         }
     }
@@ -95,7 +96,7 @@ pub fn default_modifier(self, arch: InlineAsmArch) -> Option<(char, &'static str
             Self::xmm_reg => Some(('x', "xmm0")),
             Self::ymm_reg => Some(('y', "ymm0")),
             Self::zmm_reg => Some(('z', "zmm0")),
-            Self::kreg => None,
+            Self::kreg | Self::kreg0 => None,
             Self::mmx_reg | Self::x87_reg => None,
         }
     }
@@ -132,6 +133,7 @@ pub fn supported_types(
                 avx512f: I8, I16;
                 avx512bw: I32, I64;
             },
+            Self::kreg0 => &[],
             Self::mmx_reg | Self::x87_reg => &[],
         }
     }
@@ -294,6 +296,7 @@ fn esi_reserved(
         zmm29: zmm_reg = ["zmm29", "xmm29", "ymm29"] % x86_64_only,
         zmm30: zmm_reg = ["zmm30", "xmm30", "ymm30"] % x86_64_only,
         zmm31: zmm_reg = ["zmm31", "xmm31", "ymm31"] % x86_64_only,
+        k0: kreg0 = ["k0"],
         k1: kreg = ["k1"],
         k2: kreg = ["k2"],
         k3: kreg = ["k3"],
@@ -323,8 +326,6 @@ fn esi_reserved(
             "the stack pointer cannot be used as an operand for inline asm",
         #error = ["ip", "eip", "rip"] =>
             "the instruction pointer cannot be used as an operand for inline asm",
-        #error = ["k0"] =>
-            "the k0 AVX mask register cannot be used as an operand for inline asm",
     }
 }
 
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 50e4fafdd6c829c44fe8212e244993f5689a0b3b..082402a38e3f5db45813d5078fa7456103d30e85 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.
                 //
index 7485c082f4eaf5af2b542719f7a204dccb038ebe..0c1ca65c48f6adb9230785eb5e494973c04cc70c 100644 (file)
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node};
+use rustc_middle::hir::map;
 use rustc_middle::ty::{
     self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree,
-    Infer, InferTy, ToPredicate, Ty, TyCtxt, TypeFoldable,
+    GeneratorDiagnosticData, GeneratorInteriorTypeCause, Infer, InferTy, ToPredicate, Ty, TyCtxt,
+    TypeFoldable,
 };
 use rustc_middle::ty::{TypeAndMut, TypeckResults};
 use rustc_session::Limit;
@@ -44,6 +46,123 @@ pub enum GeneratorInteriorOrUpvar {
     Upvar(Span),
 }
 
+// This type provides a uniform interface to retrieve data on generators, whether it originated from
+// the local crate being compiled or from a foreign crate.
+#[derive(Debug)]
+pub enum GeneratorData<'tcx, 'a> {
+    Local(&'a TypeckResults<'tcx>),
+    Foreign(&'tcx GeneratorDiagnosticData<'tcx>),
+}
+
+impl<'tcx, 'a> GeneratorData<'tcx, 'a> {
+    // Try to get information about variables captured by the generator that matches a type we are
+    // looking for with `ty_matches` function. We uses it to find upvar which causes a failure to
+    // meet an obligation
+    fn try_get_upvar_span<F>(
+        &self,
+        infer_context: &InferCtxt<'a, 'tcx>,
+        generator_did: DefId,
+        ty_matches: F,
+    ) -> Option<GeneratorInteriorOrUpvar>
+    where
+        F: Fn(ty::Binder<'tcx, Ty<'tcx>>) -> bool,
+    {
+        match self {
+            GeneratorData::Local(typeck_results) => {
+                infer_context.tcx.upvars_mentioned(generator_did).and_then(|upvars| {
+                    upvars.iter().find_map(|(upvar_id, upvar)| {
+                        let upvar_ty = typeck_results.node_type(*upvar_id);
+                        let upvar_ty = infer_context.resolve_vars_if_possible(upvar_ty);
+                        if ty_matches(ty::Binder::dummy(upvar_ty)) {
+                            Some(GeneratorInteriorOrUpvar::Upvar(upvar.span))
+                        } else {
+                            None
+                        }
+                    })
+                })
+            }
+            GeneratorData::Foreign(_) => None,
+        }
+    }
+
+    // Try to get the span of a type being awaited on that matches the type we are looking with the
+    // `ty_matches` function. We uses it to find awaited type which causes a failure to meet an
+    // obligation
+    fn get_from_await_ty<F>(
+        &self,
+        visitor: AwaitsVisitor,
+        hir: map::Map<'tcx>,
+        ty_matches: F,
+    ) -> Option<Span>
+    where
+        F: Fn(ty::Binder<'tcx, Ty<'tcx>>) -> bool,
+    {
+        match self {
+            GeneratorData::Local(typeck_results) => visitor
+                .awaits
+                .into_iter()
+                .map(|id| hir.expect_expr(id))
+                .find(|await_expr| {
+                    ty_matches(ty::Binder::dummy(typeck_results.expr_ty_adjusted(&await_expr)))
+                })
+                .map(|expr| expr.span),
+            GeneratorData::Foreign(generator_diagnostic_data) => visitor
+                .awaits
+                .into_iter()
+                .map(|id| hir.expect_expr(id))
+                .find(|await_expr| {
+                    ty_matches(ty::Binder::dummy(
+                        generator_diagnostic_data
+                            .adjustments
+                            .get(&await_expr.hir_id.local_id)
+                            .map_or::<&[ty::adjustment::Adjustment<'tcx>], _>(&[], |a| &a[..])
+                            .last()
+                            .map_or_else::<Ty<'tcx>, _, _>(
+                                || {
+                                    generator_diagnostic_data
+                                        .nodes_types
+                                        .get(&await_expr.hir_id.local_id)
+                                        .cloned()
+                                        .unwrap_or_else(|| {
+                                            bug!(
+                                                "node_type: no type for node `{}`",
+                                                ty::tls::with(|tcx| tcx
+                                                    .hir()
+                                                    .node_to_string(await_expr.hir_id))
+                                            )
+                                        })
+                                },
+                                |adj| adj.target,
+                            ),
+                    ))
+                })
+                .map(|expr| expr.span),
+        }
+    }
+
+    /// Get the type, expression, span and optional scope span of all types
+    /// that are live across the yield of this generator
+    fn get_generator_interior_types(
+        &self,
+    ) -> ty::Binder<'tcx, &Vec<GeneratorInteriorTypeCause<'tcx>>> {
+        match self {
+            GeneratorData::Local(typeck_result) => typeck_result.generator_interior_types.as_ref(),
+            GeneratorData::Foreign(generator_diagnostic_data) => {
+                generator_diagnostic_data.generator_interior_types.as_ref()
+            }
+        }
+    }
+
+    // Used to get the source of the data, note we don't have as much information for generators
+    // originated from foreign crates
+    fn is_foreign(&self) -> bool {
+        match self {
+            GeneratorData::Local(_) => false,
+            GeneratorData::Foreign(_) => true,
+        }
+    }
+}
+
 // This trait is public to expose the diagnostics methods to clippy.
 pub trait InferCtxtExt<'tcx> {
     fn suggest_restricting_param_bound(
@@ -152,7 +271,7 @@ fn note_obligation_cause_for_async_await(
         err: &mut Diagnostic,
         interior_or_upvar_span: GeneratorInteriorOrUpvar,
         interior_extra_info: Option<(Option<Span>, Span, Option<hir::HirId>, Option<Span>)>,
-        inner_generator_body: Option<&hir::Body<'tcx>>,
+        is_async: bool,
         outer_generator: Option<DefId>,
         trait_pred: ty::TraitPredicate<'tcx>,
         target_ty: Ty<'tcx>,
@@ -1642,6 +1761,17 @@ fn maybe_note_obligation_cause_for_async_await(
             .map(|def_id| hir.local_def_id_to_hir_id(def_id))
             .and_then(|hir_id| hir.maybe_body_owned_by(hir_id))
             .map(|body_id| hir.body(body_id));
+        let is_async = match generator_did.as_local() {
+            Some(_) => generator_body
+                .and_then(|body| body.generator_kind())
+                .map(|generator_kind| matches!(generator_kind, hir::GeneratorKind::Async(..)))
+                .unwrap_or(false),
+            None => self
+                .tcx
+                .generator_kind(generator_did)
+                .map(|generator_kind| matches!(generator_kind, hir::GeneratorKind::Async(..)))
+                .unwrap_or(false),
+        };
         let mut visitor = AwaitsVisitor::default();
         if let Some(body) = generator_body {
             visitor.visit_body(body);
@@ -1682,61 +1812,55 @@ fn maybe_note_obligation_cause_for_async_await(
         // type-checking; otherwise, get them by performing a query.  This is needed to avoid
         // cycles. If we can't use resolved types because the generator comes from another crate,
         // we still provide a targeted error but without all the relevant spans.
-        let query_typeck_results;
-        let typeck_results: Option<&TypeckResults<'tcx>> = match &in_progress_typeck_results {
-            Some(t) if t.hir_owner.to_def_id() == generator_did_root => Some(&t),
+        let generator_data: Option<GeneratorData<'tcx, '_>> = match &in_progress_typeck_results {
+            Some(t) if t.hir_owner.to_def_id() == generator_did_root => {
+                Some(GeneratorData::Local(&t))
+            }
             _ if generator_did.is_local() => {
-                query_typeck_results = self.tcx.typeck(generator_did.expect_local());
-                Some(&query_typeck_results)
+                Some(GeneratorData::Local(self.tcx.typeck(generator_did.expect_local())))
             }
-            _ => None, // Do not ICE on closure typeck (#66868).
+            _ => self
+                .tcx
+                .generator_diagnostic_data(generator_did)
+                .as_ref()
+                .map(|generator_diag_data| GeneratorData::Foreign(generator_diag_data)),
         };
-        if let Some(typeck_results) = typeck_results {
-            if let Some(upvars) = self.tcx.upvars_mentioned(generator_did) {
-                interior_or_upvar_span = upvars.iter().find_map(|(upvar_id, upvar)| {
-                    let upvar_ty = typeck_results.node_type(*upvar_id);
-                    let upvar_ty = self.resolve_vars_if_possible(upvar_ty);
-                    if ty_matches(ty::Binder::dummy(upvar_ty)) {
-                        Some(GeneratorInteriorOrUpvar::Upvar(upvar.span))
-                    } else {
-                        None
-                    }
-                });
-            };
+
+        if let Some(generator_data) = generator_data.as_ref() {
+            interior_or_upvar_span =
+                generator_data.try_get_upvar_span(&self, generator_did, ty_matches);
 
             // The generator interior types share the same binders
             if let Some(cause) =
-                typeck_results.generator_interior_types.as_ref().skip_binder().iter().find(
+                generator_data.get_generator_interior_types().skip_binder().iter().find(
                     |ty::GeneratorInteriorTypeCause { ty, .. }| {
-                        ty_matches(typeck_results.generator_interior_types.rebind(*ty))
+                        ty_matches(generator_data.get_generator_interior_types().rebind(*ty))
                     },
                 )
             {
-                // Check to see if any awaited expressions have the target type.
-                let from_awaited_ty = visitor
-                    .awaits
-                    .into_iter()
-                    .map(|id| hir.expect_expr(id))
-                    .find(|await_expr| {
-                        ty_matches(ty::Binder::dummy(typeck_results.expr_ty_adjusted(&await_expr)))
-                    })
-                    .map(|expr| expr.span);
+                let from_awaited_ty = generator_data.get_from_await_ty(visitor, hir, ty_matches);
                 let ty::GeneratorInteriorTypeCause { span, scope_span, yield_span, expr, .. } =
                     cause;
 
                 interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(*span));
                 interior_extra_info = Some((*scope_span, *yield_span, *expr, from_awaited_ty));
-            };
-        } else {
-            interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(span));
+            }
+
+            if interior_or_upvar_span.is_none() && generator_data.is_foreign() {
+                interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(span));
+            }
         }
 
         if let Some(interior_or_upvar_span) = interior_or_upvar_span {
+            let typeck_results = generator_data.and_then(|generator_data| match generator_data {
+                GeneratorData::Local(typeck_results) => Some(typeck_results),
+                GeneratorData::Foreign(_) => None,
+            });
             self.note_obligation_cause_for_async_await(
                 err,
                 interior_or_upvar_span,
                 interior_extra_info,
-                generator_body,
+                is_async,
                 outer_generator,
                 trait_ref,
                 target_ty,
@@ -1757,7 +1881,7 @@ fn note_obligation_cause_for_async_await(
         err: &mut Diagnostic,
         interior_or_upvar_span: GeneratorInteriorOrUpvar,
         interior_extra_info: Option<(Option<Span>, Span, Option<hir::HirId>, Option<Span>)>,
-        inner_generator_body: Option<&hir::Body<'tcx>>,
+        is_async: bool,
         outer_generator: Option<DefId>,
         trait_pred: ty::TraitPredicate<'tcx>,
         target_ty: Ty<'tcx>,
@@ -1767,10 +1891,6 @@ fn note_obligation_cause_for_async_await(
     ) {
         let source_map = self.tcx.sess.source_map();
 
-        let is_async = inner_generator_body
-            .and_then(|body| body.generator_kind())
-            .map(|generator_kind| matches!(generator_kind, hir::GeneratorKind::Async(..)))
-            .unwrap_or(false);
         let (await_or_yield, an_await_or_yield) =
             if is_async { ("await", "an await") } else { ("yield", "a yield") };
         let future_or_generator = if is_async { "future" } else { "generator" };
index 1a10b07cc2706fa28038dc04960ebfab847c212c..38cc74a5e37348ccca400456140e43b9650d210b 100644 (file)
@@ -10,7 +10,6 @@
 use rustc_span::{Span, DUMMY_SP};
 
 use std::collections::BTreeSet;
-use std::iter;
 
 impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
     /// On missing type parameters, emit an E0393 error and provide a structured suggestion using
@@ -323,6 +322,7 @@ pub(crate) fn complain_about_missing_associated_types(
         let mut suggestions = vec![];
         let mut types_count = 0;
         let mut where_constraints = vec![];
+        let mut already_has_generics_args_suggestion = false;
         for (span, assoc_items) in &associated_types {
             let mut names: FxHashMap<_, usize> = FxHashMap::default();
             for item in assoc_items {
@@ -343,16 +343,10 @@ pub(crate) fn complain_about_missing_associated_types(
                 }
             }
             if potential_assoc_types.len() == assoc_items.len() {
-                // Only suggest when the amount of missing associated types equals the number of
-                // extra type arguments present, as that gives us a relatively high confidence
-                // that the user forgot to give the associated type's name. The canonical
-                // example would be trying to use `Iterator<isize>` instead of
-                // `Iterator<Item = isize>`.
-                for (potential, item) in iter::zip(&potential_assoc_types, assoc_items) {
-                    if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(*potential) {
-                        suggestions.push((*potential, format!("{} = {}", item.name, snippet)));
-                    }
-                }
+                // When the amount of missing associated types equals the number of
+                // extra type arguments present.  A suggesting to replace the generic args with
+                // associated types is already emitted.
+                already_has_generics_args_suggestion = true;
             } else if let (Ok(snippet), false) =
                 (tcx.sess.source_map().span_to_snippet(*span), dupes)
             {
@@ -382,7 +376,7 @@ pub(crate) fn complain_about_missing_associated_types(
             // the same associated type name.
             err.help(where_msg);
         }
-        if suggestions.len() != 1 {
+        if suggestions.len() != 1 || already_has_generics_args_suggestion {
             // We don't need this label if there's an inline suggestion, show otherwise.
             for (span, assoc_items) in &associated_types {
                 let mut names: FxHashMap<_, usize> = FxHashMap::default();
index 6bae0f2eac9545b5cb1c92d4a6bf84f4526d2e9e..1caf93e5fe055fef2fc7eefdc603bb18b8362209 100644 (file)
@@ -2563,40 +2563,77 @@ 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![];
+
         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,
                 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 +2661,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 e88082dbb9744e36c57a8b3c7f558c0a37333a16..47cb1ea48cb54c3c6f4519979d14da23015a3ce1 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,
@@ -1978,6 +1988,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 +2077,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 +2310,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 +2340,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 +2365,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 80f6190732ac2a273fba37ba057898525803ccfb..616aa11f00a6b638870cfa61e6f9bf4c7463ee9f 100644 (file)
@@ -968,9 +968,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();
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..80c31355fe71dde81b6a7d3db6e914749b1381fe 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",
+                            );
                         }
                     }
                 }
@@ -985,7 +876,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 +962,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 +1156,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,
index 0d5e7b28a4e65e942c8e2c975f448a3b21a5e0d2..f7bb30cd13e6f030b0ba1d50e6d9225e2491f917 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};
@@ -988,3 +991,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 f3dcf5fff74cc39bd4562826d12b1263616f6d73..cf0c5703cd0ee7c724ff760b13ef9987ac79bab1 100644 (file)
@@ -2042,63 +2042,60 @@ fn error_expected_array_or_slice(&self, span: Span, expected_ty: Ty<'tcx>, ti: T
             self.tcx.sess,
             span,
             E0529,
-            "expected an array or slice, found `{}`",
-            expected_ty
+            "expected an array or slice, found `{expected_ty}`"
         );
-        if let ty::Ref(_, ty, _) = expected_ty.kind() {
-            if let ty::Array(..) | ty::Slice(..) = ty.kind() {
-                err.help("the semantics of slice patterns changed recently; see issue #62254");
-            }
+        if let ty::Ref(_, ty, _) = expected_ty.kind()
+            && let ty::Array(..) | ty::Slice(..) = ty.kind()
+        {
+            err.help("the semantics of slice patterns changed recently; see issue #62254");
         } else if Autoderef::new(&self.infcx, self.param_env, self.body_id, span, expected_ty, span)
             .any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..)))
+            && let (Some(span), true) = (ti.span, ti.origin_expr)
+            && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
         {
-            if let (Some(span), true) = (ti.span, ti.origin_expr) {
-                if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
-                    let applicability = Autoderef::new(
-                        &self.infcx,
-                        self.param_env,
-                        self.body_id,
-                        span,
-                        self.resolve_vars_if_possible(ti.expected),
+            let ty = self.resolve_vars_if_possible(ti.expected);
+            let is_slice_or_array_or_vector = self.is_slice_or_array_or_vector(&mut err, snippet.clone(), ty);
+            match is_slice_or_array_or_vector.1.kind() {
+                ty::Adt(adt_def, _)
+                    if self.tcx.is_diagnostic_item(sym::Option, adt_def.did())
+                        || self.tcx.is_diagnostic_item(sym::Result, adt_def.did()) =>
+                {
+                    // Slicing won't work here, but `.as_deref()` might (issue #91328).
+                    err.span_suggestion(
                         span,
-                    )
-                    .find_map(|(ty, _)| {
-                        match ty.kind() {
-                            ty::Adt(adt_def, _)
-                                if self.tcx.is_diagnostic_item(sym::Option, adt_def.did())
-                                    || self.tcx.is_diagnostic_item(sym::Result, adt_def.did()) =>
-                            {
-                                // Slicing won't work here, but `.as_deref()` might (issue #91328).
-                                err.span_suggestion(
-                                    span,
-                                    "consider using `as_deref` here",
-                                    format!("{}.as_deref()", snippet),
-                                    Applicability::MaybeIncorrect,
-                                );
-                                Some(None)
-                            }
-
-                            ty::Slice(..) | ty::Array(..) => {
-                                Some(Some(Applicability::MachineApplicable))
-                            }
-
-                            _ => None,
-                        }
-                    })
-                    .unwrap_or(Some(Applicability::MaybeIncorrect));
-
-                    if let Some(applicability) = applicability {
-                        err.span_suggestion(
-                            span,
-                            "consider slicing here",
-                            format!("{}[..]", snippet),
-                            applicability,
-                        );
-                    }
+                        "consider using `as_deref` here",
+                        format!("{snippet}.as_deref()"),
+                        Applicability::MaybeIncorrect,
+                    );
                 }
+                _ => ()
+            }
+            if is_slice_or_array_or_vector.0 {
+                err.span_suggestion(
+                    span,
+                    "consider slicing here",
+                    format!("{snippet}[..]"),
+                    Applicability::MachineApplicable,
+                );
             }
         }
-        err.span_label(span, format!("pattern cannot match with input type `{}`", expected_ty));
+        err.span_label(span, format!("pattern cannot match with input type `{expected_ty}`"));
         err.emit();
     }
+
+    fn is_slice_or_array_or_vector(
+        &self,
+        err: &mut Diagnostic,
+        snippet: String,
+        ty: Ty<'tcx>,
+    ) -> (bool, Ty<'tcx>) {
+        match ty.kind() {
+            ty::Adt(adt_def, _) if self.tcx.is_diagnostic_item(sym::Vec, adt_def.did()) => {
+                (true, ty)
+            }
+            ty::Ref(_, ty, _) => self.is_slice_or_array_or_vector(err, snippet, *ty),
+            ty::Slice(..) | ty::Array(..) => (true, ty),
+            _ => (false, ty),
+        }
+    }
 }
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..be77bdb0bf5f06e3b16840f6ab2e67fed4489e28 100644 (file)
@@ -160,6 +160,33 @@ struct CollectItemTypesVisitor<'tcx> {
         return;
     }
 
+    placeholder_type_error_diag(
+        tcx,
+        span,
+        generics,
+        placeholder_types,
+        vec![],
+        suggest,
+        hir_ty,
+        kind,
+    )
+    .emit();
+}
+
+crate fn placeholder_type_error_diag<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    span: Option<Span>,
+    generics: &[hir::GenericParam<'_>],
+    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 type_name = generics.next_type_param_name(None);
     let mut sugg: Vec<_> =
         placeholder_types.iter().map(|sp| (*sp, (*type_name).to_string())).collect();
@@ -182,7 +209,8 @@ struct CollectItemTypesVisitor<'tcx> {
         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 +246,8 @@ struct CollectItemTypesVisitor<'tcx> {
             );
         }
     }
-    err.emit();
+
+    err
 }
 
 fn reject_placeholder_type_signatures_in_item<'tcx>(
@@ -1868,50 +1897,17 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
             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();
+            infer_return_ty_for_fn_sig(tcx, sig, *ident, generics, def_id, &icx)
+        }
 
-                    fn_sig
-                }
-                None => <dyn AstConv<'_>>::ty_of_fn(
+        ImplItem(hir::ImplItem { kind: ImplItemKind::Fn(sig, _), ident, 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,
@@ -1920,7 +1916,9 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
                     generics,
                     Some(ident.span),
                     None,
-                ),
+                )
+            } else {
+                infer_return_ty_for_fn_sig(tcx, sig, *ident, generics, def_id, &icx)
             }
         }
 
@@ -1982,6 +1980,70 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
     }
 }
 
+fn infer_return_ty_for_fn_sig<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    sig: &hir::FnSig<'_>,
+    ident: Ident,
+    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.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();
+
+            fn_sig
+        }
+        None => <dyn AstConv<'_>>::ty_of_fn(
+            icx,
+            hir_id,
+            sig.header.unsafety,
+            sig.header.abi,
+            sig.decl,
+            generics,
+            Some(ident.span),
+            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 {
index 1088be5f566571d2ff7039c47a40b04012519dee..fc08171d2f4c290c00f831bca2b3de293c5c8e80 100644 (file)
@@ -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)>,
 }
 
index 1b1a2037d9eaa9dd5c819c67f8a76dea55d3b9af..5cd7a7d578e4bbcdaca2d1a1bf533c7b7f8bc0f4 100644 (file)
@@ -6,9 +6,10 @@
 use rustc_hir as hir;
 use rustc_middle::hir::map::fn_sig;
 use rustc_middle::middle::resolve_lifetime::LifetimeScopeForPath;
-use rustc_middle::ty::{self as ty, TyCtxt};
+use rustc_middle::ty::{self as ty, AssocItems, AssocKind, TyCtxt};
 use rustc_session::Session;
 use rustc_span::def_id::DefId;
+use std::iter;
 
 use GenericArgsInfo::*;
 
@@ -334,6 +335,22 @@ fn get_type_or_const_args_suggestions_from_param_names(
             .join(", ")
     }
 
+    fn get_unbound_associated_types(&self) -> Vec<String> {
+        if self.tcx.is_trait(self.def_id) {
+            let items: &AssocItems<'_> = self.tcx.associated_items(self.def_id);
+            items
+                .in_definition_order()
+                .filter(|item| item.kind == AssocKind::Type)
+                .filter(|item| {
+                    !self.gen_args.bindings.iter().any(|binding| binding.ident.name == item.name)
+                })
+                .map(|item| item.name.to_ident_string())
+                .collect()
+        } else {
+            Vec::default()
+        }
+    }
+
     fn create_error_message(&self) -> String {
         let def_path = self.tcx.def_path_str(self.def_id);
         let def_kind = self.tcx.def_kind(self.def_id).descr(self.def_id);
@@ -618,6 +635,7 @@ fn suggest_adding_type_and_const_args(&self, err: &mut Diagnostic) {
     fn suggest_removing_args_or_generics(&self, err: &mut Diagnostic) {
         let num_provided_lt_args = self.num_provided_lifetime_args();
         let num_provided_type_const_args = self.num_provided_type_or_const_args();
+        let unbound_types = self.get_unbound_associated_types();
         let num_provided_args = num_provided_lt_args + num_provided_type_const_args;
         assert!(num_provided_args > 0);
 
@@ -629,6 +647,8 @@ fn suggest_removing_args_or_generics(&self, err: &mut Diagnostic) {
         let redundant_type_or_const_args = num_redundant_type_or_const_args > 0;
 
         let remove_entire_generics = num_redundant_args >= self.gen_args.args.len();
+        let provided_args_matches_unbound_traits =
+            unbound_types.len() == num_redundant_type_or_const_args;
 
         let remove_lifetime_args = |err: &mut Diagnostic| {
             let mut lt_arg_spans = Vec::new();
@@ -713,7 +733,28 @@ fn suggest_removing_args_or_generics(&self, err: &mut Diagnostic) {
             );
         };
 
-        if remove_entire_generics {
+        // If there is a single unbound associated type and a single excess generic param
+        // suggest replacing the generic param with the associated type bound
+        if provided_args_matches_unbound_traits && !unbound_types.is_empty() {
+            let mut suggestions = vec![];
+            let unused_generics = &self.gen_args.args[self.num_expected_type_or_const_args()..];
+            for (potential, name) in iter::zip(unused_generics, &unbound_types) {
+                if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(potential.span()) {
+                    suggestions.push((potential.span(), format!("{} = {}", name, snippet)));
+                }
+            }
+
+            if !suggestions.is_empty() {
+                err.multipart_suggestion(
+                    &format!(
+                        "replace the generic bound{s} with the associated type{s}",
+                        s = pluralize!(unbound_types.len())
+                    ),
+                    suggestions,
+                    Applicability::MaybeIncorrect,
+                );
+            }
+        } else if remove_entire_generics {
             let span = self
                 .path_segment
                 .args
index 6e53d9b442f1609ec929f1c021984391d038e879..dd886879b145d897f50d9ddae5307caacc3293ac 100644 (file)
@@ -473,13 +473,23 @@ changelog-seen = 2
 # FIXME(#61117): Some tests fail when this option is enabled.
 #debuginfo-level-tests = 0
 
-# Whether to run `dsymutil` on Apple platforms to gather debug info into .dSYM
-# bundles. `dsymutil` adds time to builds for no clear benefit, and also makes
-# it more difficult for debuggers to find debug info. The compiler currently
-# defaults to running `dsymutil` to preserve its historical default, but when
-# compiling the compiler itself, we skip it by default since we know it's safe
-# to do so in that case.
-#run-dsymutil = false
+# Should rustc be build with split debuginfo? Default is platform dependent.
+# Valid values are the same as those accepted by `-C split-debuginfo`
+# (`off`/`unpacked`/`packed`).
+#
+# On Linux, split debuginfo is disabled by default.
+#
+# On Apple platforms, unpacked split debuginfo is used by default. Unpacked
+# debuginfo does not run `dsymutil`, which packages debuginfo from disparate
+# object files into a single `.dSYM` file. `dsymutil` adds time to builds for
+# no clear benefit, and also makes it more difficult for debuggers to find
+# debug info. The compiler currently defaults to running `dsymutil` to preserve
+# its historical default, but when compiling the compiler itself, we skip it by
+# default since we know it's safe to do so in that case.
+#
+# On Windows platforms, packed debuginfo is the only supported option,
+# producing a `.pdb` file.
+#split-debuginfo = if linux { off } else if windows { packed } else if apple { unpacked }
 
 # Whether or not `panic!`s generate backtraces (RUST_BACKTRACE)
 #backtrace = true
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 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 488671d8d8d19b7fbf1ab6129ec934969e37dc41..ab14a43fb9379ea2681d0b2436755675022fe1d9 100644 (file)
@@ -1342,6 +1342,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 +2566,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 +2577,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 +2622,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 +2638,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 +2677,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 +2691,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
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 d3e9e65c3fe57b493001b6c77c9afc99287ff126..22c19243e7f53fca729e9e75503e51b59802355f 100644 (file)
@@ -34,7 +34,7 @@
 /// be mindful of side effects.
 ///
 /// [`Vec`]: crate::vec::Vec
-#[cfg(not(test))]
+#[cfg(all(not(no_global_oom_handling), not(test)))]
 #[macro_export]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_diagnostic_item = "vec_macro"]
@@ -55,7 +55,7 @@ macro_rules! vec {
 // required for this macro definition, is not available. Instead use the
 // `slice::into_vec`  function which is only available with cfg(test)
 // NB see the slice::hack module in slice.rs for more information
-#[cfg(test)]
+#[cfg(all(not(no_global_oom_handling), test))]
 macro_rules! vec {
     () => (
         $crate::vec::Vec::new()
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 8e02ca8431744b4effcffb88f1e85ef2e6b2351a..bddbe2b9b0df104da8c8c9b500835c2fe86969ad 100644 (file)
@@ -1,7 +1,7 @@
 //! Compiler intrinsics.
 //!
-//! The corresponding definitions are in `compiler/rustc_codegen_llvm/src/intrinsic.rs`.
-//! The corresponding const implementations are in `compiler/rustc_mir/src/interpret/intrinsics.rs`
+//! The corresponding definitions are in <https://github.com/rust-lang/rust/blob/master/compiler/rustc_codegen_llvm/src/intrinsic.rs>.
+//! The corresponding const implementations are in <https://github.com/rust-lang/rust/blob/master/compiler/rustc_const_eval/src/interpret/intrinsics.rs>.
 //!
 //! # Const intrinsics
 //!
@@ -10,8 +10,8 @@
 //!
 //! In order to make an intrinsic usable at compile-time, one needs to copy the implementation
 //! from <https://github.com/rust-lang/miri/blob/master/src/shims/intrinsics.rs> to
-//! `compiler/rustc_mir/src/interpret/intrinsics.rs` and add a
-//! `#[rustc_const_unstable(feature = "foo", issue = "01234")]` to the intrinsic.
+//! <https://github.com/rust-lang/rust/blob/master/compiler/rustc_const_eval/src/interpret/intrinsics.rs> and add a
+//! `#[rustc_const_unstable(feature = "const_such_and_such", issue = "01234")]` to the intrinsic declaration.
 //!
 //! If an intrinsic is supposed to be used from a `const fn` with a `rustc_const_stable` attribute,
 //! the intrinsic's attribute must be `rustc_const_stable`, too. Such a change should not be done
index 7b75ab96ee7deea69f7f194b115490bc51702a64..e6900742c31d235d7ce15e4f1f1c1b5e4f2341fc 100644 (file)
@@ -267,8 +267,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 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 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 22662f7d18d07da1bb1d533a1e0d73711fa43c1b..98dd1521d0e85bea969b63d583f976bd74a023ee 100644 (file)
@@ -358,6 +358,20 @@ impl<'a, T: 'a, P: FnMut(&T) -> bool> Split<'a, T, P> {
     pub(super) fn new(slice: &'a [T], pred: P) -> Self {
         Self { v: slice, pred, finished: false }
     }
+    /// Returns a slice which contains items not yet handled by split.
+    /// # Example
+    ///
+    /// ```
+    /// #![feature(split_as_slice)]
+    /// let slice = [1,2,3,4,5];
+    /// let mut split = slice.split(|v| v % 2 == 0);
+    /// assert!(split.next().is_some());
+    /// assert_eq!(split.as_slice(), &[3,4,5]);
+    /// ```
+    #[unstable(feature = "split_as_slice", issue = "96137")]
+    pub fn as_slice(&self) -> &'a [T] {
+        if self.finished { &[] } else { &self.v }
+    }
 }
 
 #[stable(feature = "core_impl_debug", since = "1.9.0")]
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 447a6fcf7567e5c4242676c32fe0a4d6a3f7bae8..485fa305c00e19834cc3f4b590f08fdc15615607 100644 (file)
@@ -46,6 +46,7 @@
 #![feature(sort_internals)]
 #![feature(slice_take)]
 #![feature(slice_from_ptr_range)]
+#![feature(split_as_slice)]
 #![feature(maybe_uninit_uninit_array)]
 #![feature(maybe_uninit_array_assume_init)]
 #![feature(maybe_uninit_write_slice)]
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 ada479147db95806c3e638a9ecc36687d91bba9c..872786ed1bd8083427ef1b4f2f3719e5a51947ca 100644 (file)
@@ -2339,6 +2339,18 @@ fn slice_rsplit_array_mut() {
     }
 }
 
+#[test]
+fn split_as_slice() {
+    let arr = [1, 2, 3, 4, 5, 6];
+    let mut split = arr.split(|v| v % 2 == 0);
+    assert_eq!(split.as_slice(), &[1, 2, 3, 4, 5, 6]);
+    assert!(split.next().is_some());
+    assert_eq!(split.as_slice(), &[3, 4, 5, 6]);
+    assert!(split.next().is_some());
+    assert!(split.next().is_some());
+    assert_eq!(split.as_slice(), &[]);
+}
+
 #[should_panic]
 #[test]
 fn slice_split_array_ref_out_of_bounds() {
index db5e2e4e245ea59f84c5828116a313d543f29c4c..e54a50aa15c616bcf16b03e186ec4abf4985e51d 100644 (file)
@@ -5,3 +5,7 @@ edition = "2021"
 
 [dependencies]
 std = { path = "../std" }
+# Workaround: when documenting this crate rustdoc will try to load crate named
+# `core` when resolving doc links. Without this line a different `core` will be
+# loaded from sysroot causing duplicate lang items and other similar errors.
+core = { path = "../core" }
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 da7753216d0630b91aa893f256adf54036d96f3f..f60b604f1b167a832b6d4185dc980e74ee861fc0 100644 (file)
 #![feature(exhaustive_patterns)]
 #![feature(intra_doc_pointers)]
 #![feature(lang_items)]
+#![feature(let_chains)]
 #![feature(linkage)]
 #![feature(min_specialization)]
 #![feature(must_not_suspend)]
index 4e16a55edece26a1b71d9acf7578d712d8efa0ca..fb292ed29a18a5b90d508aaf81df12247fdb6863 100644 (file)
@@ -59,12 +59,12 @@ fn read_atomically<T, F>(&mut self, inner: F) -> Option<T>
 
     /// Run a parser, but fail if the entire input wasn't consumed.
     /// Doesn't run atomically.
-    fn parse_with<T, F>(&mut self, inner: F) -> Result<T, AddrParseError>
+    fn parse_with<T, F>(&mut self, inner: F, kind: AddrKind) -> Result<T, AddrParseError>
     where
         F: FnOnce(&mut Parser<'_>) -> Option<T>,
     {
         let result = inner(self);
-        if self.state.is_empty() { result } else { None }.ok_or(AddrParseError(()))
+        if self.state.is_empty() { result } else { None }.ok_or(AddrParseError(kind))
     }
 
     /// Peek the next character from the input
@@ -278,7 +278,7 @@ fn read_socket_addr(&mut self) -> Option<SocketAddr> {
 impl FromStr for IpAddr {
     type Err = AddrParseError;
     fn from_str(s: &str) -> Result<IpAddr, AddrParseError> {
-        Parser::new(s).parse_with(|p| p.read_ip_addr())
+        Parser::new(s).parse_with(|p| p.read_ip_addr(), AddrKind::Ip)
     }
 }
 
@@ -288,9 +288,9 @@ impl FromStr for Ipv4Addr {
     fn from_str(s: &str) -> Result<Ipv4Addr, AddrParseError> {
         // don't try to parse if too long
         if s.len() > 15 {
-            Err(AddrParseError(()))
+            Err(AddrParseError(AddrKind::Ipv4))
         } else {
-            Parser::new(s).parse_with(|p| p.read_ipv4_addr())
+            Parser::new(s).parse_with(|p| p.read_ipv4_addr(), AddrKind::Ipv4)
         }
     }
 }
@@ -299,7 +299,7 @@ fn from_str(s: &str) -> Result<Ipv4Addr, AddrParseError> {
 impl FromStr for Ipv6Addr {
     type Err = AddrParseError;
     fn from_str(s: &str) -> Result<Ipv6Addr, AddrParseError> {
-        Parser::new(s).parse_with(|p| p.read_ipv6_addr())
+        Parser::new(s).parse_with(|p| p.read_ipv6_addr(), AddrKind::Ipv6)
     }
 }
 
@@ -307,7 +307,7 @@ fn from_str(s: &str) -> Result<Ipv6Addr, AddrParseError> {
 impl FromStr for SocketAddrV4 {
     type Err = AddrParseError;
     fn from_str(s: &str) -> Result<SocketAddrV4, AddrParseError> {
-        Parser::new(s).parse_with(|p| p.read_socket_addr_v4())
+        Parser::new(s).parse_with(|p| p.read_socket_addr_v4(), AddrKind::SocketV4)
     }
 }
 
@@ -315,7 +315,7 @@ fn from_str(s: &str) -> Result<SocketAddrV4, AddrParseError> {
 impl FromStr for SocketAddrV6 {
     type Err = AddrParseError;
     fn from_str(s: &str) -> Result<SocketAddrV6, AddrParseError> {
-        Parser::new(s).parse_with(|p| p.read_socket_addr_v6())
+        Parser::new(s).parse_with(|p| p.read_socket_addr_v6(), AddrKind::SocketV6)
     }
 }
 
@@ -323,10 +323,20 @@ fn from_str(s: &str) -> Result<SocketAddrV6, AddrParseError> {
 impl FromStr for SocketAddr {
     type Err = AddrParseError;
     fn from_str(s: &str) -> Result<SocketAddr, AddrParseError> {
-        Parser::new(s).parse_with(|p| p.read_socket_addr())
+        Parser::new(s).parse_with(|p| p.read_socket_addr(), AddrKind::Socket)
     }
 }
 
+#[derive(Debug, Clone, PartialEq, Eq)]
+enum AddrKind {
+    Ip,
+    Ipv4,
+    Ipv6,
+    Socket,
+    SocketV4,
+    SocketV6,
+}
+
 /// An error which can be returned when parsing an IP address or a socket address.
 ///
 /// This error is used as the error type for the [`FromStr`] implementation for
@@ -353,7 +363,7 @@ fn from_str(s: &str) -> Result<SocketAddr, AddrParseError> {
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 #[derive(Debug, Clone, PartialEq, Eq)]
-pub struct AddrParseError(());
+pub struct AddrParseError(AddrKind);
 
 #[stable(feature = "addr_parse_error_error", since = "1.4.0")]
 impl fmt::Display for AddrParseError {
@@ -367,6 +377,13 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
 impl Error for AddrParseError {
     #[allow(deprecated)]
     fn description(&self) -> &str {
-        "invalid IP address syntax"
+        match self.0 {
+            AddrKind::Ip => "invalid IP address syntax",
+            AddrKind::Ipv4 => "invalid IPv4 address syntax",
+            AddrKind::Ipv6 => "invalid IPv6 address syntax",
+            AddrKind::Socket => "invalid socket address syntax",
+            AddrKind::SocketV4 => "invalid IPv4 socket address syntax",
+            AddrKind::SocketV6 => "invalid IPv6 socket address syntax",
+        }
     }
 }
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 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 7181451de575fcb8ff7df27ba5a66b18a08904be..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)
     }
 
@@ -1647,8 +1647,9 @@ fn is_dir(ent: &DirEntry) -> Option<bool> {
     fn remove_dir_all_recursive(parent_fd: Option<RawFd>, path: &CStr) -> io::Result<()> {
         // try opening as directory
         let fd = match openat_nofollow_dironly(parent_fd, &path) {
-            Err(err) if err.raw_os_error() == Some(libc::ENOTDIR) => {
+            Err(err) if matches!(err.raw_os_error(), Some(libc::ENOTDIR | libc::ELOOP)) => {
                 // not a directory - don't traverse further
+                // (for symlinks, older Linux kernels may return ELOOP instead of ENOTDIR)
                 return match parent_fd {
                     // unlink...
                     Some(parent_fd) => {
index 62760373a6affecba019d63754011973ffaa2db1..c12ee169e797aa78c904d3e5d125e16ceed4145d 100644 (file)
@@ -52,25 +52,6 @@ pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -
     }
 }
 
-#[cfg(target_os = "emscripten")]
-pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) {
-    extern "C" {
-        fn emscripten_futex_wait(
-            addr: *const AtomicU32,
-            val: libc::c_uint,
-            max_wait_ms: libc::c_double,
-        ) -> libc::c_int;
-    }
-
-    unsafe {
-        emscripten_futex_wait(
-            futex,
-            expected,
-            timeout.map_or(crate::f64::INFINITY, |d| d.as_secs_f64() * 1000.0),
-        );
-    }
-}
-
 /// Wake up one thread that's blocked on futex_wait on this futex.
 ///
 /// Returns true if this actually woke up such a thread,
@@ -101,10 +82,32 @@ pub fn futex_wake_all(futex: &AtomicU32) {
 }
 
 #[cfg(target_os = "emscripten")]
-pub fn futex_wake(futex: &AtomicU32) -> bool {
-    extern "C" {
-        fn emscripten_futex_wake(addr: *const AtomicU32, count: libc::c_int) -> libc::c_int;
+extern "C" {
+    fn emscripten_futex_wake(addr: *const AtomicU32, count: libc::c_int) -> libc::c_int;
+    fn emscripten_futex_wait(
+        addr: *const AtomicU32,
+        val: libc::c_uint,
+        max_wait_ms: libc::c_double,
+    ) -> libc::c_int;
+}
+
+#[cfg(target_os = "emscripten")]
+pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -> bool {
+    unsafe {
+        emscripten_futex_wait(
+            futex,
+            expected,
+            timeout.map_or(f64::INFINITY, |d| d.as_secs_f64() * 1000.0),
+        ) != -libc::ETIMEDOUT
     }
+}
 
+#[cfg(target_os = "emscripten")]
+pub fn futex_wake(futex: &AtomicU32) -> bool {
     unsafe { emscripten_futex_wake(futex, 1) > 0 }
 }
+
+#[cfg(target_os = "emscripten")]
+pub fn futex_wake_all(futex: &AtomicU32) {
+    unsafe { emscripten_futex_wake(futex, i32::MAX) };
+}
index 17796f8894b5d049ad3a1478ab47d67fd70c79a2..3e39c8b9b23e7a00ab22c9c317d49d97e73d45a2 100644 (file)
@@ -2,6 +2,7 @@
     if #[cfg(any(
         target_os = "linux",
         target_os = "android",
+        all(target_os = "emscripten", target_feature = "atomics"),
     ))] {
         mod futex;
         mod futex_rwlock;
index 1be733ba106e866828c87a9f8cc1769a1530ba14..92bea9346d8f8ea888515778589c5d42c66d8ea8 100644 (file)
@@ -427,7 +427,7 @@ pub fn current_exe() -> io::Result<PathBuf> {
     crate::fs::read_to_string("sys:exe").map(PathBuf::from)
 }
 
-#[cfg(any(target_os = "fuchsia", target_os = "l4re"))]
+#[cfg(target_os = "l4re")]
 pub fn current_exe() -> io::Result<PathBuf> {
     use crate::io::ErrorKind;
     Err(io::const_io_error!(ErrorKind::Unsupported, "Not yet implemented!"))
@@ -451,6 +451,26 @@ pub fn current_exe() -> io::Result<PathBuf> {
     super::unsupported::unsupported()
 }
 
+#[cfg(target_os = "fuchsia")]
+pub fn current_exe() -> io::Result<PathBuf> {
+    use crate::io::ErrorKind;
+
+    #[cfg(test)]
+    use realstd::env;
+
+    #[cfg(not(test))]
+    use crate::env;
+
+    let exe_path = env::args().next().ok_or(io::const_io_error!(
+        ErrorKind::Uncategorized,
+        "an executable path was not found because no arguments were provided through argv"
+    ))?;
+    let path = PathBuf::from(exe_path);
+
+    // Prepend the current working directory to the path if it's not absolute.
+    if !path.is_absolute() { getcwd().map(|cwd| cwd.join(path)) } else { Ok(path) }
+}
+
 pub struct Env {
     iter: vec::IntoIter<(OsString, OsString)>,
 }
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 {
index da63c068384a2b56a4926360db10c4213646d616..e4ff21b25bd9ce47aea69b7fd0f2eb696c873306 100644 (file)
@@ -25,7 +25,8 @@
 use crate::ffi::CStr;
 use crate::marker::PhantomData;
 use crate::mem;
-use crate::sync::atomic::{self, AtomicUsize, Ordering};
+use crate::ptr;
+use crate::sync::atomic::{self, AtomicPtr, Ordering};
 
 // We can use true weak linkage on ELF targets.
 #[cfg(not(any(target_os = "macos", target_os = "ios")))]
@@ -83,13 +84,13 @@ pub(crate) fn get(&self) -> Option<F> {
 }
 pub(crate) struct DlsymWeak<F> {
     name: &'static str,
-    addr: AtomicUsize,
+    func: AtomicPtr<libc::c_void>,
     _marker: PhantomData<F>,
 }
 
 impl<F> DlsymWeak<F> {
     pub(crate) const fn new(name: &'static str) -> Self {
-        DlsymWeak { name, addr: AtomicUsize::new(1), _marker: PhantomData }
+        DlsymWeak { name, func: AtomicPtr::new(ptr::invalid_mut(1)), _marker: PhantomData }
     }
 
     #[inline]
@@ -97,11 +98,11 @@ pub(crate) fn get(&self) -> Option<F> {
         unsafe {
             // Relaxed is fine here because we fence before reading through the
             // pointer (see the comment below).
-            match self.addr.load(Ordering::Relaxed) {
-                1 => self.initialize(),
-                0 => None,
-                addr => {
-                    let func = mem::transmute_copy::<usize, F>(&addr);
+            match self.func.load(Ordering::Relaxed) {
+                func if func.addr() == 1 => self.initialize(),
+                func if func.is_null() => None,
+                func => {
+                    let func = mem::transmute_copy::<*mut libc::c_void, F>(&func);
                     // The caller is presumably going to read through this value
                     // (by calling the function we've dlsymed). This means we'd
                     // need to have loaded it with at least C11's consume
@@ -129,25 +130,22 @@ pub(crate) fn get(&self) -> Option<F> {
     // Cold because it should only happen during first-time initialization.
     #[cold]
     unsafe fn initialize(&self) -> Option<F> {
-        assert_eq!(mem::size_of::<F>(), mem::size_of::<usize>());
+        assert_eq!(mem::size_of::<F>(), mem::size_of::<*mut libc::c_void>());
 
         let val = fetch(self.name);
         // This synchronizes with the acquire fence in `get`.
-        self.addr.store(val, Ordering::Release);
+        self.func.store(val, Ordering::Release);
 
-        match val {
-            0 => None,
-            addr => Some(mem::transmute_copy::<usize, F>(&addr)),
-        }
+        if val.is_null() { None } else { Some(mem::transmute_copy::<*mut libc::c_void, F>(&val)) }
     }
 }
 
-unsafe fn fetch(name: &str) -> usize {
+unsafe fn fetch(name: &str) -> *mut libc::c_void {
     let name = match CStr::from_bytes_with_nul(name.as_bytes()) {
         Ok(cstr) => cstr,
-        Err(..) => return 0,
+        Err(..) => return ptr::null_mut(),
     };
-    libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr()) as usize
+    libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr())
 }
 
 #[cfg(not(any(target_os = "linux", target_os = "android")))]
diff --git a/library/std/src/sys/wasm/atomics/condvar.rs b/library/std/src/sys/wasm/atomics/condvar.rs
deleted file mode 100644 (file)
index f06c07c..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-use crate::arch::wasm32;
-use crate::cmp;
-use crate::mem;
-use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst};
-use crate::sys::locks::Mutex;
-use crate::time::Duration;
-
-pub struct Condvar {
-    cnt: AtomicUsize,
-}
-
-pub type MovableCondvar = Condvar;
-
-// Condition variables are implemented with a simple counter internally that is
-// likely to cause spurious wakeups. Blocking on a condition variable will first
-// read the value of the internal counter, unlock the given mutex, and then
-// block if and only if the counter's value is still the same. Notifying a
-// condition variable will modify the counter (add one for now) and then wake up
-// a thread waiting on the address of the counter.
-//
-// A thread waiting on the condition variable will as a result avoid going to
-// sleep if it's notified after the lock is unlocked but before it fully goes to
-// sleep. A sleeping thread is guaranteed to be woken up at some point as it can
-// only be woken up with a call to `wake`.
-//
-// Note that it's possible for 2 or more threads to be woken up by a call to
-// `notify_one` with this implementation. That can happen where the modification
-// of `cnt` causes any threads in the middle of `wait` to avoid going to sleep,
-// and the subsequent `wake` may wake up a thread that's actually blocking. We
-// consider this a spurious wakeup, though, which all users of condition
-// variables must already be prepared to handle. As a result, this source of
-// spurious wakeups is currently though to be ok, although it may be problematic
-// later on if it causes too many spurious wakeups.
-
-impl Condvar {
-    pub const fn new() -> Condvar {
-        Condvar { cnt: AtomicUsize::new(0) }
-    }
-
-    #[inline]
-    pub unsafe fn init(&mut self) {
-        // nothing to do
-    }
-
-    pub unsafe fn notify_one(&self) {
-        self.cnt.fetch_add(1, SeqCst);
-        // SAFETY: ptr() is always valid
-        unsafe {
-            wasm32::memory_atomic_notify(self.ptr(), 1);
-        }
-    }
-
-    #[inline]
-    pub unsafe fn notify_all(&self) {
-        self.cnt.fetch_add(1, SeqCst);
-        // SAFETY: ptr() is always valid
-        unsafe {
-            wasm32::memory_atomic_notify(self.ptr(), u32::MAX); // -1 == "wake everyone"
-        }
-    }
-
-    pub unsafe fn wait(&self, mutex: &Mutex) {
-        // "atomically block and unlock" implemented by loading our current
-        // counter's value, unlocking the mutex, and blocking if the counter
-        // still has the same value.
-        //
-        // Notifications happen by incrementing the counter and then waking a
-        // thread. Incrementing the counter after we unlock the mutex will
-        // prevent us from sleeping and otherwise the call to `wake` will
-        // wake us up once we're asleep.
-        let ticket = self.cnt.load(SeqCst) as i32;
-        mutex.unlock();
-        let val = wasm32::memory_atomic_wait32(self.ptr(), ticket, -1);
-        // 0 == woken, 1 == not equal to `ticket`, 2 == timeout (shouldn't happen)
-        debug_assert!(val == 0 || val == 1);
-        mutex.lock();
-    }
-
-    pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
-        let ticket = self.cnt.load(SeqCst) as i32;
-        mutex.unlock();
-        let nanos = dur.as_nanos();
-        let nanos = cmp::min(i64::MAX as u128, nanos);
-
-        // If the return value is 2 then a timeout happened, so we return
-        // `false` as we weren't actually notified.
-        let ret = wasm32::memory_atomic_wait32(self.ptr(), ticket, nanos as i64) != 2;
-        mutex.lock();
-        return ret;
-    }
-
-    #[inline]
-    pub unsafe fn destroy(&self) {
-        // nothing to do
-    }
-
-    #[inline]
-    fn ptr(&self) -> *mut i32 {
-        assert_eq!(mem::size_of::<usize>(), mem::size_of::<i32>());
-        self.cnt.as_mut_ptr() as *mut i32
-    }
-}
index bbe9bd6951af967e12d9be38040d0e07b9349292..11413ba3bf5642d484b1a3de09f3c0579b18e426 100644 (file)
@@ -3,19 +3,33 @@
 use crate::sync::atomic::AtomicU32;
 use crate::time::Duration;
 
-pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) {
+/// Wait for a futex_wake operation to wake us.
+///
+/// Returns directly if the futex doesn't hold the expected value.
+///
+/// Returns false on timeout, and true in all other cases.
+pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -> bool {
     let timeout = timeout.and_then(|t| t.as_nanos().try_into().ok()).unwrap_or(-1);
     unsafe {
         wasm32::memory_atomic_wait32(
             futex as *const AtomicU32 as *mut i32,
             expected as i32,
             timeout,
-        );
+        ) < 2
     }
 }
 
-pub fn futex_wake(futex: &AtomicU32) {
+/// Wake up one thread that's blocked on futex_wait on this futex.
+///
+/// Returns true if this actually woke up such a thread,
+/// or false if no thread was waiting on this futex.
+pub fn futex_wake(futex: &AtomicU32) -> bool {
+    unsafe { wasm32::memory_atomic_notify(futex as *const AtomicU32 as *mut i32, 1) > 0 }
+}
+
+/// Wake up all threads that are waiting on futex_wait on this futex.
+pub fn futex_wake_all(futex: &AtomicU32) {
     unsafe {
-        wasm32::memory_atomic_notify(futex as *const AtomicU32 as *mut i32, 1);
+        wasm32::memory_atomic_notify(futex as *const AtomicU32 as *mut i32, i32::MAX as u32);
     }
 }
diff --git a/library/std/src/sys/wasm/atomics/mutex.rs b/library/std/src/sys/wasm/atomics/mutex.rs
deleted file mode 100644 (file)
index 1acc839..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-use crate::arch::wasm32;
-use crate::mem;
-use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst};
-
-pub struct Mutex {
-    locked: AtomicUsize,
-}
-
-pub type MovableMutex = Mutex;
-
-// Mutexes have a pretty simple implementation where they contain an `i32`
-// internally that is 0 when unlocked and 1 when the mutex is locked.
-// Acquisition has a fast path where it attempts to cmpxchg the 0 to a 1, and
-// if it fails it then waits for a notification. Releasing a lock is then done
-// by swapping in 0 and then notifying any waiters, if present.
-
-impl Mutex {
-    pub const fn new() -> Mutex {
-        Mutex { locked: AtomicUsize::new(0) }
-    }
-
-    #[inline]
-    pub unsafe fn init(&mut self) {
-        // nothing to do
-    }
-
-    pub unsafe fn lock(&self) {
-        while !self.try_lock() {
-            // SAFETY: the caller must uphold the safety contract for `memory_atomic_wait32`.
-            let val = unsafe {
-                wasm32::memory_atomic_wait32(
-                    self.ptr(),
-                    1,  // we expect our mutex is locked
-                    -1, // wait infinitely
-                )
-            };
-            // we should have either woke up (0) or got a not-equal due to a
-            // race (1). We should never time out (2)
-            debug_assert!(val == 0 || val == 1);
-        }
-    }
-
-    pub unsafe fn unlock(&self) {
-        let prev = self.locked.swap(0, SeqCst);
-        debug_assert_eq!(prev, 1);
-        wasm32::memory_atomic_notify(self.ptr(), 1); // wake up one waiter, if any
-    }
-
-    #[inline]
-    pub unsafe fn try_lock(&self) -> bool {
-        self.locked.compare_exchange(0, 1, SeqCst, SeqCst).is_ok()
-    }
-
-    #[inline]
-    pub unsafe fn destroy(&self) {
-        // nothing to do
-    }
-
-    #[inline]
-    fn ptr(&self) -> *mut i32 {
-        assert_eq!(mem::size_of::<usize>(), mem::size_of::<i32>());
-        self.locked.as_mut_ptr() as *mut i32
-    }
-}
diff --git a/library/std/src/sys/wasm/atomics/rwlock.rs b/library/std/src/sys/wasm/atomics/rwlock.rs
deleted file mode 100644 (file)
index 690bb15..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-use crate::cell::UnsafeCell;
-use crate::sys::locks::{Condvar, Mutex};
-
-pub struct RwLock {
-    lock: Mutex,
-    cond: Condvar,
-    state: UnsafeCell<State>,
-}
-
-pub type MovableRwLock = RwLock;
-
-enum State {
-    Unlocked,
-    Reading(usize),
-    Writing,
-}
-
-unsafe impl Send for RwLock {}
-unsafe impl Sync for RwLock {}
-
-// This rwlock implementation is a relatively simple implementation which has a
-// condition variable for readers/writers as well as a mutex protecting the
-// internal state of the lock. A current downside of the implementation is that
-// unlocking the lock will notify *all* waiters rather than just readers or just
-// writers. This can cause lots of "thundering stampede" problems. While
-// hopefully correct this implementation is very likely to want to be changed in
-// the future.
-
-impl RwLock {
-    pub const fn new() -> RwLock {
-        RwLock { lock: Mutex::new(), cond: Condvar::new(), state: UnsafeCell::new(State::Unlocked) }
-    }
-
-    #[inline]
-    pub unsafe fn read(&self) {
-        self.lock.lock();
-        while !(*self.state.get()).inc_readers() {
-            self.cond.wait(&self.lock);
-        }
-        self.lock.unlock();
-    }
-
-    #[inline]
-    pub unsafe fn try_read(&self) -> bool {
-        self.lock.lock();
-        let ok = (*self.state.get()).inc_readers();
-        self.lock.unlock();
-        return ok;
-    }
-
-    #[inline]
-    pub unsafe fn write(&self) {
-        self.lock.lock();
-        while !(*self.state.get()).inc_writers() {
-            self.cond.wait(&self.lock);
-        }
-        self.lock.unlock();
-    }
-
-    #[inline]
-    pub unsafe fn try_write(&self) -> bool {
-        self.lock.lock();
-        let ok = (*self.state.get()).inc_writers();
-        self.lock.unlock();
-        return ok;
-    }
-
-    #[inline]
-    pub unsafe fn read_unlock(&self) {
-        self.lock.lock();
-        let notify = (*self.state.get()).dec_readers();
-        self.lock.unlock();
-        if notify {
-            // FIXME: should only wake up one of these some of the time
-            self.cond.notify_all();
-        }
-    }
-
-    #[inline]
-    pub unsafe fn write_unlock(&self) {
-        self.lock.lock();
-        (*self.state.get()).dec_writers();
-        self.lock.unlock();
-        // FIXME: should only wake up one of these some of the time
-        self.cond.notify_all();
-    }
-
-    #[inline]
-    pub unsafe fn destroy(&self) {
-        self.lock.destroy();
-        self.cond.destroy();
-    }
-}
-
-impl State {
-    fn inc_readers(&mut self) -> bool {
-        match *self {
-            State::Unlocked => {
-                *self = State::Reading(1);
-                true
-            }
-            State::Reading(ref mut cnt) => {
-                *cnt += 1;
-                true
-            }
-            State::Writing => false,
-        }
-    }
-
-    fn inc_writers(&mut self) -> bool {
-        match *self {
-            State::Unlocked => {
-                *self = State::Writing;
-                true
-            }
-            State::Reading(_) | State::Writing => false,
-        }
-    }
-
-    fn dec_readers(&mut self) -> bool {
-        let zero = match *self {
-            State::Reading(ref mut cnt) => {
-                *cnt -= 1;
-                *cnt == 0
-            }
-            State::Unlocked | State::Writing => invalid(),
-        };
-        if zero {
-            *self = State::Unlocked;
-        }
-        zero
-    }
-
-    fn dec_writers(&mut self) {
-        match *self {
-            State::Writing => {}
-            State::Unlocked | State::Reading(_) => invalid(),
-        }
-        *self = State::Unlocked;
-    }
-}
-
-fn invalid() -> ! {
-    panic!("inconsistent rwlock");
-}
index 16418a06226e4884a89e022feb6152f255ecae7d..714b7049227940bdcd8578cc0f3f609a4478f2d0 100644 (file)
@@ -53,37 +53,3 @@ pub unsafe fn init() -> Option<Guard> {
         None
     }
 }
-
-// We currently just use our own thread-local to store our
-// current thread's ID, and then we lazily initialize it to something allocated
-// from a global counter.
-pub fn my_id() -> u32 {
-    use crate::sync::atomic::{AtomicU32, Ordering::SeqCst};
-
-    static NEXT_ID: AtomicU32 = AtomicU32::new(0);
-
-    #[thread_local]
-    static mut MY_ID: u32 = 0;
-
-    unsafe {
-        // If our thread ID isn't set yet then we need to allocate one. Do so
-        // with with a simple "atomically add to a global counter" strategy.
-        // This strategy doesn't handled what happens when the counter
-        // overflows, however, so just abort everything once the counter
-        // overflows and eventually we could have some sort of recycling scheme
-        // (or maybe this is all totally irrelevant by that point!). In any case
-        // though we're using a CAS loop instead of a `fetch_add` to ensure that
-        // the global counter never overflows.
-        if MY_ID == 0 {
-            let mut cur = NEXT_ID.load(SeqCst);
-            MY_ID = loop {
-                let next = cur.checked_add(1).unwrap_or_else(|| crate::process::abort());
-                match NEXT_ID.compare_exchange(cur, next, SeqCst, SeqCst) {
-                    Ok(_) => break next,
-                    Err(i) => cur = i,
-                }
-            };
-        }
-        MY_ID
-    }
-}
index 9f6700caf14bf9dbc7d7c40e9b981ec94dd931dc..9992e44b0e7566b2fb9f8857550dcb2e29999477 100644 (file)
 
 cfg_if::cfg_if! {
     if #[cfg(target_feature = "atomics")] {
-        #[path = "atomics/condvar.rs"]
-        mod condvar;
-        #[path = "atomics/mutex.rs"]
-        mod mutex;
-        #[path = "atomics/rwlock.rs"]
-        mod rwlock;
+        #[path = "../unix/locks"]
         pub mod locks {
-            pub use super::condvar::*;
-            pub use super::mutex::*;
-            pub use super::rwlock::*;
+            #![allow(unsafe_op_in_unsafe_fn)]
+            mod futex;
+            mod futex_rwlock;
+            pub use futex::{Mutex, MovableMutex, Condvar, MovableCondvar};
+            pub use futex_rwlock::{RwLock, MovableRwLock};
         }
         #[path = "atomics/futex.rs"]
         pub mod futex;
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 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 a0c0f5dc3ec2cf499741a2d990a163c64c93fae5..e6f01df2627305aec41b859888a560bca566b2a6 100644 (file)
@@ -17,6 +17,7 @@
 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;
@@ -27,7 +28,7 @@
 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 {
@@ -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.
@@ -730,96 +734,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 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 d437397045c64d0920b6d6330891fad2ac858b2c..ac1c47524fd0e2f65c295411645e47dfafcfe69a 100644 (file)
@@ -817,7 +817,7 @@ class RustBuild(object):
         return os.path.join(self.bin_root(True), '.rustfmt-stamp')
 
     def llvm_stamp(self):
-        """Return the path for .rustfmt-stamp
+        """Return the path for .llvm-stamp
 
         >>> rb = RustBuild()
         >>> rb.build_dir = "build"
index d688f798956d66ce82e1a5200faaf04d0b786810..f803388f0a6baa71bfa2abced3536f9f20f2e16a 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;
@@ -14,7 +14,7 @@
 use crate::cache::{Cache, Interned, INTERNER};
 use crate::check;
 use crate::compile;
-use crate::config::TargetSelection;
+use crate::config::{SplitDebuginfo, TargetSelection};
 use crate::dist;
 use crate::doc;
 use crate::flags::{Color, Subcommand};
@@ -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());
                 }
             }
@@ -388,11 +389,13 @@ pub fn paths(mut self, paths: &[&str]) -> Self {
             paths
                 .iter()
                 .map(|p| {
-                    assert!(
-                        self.builder.src.join(p).exists(),
-                        "`should_run.paths` should correspond to real on-disk paths - use `alias` if there is no relevant path: {}",
-                        p
-                    );
+                    // FIXME(#96188): make sure this is actually a path.
+                    // This currently breaks for paths within submodules.
+                    //assert!(
+                    //    self.builder.src.join(p).exists(),
+                    //    "`should_run.paths` should correspond to real on-disk paths - use `alias` if there is no relevant path: {}",
+                    //    p
+                    //);
                     TaskPath { path: p.into(), kind: Some(self.kind) }
                 })
                 .collect(),
@@ -429,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",
         }
     }
 }
@@ -509,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,
@@ -639,32 +652,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 {
@@ -1388,17 +1398,17 @@ pub fn cargo(
             },
         );
 
-        // `dsymutil` adds time to builds on Apple platforms for no clear benefit, and also makes
-        // it more difficult for debuggers to find debug info. The compiler currently defaults to
-        // running `dsymutil` to preserve its historical default, but when compiling the compiler
-        // itself, we skip it by default since we know it's safe to do so in that case.
-        // See https://github.com/rust-lang/rust/issues/79361 for more info on this flag.
-        if target.contains("apple") {
-            if self.config.rust_run_dsymutil {
-                rustflags.arg("-Csplit-debuginfo=packed");
-            } else {
-                rustflags.arg("-Csplit-debuginfo=unpacked");
+        // FIXME(davidtwco): #[cfg(not(bootstrap))] - #95612 needs to be in the bootstrap compiler
+        // for this conditional to be removed.
+        if !target.contains("windows") || compiler.stage >= 1 {
+            if target.contains("linux") || target.contains("windows") {
+                rustflags.arg("-Zunstable-options");
             }
+            match self.config.rust_split_debuginfo {
+                SplitDebuginfo::Packed => rustflags.arg("-Csplit-debuginfo=packed"),
+                SplitDebuginfo::Unpacked => rustflags.arg("-Csplit-debuginfo=unpacked"),
+                SplitDebuginfo::Off => rustflags.arg("-Csplit-debuginfo=off"),
+            };
         }
 
         if self.config.cmd.bless() {
@@ -1753,7 +1763,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..a212c659b5c2b3a9931ab3b0690299d00388bc6a 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<'_>) {
@@ -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 d7c29f6900a534028c53746ff9c1182f58380ddb..1638d3ed3c2814fe19351268c733e540ea284002 100644 (file)
@@ -41,6 +41,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>,
@@ -130,7 +131,7 @@ pub struct Config {
     pub rust_debuginfo_level_std: u32,
     pub rust_debuginfo_level_tools: u32,
     pub rust_debuginfo_level_tests: u32,
-    pub rust_run_dsymutil: bool,
+    pub rust_split_debuginfo: SplitDebuginfo,
     pub rust_rpath: bool,
     pub rustc_parallel: bool,
     pub rustc_default_linker: Option<String>,
@@ -221,6 +222,46 @@ fn from_str(value: &str) -> Result<Self, Self::Err> {
     }
 }
 
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub enum SplitDebuginfo {
+    Packed,
+    Unpacked,
+    Off,
+}
+
+impl Default for SplitDebuginfo {
+    fn default() -> Self {
+        SplitDebuginfo::Off
+    }
+}
+
+impl std::str::FromStr for SplitDebuginfo {
+    type Err = ();
+
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        match s {
+            "packed" => Ok(SplitDebuginfo::Packed),
+            "unpacked" => Ok(SplitDebuginfo::Unpacked),
+            "off" => Ok(SplitDebuginfo::Off),
+            _ => Err(()),
+        }
+    }
+}
+
+impl SplitDebuginfo {
+    /// Returns the default `-Csplit-debuginfo` value for the current target. See the comment for
+    /// `rust.split-debuginfo` in `config.toml.example`.
+    fn default_for_platform(target: &str) -> Self {
+        if target.contains("apple") {
+            SplitDebuginfo::Unpacked
+        } else if target.contains("windows") {
+            SplitDebuginfo::Packed
+        } else {
+            SplitDebuginfo::Off
+        }
+    }
+}
+
 #[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub struct TargetSelection {
     pub triple: Interned<String>,
@@ -290,6 +331,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>,
@@ -586,6 +628,7 @@ struct Rust {
         debuginfo_level_std: Option<u32> = "debuginfo-level-std",
         debuginfo_level_tools: Option<u32> = "debuginfo-level-tools",
         debuginfo_level_tests: Option<u32> = "debuginfo-level-tests",
+        split_debuginfo: Option<String> = "split-debuginfo",
         run_dsymutil: Option<bool> = "run-dsymutil",
         backtrace: Option<bool> = "backtrace",
         incremental: Option<bool> = "incremental",
@@ -992,7 +1035,12 @@ pub fn parse(args: &[String]) -> Config {
             debuginfo_level_std = rust.debuginfo_level_std;
             debuginfo_level_tools = rust.debuginfo_level_tools;
             debuginfo_level_tests = rust.debuginfo_level_tests;
-            config.rust_run_dsymutil = rust.run_dsymutil.unwrap_or(false);
+            config.rust_split_debuginfo = rust
+                .split_debuginfo
+                .as_deref()
+                .map(SplitDebuginfo::from_str)
+                .map(|v| v.expect("invalid value for rust.split_debuginfo"))
+                .unwrap_or(SplitDebuginfo::default_for_platform(&config.build.triple));
             optimize = rust.optimize;
             ignore_git = rust.ignore_git;
             config.rust_new_symbol_mangling = rust.new_symbol_mangling;
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 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..9c376602d283f35af052c956683ca63e5580a691 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);
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
diff --git a/src/doc/unstable-book/src/compiler-flags/extern-location.md b/src/doc/unstable-book/src/compiler-flags/extern-location.md
deleted file mode 100644 (file)
index 1c80d54..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-# `extern-location`
-
-MCP for this feature: [#303]
-
-[#303]: https://github.com/rust-lang/compiler-team/issues/303
-
-------------------------
-
-The `unused-extern-crates` lint reports when a crate was specified on the rustc
-command-line with `--extern name=path` but no symbols were referenced in it.
-This is useful to know, but it's hard to map that back to a specific place a user
-or tool could fix (ie, to remove the unused dependency).
-
-The `--extern-location` flag allows the build system to associate a location with
-the `--extern` option, which is then emitted as part of the diagnostics. This location
-is abstract and just round-tripped through rustc; the compiler never attempts to
-interpret it in any way.
-
-There are two supported forms of location: a bare string, or a blob of json:
-- `--extern-location foo=raw:Makefile:123` would associate the raw string `Makefile:123`
-- `--extern-location 'bar=json:{"target":"//my_project:library","dep":"//common:serde"}` would
-  associate the json structure with `--extern bar=<path>`, indicating which dependency of
-  which rule introduced the unused extern crate.
-
-This primarily intended to be used with tooling - for example a linter which can automatically
-remove unused dependencies - rather than being directly presented to users.
-
-`raw` locations are presented as part of the normal rendered diagnostics and included in
-the json form. `json` locations are only included in the json form of diagnostics,
-as a `tool_metadata` field. For `raw` locations `tool_metadata` is simply a json string,
-whereas `json` allows the rustc invoker to fully control its form and content.
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 21016afbf5f99369e253d179dede250e40882a7d..a070cef227252b5b3bf25001bba3fc2ebd82f249 100644 (file)
@@ -15,7 +15,7 @@
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, Res};
-use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData};
 use rustc_middle::middle::resolve_lifetime as rl;
 use rustc_middle::ty::fold::TypeFolder;
@@ -1975,7 +1975,7 @@ fn clean_extern_crate(
     // this is the ID of the `extern crate` statement
     let cnum = cx.tcx.extern_mod_stmt_cnum(krate.def_id).unwrap_or(LOCAL_CRATE);
     // this is the ID of the crate itself
-    let crate_def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX };
+    let crate_def_id = cnum.as_def_id();
     let attrs = cx.tcx.hir().attrs(krate.hir_id());
     let ty_vis = cx.tcx.visibility(krate.def_id);
     let please_inline = ty_vis.is_public()
@@ -2094,7 +2094,7 @@ fn clean_use_statement(
     } else {
         if inline_attr.is_none() {
             if let Res::Def(DefKind::Mod, did) = path.res {
-                if !did.is_local() && did.index == CRATE_DEF_INDEX {
+                if !did.is_local() && did.is_crate_root() {
                     // if we're `pub use`ing an extern crate root, don't inline it unless we
                     // were specifically asked for it
                     denied = true;
index 4b473df155f588c925defb7a20d5062ef77d00d4..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;
 
@@ -20,7 +18,7 @@
 use rustc_data_structures::thin_vec::ThinVec;
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, Res};
-use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{BodyId, Mutability};
 use rustc_index::vec::IndexVec;
@@ -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)]
@@ -104,14 +105,6 @@ impl ItemId {
             ItemId::Primitive(_, krate) => krate,
         }
     }
-
-    #[inline]
-    crate fn index(self) -> Option<DefIndex> {
-        match self {
-            ItemId::DefId(id) => Some(id.index),
-            _ => None,
-        }
-    }
 }
 
 impl From<DefId> for ItemId {
@@ -160,7 +153,7 @@ impl ExternalCrate {
 
     #[inline]
     crate fn def_id(&self) -> DefId {
-        DefId { krate: self.crate_num, index: CRATE_DEF_INDEX }
+        self.crate_num.as_def_id()
     }
 
     crate fn src(&self, tcx: TyCtxt<'_>) -> FileName {
@@ -217,7 +210,7 @@ fn to_remote(url: impl ToString) -> ExternalLocation {
 
         // Failing that, see if there's an attribute specifying where to find this
         // external crate
-        let did = DefId { krate: self.crate_num, index: CRATE_DEF_INDEX };
+        let did = self.crate_num.as_def_id();
         tcx.get_attrs(did)
             .lists(sym::doc)
             .filter(|a| a.has_name(sym::html_root_url))
@@ -559,7 +552,7 @@ impl Item {
     }
 
     crate fn is_crate(&self) -> bool {
-        self.is_mod() && self.item_id.as_def_id().map_or(false, |did| did.index == CRATE_DEF_INDEX)
+        self.is_mod() && self.item_id.as_def_id().map_or(false, |did| did.is_crate_root())
     }
     crate fn is_mod(&self) -> bool {
         self.type_() == ItemType::Module
@@ -1036,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`].
@@ -1097,35 +1170,37 @@ impl Attributes {
         attrs: &[ast::Attribute],
         additional_attrs: Option<(&[ast::Attribute], DefId)>,
     ) -> Attributes {
-        let mut doc_strings: Vec<DocFragment> = vec![];
-        let clean_attr = |(attr, parent_module): (&ast::Attribute, Option<DefId>)| {
-            if let Some((value, kind)) = attr.doc_str_and_comment_kind() {
-                trace!("got doc_str={:?}", value);
-                let value = beautify_doc_string(value, kind);
+        // Additional documentation should be shown before the original documentation.
+        let attrs1 = additional_attrs
+            .into_iter()
+            .flat_map(|(attrs, def_id)| attrs.iter().map(move |attr| (attr, Some(def_id))));
+        let attrs2 = attrs.iter().map(|attr| (attr, None));
+        Attributes::from_ast_iter(attrs1.chain(attrs2), false)
+    }
+
+    crate fn from_ast_iter<'a>(
+        attrs: impl Iterator<Item = (&'a ast::Attribute, Option<DefId>)>,
+        doc_only: bool,
+    ) -> Attributes {
+        let mut doc_strings = Vec::new();
+        let mut other_attrs = Vec::new();
+        for (attr, parent_module) in attrs {
+            if let Some((doc_str, comment_kind)) = attr.doc_str_and_comment_kind() {
+                trace!("got doc_str={doc_str:?}");
+                let doc = beautify_doc_string(doc_str, comment_kind);
                 let kind = if attr.is_doc_comment() {
                     DocFragmentKind::SugaredDoc
                 } else {
                     DocFragmentKind::RawDoc
                 };
-
-                let frag =
-                    DocFragment { span: attr.span, doc: value, kind, parent_module, indent: 0 };
-
-                doc_strings.push(frag);
-
-                None
-            } else {
-                Some(attr.clone())
+                let fragment = DocFragment { span: attr.span, doc, kind, parent_module, indent: 0 };
+                doc_strings.push(fragment);
+            } else if !doc_only {
+                other_attrs.push(attr.clone());
             }
-        };
+        }
 
-        // Additional documentation should be shown before the original documentation
-        let other_attrs = additional_attrs
-            .into_iter()
-            .flat_map(|(attrs, id)| attrs.iter().map(move |attr| (attr, Some(id))))
-            .chain(attrs.iter().map(|attr| (attr, None)))
-            .filter_map(clean_attr)
-            .collect();
+        unindent_doc_fragments(&mut doc_strings);
 
         Attributes { doc_strings, other_attrs }
     }
@@ -1146,23 +1221,17 @@ impl Attributes {
     }
 
     /// Return the doc-comments on this item, grouped by the module they came from.
-    ///
     /// The module can be different if this is a re-export with added documentation.
-    crate fn collapsed_doc_value_by_module_level(&self) -> FxHashMap<Option<DefId>, String> {
-        let mut ret = FxHashMap::default();
-        if self.doc_strings.len() == 0 {
-            return ret;
-        }
-        let last_index = self.doc_strings.len() - 1;
-
-        for (i, new_frag) in self.doc_strings.iter().enumerate() {
-            let out = ret.entry(new_frag.parent_module).or_default();
-            add_doc_fragment(out, new_frag);
-            if i == last_index {
-                out.pop();
-            }
+    ///
+    /// The last newline is not trimmed so the produced strings are reusable between
+    /// early and late doc link resolution regardless of their position.
+    crate fn prepare_to_doc_link_resolution(&self) -> FxHashMap<Option<DefId>, String> {
+        let mut res = FxHashMap::default();
+        for fragment in &self.doc_strings {
+            let out_str = res.entry(fragment.parent_module).or_default();
+            add_doc_fragment(out_str, fragment);
         }
-        ret
+        res
     }
 
     /// Finds all `doc` attributes as NameValues and returns their corresponding values, joined
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 b9e20c41b681fbcde73f99685551116dff064070..1db6064551cae362fc30911ba5528b00e052b1c7 100644 (file)
@@ -4,7 +4,7 @@
 use rustc_errors::emitter::{Emitter, EmitterWriter};
 use rustc_errors::json::JsonEmitter;
 use rustc_feature::UnstableFeatures;
-use rustc_hir::def::Res;
+use rustc_hir::def::{Namespace, Res};
 use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId};
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{HirId, Path, TraitCandidate};
 use crate::clean::{self, ItemId, TraitWithExtraInfo};
 use crate::config::{Options as RustdocOptions, OutputFormat, RenderOptions};
 use crate::formats::cache::Cache;
+use crate::passes::collect_intra_doc_links::PreprocessedMarkdownLink;
 use crate::passes::{self, Condition::*};
 
 crate use rustc_session::config::{DebuggingOptions, Input, Options};
 
 crate struct ResolverCaches {
+    crate markdown_links: Option<FxHashMap<String, Vec<PreprocessedMarkdownLink>>>,
+    crate doc_link_resolutions: FxHashMap<(Symbol, Namespace, DefId), Option<Res<NodeId>>>,
     /// Traits in scope for a given module.
     /// See `collect_intra_doc_links::traits_implemented_by` for more details.
     crate traits_in_scope: DefIdMap<Vec<TraitCandidate>>,
index 618268445743acbb10d3959b33aafffbc3d8e832..45ac16e75aa37474e81be14ddbaf9068d06375cf 100644 (file)
@@ -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 06e7c9e763df970e98416569f58448e5aaa60d14..b4d2772b31da2d2ea0c860d398157fa3b777f47a 100644 (file)
@@ -1,7 +1,7 @@
 use std::mem;
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{CrateNum, DefId};
 use rustc_middle::middle::privacy::AccessLevels;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::{sym, Symbol};
@@ -302,7 +302,7 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
                     // A crate has a module at its root, containing all items,
                     // which should not be indexed. The crate-item itself is
                     // inserted later on when serializing the search-index.
-                    if item.item_id.index().map_or(false, |idx| idx != CRATE_DEF_INDEX) {
+                    if item.item_id.as_def_id().map_or(false, |idx| !idx.is_crate_root()) {
                         let desc = item.doc_value().map_or_else(String::new, |x| {
                             short_markdown_summary(x.as_str(), &item.link_names(self.cache))
                         });
index 55b0028180f66fece8164bb2f1c903a36154e7c4..118807a82864faceeac7ad25cc7b28c1b447a052 100644 (file)
@@ -18,7 +18,7 @@
 use rustc_middle::ty;
 use rustc_middle::ty::DefIdTree;
 use rustc_middle::ty::TyCtxt;
-use rustc_span::def_id::CRATE_DEF_INDEX;
+use rustc_span::symbol::kw;
 use rustc_span::{sym, Symbol};
 use rustc_target::spec::abi::Abi;
 
@@ -268,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())
@@ -281,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))
                         }
                     }
                 }
@@ -341,40 +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 {
-                clause.insert_str(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}")
     })
 }
 
@@ -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() {
@@ -1312,7 +1305,7 @@ impl clean::Visibility {
                 //                 visibility, so it shouldn't matter.
                 let parent_module = find_nearest_parent_module(cx.tcx(), item_did.expect_def_id());
 
-                if vis_did.index == CRATE_DEF_INDEX {
+                if vis_did.is_crate_root() {
                     "pub(crate) ".to_owned()
                 } else if parent_module == Some(vis_did) {
                     // `pub(in foo)` where `foo` is the parent module
@@ -1360,7 +1353,7 @@ impl clean::Visibility {
                 //                 visibility, so it shouldn't matter.
                 let parent_module = find_nearest_parent_module(tcx, item_did);
 
-                if vis_did.index == CRATE_DEF_INDEX {
+                if vis_did.is_crate_root() {
                     "pub(crate) ".to_owned()
                 } else if parent_module == Some(vis_did) {
                     // `pub(in foo)` where `foo` is the parent module
index 1ebb41b5933d0b0350165494ce61bbe4198cd7d9..9e76af982985416563472f544b8f21c13c89e443 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;
@@ -1255,7 +1256,7 @@ fn markdown_summary_with_limit(
     pub range: Range<usize>,
 }
 
-crate fn markdown_links(md: &str) -> Vec<MarkdownLink> {
+crate fn markdown_links<R>(md: &str, filter_map: impl Fn(MarkdownLink) -> Option<R>) -> Vec<R> {
     if md.is_empty() {
         return vec![];
     }
@@ -1295,11 +1296,12 @@ fn markdown_summary_with_limit(
 
     let mut push = |link: BrokenLink<'_>| {
         let span = span_for_link(&link.reference, link.span);
-        links.borrow_mut().push(MarkdownLink {
+        filter_map(MarkdownLink {
             kind: LinkType::ShortcutUnknown,
             link: link.reference.to_string(),
             range: span,
-        });
+        })
+        .map(|link| links.borrow_mut().push(link));
         None
     };
     let p = Parser::new_with_broken_link_callback(md, main_body_opts(), Some(&mut push))
@@ -1311,10 +1313,23 @@ fn markdown_summary_with_limit(
     let iter = Footnotes::new(HeadingLinks::new(p, None, &mut ids, HeadingOffset::H1));
 
     for ev in iter {
-        if let Event::Start(Tag::Link(kind, dest, _)) = ev.0 {
+        if let Event::Start(Tag::Link(
+            // `<>` links cannot be intra-doc links so we skip them.
+            kind @ (LinkType::Inline
+            | LinkType::Reference
+            | LinkType::ReferenceUnknown
+            | LinkType::Collapsed
+            | LinkType::CollapsedUnknown
+            | LinkType::Shortcut
+            | LinkType::ShortcutUnknown),
+            dest,
+            _,
+        )) = ev.0
+        {
             debug!("found link: {dest}");
             let span = span_for_link(&dest, ev.1);
-            links.borrow_mut().push(MarkdownLink { kind, link: dest.into_string(), range: span });
+            filter_map(MarkdownLink { kind, link: dest.into_string(), range: span })
+                .map(|link| links.borrow_mut().push(link));
         }
     }
 
@@ -1415,62 +1430,65 @@ 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);
     // 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("search".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 {
@@ -1483,7 +1501,7 @@ pub fn new() -> Self {
             }
         };
 
-        self.map.insert(id.clone(), 1);
+        self.map.insert(id.clone().into(), 1);
         id
     }
 }
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 629f90728d2f61cfaa952de308a3c613079a31af..0fe0fdadbd21050b3c27aa51331e81797a5a74b5 100644 (file)
@@ -8,10 +8,34 @@ function initSearch(searchIndex){}
 
 /**
  * @typedef {{
- *   raw: string,
- *   query: string,
- *   type: string,
- *   id: string,
+ *     name: string,
+ *     fullPath: Array<string>,
+ *     pathWithoutLast: Array<string>,
+ *     pathLast: string,
+ *     generics: Array<QueryElement>,
+ * }}
+ */
+var QueryElement;
+
+/**
+ * @typedef {{
+ *      pos: number,
+ *      totalElems: number,
+ *      typeFilter: (null|string),
+ *      userQuery: string,
+ * }}
+ */
+var ParserState;
+
+/**
+ * @typedef {{
+ *     original: string,
+ *     userQuery: string,
+ *     typeFilter: number,
+ *     elems: Array<QueryElement>,
+ *     args: Array<QueryElement>,
+ *     returned: Array<QueryElement>,
+ *     foundElems: number,
  * }}
  */
 var ParsedQuery;
@@ -30,3 +54,30 @@ var ParsedQuery;
  * }}
  */
 var Row;
+
+/**
+ * @typedef {{
+ *    in_args: Array<Object>,
+ *    returned: Array<Object>,
+ *    others: Array<Object>,
+ *    query: ParsedQuery,
+ * }}
+ */
+var ResultsTable;
+
+/**
+ * @typedef {{
+ *     desc: string,
+ *     displayPath: string,
+ *     fullPath: string,
+ *     href: string,
+ *     id: number,
+ *     lev: number,
+ *     name: string,
+ *     normalizedName: string,
+ *     parent: (Object|undefined),
+ *     path: string,
+ *     ty: number,
+ * }}
+ */
+var Results;
index ab52304491a2bc17841d3515f9227f9c916a57a2..c1d2ec540b0b0bcf14cfcbc5cbe7e4253986ccf7 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 */
 
 (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");
@@ -61,15 +64,6 @@ function printTab(nb) {
     });
 }
 
-function removeEmptyStringsFromArray(x) {
-    for (var i = 0, len = x.length; i < len; ++i) {
-        if (x[i] === "") {
-            x.splice(i, 1);
-            i -= 1;
-        }
-    }
-}
-
 /**
  * A function to compute the Levenshtein distance between two strings
  * Licensed under the Creative Commons Attribution-ShareAlike 3.0 Unported
@@ -77,14 +71,15 @@ function removeEmptyStringsFromArray(x) {
  * 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;
         }
@@ -106,24 +101,24 @@ 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;
+    let searchIndex;
     /**
      *  @type {Array<string>}
      */
-    var searchWords;
-    var currentResults;
-    var ALIASES = {};
-    var params = searchState.getQueryStringParams();
+    let searchWords = [];
+    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
@@ -133,15 +128,451 @@ window.initSearch = function(rawSearchIndex) {
         searchState.input.value = params.search || "";
     }
 
+    function isWhitespace(c) {
+        return " \t\n\r".indexOf(c) !== -1;
+    }
+
+    function isSpecialStartCharacter(c) {
+        return "<\"".indexOf(c) !== -1;
+    }
+
+    function isEndCharacter(c) {
+        return ",>-".indexOf(c) !== -1;
+    }
+
+    function isStopCharacter(c) {
+        return isWhitespace(c) || isEndCharacter(c);
+    }
+
+    function isErrorCharacter(c) {
+        return "()".indexOf(c) !== -1;
+    }
+
+    function itemTypeFromName(typename) {
+        for (let i = 0, len = itemTypes.length; i < len; ++i) {
+            if (itemTypes[i] === typename) {
+                return i;
+            }
+        }
+
+        throw new Error("Unknown type filter `" + typename + "`");
+    }
+
+    /**
+     * If we encounter a `"`, then we try to extract the string from it until we find another `"`.
+     *
+     * This function will throw an error in the following cases:
+     * * There is already another string element.
+     * * We are parsing a generic argument.
+     * * There is more than one element.
+     * * There is no closing `"`.
+     *
+     * @param {ParsedQuery} query
+     * @param {ParserState} parserState
+     * @param {boolean} isInGenerics
+     */
+    function getStringElem(query, parserState, isInGenerics) {
+        if (isInGenerics) {
+            throw new Error("`\"` cannot be used in generics");
+        } else if (query.literalSearch) {
+            throw new Error("Cannot have more than one literal search element");
+        } else if (parserState.totalElems - parserState.genericsElems > 0) {
+            throw new Error("Cannot use literal search when there is more than one element");
+        }
+        parserState.pos += 1;
+        const start = parserState.pos;
+        const end = getIdentEndPosition(parserState);
+        if (parserState.pos >= parserState.length) {
+            throw new Error("Unclosed `\"`");
+        } else if (parserState.userQuery[end] !== "\"") {
+            throw new Error(`Unexpected \`${parserState.userQuery[end]}\` in a string element`);
+        } else if (start === end) {
+            throw new Error("Cannot have empty string element");
+        }
+        // To skip the quote at the end.
+        parserState.pos += 1;
+        query.literalSearch = true;
+    }
+
+    /**
+     * Returns `true` if the current parser position is starting with "::".
+     *
+     * @param {ParserState} parserState
+     *
+     * @return {boolean}
+     */
+    function isPathStart(parserState) {
+        return parserState.userQuery.slice(parserState.pos, parserState.pos + 2) == '::';
+    }
+
+    /**
+     * Returns `true` if the current parser position is starting with "->".
+     *
+     * @param {ParserState} parserState
+     *
+     * @return {boolean}
+     */
+    function isReturnArrow(parserState) {
+        return parserState.userQuery.slice(parserState.pos, parserState.pos + 2) == '->';
+    }
+
+    /**
+     * Returns `true` if the given `c` character is valid for an ident.
+     *
+     * @param {string} c
+     *
+     * @return {boolean}
+     */
+    function isIdentCharacter(c) {
+        return (
+            c === '_' ||
+            (c >= '0' && c <= '9') ||
+            (c >= 'a' && c <= 'z') ||
+            (c >= 'A' && c <= 'Z'));
+    }
+
+    /**
+     * Returns `true` if the given `c` character is a separator.
+     *
+     * @param {string} c
+     *
+     * @return {boolean}
+     */
+    function isSeparatorCharacter(c) {
+        return c === "," || isWhitespaceCharacter(c);
+    }
+
+    /**
+     * Returns `true` if the given `c` character is a whitespace.
+     *
+     * @param {string} c
+     *
+     * @return {boolean}
+     */
+    function isWhitespaceCharacter(c) {
+        return c === " " || c === "\t";
+    }
+
+    /**
+     * @param {ParsedQuery} query
+     * @param {ParserState} parserState
+     * @param {string} name                  - Name of the query element.
+     * @param {Array<QueryElement>} generics - List of generics of this query element.
+     *
+     * @return {QueryElement}                - The newly created `QueryElement`.
+     */
+    function createQueryElement(query, parserState, name, generics, isInGenerics) {
+        if (name === '*' || (name.length === 0 && generics.length === 0)) {
+            return;
+        }
+        if (query.literalSearch && parserState.totalElems - parserState.genericsElems > 0) {
+            throw new Error("You cannot have more than one element if you use quotes");
+        }
+        const pathSegments = name.split("::");
+        if (pathSegments.length > 1) {
+            for (let i = 0, len = pathSegments.length; i < len; ++i) {
+                const pathSegment = pathSegments[i];
+
+                if (pathSegment.length === 0) {
+                    if (i === 0) {
+                        throw new Error("Paths cannot start with `::`");
+                    } else if (i + 1 === len) {
+                        throw new Error("Paths cannot end with `::`");
+                    }
+                    throw new Error("Unexpected `::::`");
+                }
+            }
+        }
+        // In case we only have something like `<p>`, there is no name.
+        if (pathSegments.length === 0 || (pathSegments.length === 1 && pathSegments[0] === "")) {
+            throw new Error("Found generics without a path");
+        }
+        parserState.totalElems += 1;
+        if (isInGenerics) {
+            parserState.genericsElems += 1;
+        }
+        return {
+            name: name,
+            fullPath: pathSegments,
+            pathWithoutLast: pathSegments.slice(0, pathSegments.length - 1),
+            pathLast: pathSegments[pathSegments.length - 1],
+            generics: generics,
+        };
+    }
+
+    /**
+     * This function goes through all characters until it reaches an invalid ident character or the
+     * end of the query. It returns the position of the last character of the ident.
+     *
+     * @param {ParserState} parserState
+     *
+     * @return {integer}
+     */
+    function getIdentEndPosition(parserState) {
+        let end = parserState.pos;
+        let foundExclamation = false;
+        while (parserState.pos < parserState.length) {
+            const c = parserState.userQuery[parserState.pos];
+            if (!isIdentCharacter(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) ||
+                    isSpecialStartCharacter(c) ||
+                    isSeparatorCharacter(c))
+                {
+                    break;
+                }
+                // If we allow paths ("str::string" for example).
+                else if (c === ":") {
+                    if (!isPathStart(parserState)) {
+                        break;
+                    }
+                    // Skip current ":".
+                    parserState.pos += 1;
+                    foundExclamation = false;
+                } else {
+                    throw new Error(`Unexpected \`${c}\``);
+                }
+            }
+            parserState.pos += 1;
+            end = parserState.pos;
+        }
+        return end;
+    }
+
+    /**
+     * @param {ParsedQuery} query
+     * @param {ParserState} parserState
+     * @param {Array<QueryElement>} elems - This is where the new {QueryElement} will be added.
+     * @param {boolean} isInGenerics
+     */
+    function getNextElem(query, parserState, elems, isInGenerics) {
+        const generics = [];
+
+        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;
+            getStringElem(query, parserState, isInGenerics);
+            end = parserState.pos - 1;
+        } else {
+            end = getIdentEndPosition(parserState);
+        }
+        if (parserState.pos < parserState.length &&
+            parserState.userQuery[parserState.pos] === "<")
+        {
+            if (isInGenerics) {
+                throw new Error("Unexpected `<` after `<`");
+            } else if (start >= end) {
+                throw new Error("Found generics without a path");
+            }
+            parserState.pos += 1;
+            getItemsBefore(query, parserState, generics, ">");
+        }
+        if (start >= end && generics.length === 0) {
+            return;
+        }
+        elems.push(
+            createQueryElement(
+                query,
+                parserState,
+                parserState.userQuery.slice(start, end),
+                generics,
+                isInGenerics
+            )
+        );
+    }
+
+    /**
+     * This function parses the next query element until it finds `endChar`, calling `getNextElem`
+     * to collect each element.
+     *
+     * If there is no `endChar`, this function will implicitly stop at the end without raising an
+     * error.
+     *
+     * @param {ParsedQuery} query
+     * @param {ParserState} parserState
+     * @param {Array<QueryElement>} elems - This is where the new {QueryElement} will be added.
+     * @param {string} endChar            - This function will stop when it'll encounter this
+     *                                      character.
+     */
+    function getItemsBefore(query, parserState, elems, endChar) {
+        let foundStopChar = true;
+
+        while (parserState.pos < parserState.length) {
+            const c = parserState.userQuery[parserState.pos];
+            if (c === endChar) {
+                break;
+            } else if (isSeparatorCharacter(c)) {
+                parserState.pos += 1;
+                foundStopChar = true;
+                continue;
+            } else if (c === ":" && isPathStart(parserState)) {
+                throw new Error("Unexpected `::`: paths cannot start with `::`");
+            } else if (c === ":" || isEndCharacter(c)) {
+                let extra = "";
+                if (endChar === ">") {
+                    extra = "`<`";
+                } else if (endChar === "") {
+                    extra = "`->`";
+                }
+                throw new Error("Unexpected `" + c + "` after " + extra);
+            }
+            if (!foundStopChar) {
+                if (endChar !== "") {
+                    throw new Error(`Expected \`,\`, \` \` or \`${endChar}\`, found \`${c}\``);
+                }
+                throw new Error(`Expected \`,\` or \` \`, found \`${c}\``);
+            }
+            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
+            // current position to continue the parsing.
+            if (posBefore === parserState.pos) {
+                parserState.pos += 1;
+            }
+            foundStopChar = false;
+        }
+        // We are either at the end of the string or on the `endChar`` character, let's move forward
+        // in any case.
+        parserState.pos += 1;
+    }
+
+    /**
+     * Checks that the type filter doesn't have unwanted characters like `<>` (which are ignored
+     * if empty).
+     *
+     * @param {ParserState} parserState
+     */
+    function checkExtraTypeFilterCharacters(parserState) {
+        const query = parserState.userQuery;
+
+        for (let pos = 0; pos < parserState.pos; ++pos) {
+            if (!isIdentCharacter(query[pos]) && !isWhitespaceCharacter(query[pos])) {
+                throw new Error(`Unexpected \`${query[pos]}\` in type filter`);
+            }
+        }
+    }
+
+    /**
+     * Parses the provided `query` input to fill `parserState`. If it encounters an error while
+     * parsing `query`, it'll throw an error.
+     *
+     * @param {ParsedQuery} query
+     * @param {ParserState} parserState
+     */
+    function parseInput(query, parserState) {
+        let c, before;
+        let foundStopChar = true;
+
+        while (parserState.pos < parserState.length) {
+            c = parserState.userQuery[parserState.pos];
+            if (isStopCharacter(c)) {
+                foundStopChar = true;
+                if (isSeparatorCharacter(c)) {
+                    parserState.pos += 1;
+                    continue;
+                } else if (c === "-" || c === ">") {
+                    if (isReturnArrow(parserState)) {
+                        break;
+                    }
+                    throw new Error(`Unexpected \`${c}\` (did you mean \`->\`?)`);
+                }
+                throw new Error(`Unexpected \`${c}\``);
+            } else if (c === ":" && !isPathStart(parserState)) {
+                if (parserState.typeFilter !== null) {
+                    throw new Error("Unexpected `:`");
+                }
+                if (query.elems.length === 0) {
+                    throw new Error("Expected type filter before `:`");
+                } else if (query.elems.length !== 1 || parserState.totalElems !== 1) {
+                    throw new Error("Unexpected `:`");
+                } else if (query.literalSearch) {
+                    throw new Error("You cannot use quotes on type filter");
+                }
+                checkExtraTypeFilterCharacters(parserState);
+                // The type filter doesn't count as an element since it's a modifier.
+                parserState.typeFilter = query.elems.pop().name;
+                parserState.pos += 1;
+                parserState.totalElems = 0;
+                query.literalSearch = false;
+                foundStopChar = true;
+                continue;
+            }
+            if (!foundStopChar) {
+                if (parserState.typeFilter !== null) {
+                    throw new Error(`Expected \`,\`, \` \` or \`->\`, found \`${c}\``);
+                }
+                throw new Error(`Expected \`,\`, \` \`, \`:\` or \`->\`, found \`${c}\``);
+            }
+            before = query.elems.length;
+            getNextElem(query, parserState, query.elems, false);
+            if (query.elems.length === before) {
+                // Nothing was added, weird... Let's increase the position to not remain stuck.
+                parserState.pos += 1;
+            }
+            foundStopChar = false;
+        }
+        while (parserState.pos < parserState.length) {
+            c = parserState.userQuery[parserState.pos];
+            if (isReturnArrow(parserState)) {
+                parserState.pos += 2;
+                // Get returned elements.
+                getItemsBefore(query, parserState, query.returned, "");
+                // Nothing can come afterward!
+                if (query.returned.length === 0) {
+                    throw new Error("Expected at least one item after `->`");
+                }
+                break;
+            } else {
+                parserState.pos += 1;
+            }
+        }
+    }
+
+    /**
+     * Takes the user search input and returns an empty `ParsedQuery`.
+     *
+     * @param {string} userQuery
+     *
+     * @return {ParsedQuery}
+     */
+    function newParsedQuery(userQuery) {
+        return {
+            original: userQuery,
+            userQuery: userQuery.toLowerCase(),
+            typeFilter: NO_TYPE_FILTER,
+            elems: [],
+            returned: [],
+            // Total number of "top" elements (does not include generics).
+            foundElems: 0,
+            literalSearch: false,
+            error: null,
+        };
+    }
+
     /**
      * Build an URL with search parameters.
      *
      * @param {string} search            - The current search being performed.
      * @param {string|null} filterCrates - The current filtering crate (if any).
+     *
      * @return {string}
      */
     function buildUrl(search, filterCrates) {
-        var extra = "?search=" + encodeURIComponent(search);
+        let extra = "?search=" + encodeURIComponent(search);
 
         if (filterCrates !== null) {
             extra += "&filter-crate=" + encodeURIComponent(filterCrates);
@@ -155,7 +586,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" &&
@@ -167,45 +598,149 @@ window.initSearch = function(rawSearchIndex) {
     }
 
     /**
-     * Executes the query and returns a list of results for each results tab.
-     * @param  {Object}        query          - The user query
-     * @param  {Array<string>} searchWords    - The list of search words to query against
-     * @param  {string}        [filterCrates] - Crate to search in
-     * @return {{
-     *   in_args: Array<?>,
-     *   returned: Array<?>,
-     *   others: Array<?>
-     * }}
+     * Parses the query.
+     *
+     * The supported syntax by this parser is as follow:
+     *
+     * ident = *(ALPHA / DIGIT / "_") [!]
+     * path = ident *(DOUBLE-COLON ident)
+     * arg = path [generics]
+     * arg-without-generic = path
+     * type-sep = COMMA/WS *(COMMA/WS)
+     * nonempty-arg-list = *(type-sep) arg *(type-sep arg) *(type-sep)
+     * nonempty-arg-list-without-generics = *(type-sep) arg-without-generic
+     *                                      *(type-sep arg-without-generic) *(type-sep)
+     * generics = OPEN-ANGLE-BRACKET [ nonempty-arg-list-without-generics ] *(type-sep)
+     *            CLOSE-ANGLE-BRACKET/EOF
+     * return-args = RETURN-ARROW *(type-sep) nonempty-arg-list
+     *
+     * exact-search = [type-filter *WS COLON] [ RETURN-ARROW ] *WS QUOTE ident QUOTE [ generics ]
+     * type-search = [type-filter *WS COLON] [ nonempty-arg-list ] [ return-args ]
+     *
+     * query = *WS (exact-search / type-search) *WS
+     *
+     * type-filter = (
+     *     "mod" /
+     *     "externcrate" /
+     *     "import" /
+     *     "struct" /
+     *     "enum" /
+     *     "fn" /
+     *     "type" /
+     *     "static" /
+     *     "trait" /
+     *     "impl" /
+     *     "tymethod" /
+     *     "method" /
+     *     "structfield" /
+     *     "variant" /
+     *     "macro" /
+     *     "primitive" /
+     *     "associatedtype" /
+     *     "constant" /
+     *     "associatedconstant" /
+     *     "union" /
+     *     "foreigntype" /
+     *     "keyword" /
+     *     "existential" /
+     *     "attr" /
+     *     "derive" /
+     *     "traitalias")
+     *
+     * OPEN-ANGLE-BRACKET = "<"
+     * CLOSE-ANGLE-BRACKET = ">"
+     * COLON = ":"
+     * DOUBLE-COLON = "::"
+     * QUOTE = %x22
+     * COMMA = ","
+     * RETURN-ARROW = "->"
+     *
+     * ALPHA = %x41-5A / %x61-7A ; A-Z / a-z
+     * DIGIT = %x30-39
+     * WS = %x09 / " "
+     *
+     * @param  {string} val     - The user query
+     *
+     * @return {ParsedQuery}    - The parsed query
      */
-    function execQuery(query, searchWords, filterCrates) {
-        function itemTypeFromName(typename) {
-            for (var i = 0, len = itemTypes.length; i < len; ++i) {
-                if (itemTypes[i] === typename) {
-                    return i;
+    function parseQuery(userQuery) {
+        userQuery = userQuery.trim();
+        const parserState = {
+            length: userQuery.length,
+            pos: 0,
+            // Total number of elements (includes generics).
+            totalElems: 0,
+            genericsElems: 0,
+            typeFilter: null,
+            userQuery: userQuery.toLowerCase(),
+        };
+        let query = newParsedQuery(userQuery);
+
+        try {
+            parseInput(query, parserState);
+            if (parserState.typeFilter !== null) {
+                let typeFilter = parserState.typeFilter;
+                if (typeFilter === "const") {
+                    typeFilter = "constant";
                 }
+                query.typeFilter = itemTypeFromName(typeFilter);
             }
-            return NO_TYPE_FILTER;
+        } catch (err) {
+            query = newParsedQuery(userQuery);
+            query.error = err.message;
+            query.typeFilter = -1;
+            return query;
         }
 
-        var valLower = query.query.toLowerCase(),
-            val = valLower,
-            typeFilter = itemTypeFromName(query.type),
-            results = {}, results_in_args = {}, results_returned = {},
-            split = valLower.split("::");
+        if (!query.literalSearch) {
+            // If there is more than one element in the query, we switch to literalSearch in any
+            // case.
+            query.literalSearch = parserState.totalElems > 1;
+        }
+        query.foundElems = query.elems.length + query.returned.length;
+        return query;
+    }
+
+    /**
+     * Creates the query results.
+     *
+     * @param {Array<Result>} results_in_args
+     * @param {Array<Result>} results_returned
+     * @param {Array<Result>} results_in_args
+     * @param {ParsedQuery} parsedQuery
+     *
+     * @return {ResultsTable}
+     */
+    function createQueryResults(results_in_args, results_returned, results_others, parsedQuery) {
+        return {
+            "in_args": results_in_args,
+            "returned": results_returned,
+            "others": results_others,
+            "query": parsedQuery,
+        };
+    }
 
-        removeEmptyStringsFromArray(split);
+    /**
+     * Executes the parsed query and builds a {ResultsTable}.
+     *
+     * @param  {ParsedQuery} parsedQuery - The parsed user query
+     * @param  {Object} searchWords      - The list of search words to query against
+     * @param  {Object} [filterCrates]   - Crate to search in if defined
+     *
+     * @return {ResultsTable}
+     */
+    function execQuery(parsedQuery, searchWords, filterCrates) {
+        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.
@@ -227,10 +762,11 @@ window.initSearch = function(rawSearchIndex) {
         }
 
         function sortResults(results, isType) {
-            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);
@@ -243,11 +779,11 @@ 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 !== val);
-                b = (bbb.word !== val);
+                a = (aaa.word !== userQuery);
+                b = (bbb.word !== userQuery);
                 if (a !== b) { return a - b; }
 
                 // Sort by non levenshtein results and then levenshtein results by the distance
@@ -309,270 +845,273 @@ window.initSearch = function(rawSearchIndex) {
                 return 0;
             });
 
-            for (var i = 0, len = results.length; i < len; ++i) {
-                result = results[i];
+            let nameSplit = null;
+            if (parsedQuery.elems.length === 1) {
+                const hasPath = typeof parsedQuery.elems[0].path === "undefined";
+                nameSplit = hasPath ? null : parsedQuery.elems[0].path;
+            }
 
+            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;
 
-                if (!isType && !validateResult(name, path, split, parent)) {
+                if (!isType && !validateResult(name, path, nameSplit, parent)) {
                     result.id = -1;
                 }
             }
             return transformResults(results);
         }
 
-        function extractGenerics(val) {
-            val = val.toLowerCase();
-            if (val.indexOf("<") !== -1) {
-                var values = val.substring(val.indexOf("<") + 1, val.lastIndexOf(">"));
-                return {
-                    name: val.substring(0, val.indexOf("<")),
-                    generics: values.split(/\s*,\s*/),
-                };
+        /**
+         * This function checks if the object (`row`) generics match the given type (`elem`)
+         * generics. If there are no generics on `row`, `defaultLev` is returned.
+         *
+         * @param {Row} row            - The object to check.
+         * @param {QueryElement} elem  - The element from the parsed query.
+         * @param {integer} defaultLev - This is the value to return in case there are no generics.
+         *
+         * @return {integer}           - Returns the best match (if any) or `MAX_LEV_DISTANCE + 1`.
+         */
+        function checkGenerics(row, elem, defaultLev) {
+            if (row.length <= GENERICS_DATA || row[GENERICS_DATA].length === 0) {
+                return elem.generics.length === 0 ? defaultLev : MAX_LEV_DISTANCE + 1;
+            } else if (row[GENERICS_DATA].length > 0 && row[GENERICS_DATA][0][NAME] === "") {
+                if (row.length > GENERICS_DATA) {
+                    return checkGenerics(row[GENERICS_DATA][0], elem, defaultLev);
+                }
+                return elem.generics.length === 0 ? defaultLev : MAX_LEV_DISTANCE + 1;
             }
-            return {
-                name: val,
-                generics: [],
-            };
-        }
-
-        function checkGenerics(obj, val) {
             // The names match, but we need to be sure that all generics kinda
             // match as well.
-            var tmp_lev, elem_name;
-            if (val.generics.length > 0) {
-                if (obj.length > GENERICS_DATA &&
-                      obj[GENERICS_DATA].length >= val.generics.length) {
-                    var elems = Object.create(null);
-                    var elength = obj[GENERICS_DATA].length;
-                    for (var x = 0; x < elength; ++x) {
-                        if (!elems[obj[GENERICS_DATA][x][NAME]]) {
-                            elems[obj[GENERICS_DATA][x][NAME]] = 0;
+            let elem_name;
+            if (elem.generics.length > 0 && row[GENERICS_DATA].length >= elem.generics.length) {
+                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(entry, elem, MAX_LEV_DISTANCE + 1) !== 0) {
+                            return MAX_LEV_DISTANCE + 1;
                         }
-                        elems[obj[GENERICS_DATA][x][NAME]] += 1;
+                        continue;
+                    }
+                    if (elems[elem_name] === undefined) {
+                        elems[elem_name] = 0;
                     }
-                    var total = 0;
-                    var done = 0;
-                    // We need to find the type that matches the most to remove it in order
-                    // to move forward.
-                    var vlength = val.generics.length;
-                    for (x = 0; x < vlength; ++x) {
-                        var lev = MAX_LEV_DISTANCE + 1;
-                        var firstGeneric = val.generics[x];
-                        var match = null;
-                        if (elems[firstGeneric]) {
-                            match = firstGeneric;
-                            lev = 0;
-                        } else {
-                            for (elem_name in elems) {
-                                tmp_lev = levenshtein(elem_name, firstGeneric);
-                                if (tmp_lev < lev) {
-                                    lev = tmp_lev;
-                                    match = elem_name;
-                                }
+                    elems[elem_name] += 1;
+                }
+                // We need to find the type that matches the most to remove it in order
+                // to move forward.
+                for (const generic of elem.generics) {
+                    let match = null;
+                    if (elems[generic.name]) {
+                        match = generic.name;
+                    } else {
+                        for (elem_name in elems) {
+                            if (!hasOwnPropertyRustdoc(elems, elem_name)) {
+                                continue;
                             }
-                        }
-                        if (match !== null) {
-                            elems[match] -= 1;
-                            if (elems[match] == 0) {
-                                delete elems[match];
+                            if (elem_name === generic) {
+                                match = elem_name;
+                                break;
                             }
-                            total += lev;
-                            done += 1;
-                        } else {
-                            return MAX_LEV_DISTANCE + 1;
                         }
                     }
-                    return Math.ceil(total / done);
+                    if (match === null) {
+                        return MAX_LEV_DISTANCE + 1;
+                    }
+                    elems[match] -= 1;
+                    if (elems[match] === 0) {
+                        delete elems[match];
+                    }
                 }
+                return 0;
             }
             return MAX_LEV_DISTANCE + 1;
         }
 
         /**
-          * This function checks if the object (`obj`) matches the given type (`val`) and its
+          * This function checks if the object (`row`) matches the given type (`elem`) and its
+          * generics (if any).
+          *
+          * @param {Row} row
+          * @param {QueryElement} elem    - The element from the parsed query.
+          *
+          * @return {integer} - Returns a Levenshtein distance to the best match.
+          */
+        function checkIfInGenerics(row, elem) {
+            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;
+        }
+
+        /**
+          * This function checks if the object (`row`) matches the given type (`elem`) and its
           * generics (if any).
           *
-          * @param {Object} obj
-          * @param {string} val
+          * @param {Row} row
+          * @param {QueryElement} elem      - The element from the parsed query.
           * @param {boolean} literalSearch
           *
           * @return {integer} - Returns a Levenshtein distance to the best match. If there is
           *                     no match, returns `MAX_LEV_DISTANCE + 1`.
           */
-        function checkType(obj, val, literalSearch) {
-            var lev_distance = MAX_LEV_DISTANCE + 1;
-            var tmp_lev = MAX_LEV_DISTANCE + 1;
-            var len, x, firstGeneric;
-            if (obj[NAME] === val.name) {
-                if (literalSearch) {
-                    if (val.generics && val.generics.length !== 0) {
-                        if (obj.length > GENERICS_DATA &&
-                             obj[GENERICS_DATA].length > 0) {
-                            var elems = Object.create(null);
-                            len = obj[GENERICS_DATA].length;
-                            for (x = 0; x < len; ++x) {
-                                if (!elems[obj[GENERICS_DATA][x][NAME]]) {
-                                    elems[obj[GENERICS_DATA][x][NAME]] = 0;
-                                }
-                                elems[obj[GENERICS_DATA][x][NAME]] += 1;
-                            }
+        function checkType(row, elem, literalSearch) {
+            if (row[NAME].length === 0) {
+                // This is a pure "generic" search, no need to run other checks.
+                if (row.length > GENERICS_DATA) {
+                    return checkIfInGenerics(row, elem);
+                }
+                return MAX_LEV_DISTANCE + 1;
+            }
 
-                            len = val.generics.length;
-                            for (x = 0; x < len; ++x) {
-                                firstGeneric = val.generics[x];
-                                if (elems[firstGeneric]) {
-                                    elems[firstGeneric] -= 1;
-                                } else {
-                                    // Something wasn't found and this is a literal search so
-                                    // abort and return a "failing" distance.
-                                    return MAX_LEV_DISTANCE + 1;
-                                }
-                            }
-                            // Everything was found, success!
+            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) {
+                        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;
+                        }) !== -1) {
                             return 0;
                         }
-                        return MAX_LEV_DISTANCE + 1;
                     }
-                    return 0;
-                } else {
-                    // If the type has generics but don't match, then it won't return at this point.
-                    // Otherwise, `checkGenerics` will return 0 and it'll return.
-                    if (obj.length > GENERICS_DATA && obj[GENERICS_DATA].length !== 0) {
-                        tmp_lev = checkGenerics(obj, val);
-                        if (tmp_lev <= MAX_LEV_DISTANCE) {
-                            return tmp_lev;
-                        }
-                    }
-                }
-            } else if (literalSearch) {
-                var found = false;
-                if ((!val.generics || val.generics.length === 0) &&
-                      obj.length > GENERICS_DATA && obj[GENERICS_DATA].length > 0) {
-                    found = obj[GENERICS_DATA].some(
-                        function(gen) {
-                            return gen[NAME] === val.name;
-                        });
+                    return MAX_LEV_DISTANCE + 1;
+                } else if (elem.generics.length > 0) {
+                    return checkGenerics(row, elem, MAX_LEV_DISTANCE + 1);
                 }
-                return found ? 0 : MAX_LEV_DISTANCE + 1;
-            }
-            lev_distance = Math.min(levenshtein(obj[NAME], val.name), lev_distance);
-            if (lev_distance <= MAX_LEV_DISTANCE) {
-                // The generics didn't match but the name kinda did so we give it
-                // a levenshtein distance value that isn't *this* good so it goes
-                // into the search results but not too high.
-                lev_distance = Math.ceil((checkGenerics(obj, val) + lev_distance) / 2);
-            }
-            if (obj.length > GENERICS_DATA && obj[GENERICS_DATA].length > 0) {
-                // We can check if the type we're looking for is inside the generics!
-                var olength = obj[GENERICS_DATA].length;
-                for (x = 0; x < olength; ++x) {
-                    tmp_lev = Math.min(levenshtein(obj[GENERICS_DATA][x][NAME], val.name), tmp_lev);
-                }
-                if (tmp_lev !== 0) {
-                    // If we didn't find a good enough result, we go check inside the generics of
-                    // the generics.
-                    for (x = 0; x < olength && tmp_lev !== 0; ++x) {
-                        tmp_lev = Math.min(
-                            checkType(obj[GENERICS_DATA][x], val, literalSearch),
-                            tmp_lev
-                        );
+                return 0;
+            } else if (row.length > GENERICS_DATA) {
+                if (elem.generics.length === 0) {
+                    if (lev === 0) {
+                        return 0;
                     }
+                    // The name didn't match so we now check if the type we're looking for is inside
+                    // the generics!
+                    lev = checkIfInGenerics(row, elem);
+                    // Now whatever happens, the returned distance is "less good" so we should mark
+                    // it as such, and so we add 0.5 to the distance to make it "less good".
+                    return lev + 0.5;
+                } else if (lev > MAX_LEV_DISTANCE) {
+                    // So our item's name doesn't match at all and has generics.
+                    //
+                    // Maybe it's present in a sub generic? For example "f<A<B<C>>>()", if we're
+                    // looking for "B<C>", we'll need to go down.
+                    return checkIfInGenerics(row, elem);
+                } else {
+                    // At this point, the name kinda match and we have generics to check, so
+                    // let's go!
+                    const tmp_lev = checkGenerics(row, elem, lev);
+                    if (tmp_lev > MAX_LEV_DISTANCE) {
+                        return MAX_LEV_DISTANCE + 1;
+                    }
+                    // We compute the median value of both checks and return it.
+                    return (tmp_lev + lev) / 2;
                 }
+            } else if (elem.generics.length > 0) {
+                // In this case, we were expecting generics but there isn't so we simply reject this
+                // one.
+                return MAX_LEV_DISTANCE + 1;
             }
-            // Now whatever happens, the returned distance is "less good" so we should mark it
-            // as such, and so we add 1 to the distance to make it "less good".
-            return Math.min(lev_distance, tmp_lev) + 1;
+            // No generics on our query or on the target type so we can return without doing
+            // anything else.
+            return lev;
         }
 
         /**
-         * This function checks if the object (`obj`) has an argument with the given type (`val`).
+         * This function checks if the object (`row`) has an argument with the given type (`elem`).
          *
-         * @param {Object} obj
-         * @param {string} val
-         * @param {boolean} literalSearch
+         * @param {Row} row
+         * @param {QueryElement} elem    - The element from the parsed query.
          * @param {integer} typeFilter
          *
          * @return {integer} - Returns a Levenshtein distance to the best match. If there is no
          *                      match, returns `MAX_LEV_DISTANCE + 1`.
          */
-        function findArg(obj, val, literalSearch, typeFilter) {
-            var lev_distance = MAX_LEV_DISTANCE + 1;
-
-            if (obj && obj.type && obj.type[INPUTS_DATA] && obj.type[INPUTS_DATA].length > 0) {
-                var length = obj.type[INPUTS_DATA].length;
-                for (var i = 0; i < length; i++) {
-                    var tmp = obj.type[INPUTS_DATA][i];
-                    if (!typePassesFilter(typeFilter, tmp[1])) {
+        function findArg(row, elem, typeFilter) {
+            let lev = MAX_LEV_DISTANCE + 1;
+
+            if (row && row.type && row.type[INPUTS_DATA] && row.type[INPUTS_DATA].length > 0) {
+                for (const input of row.type[INPUTS_DATA]) {
+                    if (!typePassesFilter(typeFilter, input[1])) {
                         continue;
                     }
-                    tmp = checkType(tmp, val, literalSearch);
-                    if (tmp === 0) {
+                    lev = Math.min(lev, checkType(input, elem, parsedQuery.literalSearch));
+                    if (lev === 0) {
                         return 0;
-                    } else if (literalSearch) {
-                        continue;
                     }
-                    lev_distance = Math.min(tmp, lev_distance);
                 }
             }
-            return literalSearch ? MAX_LEV_DISTANCE + 1 : lev_distance;
+            return parsedQuery.literalSearch ? MAX_LEV_DISTANCE + 1 : lev;
         }
 
-        function checkReturned(obj, val, literalSearch, typeFilter) {
-            var lev_distance = MAX_LEV_DISTANCE + 1;
+        /**
+         * This function checks if the object (`row`) returns the given type (`elem`).
+         *
+         * @param {Row} row
+         * @param {QueryElement} elem   - The element from the parsed query.
+         * @param {integer} typeFilter
+         *
+         * @return {integer} - Returns a Levenshtein distance to the best match. If there is no
+         *                      match, returns `MAX_LEV_DISTANCE + 1`.
+         */
+        function checkReturned(row, elem, typeFilter) {
+            let lev = MAX_LEV_DISTANCE + 1;
 
-            if (obj && obj.type && obj.type.length > OUTPUT_DATA) {
-                var ret = obj.type[OUTPUT_DATA];
+            if (row && row.type && row.type.length > 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;
                     }
-                    tmp = checkType(tmp, val, literalSearch);
-                    if (tmp === 0) {
+                    lev = Math.min(lev, checkType(ret_ty, elem, parsedQuery.literalSearch));
+                    if (lev === 0) {
                         return 0;
-                    } else if (literalSearch) {
-                        continue;
                     }
-                    lev_distance = Math.min(tmp, lev_distance);
                 }
             }
-            return literalSearch ? MAX_LEV_DISTANCE + 1 : lev_distance;
+            return parsedQuery.literalSearch ? MAX_LEV_DISTANCE + 1 : lev;
         }
 
         function checkPath(contains, lastElem, ty) {
             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;
@@ -591,7 +1130,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";
@@ -621,32 +1160,31 @@ window.initSearch = function(rawSearchIndex) {
         }
 
         function handleAliases(ret, query, filterCrates) {
+            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][query.search]) {
-                    var query_aliases = ALIASES[filterCrates][query.search];
-                    var len = query_aliases.length;
-                    for (var i = 0; i < len; ++i) {
-                        aliases.push(createAliasFromItem(searchIndex[query_aliases[i]]));
+                if (ALIASES[filterCrates] && ALIASES[filterCrates][lowerQuery]) {
+                    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][query.search]) {
-                        var pushTo = crate === window.currentCrate ? crateAliases : aliases;
-                        var query_aliases = ALIASES[crate][query.search];
-                        var len = query_aliases.length;
-                        for (var i = 0; i < len; ++i) {
-                            pushTo.push(createAliasFromItem(searchIndex[query_aliases[i]]));
+                    if (ALIASES[crate][lowerQuery]) {
+                        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) {
@@ -657,9 +1195,9 @@ window.initSearch = function(rawSearchIndex) {
             crateAliases.sort(sortFunc);
             aliases.sort(sortFunc);
 
-            var pushFunc = function(alias) {
-                alias.alias = query.raw;
-                var res = buildHrefAndPath(alias);
+            const pushFunc = function(alias) {
+                alias.alias = query;
+                const res = buildHrefAndPath(alias);
                 alias.displayPath = pathSplitter(res[0]);
                 alias.fullPath = alias.displayPath + alias.name;
                 alias.href = res[1];
@@ -674,208 +1212,235 @@ window.initSearch = function(rawSearchIndex) {
         }
 
         /**
-         * This function adds the given result into the provided `res` map if it matches the
+         * This function adds the given result into the provided `results` map if it matches the
          * following condition:
          *
-         * * If it is a "literal search" (`isExact`), then `lev` must be 0.
+         * * If it is a "literal search" (`parsedQuery.literalSearch`), then `lev` must be 0.
          * * If it is not a "literal search", `lev` must be <= `MAX_LEV_DISTANCE`.
          *
-         * The `res` map contains information which will be used to sort the search results:
+         * The `results` map contains information which will be used to sort the search results:
          *
-         * * `fullId` is a `string`` used as the key of the object we use for the `res` map.
+         * * `fullId` is a `string`` used as the key of the object we use for the `results` map.
          * * `id` is the index in both `searchWords` and `searchIndex` arrays for this element.
          * * `index` is an `integer`` used to sort by the position of the word in the item's name.
          * * `lev` is the main metric used to sort the search results.
          *
-         * @param {boolean} isExact
-         * @param {Object} res
+         * @param {Results} results
          * @param {string} fullId
          * @param {integer} id
          * @param {integer} index
          * @param {integer} lev
          */
-        function addIntoResults(isExact, res, fullId, id, index, lev) {
-            if (lev === 0 || (!isExact && lev <= MAX_LEV_DISTANCE)) {
-                if (res[fullId] !== undefined) {
-                    var result = res[fullId];
+        function addIntoResults(results, fullId, id, index, lev) {
+            if (lev === 0 || (!parsedQuery.literalSearch && lev <= MAX_LEV_DISTANCE)) {
+                if (results[fullId] !== undefined) {
+                    const result = results[fullId];
                     if (result.dontValidate || result.lev <= lev) {
                         return;
                     }
                 }
-                res[fullId] = {
+                results[fullId] = {
                     id: id,
                     index: index,
-                    dontValidate: isExact,
+                    dontValidate: parsedQuery.literalSearch,
                     lev: lev,
                 };
             }
         }
 
-        // quoted values mean literal search
-        var nSearchWords = searchWords.length;
-        var i, it;
-        var ty;
-        var fullId;
-        var returned;
-        var in_args;
-        var len;
-        if ((val.charAt(0) === "\"" || val.charAt(0) === "'") &&
-            val.charAt(val.length - 1) === val.charAt(0))
-        {
-            val = extractGenerics(val.substr(1, val.length - 2));
-            for (i = 0; i < nSearchWords; ++i) {
-                if (filterCrates !== null && searchIndex[i].crate !== filterCrates) {
-                    continue;
+        /**
+         * This function is called in case the query is only one element (with or without generics).
+         * This element will be compared to arguments' and returned values' items and also to items.
+         *
+         * Other important thing to note: since there is only one element, we use levenshtein
+         * distance for name comparisons.
+         *
+         * @param {Row} row
+         * @param {integer} pos              - Position in the `searchIndex`.
+         * @param {QueryElement} elem        - The element from the parsed query.
+         * @param {Results} results_others   - Unqualified results (not in arguments nor in
+         *                                     returned values).
+         * @param {Results} results_in_args  - Matching arguments results.
+         * @param {Results} results_returned - Matching returned arguments results.
+         */
+        function handleSingleArg(
+            row,
+            pos,
+            elem,
+            results_others,
+            results_in_args,
+            results_returned
+        ) {
+            if (!row || (filterCrates !== null && row.crate !== filterCrates)) {
+                return;
+            }
+            let lev, lev_add = 0, index = -1;
+            const fullId = row.id;
+
+            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);
+
+            if (!typePassesFilter(parsedQuery.typeFilter, row.ty)) {
+                return;
+            }
+            const searchWord = searchWords[pos];
+
+            if (parsedQuery.literalSearch) {
+                if (searchWord === elem.name) {
+                    addIntoResults(results_others, fullId, pos, -1, 0);
                 }
-                in_args = findArg(searchIndex[i], val, true, typeFilter);
-                returned = checkReturned(searchIndex[i], val, true, typeFilter);
-                ty = searchIndex[i];
-                fullId = ty.id;
-
-                if (searchWords[i] === val.name
-                    && typePassesFilter(typeFilter, searchIndex[i].ty)) {
-                    addIntoResults(true, results, fullId, i, -1, 0);
+                return;
+            }
+
+            // No need to check anything else if it's a "pure" generics search.
+            if (elem.name.length === 0) {
+                if (row.type !== null) {
+                    lev = checkGenerics(row.type, elem, MAX_LEV_DISTANCE + 1);
+                    addIntoResults(results_others, fullId, pos, index, lev);
                 }
-                addIntoResults(true, results_in_args, fullId, i, -1, in_args);
-                addIntoResults(true, results_returned, fullId, i, -1, returned);
-            }
-            query.inputs = [val];
-            query.output = val;
-            query.search = val;
-        // searching by type
-        } else if (val.search("->") > -1) {
-            var trimmer = function(s) { return s.trim(); };
-            var parts = val.split("->").map(trimmer);
-            var input = parts[0];
-            // sort inputs so that order does not matter
-            var inputs = input.split(",").map(trimmer).sort();
-            for (i = 0, len = inputs.length; i < len; ++i) {
-                inputs[i] = extractGenerics(inputs[i]);
-            }
-            var output = extractGenerics(parts[1]);
-
-            for (i = 0; i < nSearchWords; ++i) {
-                if (filterCrates !== null && searchIndex[i].crate !== filterCrates) {
-                    continue;
+                return;
+            }
+
+            if (elem.fullPath.length > 1) {
+                lev = checkPath(elem.pathWithoutLast, elem.pathLast, row);
+                if (lev > MAX_LEV_DISTANCE || (parsedQuery.literalSearch && lev !== 0)) {
+                    return;
+                } else if (lev > 0) {
+                    lev_add = lev / 10;
                 }
-                var type = searchIndex[i].type;
-                ty = searchIndex[i];
-                if (!type) {
-                    continue;
+            }
+
+            if (searchWord.indexOf(elem.pathLast) > -1 ||
+                row.normalizedName.indexOf(elem.pathLast) > -1)
+            {
+                // filter type: ... queries
+                if (!results_others[fullId] !== undefined) {
+                    index = row.normalizedName.indexOf(elem.pathLast);
+                }
+            }
+            lev = levenshtein(searchWord, elem.pathLast);
+            lev += lev_add;
+            if (lev > 0 && elem.pathLast.length > 2 && searchWord.indexOf(elem.pathLast) > -1)
+            {
+                if (elem.pathLast.length < 6) {
+                    lev = 1;
+                } else {
+                    lev = 0;
                 }
-                fullId = ty.id;
+            }
+            if (lev > MAX_LEV_DISTANCE) {
+                return;
+            } else if (index !== -1 && elem.fullPath.length < 2) {
+                lev -= 1;
+            }
+            if (lev < 0) {
+                lev = 0;
+            }
+            addIntoResults(results_others, fullId, pos, index, lev);
+        }
 
-                returned = checkReturned(ty, output, true, NO_TYPE_FILTER);
-                if (output.name === "*" || returned === 0) {
-                    in_args = false;
-                    var is_module = false;
+        /**
+         * This function is called in case the query has more than one element. In this case, it'll
+         * try to match the items which validates all the elements. For `aa -> bb` will look for
+         * functions which have a parameter `aa` and has `bb` in its returned values.
+         *
+         * @param {Row} row
+         * @param {integer} pos      - Position in the `searchIndex`.
+         * @param {Object} results
+         */
+        function handleArgs(row, pos, results) {
+            if (!row || (filterCrates !== null && row.crate !== filterCrates)) {
+                return;
+            }
 
-                    if (input === "*") {
-                        is_module = true;
+            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 (const elem of elems) {
+                    // There is more than one parameter to the query so all checks should be "exact"
+                    const lev = callback(row, elem, NO_TYPE_FILTER);
+                    if (lev <= 1) {
+                        nbLev += 1;
+                        totalLev += lev;
                     } else {
-                        var firstNonZeroDistance = 0;
-                        for (it = 0, len = inputs.length; it < len; it++) {
-                            var distance = checkType(type, inputs[it], true);
-                            if (distance > 0) {
-                                firstNonZeroDistance = distance;
-                                break;
-                            }
-                        }
-                        in_args = firstNonZeroDistance;
-                    }
-                    addIntoResults(true, results_in_args, fullId, i, -1, in_args);
-                    addIntoResults(true, results_returned, fullId, i, -1, returned);
-                    if (is_module) {
-                        addIntoResults(true, results, fullId, i, -1, 0);
+                        return false;
                     }
                 }
+                return true;
+            }
+            if (!checkArgs(parsedQuery.elems, findArg)) {
+                return;
+            }
+            if (!checkArgs(parsedQuery.returned, checkReturned)) {
+                return;
             }
-            query.inputs = inputs.map(function(input) {
-                return input.name;
-            });
-            query.output = output.name;
-        } else {
-            query.inputs = [val];
-            query.output = val;
-            query.search = val;
-            // gather matching search results up to a certain maximum
-            val = val.replace(/_/g, "");
-
-            var valGenerics = extractGenerics(val);
-
-            var paths = valLower.split("::");
-            removeEmptyStringsFromArray(paths);
-            val = paths[paths.length - 1];
-            var contains = paths.slice(0, paths.length > 1 ? paths.length - 1 : 1);
-
-            var lev, j;
-            for (j = 0; j < nSearchWords; ++j) {
-                ty = searchIndex[j];
-                if (!ty || (filterCrates !== null && ty.crate !== filterCrates)) {
-                    continue;
-                }
-                var lev_add = 0;
-                if (paths.length > 1) {
-                    lev = checkPath(contains, paths[paths.length - 1], ty);
-                    if (lev > MAX_LEV_DISTANCE) {
-                        continue;
-                    } else if (lev > 0) {
-                        lev_add = lev / 10;
-                    }
-                }
 
-                returned = MAX_LEV_DISTANCE + 1;
-                in_args = MAX_LEV_DISTANCE + 1;
-                var index = -1;
-                // we want lev results to go lower than others
-                lev = MAX_LEV_DISTANCE + 1;
-                fullId = ty.id;
+            if (nbLev === 0) {
+                return;
+            }
+            const lev = Math.round(totalLev / nbLev);
+            addIntoResults(results, row.id, pos, 0, lev);
+        }
 
-                if (searchWords[j].indexOf(split[i]) > -1 ||
-                    searchWords[j].indexOf(val) > -1 ||
-                    ty.normalizedName.indexOf(val) > -1)
-                {
-                    // filter type: ... queries
-                    if (typePassesFilter(typeFilter, ty.ty) && results[fullId] === undefined) {
-                        index = ty.normalizedName.indexOf(val);
+        function innerRunQuery() {
+            let elem, i, nSearchWords, in_returned, row;
+
+            if (parsedQuery.foundElems === 1) {
+                if (parsedQuery.elems.length === 1) {
+                    elem = parsedQuery.elems[0];
+                    for (i = 0, nSearchWords = searchWords.length; i < nSearchWords; ++i) {
+                        // It means we want to check for this element everywhere (in names, args and
+                        // returned).
+                        handleSingleArg(
+                            searchIndex[i],
+                            i,
+                            elem,
+                            results_others,
+                            results_in_args,
+                            results_returned
+                        );
                     }
-                }
-                if ((lev = levenshtein(searchWords[j], val)) <= MAX_LEV_DISTANCE) {
-                    if (typePassesFilter(typeFilter, ty.ty)) {
-                        lev += 1;
-                    } else {
-                        lev = MAX_LEV_DISTANCE + 1;
+                } else if (parsedQuery.returned.length === 1) {
+                    // We received one returned argument to check, so looking into returned values.
+                    elem = parsedQuery.returned[0];
+                    for (i = 0, nSearchWords = searchWords.length; i < nSearchWords; ++i) {
+                        row = searchIndex[i];
+                        in_returned = checkReturned(row, elem, parsedQuery.typeFilter);
+                        addIntoResults(results_returned, row.id, i, -1, in_returned);
                     }
                 }
-                in_args = findArg(ty, valGenerics, false, typeFilter);
-                returned = checkReturned(ty, valGenerics, false, typeFilter);
-
-                lev += lev_add;
-                if (lev > 0 && val.length > 3 && searchWords[j].indexOf(val) > -1) {
-                    if (val.length < 6) {
-                        lev -= 1;
-                    } else {
-                        lev = 0;
-                    }
+            } else if (parsedQuery.foundElems > 0) {
+                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) {
+                    container = results_returned;
                 }
-                addIntoResults(false, results_in_args, fullId, j, index, in_args);
-                addIntoResults(false, results_returned, fullId, j, index, returned);
-                if (typePassesFilter(typeFilter, ty.ty) &&
-                        (index !== -1 || lev <= MAX_LEV_DISTANCE)) {
-                    if (index !== -1 && paths.length < 2) {
-                        lev = 0;
-                    }
-                    addIntoResults(false, results, fullId, j, index, lev);
+                for (i = 0, nSearchWords = searchWords.length; i < nSearchWords; ++i) {
+                    handleArgs(searchIndex[i], i, container);
                 }
             }
         }
 
-        var ret = {
-            "in_args": sortResults(results_in_args, true),
-            "returned": sortResults(results_returned, true),
-            "others": sortResults(results, false),
-        };
-        handleAliases(ret, query, filterCrates);
+        if (parsedQuery.error === null) {
+            innerRunQuery();
+        }
+
+        const ret = createQueryResults(
+            sortResults(results_in_args, true),
+            sortResults(results_returned, true),
+            sortResults(results_others, false),
+            parsedQuery);
+        handleAliases(ret, parsedQuery.original.replace(/"/g, ""), filterCrates);
+        if (parsedQuery.error !== null && ret.others.length !== 0) {
+            // It means some doc aliases were found so let's "remove" the error!
+            ret.query.error = null;
+        }
         return ret;
     }
 
@@ -892,53 +1457,33 @@ window.initSearch = function(rawSearchIndex) {
      * @param  {string} path   - The path of the result
      * @param  {string} keys   - The keys to be used (["file", "open"])
      * @param  {Object} parent - The parent of the result
+     *
      * @return {boolean}       - Whether the result is valid or not
      */
     function validateResult(name, path, keys, parent) {
-        for (var i = 0, len = keys.length; i < len; ++i) {
+        if (!keys || !keys.length) {
+            return true;
+        }
+        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;
             }
         }
         return true;
     }
 
-    /**
-     * Parse a string into a query object.
-     *
-     * @param {string} raw - The text that the user typed.
-     * @returns {ParsedQuery}
-     */
-    function getQuery(raw) {
-        var matches, type = "", query;
-        query = raw;
-
-        matches = query.match(/^(fn|mod|struct|enum|trait|type|const|macro)\s*:\s*/i);
-        if (matches) {
-            type = matches[1].replace(/^const$/, "constant");
-            query = query.substring(matches[0].length);
-        }
-
-        return {
-            raw: raw,
-            query: query,
-            type: type,
-            id: query + type
-        };
-    }
-
     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();
@@ -947,7 +1492,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) {
@@ -956,11 +1501,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 + "::";
@@ -974,19 +1519,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;
@@ -1008,13 +1553,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);
         }
@@ -1028,42 +1573,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);
 
@@ -1078,9 +1623,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);
@@ -1088,11 +1633,11 @@ window.initSearch = function(rawSearchIndex) {
                 link.appendChild(wrapper);
                 output.appendChild(link);
             });
-        } else {
+        } else if (query.error === null) {
             output.className = "search-failed" + extraClass;
             output.innerHTML = "No results :(<br/>" +
                 "Try on <a href=\"https://duckduckgo.com/?q=" +
-                encodeURIComponent("rust " + query.query) +
+                encodeURIComponent("rust " + query.userQuery) +
                 "\">DuckDuckGo</a>?<br/><br/>" +
                 "Or try looking in one of these:<ul><li>The <a " +
                 "href=\"https://doc.rust-lang.org/reference/index.html\">Rust Reference</a> " +
@@ -1115,8 +1660,13 @@ window.initSearch = function(rawSearchIndex) {
         return "<button>" + text + " <div class=\"count\">(" + nbElems + ")</div></button>";
     }
 
+    /**
+     * @param {ResultsTable} results
+     * @param {boolean} go_to_first
+     * @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
@@ -1124,7 +1674,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.
@@ -1132,18 +1682,20 @@ window.initSearch = function(rawSearchIndex) {
             elem.click();
             return;
         }
-        var query = getQuery(searchState.input.value);
+        if (results.query === undefined) {
+            results.query = parseQuery(searchState.input.value);
+        }
 
-        currentResults = query.id;
+        currentResults = results.query.userQuery;
 
-        var ret_others = addTab(results.others, query, true);
-        var ret_in_args = addTab(results.in_args, query, false);
-        var ret_returned = addTab(results.returned, 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)) {
@@ -1159,29 +1711,37 @@ 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 output = `<div id="search-settings">
-            <h1 class="search-results-title">Results for ${escape(query.query)} ` +
-            (query.type ? " (type: " + escape(query.type) + ")" : "") + "</h1>" +
-            crates +
-            `</div><div id="titles">` +
+
+        let typeFilter = "";
+        if (results.query.typeFilter !== NO_TYPE_FILTER) {
+            typeFilter = " (type: " + escape(itemTypes[results.query.typeFilter]) + ")";
+        }
+
+        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) {
+            output += `<h3>Query parser error: "${results.query.error}".</h3>`;
+        }
+        output += `<div id="titles">` +
             makeTabHeader(0, "In Names", ret_others[1]) +
             makeTabHeader(1, "In Parameters", ret_in_args[1]) +
             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);
         }
@@ -1189,35 +1749,13 @@ 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); };
         printTab(currentTab);
     }
 
-    function execSearch(query, searchWords, filterCrates) {
-        query = query.raw.trim();
-        var results = {
-            "in_args": [],
-            "returned": [],
-            "others": [],
-        };
-
-        if (query.length !== 0) {
-            var tmp = execQuery(getQuery(query), searchWords, filterCrates);
-
-            results.in_args.push(tmp.in_args);
-            results.returned.push(tmp.returned);
-            results.others.push(tmp.others);
-        }
-        return {
-            "in_args": results.in_args[0],
-            "returned": results.returned[0],
-            "others": results.others[0],
-        };
-    }
-
     /**
      * Perform a search based on the current state of the search input element
      * and display the results.
@@ -1225,24 +1763,21 @@ window.initSearch = function(rawSearchIndex) {
      * @param {boolean} [forced]
      */
     function search(e, forced) {
-        var params = searchState.getQueryStringParams();
-        var query = getQuery(searchState.input.value.trim());
+        const params = searchState.getQueryStringParams();
+        const query = parseQuery(searchState.input.value.trim());
 
         if (e) {
             e.preventDefault();
         }
 
-        if (query.query.length === 0) {
-            return;
-        }
-        if (!forced && query.id === currentResults) {
-            if (query.query.length > 0) {
+        if (!forced && query.userQuery === currentResults) {
+            if (query.userQuery.length > 0) {
                 putBackSearch();
             }
             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.
@@ -1251,13 +1786,12 @@ window.initSearch = function(rawSearchIndex) {
         }
 
         // Update document title to maintain a meaningful browser history
-        searchState.title = "Results for " + query.query + " - Rust";
+        searchState.title = "Results for " + query.original + " - Rust";
 
         // 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.raw, filterCrates);
-
+            const newURL = buildUrl(query.original, filterCrates);
             if (!history.state && !params.search) {
                 history.pushState(null, "", newURL);
             } else {
@@ -1265,8 +1799,10 @@ window.initSearch = function(rawSearchIndex) {
             }
         }
 
-        showResults(execSearch(query, searchWords, filterCrates),
-            params["go_to_first"], filterCrates);
+        showResults(
+            execQuery(query, searchWords, filterCrates),
+            params.go_to_first,
+            filterCrates);
     }
 
     function buildIndex(rawSearchIndex) {
@@ -1274,17 +1810,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`
@@ -1316,13 +1852,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,
@@ -1338,26 +1874,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]};
             }
@@ -1370,7 +1906,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.
@@ -1381,7 +1917,7 @@ window.initSearch = function(rawSearchIndex) {
                     word = "";
                     searchWords.push("");
                 }
-                var row = {
+                const row = {
                     crate: crate,
                     ty: itemTypes[i],
                     name: itemNames[i],
@@ -1400,8 +1936,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;
                     }
@@ -1409,9 +1944,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);
                     }
                 }
             }
@@ -1431,11 +1965,11 @@ window.initSearch = function(rawSearchIndex) {
     }
 
     function putBackSearch() {
-        var search_input = searchState.input;
+        const search_input = searchState.input;
         if (!searchState.input) {
             return;
         }
-        var search = searchState.outputElement();
+        const search = searchState.outputElement();
         if (search_input.value !== "" && hasClass(search, "hidden")) {
             searchState.showResults(search);
             if (searchState.browserSupportsHistoryApi()) {
@@ -1447,7 +1981,7 @@ window.initSearch = function(rawSearchIndex) {
     }
 
     function registerSearchEvents() {
-        var searchAfter500ms = function() {
+        const searchAfter500ms = function() {
             searchState.clearInputTimeout();
             if (searchState.input.value.length === 0) {
                 if (searchState.browserSupportsHistoryApi()) {
@@ -1485,7 +2019,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 {
@@ -1493,11 +2027,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);
                 }
@@ -1530,10 +2064,10 @@ window.initSearch = function(rawSearchIndex) {
         // history.
         if (searchState.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;
@@ -1569,7 +2103,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;
             }
@@ -1580,8 +2114,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 {
index 139fa5c9a11a62e4db3586a604a1dd849c7a729c..549d56450d8032698a50b582bc0373c3047494c0 100644 (file)
@@ -1,4 +1,7 @@
 // Local js definitions:
+/* eslint-env es6 */
+/* eslint no-var: "error" */
+/* eslint prefer-const: "error" */
 /* global getSettingValue, getVirtualKey, onEachLazy, updateLocalStorage, updateSystemTheme */
 /* global addClass, removeClass */
 
@@ -55,9 +58,9 @@
     function setEvents() {
         updateLightAndDark();
         onEachLazy(document.getElementsByClassName("slider"), function(elem) {
-            var toggle = elem.previousElementSibling;
-            var settingId = toggle.id;
-            var settingValue = getSettingValue(settingId);
+            const toggle = elem.previousElementSibling;
+            const settingId = toggle.id;
+            const settingValue = getSettingValue(settingId);
             if (settingValue !== null) {
                 toggle.checked = settingValue === "true";
             }
@@ -68,9 +71,9 @@
             toggle.onkeyrelease = handleKey;
         });
         onEachLazy(document.getElementsByClassName("select-wrapper"), function(elem) {
-            var select = elem.getElementsByTagName("select")[0];
-            var settingId = select.id;
-            var settingValue = getSettingValue(settingId);
+            const select = elem.getElementsByTagName("select")[0];
+            const settingId = select.id;
+            const settingValue = getSettingValue(settingId);
             if (settingValue !== null) {
                 select.value = settingValue;
             }
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 0b5fb480595797a3fbc96264fd079961371e0f45..56b02cd848041236e30fab13cfc70fa0de4f62ff 100644 (file)
@@ -10,7 +10,6 @@
 use rustc_ast::ast;
 use rustc_hir::{def::CtorKind, def_id::DefId};
 use rustc_middle::ty::{self, TyCtxt};
-use rustc_span::def_id::CRATE_DEF_INDEX;
 use rustc_span::Pos;
 use rustc_target::spec::abi::Abi as RustcAbi;
 
@@ -83,7 +82,7 @@ fn convert_visibility(&self, v: clean::Visibility) -> Visibility {
         match v {
             Public => Visibility::Public,
             Inherited => Visibility::Default,
-            Restricted(did) if did.index == CRATE_DEF_INDEX => Visibility::Crate,
+            Restricted(did) if did.is_crate_root() => Visibility::Crate,
             Restricted(did) => Visibility::Restricted {
                 parent: from_item_id(did.into()),
                 path: self.tcx.def_path(did).to_string_no_crate_verbose(),
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 c48f8bd0c7cc5a0cced4aa8341630a5157369718..42e87f3f9610b1b54cb855fce0679998e7cce810 100644 (file)
@@ -3,6 +3,7 @@
 //! [RFC 1946]: https://github.com/rust-lang/rfcs/blob/master/text/1946-intra-rustdoc-links.md
 
 use pulldown_cmark::LinkType;
+use rustc_ast::util::comments::may_have_doc_links;
 use rustc_data_structures::{fx::FxHashMap, intern::Interned, stable_set::FxHashSet};
 use rustc_errors::{Applicability, Diagnostic};
 use rustc_hir::def::Namespace::*;
@@ -159,7 +160,7 @@ fn try_from(res: ResolveRes) -> Result<Self, ()> {
 }
 
 /// A link failed to resolve.
-#[derive(Debug)]
+#[derive(Clone, Debug)]
 enum ResolutionFailure<'a> {
     /// This resolved, but with the wrong namespace.
     WrongNamespace {
@@ -199,7 +200,7 @@ enum ResolutionFailure<'a> {
     Dummy,
 }
 
-#[derive(Debug)]
+#[derive(Clone, Debug)]
 enum MalformedGenerics {
     /// This link has unbalanced angle brackets.
     ///
@@ -252,6 +253,7 @@ fn full_res(&self) -> Option<Res> {
     }
 }
 
+#[derive(Clone, Copy)]
 enum AnchorFailure {
     /// User error: `[std#x#y]` is not valid
     MultipleAnchors,
@@ -556,7 +558,15 @@ fn resolve_path(
         // Resolver doesn't know about true, false, and types that aren't paths (e.g. `()`).
         let result = self
             .cx
-            .enter_resolver(|resolver| resolver.resolve_rustdoc_path(path_str, ns, module_id))
+            .resolver_caches
+            .doc_link_resolutions
+            .get(&(Symbol::intern(path_str), ns, module_id))
+            .copied()
+            .unwrap_or_else(|| {
+                self.cx.enter_resolver(|resolver| {
+                    resolver.resolve_rustdoc_path(path_str, ns, module_id)
+                })
+            })
             .and_then(|res| res.try_into().ok())
             .or_else(|| resolve_primitive(path_str, ns))
             .or_else(|| self.resolve_macro_rules(path_str, ns));
@@ -1040,17 +1050,30 @@ fn visit_item(&mut self, item: &Item) {
         // In the presence of re-exports, this is not the same as the module of the item.
         // Rather than merging all documentation into one, resolve it one attribute at a time
         // so we know which module it came from.
-        for (parent_module, doc) in item.attrs.collapsed_doc_value_by_module_level() {
+        for (parent_module, doc) in item.attrs.prepare_to_doc_link_resolution() {
+            if !may_have_doc_links(&doc) {
+                continue;
+            }
             debug!("combined_docs={}", doc);
             // NOTE: if there are links that start in one crate and end in another, this will not resolve them.
             // This is a degenerate case and it's not supported by rustdoc.
             let parent_node = parent_module.or(parent_node);
-            for md_link in markdown_links(&doc) {
+            let mut tmp_links = self
+                .cx
+                .resolver_caches
+                .markdown_links
+                .take()
+                .expect("`markdown_links` are already borrowed");
+            if !tmp_links.contains_key(&doc) {
+                tmp_links.insert(doc.clone(), preprocessed_markdown_links(&doc));
+            }
+            for md_link in &tmp_links[&doc] {
                 let link = self.resolve_link(&item, &doc, parent_node, md_link);
                 if let Some(link) = link {
                     self.cx.cache.intra_doc_links.entry(item.item_id).or_default().push(link);
                 }
             }
+            self.cx.resolver_caches.markdown_links = Some(tmp_links);
         }
 
         if item.is_mod() {
@@ -1066,18 +1089,19 @@ fn visit_item(&mut self, item: &Item) {
     }
 }
 
-enum PreprocessingError<'a> {
+enum PreprocessingError {
     Anchor(AnchorFailure),
     Disambiguator(Range<usize>, String),
-    Resolution(ResolutionFailure<'a>, String, Option<Disambiguator>),
+    Resolution(ResolutionFailure<'static>, String, Option<Disambiguator>),
 }
 
-impl From<AnchorFailure> for PreprocessingError<'_> {
+impl From<AnchorFailure> for PreprocessingError {
     fn from(err: AnchorFailure) -> Self {
         Self::Anchor(err)
     }
 }
 
+#[derive(Clone)]
 struct PreprocessingInfo {
     path_str: String,
     disambiguator: Option<Disambiguator>,
@@ -1085,15 +1109,18 @@ struct PreprocessingInfo {
     link_text: String,
 }
 
+// Not a typedef to avoid leaking several private structures from this module.
+crate struct PreprocessedMarkdownLink(Result<PreprocessingInfo, PreprocessingError>, MarkdownLink);
+
 /// Returns:
 /// - `None` if the link should be ignored.
 /// - `Some(Err)` if the link should emit an error
 /// - `Some(Ok)` if the link is valid
 ///
 /// `link_buffer` is needed for lifetime reasons; it will always be overwritten and the contents ignored.
-fn preprocess_link<'a>(
-    ori_link: &'a MarkdownLink,
-) -> Option<Result<PreprocessingInfo, PreprocessingError<'a>>> {
+fn preprocess_link(
+    ori_link: &MarkdownLink,
+) -> Option<Result<PreprocessingInfo, PreprocessingError>> {
     // [] is mostly likely not supposed to be a link
     if ori_link.link.is_empty() {
         return None;
@@ -1172,6 +1199,12 @@ fn preprocess_link<'a>(
     }))
 }
 
+fn preprocessed_markdown_links(s: &str) -> Vec<PreprocessedMarkdownLink> {
+    markdown_links(s, |link| {
+        preprocess_link(&link).map(|pp_link| PreprocessedMarkdownLink(pp_link, link))
+    })
+}
+
 impl LinkCollector<'_, '_> {
     /// This is the entry point for resolving an intra-doc link.
     ///
@@ -1181,8 +1214,9 @@ fn resolve_link(
         item: &Item,
         dox: &str,
         parent_node: Option<DefId>,
-        ori_link: MarkdownLink,
+        link: &PreprocessedMarkdownLink,
     ) -> Option<ItemLink> {
+        let PreprocessedMarkdownLink(pp_link, ori_link) = link;
         trace!("considering link '{}'", ori_link.link);
 
         let diag_info = DiagnosticInfo {
@@ -1192,28 +1226,29 @@ fn resolve_link(
             link_range: ori_link.range.clone(),
         };
 
-        let PreprocessingInfo { ref path_str, disambiguator, extra_fragment, link_text } =
-            match preprocess_link(&ori_link)? {
-                Ok(x) => x,
-                Err(err) => {
-                    match err {
-                        PreprocessingError::Anchor(err) => anchor_failure(self.cx, diag_info, err),
-                        PreprocessingError::Disambiguator(range, msg) => {
-                            disambiguator_error(self.cx, diag_info, range, &msg)
-                        }
-                        PreprocessingError::Resolution(err, path_str, disambiguator) => {
-                            resolution_failure(
-                                self,
-                                diag_info,
-                                &path_str,
-                                disambiguator,
-                                smallvec![err],
-                            );
-                        }
+        let PreprocessingInfo { path_str, disambiguator, extra_fragment, link_text } = match pp_link
+        {
+            Ok(x) => x,
+            Err(err) => {
+                match err {
+                    PreprocessingError::Anchor(err) => anchor_failure(self.cx, diag_info, *err),
+                    PreprocessingError::Disambiguator(range, msg) => {
+                        disambiguator_error(self.cx, diag_info, range.clone(), msg)
+                    }
+                    PreprocessingError::Resolution(err, path_str, disambiguator) => {
+                        resolution_failure(
+                            self,
+                            diag_info,
+                            path_str,
+                            *disambiguator,
+                            smallvec![err.clone()],
+                        );
                     }
-                    return None;
                 }
-            };
+                return None;
+            }
+        };
+        let disambiguator = *disambiguator;
 
         let inner_docs = item.inner_docs(self.cx.tcx);
 
@@ -1250,7 +1285,7 @@ fn resolve_link(
                 module_id,
                 dis: disambiguator,
                 path_str: path_str.to_owned(),
-                extra_fragment,
+                extra_fragment: extra_fragment.clone(),
             },
             diag_info.clone(), // this struct should really be Copy, but Range is not :(
             matches!(ori_link.kind, LinkType::Reference | LinkType::Shortcut),
@@ -1320,8 +1355,8 @@ fn resolve_link(
                 }
 
                 Some(ItemLink {
-                    link: ori_link.link,
-                    link_text,
+                    link: ori_link.link.clone(),
+                    link_text: link_text.clone(),
                     did: res.def_id(self.cx.tcx),
                     fragment,
                 })
@@ -1343,7 +1378,12 @@ fn resolve_link(
                     &diag_info,
                 )?;
                 let id = clean::register_res(self.cx, rustc_hir::def::Res::Def(kind, id));
-                Some(ItemLink { link: ori_link.link, link_text, did: id, fragment })
+                Some(ItemLink {
+                    link: ori_link.link.clone(),
+                    link_text: link_text.clone(),
+                    did: id,
+                    fragment,
+                })
             }
         }
     }
index dffceff045d0b6d6e2cc239c422f6e97ff6f8655..68e10e3a18c7ec40b6e7acf2b1d2a5bb0c12f664 100644 (file)
@@ -1,33 +1,39 @@
 use crate::clean::Attributes;
 use crate::core::ResolverCaches;
-use crate::html::markdown::markdown_links;
-use crate::passes::collect_intra_doc_links::preprocess_link;
+use crate::passes::collect_intra_doc_links::preprocessed_markdown_links;
+use crate::passes::collect_intra_doc_links::PreprocessedMarkdownLink;
 
 use rustc_ast::visit::{self, AssocCtxt, Visitor};
 use rustc_ast::{self as ast, ItemKind};
 use rustc_ast_lowering::ResolverAstLowering;
-use rustc_hir::def::Namespace::TypeNS;
-use rustc_hir::def::{DefKind, Res};
+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::TraitCandidate;
 use rustc_middle::ty::{DefIdTree, Visibility};
 use rustc_resolve::{ParentScope, Resolver};
 use rustc_session::config::Externs;
-use rustc_span::SyntaxContext;
+use rustc_session::Session;
+use rustc_span::{Symbol, SyntaxContext};
 
 use std::collections::hash_map::Entry;
 use std::mem;
 
 crate fn early_resolve_intra_doc_links(
     resolver: &mut Resolver<'_>,
+    sess: &Session,
     krate: &ast::Crate,
     externs: Externs,
     document_private_items: bool,
 ) -> ResolverCaches {
     let mut link_resolver = EarlyDocLinkResolver {
         resolver,
+        sess,
         current_mod: CRATE_DEF_ID,
         visited_mods: Default::default(),
+        markdown_links: Default::default(),
+        doc_link_resolutions: Default::default(),
         traits_in_scope: Default::default(),
         all_traits: Default::default(),
         all_trait_impls: Default::default(),
@@ -36,7 +42,7 @@
 
     // Overridden `visit_item` below doesn't apply to the crate root,
     // so we have to visit its attributes and reexports separately.
-    link_resolver.load_links_in_attrs(&krate.attrs);
+    link_resolver.resolve_doc_links_local(&krate.attrs);
     link_resolver.process_module_children_or_reexports(CRATE_DEF_ID.to_def_id());
     visit::walk_crate(&mut link_resolver, krate);
     link_resolver.process_extern_impls();
@@ -50,6 +56,8 @@
     }
 
     ResolverCaches {
+        markdown_links: Some(link_resolver.markdown_links),
+        doc_link_resolutions: link_resolver.doc_link_resolutions,
         traits_in_scope: link_resolver.traits_in_scope,
         all_traits: Some(link_resolver.all_traits),
         all_trait_impls: Some(link_resolver.all_trait_impls),
     }
 }
 
+fn doc_attrs<'a>(attrs: impl Iterator<Item = &'a ast::Attribute>) -> Attributes {
+    Attributes::from_ast_iter(attrs.map(|attr| (attr, None)), true)
+}
+
 struct EarlyDocLinkResolver<'r, 'ra> {
     resolver: &'r mut Resolver<'ra>,
+    sess: &'r Session,
     current_mod: LocalDefId,
     visited_mods: DefIdSet,
+    markdown_links: FxHashMap<String, Vec<PreprocessedMarkdownLink>>,
+    doc_link_resolutions: FxHashMap<(Symbol, Namespace, DefId), Option<Res<ast::NodeId>>>,
     traits_in_scope: DefIdMap<Vec<TraitCandidate>>,
     all_traits: Vec<DefId>,
     all_trait_impls: Vec<DefId>,
@@ -92,18 +107,11 @@ fn add_traits_in_scope(&mut self, def_id: DefId) {
         }
     }
 
-    fn add_traits_in_parent_scope(&mut self, def_id: DefId) {
-        if let Some(module_id) = self.resolver.parent(def_id) {
-            self.add_traits_in_scope(module_id);
-        }
-    }
-
     /// Add traits in scope for links in impls collected by the `collect-intra-doc-links` pass.
     /// That pass filters impls using type-based information, but we don't yet have such
     /// information here, so we just conservatively calculate traits in scope for *all* modules
     /// having impls in them.
     fn process_extern_impls(&mut self) {
-        // FIXME: Need to resolve doc links on all these impl and trait items below.
         // Resolving links in already existing crates may trigger loading of new crates.
         let mut start_cnum = 0;
         loop {
@@ -124,7 +132,7 @@ fn process_extern_impls(&mut self) {
                 // the current crate, and links in their doc comments are not resolved.
                 for &def_id in &all_traits {
                     if self.resolver.cstore().visibility_untracked(def_id) == Visibility::Public {
-                        self.add_traits_in_parent_scope(def_id);
+                        self.resolve_doc_links_extern_impl(def_id, false);
                     }
                 }
                 for &(trait_def_id, impl_def_id, simplified_self_ty) in &all_trait_impls {
@@ -135,17 +143,17 @@ fn process_extern_impls(&mut self) {
                                 == Visibility::Public
                         })
                     {
-                        self.add_traits_in_parent_scope(impl_def_id);
+                        self.resolve_doc_links_extern_impl(impl_def_id, false);
                     }
                 }
                 for (ty_def_id, impl_def_id) in all_inherent_impls {
                     if self.resolver.cstore().visibility_untracked(ty_def_id) == Visibility::Public
                     {
-                        self.add_traits_in_parent_scope(impl_def_id);
+                        self.resolve_doc_links_extern_impl(impl_def_id, true);
                     }
                 }
-                for def_id in all_incoherent_impls {
-                    self.add_traits_in_parent_scope(def_id);
+                for impl_def_id in all_incoherent_impls {
+                    self.resolve_doc_links_extern_impl(impl_def_id, true);
                 }
 
                 self.all_traits.extend(all_traits);
@@ -161,16 +169,63 @@ fn process_extern_impls(&mut self) {
         }
     }
 
-    fn load_links_in_attrs(&mut self, attrs: &[ast::Attribute]) {
+    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) {
+        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) {
+            self.add_traits_in_scope(parent_id);
+        }
+    }
+
+    fn resolve_doc_links_extern_inner(&mut self, def_id: DefId) {
+        if !self.resolver.cstore().may_have_doc_links_untracked(def_id) {
+            return;
+        }
+        // FIXME: actually resolve links, not just add traits in scope.
+        self.add_traits_in_scope(def_id);
+    }
+
+    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);
+    }
+
+    fn resolve_doc_links(&mut self, attrs: Attributes, module_id: DefId) {
         let mut need_traits_in_scope = false;
-        for (doc_module, doc) in
-            Attributes::from_ast(attrs, None).collapsed_doc_value_by_module_level()
-        {
+        for (doc_module, doc) in attrs.prepare_to_doc_link_resolution() {
             assert_eq!(doc_module, None);
-            for link in markdown_links(&doc.as_str()) {
-                if let Some(Ok(pinfo)) = preprocess_link(&link) {
-                    self.resolver.resolve_rustdoc_path(&pinfo.path_str, TypeNS, module_id);
+            let links = self
+                .markdown_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;
                 }
             }
@@ -197,15 +252,13 @@ fn process_module_children_or_reexports(&mut self, module_id: DefId) {
                     && module_id.is_local()
             {
                 if let Some(def_id) = child.res.opt_def_id() && !def_id.is_local() {
-                    // FIXME: Need to resolve doc links on all these extern items
-                    // reached through reexports.
                     let scope_id = match child.res {
                         Res::Def(DefKind::Variant, ..) => self.resolver.parent(def_id).unwrap(),
                         _ => def_id,
                     };
-                    self.add_traits_in_parent_scope(scope_id); // 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.add_traits_in_scope(def_id); // Inner attribute scope
+                        self.resolve_doc_links_extern_inner(def_id); // Inner attribute scope
                     }
                     // Traits are processed in `add_extern_traits_in_scope`.
                     if let Res::Def(DefKind::Mod | DefKind::Enum, ..) = child.res {
@@ -219,10 +272,10 @@ fn process_module_children_or_reexports(&mut self, module_id: DefId) {
 
 impl Visitor<'_> for EarlyDocLinkResolver<'_, '_> {
     fn visit_item(&mut self, item: &ast::Item) {
-        self.load_links_in_attrs(&item.attrs); // Outer attribute scope
+        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));
-            self.load_links_in_attrs(&item.attrs); // Inner attribute scope
+            self.resolve_doc_links_local(&item.attrs); // Inner attribute scope
             self.process_module_children_or_reexports(self.current_mod.to_def_id());
             visit::walk_item(self, item);
             self.current_mod = old_mod;
@@ -241,22 +294,22 @@ fn visit_item(&mut self, item: &ast::Item) {
     }
 
     fn visit_assoc_item(&mut self, item: &ast::AssocItem, ctxt: AssocCtxt) {
-        self.load_links_in_attrs(&item.attrs);
+        self.resolve_doc_links_local(&item.attrs);
         visit::walk_assoc_item(self, item, ctxt)
     }
 
     fn visit_foreign_item(&mut self, item: &ast::ForeignItem) {
-        self.load_links_in_attrs(&item.attrs);
+        self.resolve_doc_links_local(&item.attrs);
         visit::walk_foreign_item(self, item)
     }
 
     fn visit_variant(&mut self, v: &ast::Variant) {
-        self.load_links_in_attrs(&v.attrs);
+        self.resolve_doc_links_local(&v.attrs);
         visit::walk_variant(self, v)
     }
 
     fn visit_field_def(&mut self, field: &ast::FieldDef) {
-        self.load_links_in_attrs(&field.attrs);
+        self.resolve_doc_links_local(&field.attrs);
         visit::walk_field_def(self, field)
     }
 
index 65459913eeaa80d09415c56d2e78ba28f2890358..6962b5c7ee302fd18a30b8b4556182d0b8dd654e 100644 (file)
         }
     });
 
-    // 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) {
+            }
+        }
+        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)));
                 }
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 5bcec779bc0e7d130be976f1cb17ba9d660b13ed..9723cdbe3345f3e1fc572f4c0cea5919de4b9457 100644 (file)
@@ -1,6 +1,6 @@
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{CrateNum, DefId};
 use rustc_middle::middle::privacy::{AccessLevel, AccessLevels};
 use rustc_middle::ty::TyCtxt;
 
@@ -29,7 +29,7 @@ impl<'a, 'tcx> LibEmbargoVisitor<'a, 'tcx> {
     }
 
     crate fn visit_lib(&mut self, cnum: CrateNum) {
-        let did = DefId { krate: cnum, index: CRATE_DEF_INDEX };
+        let did = cnum.as_def_id();
         self.update(did, Some(AccessLevel::Public));
         self.visit_mod(did);
     }
index fd336816c3a6d228dcef22171c43140f6fa7656f..326efc90ac5bf79a8fdd90898addf86bb6a6e404 160000 (submodule)
@@ -1 +1 @@
-Subproject commit fd336816c3a6d228dcef22171c43140f6fa7656f
+Subproject commit 326efc90ac5bf79a8fdd90898addf86bb6a6e404
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 69e35270266555d0f0cdf8f583cda8d63a382217..a87152e0321b9b4a658f53e1772894c8e471b904 100644 (file)
@@ -6,21 +6,21 @@
 use std::arch::asm;
 
 // CHECK-LABEL: @clobber_sysv64
-// CHECK: ={ax},={cx},={dx},={si},={di},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{dirflag},~{fpsr},~{flags},~{memory}
+// CHECK: ={ax},={cx},={dx},={si},={di},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k0},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{dirflag},~{fpsr},~{flags},~{memory}
 #[no_mangle]
 pub unsafe fn clobber_sysv64() {
     asm!("", clobber_abi("sysv64"));
 }
 
 // CHECK-LABEL: @clobber_win64
-// CHECK: ={ax},={cx},={dx},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{dirflag},~{fpsr},~{flags},~{memory}
+// CHECK: ={ax},={cx},={dx},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k0},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{dirflag},~{fpsr},~{flags},~{memory}
 #[no_mangle]
 pub unsafe fn clobber_win64() {
     asm!("", clobber_abi("win64"));
 }
 
 // CHECK-LABEL: @clobber_sysv64
-// CHECK: =&{dx},={ax},={cx},={si},={di},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{dirflag},~{fpsr},~{flags},~{memory}
+// CHECK: =&{dx},={ax},={cx},={si},={di},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k0},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{dirflag},~{fpsr},~{flags},~{memory}
 #[no_mangle]
 pub unsafe fn clobber_sysv64_edx() {
     let foo: i32;
@@ -28,7 +28,7 @@ pub unsafe fn clobber_sysv64_edx() {
 }
 
 // CHECK-LABEL: @clobber_win64
-// CHECK: =&{dx},={ax},={cx},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{dirflag},~{fpsr},~{flags},~{memory}
+// CHECK: =&{dx},={ax},={cx},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k0},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{dirflag},~{fpsr},~{flags},~{memory}
 #[no_mangle]
 pub unsafe fn clobber_win64_edx() {
     let foo: i32;
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 d9614f062b7e96e8ab3d2af71e4a2c3b635214e0..bccb9e4c7586254462e1164cb29b2d81fe4a5261 100644 (file)
@@ -28,7 +28,7 @@ impl IntoError<Error> for Api
     #[no_mangle]
     fn into_error(self, error: Self::Source) -> Error {
         Error::Api {
-            source: (|v| v)(error),
+            source: error,
         }
     }
 }
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..fc20165
--- /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..73b9ec4
--- /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..b2d4abce2947dd8c644d95c4b80d70065a7bd6da 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
index db24f71c75045fc7995c354a11bb1770f5e08e35..c48f3ac12c4e13b76b1fb0335d05908ddc30ae85 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
 +         _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
index e40274dc393401734ba33a5a1a4b2e30c1f142b1..038a1afc58bb6e44becf9780f93ee84489a895d3 100644 (file)
 +     bb3: {
           StorageDead(_3);                 // scope 0 at $DIR/early_otherwise_branch.rs:8:1: 8:2
           return;                          // scope 0 at $DIR/early_otherwise_branch.rs:8:2: 8:2
-+     }
-+ 
+      }
+  
+-     bb5 (cleanup): {
+-         resume;                          // scope 0 at $DIR/early_otherwise_branch.rs:3:1: 8:2
 +     bb4: {
 +         StorageDead(_11);                // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17
 +         switchInt(_7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17
index 4f2b9696f8c821ccab2bfe4a5ff7deced7841d8f..75549c1b3ddf276e0e5749c38637a160623f2761 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
@@ -84,8 +84,8 @@
           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
+-     bb7 (cleanup): {
+-         resume;                          // scope 0 at $DIR/early_otherwise_branch.rs:11:1: 17:2
 +     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 96c7e46853f145d994797691c16b078868156316..30726d8621e1f98f63a6758829dcace56c9bd42b 100644 (file)
 +     bb3: {
           StorageDead(_3);                 // scope 0 at $DIR/early_otherwise_branch.rs:26:1: 26:2
           return;                          // scope 0 at $DIR/early_otherwise_branch.rs:26:2: 26:2
-+     }
-+ 
+      }
+  
+-     bb5 (cleanup): {
+-         resume;                          // scope 0 at $DIR/early_otherwise_branch.rs:21:1: 26:2
 +     bb4: {
 +         StorageDead(_11);                // scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17
 +         switchInt(_7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22: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 379d0e9ea48b38ff83254fe909f836fa8a0c1e46..ddf26ad8ab323c5ef55aa6c48e61bf4165717ad5 100644 (file)
 +     bb4: {
           StorageDead(_4);                 // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:9:1: 9:2
           return;                          // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:9:2: 9:2
-+     }
-+ 
+      }
+  
+-     bb6 (cleanup): {
+-         resume;                          // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:4:1: 9:2
 +     bb5: {
 +         StorageDead(_15);                // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20
 +         switchInt(_10) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20
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..4d2db490836d834ab49144e9fe12a3a87e80a6c1 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
       }
+  
+      bb9 (cleanup): {
+          resume;                          // scope 0 at $DIR/early_otherwise_branch_noopt.rs:7:1: 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..92a719d997d6bea4738cf21a3adb84964124a0b0 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
+      }
+  
+      bb6 (cleanup): {
+          resume;                          // scope 0 at $DIR/early_otherwise_branch_soundness.rs:18:1: 27:2
       }
   }
   
index 56b7c9a2db47815e93b688c19054e01a1eb35e42..3ec5f0f8b3f01c72f72212f222f3545f716ae449 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
+      }
+  
+      bb5 (cleanup): {
+          resume;                          // scope 0 at $DIR/early_otherwise_branch_soundness.rs:12:1: 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 dddb7acae2b2c21c7bf8e4479051b1700b043f6f..319a47367b3ab6bbc117a63f7fa3214bbbd14711 100644 (file)
@@ -26,5 +26,9 @@
           StorageDead(_2);                 // scope 0 at $DIR/if-condition-int.rs:17:25: 17:26
           return;                          // scope 0 at $DIR/if-condition-int.rs:18:2: 18:2
       }
+  
+      bb4 (cleanup): {
+          resume;                          // scope 0 at $DIR/if-condition-int.rs:16:1: 18:2
+      }
   }
   
index 2ff8386b205bd024894f9bfe903e0b4712ede733..98a6c83cbffae6da358335b4fc1915f87c0acc68 100644 (file)
@@ -30,5 +30,9 @@
           StorageDead(_2);                 // scope 0 at $DIR/if-condition-int.rs:53:34: 53:35
           return;                          // scope 0 at $DIR/if-condition-int.rs:54:2: 54:2
       }
+  
+      bb4 (cleanup): {
+          resume;                          // scope 0 at $DIR/if-condition-int.rs:52:1: 54:2
+      }
   }
   
index fd4dcb2265e61df2a0530bb17aca2151e9b61cf8..4019021ede8d57bb6a54e43cd6c47e2162628de9 100644 (file)
@@ -54,5 +54,9 @@
           StorageDead(_2);                 // scope 0 at $DIR/if-condition-int.rs:49:1: 49:2
           return;                          // scope 0 at $DIR/if-condition-int.rs:49:2: 49:2
       }
+  
+      bb4 (cleanup): {
+          resume;                          // scope 0 at $DIR/if-condition-int.rs:43:1: 49:2
+      }
   }
   
index 40de48385f02e3894129090d91eb2557ad08b780..d4f100e289f06d860a1f577feaea5de964729ed6 100644 (file)
@@ -35,5 +35,9 @@
           StorageDead(_2);                 // scope 0 at $DIR/if-condition-int.rs:21:32: 21:33
           return;                          // scope 0 at $DIR/if-condition-int.rs:22:2: 22:2
       }
+  
+      bb4 (cleanup): {
+          resume;                          // scope 0 at $DIR/if-condition-int.rs:20:1: 22:2
+      }
   }
   
index 28c36aed84c38270a3b9a705a4e2965416db6a21..06d2c666aeca69d17b4d6f51b5b9fac53840d681 100644 (file)
@@ -35,5 +35,9 @@
           StorageDead(_2);                 // scope 0 at $DIR/if-condition-int.rs:25:31: 25:32
           return;                          // scope 0 at $DIR/if-condition-int.rs:26:2: 26:2
       }
+  
+      bb4 (cleanup): {
+          resume;                          // scope 0 at $DIR/if-condition-int.rs:24:1: 26:2
+      }
   }
   
index 55932fee9600cb28a3644461026d20246356ee7e..a7e4edf40a8d66686afa346b54efd17056bc54dd 100644 (file)
@@ -61,5 +61,9 @@
           StorageDead(_2);                 // scope 0 at $DIR/if-condition-int.rs:39:5: 39:6
           return;                          // scope 0 at $DIR/if-condition-int.rs:40:2: 40:2
       }
+  
+      bb7 (cleanup): {
+          resume;                          // scope 0 at $DIR/if-condition-int.rs:32:1: 40:2
+      }
   }
   
index c4574b32a59991f086505352cc870fee9c1a7dac..47f69b85e898c71256e46a7a03b4f686e4515457 100644 (file)
@@ -35,5 +35,9 @@
           StorageDead(_2);                 // scope 0 at $DIR/if-condition-int.rs:29:32: 29:33
           return;                          // scope 0 at $DIR/if-condition-int.rs:30:2: 30:2
       }
+  
+      bb4 (cleanup): {
+          resume;                          // scope 0 at $DIR/if-condition-int.rs:28:1: 30:2
+      }
   }
   
index 88d9d5622b8ec060a8d3ff45fcb66d7db8069218..3920627d5248783f9edb5ea5a97a1b92bf273bb0 100644 (file)
@@ -35,5 +35,9 @@
           StorageDead(_2);                 // scope 0 at $DIR/if-condition-int.rs:12:31: 12:32
           return;                          // scope 0 at $DIR/if-condition-int.rs:13:2: 13:2
       }
+  
+      bb4 (cleanup): {
+          resume;                          // scope 0 at $DIR/if-condition-int.rs:11:1: 13:2
+      }
   }
   
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 bea33073366f733e63a08450723fee0fdb890890..3b890e4be2e290f4ce98f0f44797418eed439191 100644 (file)
@@ -4,21 +4,22 @@
   fn h() -> () {
       let mut _0: ();                      // return place in scope 0 at $DIR/inline-diverging.rs:21:12: 21:12
       let _1: (!, !);                      // in scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
-+     let mut _2: fn() -> ! {sleep};       // in scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
-+     let mut _9: ();                      // in scope 0 at $DIR/inline-diverging.rs:27:13: 27:16
-+     let mut _10: ();                     // in scope 0 at $DIR/inline-diverging.rs:28:13: 28:16
++     let mut _2: (!, !);                  // in scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
++     let mut _3: fn() -> ! {sleep};       // in scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
++     let mut _10: ();                     // in scope 0 at $DIR/inline-diverging.rs:27:13: 27:16
++     let mut _11: ();                     // in scope 0 at $DIR/inline-diverging.rs:28:13: 28:16
 +     scope 1 (inlined call_twice::<!, fn() -> ! {sleep}>) { // at $DIR/inline-diverging.rs:22:5: 22:22
-+         debug f => _2;                   // in scope 1 at $DIR/inline-diverging.rs:26:36: 26:37
-+         let _3: !;                       // in scope 1 at $DIR/inline-diverging.rs:27:9: 27:10
-+         let mut _4: &fn() -> ! {sleep};  // in scope 1 at $DIR/inline-diverging.rs:27:13: 27:14
-+         let mut _6: &fn() -> ! {sleep};  // in scope 1 at $DIR/inline-diverging.rs:28:13: 28:14
-+         let mut _7: !;                   // in scope 1 at $DIR/inline-diverging.rs:29:6: 29:7
-+         let mut _8: !;                   // in scope 1 at $DIR/inline-diverging.rs:29:9: 29:10
++         debug f => _3;                   // in scope 1 at $DIR/inline-diverging.rs:26:36: 26:37
++         let _4: !;                       // in scope 1 at $DIR/inline-diverging.rs:27:9: 27:10
++         let mut _5: &fn() -> ! {sleep};  // in scope 1 at $DIR/inline-diverging.rs:27:13: 27:14
++         let mut _7: &fn() -> ! {sleep};  // in scope 1 at $DIR/inline-diverging.rs:28:13: 28:14
++         let mut _8: !;                   // in scope 1 at $DIR/inline-diverging.rs:29:6: 29:7
++         let mut _9: !;                   // in scope 1 at $DIR/inline-diverging.rs:29:9: 29:10
 +         scope 2 {
-+             debug a => _3;               // in scope 2 at $DIR/inline-diverging.rs:27:9: 27:10
-+             let _5: !;                   // in scope 2 at $DIR/inline-diverging.rs:28:9: 28:10
++             debug a => _4;               // in scope 2 at $DIR/inline-diverging.rs:27:9: 27:10
++             let _6: !;                   // in scope 2 at $DIR/inline-diverging.rs:28:9: 28:10
 +             scope 3 {
-+                 debug b => _5;           // in scope 3 at $DIR/inline-diverging.rs:28:9: 28:10
++                 debug b => _6;           // in scope 3 at $DIR/inline-diverging.rs:28:9: 28:10
 +             }
 +             scope 6 (inlined <fn() -> ! {sleep} as Fn<()>>::call - shim(fn() -> ! {sleep})) { // at $DIR/inline-diverging.rs:28:13: 28:16
 +                 scope 7 (inlined sleep) { // at $SRC_DIR/core/src/ops/function.rs:LL:COL
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
--         _1 = call_twice::<!, fn() -> ! {sleep}>(sleep) -> bb1; // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
+-         call_twice::<!, fn() -> ! {sleep}>(sleep); // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
 +         StorageLive(_2);                 // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
-+         _2 = sleep;                      // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
++         StorageLive(_3);                 // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
++         _3 = sleep;                      // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
                                            // mir::Constant
 -                                          // + span: $DIR/inline-diverging.rs:22:5: 22:15
 -                                          // + literal: Const { ty: fn(fn() -> ! {sleep}) -> (!, !) {call_twice::<!, fn() -> ! {sleep}>}, val: Value(Scalar(<ZST>)) }
 -                                          // mir::Constant
                                            // + span: $DIR/inline-diverging.rs:22:16: 22:21
                                            // + literal: Const { ty: fn() -> ! {sleep}, val: Value(Scalar(<ZST>)) }
-+         StorageLive(_3);                 // scope 1 at $DIR/inline-diverging.rs:27:9: 27:10
-+         StorageLive(_4);                 // scope 1 at $DIR/inline-diverging.rs:27:13: 27:14
-+         _4 = &_2;                        // scope 1 at $DIR/inline-diverging.rs:27:13: 27:14
-+         StorageLive(_9);                 // scope 1 at $DIR/inline-diverging.rs:27:13: 27:16
-+         _9 = const ();                   // scope 1 at $DIR/inline-diverging.rs:27:13: 27:16
++         StorageLive(_4);                 // scope 1 at $DIR/inline-diverging.rs:27:9: 27:10
++         StorageLive(_5);                 // scope 1 at $DIR/inline-diverging.rs:27:13: 27:14
++         _5 = &_3;                        // scope 1 at $DIR/inline-diverging.rs:27:13: 27:14
++         StorageLive(_10);                // scope 1 at $DIR/inline-diverging.rs:27:13: 27:16
++         _10 = const ();                  // scope 1 at $DIR/inline-diverging.rs:27:13: 27:16
 +         goto -> bb1;                     // scope 5 at $DIR/inline-diverging.rs:39:5: 39:12
-      }
-  
-      bb1: {
--         StorageDead(_1);                 // scope 0 at $DIR/inline-diverging.rs:22:22: 22:23
--         _0 = const ();                   // scope 0 at $DIR/inline-diverging.rs:21:12: 23:2
--         return;                          // scope 0 at $DIR/inline-diverging.rs:23:2: 23:2
++     }
++ 
++     bb1: {
 +         goto -> bb1;                     // scope 5 at $DIR/inline-diverging.rs:39:5: 39:12
       }
   }
index 5fb57c285becac09f46b5cc6ee447bc308bc6ce5..4aff4445158098efdaa023a3393314f1d9e207d6 100644 (file)
@@ -21,7 +21,7 @@ fn main() -> () {
         StorageLive(_2);                 // scope 0 at $DIR/issue-72181-1.rs:16:9: 16:10
         StorageLive(_3);                 // scope 2 at $DIR/issue-72181-1.rs:17:41: 17:43
         _3 = ();                         // scope 2 at $DIR/issue-72181-1.rs:17:41: 17:43
-        _2 = transmute::<(), Void>(move _3) -> [return: bb1, unwind: bb4]; // scope 2 at $DIR/issue-72181-1.rs:17:9: 17:44
+        transmute::<(), Void>(move _3) -> bb4; // scope 2 at $DIR/issue-72181-1.rs:17:9: 17:44
                                          // mir::Constant
                                          // + span: $DIR/issue-72181-1.rs:17:9: 17:40
                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(()) -> Void {transmute::<(), Void>}, val: Value(Scalar(<ZST>)) }
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 9f235248ca59f9a2c61112c005979684576aa0a5..8423128123ab76e108fcee5a8866a21ff2d1287d 100644 (file)
 | '_#2r live at {bb0[0..=1]}
 | '_#3r live at {bb0[0..=1]}
 | '_#4r live at {bb0[0..=1]}
-| '_#1r: '_#6r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:26: 12:27)
-| '_#1r: '_#8r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:54: 12:55)
-| '_#2r: '_#7r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:42: 12:43)
-| '_#3r: '_#9r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:66: 12:67)
-| '_#6r: '_#1r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:26: 12:27)
-| '_#7r: '_#2r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:42: 12:43)
-| '_#8r: '_#1r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:54: 12:55)
-| '_#9r: '_#3r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:66: 12:67)
+| '_#1r: '_#6r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:26: 12:27) ($DIR/named-lifetimes-basic.rs:12:26: 12:27 (#0)
+| '_#1r: '_#8r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:54: 12:55) ($DIR/named-lifetimes-basic.rs:12:54: 12:55 (#0)
+| '_#2r: '_#7r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:42: 12:43) ($DIR/named-lifetimes-basic.rs:12:42: 12:43 (#0)
+| '_#3r: '_#9r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:66: 12:67) ($DIR/named-lifetimes-basic.rs:12:66: 12:67 (#0)
+| '_#6r: '_#1r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:26: 12:27) ($DIR/named-lifetimes-basic.rs:12:26: 12:27 (#0)
+| '_#7r: '_#2r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:42: 12:43) ($DIR/named-lifetimes-basic.rs:12:42: 12:43 (#0)
+| '_#8r: '_#1r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:54: 12:55) ($DIR/named-lifetimes-basic.rs:12:54: 12:55 (#0)
+| '_#9r: '_#3r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:66: 12:67) ($DIR/named-lifetimes-basic.rs:12:66: 12:67 (#0)
 |
 fn use_x(_1: &'_#6r mut i32, _2: &'_#7r u32, _3: &'_#8r u32, _4: &'_#9r u32) -> bool {
     debug w => _1;                       // in scope 0 at $DIR/named-lifetimes-basic.rs:12:26: 12:27
index ed94a1ecf006252f79da61898d048595d549c779..f79e2705ad29cce82115f971e7ec67ee98567dff 100644 (file)
@@ -18,8 +18,8 @@
 | '_#3r live at {bb1[0]}
 | '_#4r live at {bb1[1..=3]}
 | '_#5r live at {bb1[4..=7], bb2[0..=2]}
-| '_#3r: '_#4r due to Assignment at Single(bb1[0])
-| '_#4r: '_#5r due to Assignment at Single(bb1[3])
+| '_#3r: '_#4r due to Assignment at Single(bb1[0]) ($DIR/region-subtyping-basic.rs:18:13: 18:18 (#0)
+| '_#4r: '_#5r due to Assignment at Single(bb1[3]) ($DIR/region-subtyping-basic.rs:19:13: 19:14 (#0)
 |
 fn main() -> () {
     let mut _0: ();                      // return place in scope 0 at $DIR/region-subtyping-basic.rs:16:11: 16:11
index 95997b2070172d955de39b41256af0eec0df2c76..162cacef8a54afab04bf2bc554858e6cbb6fb96f 100644 (file)
@@ -18,8 +18,8 @@
 | '_#3r live at {bb1[0]}
 | '_#4r live at {bb1[1..=3]}
 | '_#5r live at {bb1[4..=7], bb2[0..=2]}
-| '_#3r: '_#4r due to Assignment at Single(bb1[0])
-| '_#4r: '_#5r due to Assignment at Single(bb1[3])
+| '_#3r: '_#4r due to Assignment at Single(bb1[0]) ($DIR/region-subtyping-basic.rs:18:13: 18:18 (#0)
+| '_#4r: '_#5r due to Assignment at Single(bb1[3]) ($DIR/region-subtyping-basic.rs:19:13: 19:14 (#0)
 |
 fn main() -> () {
     let mut _0: ();                      // return place in scope 0 at $DIR/region-subtyping-basic.rs:16:11: 16:11
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 f438eaa002780958f07d88a70f123bd229129de0..e07af6d5983112bb846139193059f86c0a8370a4 100644 (file)
@@ -39,5 +39,9 @@
 -         StorageDead(_2);                 // scope 0 at $DIR/nrvo-simple.rs:8:1: 8:2
           return;                          // scope 0 at $DIR/nrvo-simple.rs:8:2: 8:2
       }
+  
+      bb2 (cleanup): {
+          resume;                          // scope 0 at $DIR/nrvo-simple.rs:4:1: 8:2
+      }
   }
   
index e02580135af38f3f9a02d8745b52b024052d91c9..b383c5ec9dc60a173fc9a8391828a6467faa3d86 100644 (file)
@@ -16,7 +16,7 @@
 | '_#1r live at {bb0[0..=22]}
 | '_#3r live at {bb0[10]}
 | '_#4r live at {bb0[11]}
-| '_#3r: '_#4r due to Assignment at Single(bb0[10])
+| '_#3r: '_#4r due to Assignment at Single(bb0[10]) ($DIR/storage_ranges.rs:6:17: 6:25 (#0)
 |
 fn main() -> () {
     let mut _0: ();                      // return place in scope 0 at $DIR/storage_ranges.rs:3:11: 3:11
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),
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 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;
index 2e0330c449721153bc3c57d08d8b61694828e38b..b47a1fefa41d00d7e8646c32bdf38d1016733914 100644 (file)
@@ -1,6 +1,6 @@
 // exact-check
 
-const QUERY = 'hashmap';
+const QUERY = '"hashmap"';
 const FILTER_CRATE = 'core';
 
 const EXPECTED = {
diff --git a/src/test/rustdoc-js-std/parser-errors.js b/src/test/rustdoc-js-std/parser-errors.js
new file mode 100644 (file)
index 0000000..dc42031
--- /dev/null
@@ -0,0 +1,385 @@
+const QUERY = [
+    '<P>',
+    '-> <P>',
+    'a<"P">',
+    '"P" "P"',
+    'P "P"',
+    '"p" p',
+    '"const": p',
+    "a<:a>",
+    "a<::a>",
+    "((a))",
+    "(p -> p",
+    "::a::b",
+    "a::::b",
+    "a::b::",
+    ":a",
+    "a b:",
+    "a (b:",
+    "_:",
+    "a-bb",
+    "a>bb",
+    "ab'",
+    "a->",
+    '"p" <a>',
+    '"p" a<a>',
+    "a,<",
+    "aaaaa<>b",
+    "fn:aaaaa<>b",
+    "->a<>b",
+    "a<->",
+    "a:: a",
+    "a ::a",
+    "a<a>:",
+    "a<>:",
+    "a,:",
+    "  a<>  :",
+    "mod : :",
+    "a!a",
+    "a!!",
+];
+
+const PARSED = [
+    {
+        elems: [],
+        foundElems: 0,
+        original: "<P>",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "<p>",
+        error: "Found generics without a path",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "-> <P>",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "-> <p>",
+        error: "Found generics without a path",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "a<\"P\">",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "a<\"p\">",
+        error: "`\"` cannot be used in generics",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "\"P\" \"P\"",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "\"p\" \"p\"",
+        error: "Cannot have more than one literal search element",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "P \"P\"",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "p \"p\"",
+        error: "Cannot use literal search when there is more than one element",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "\"p\" p",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "\"p\" p",
+        error: "You cannot have more than one element if you use quotes",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "\"const\": p",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "\"const\": p",
+        error: "You cannot use quotes on type filter",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "a<:a>",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "a<:a>",
+        error: "Unexpected `:` after `<`",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "a<::a>",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "a<::a>",
+        error: "Unexpected `::`: paths cannot start with `::`",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "((a))",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "((a))",
+        error: "Unexpected `(`",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "(p -> p",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "(p -> p",
+        error: "Unexpected `(`",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "::a::b",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "::a::b",
+        error: "Paths cannot start with `::`",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "a::::b",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "a::::b",
+        error: "Unexpected `::::`",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "a::b::",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "a::b::",
+        error: "Paths cannot end with `::`",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: ":a",
+        returned: [],
+        typeFilter: -1,
+        userQuery: ":a",
+        error: "Expected type filter before `:`",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "a b:",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "a b:",
+        error: "Unexpected `:`",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "a (b:",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "a (b:",
+        error: "Unexpected `(`",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "_:",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "_:",
+        error: "Unknown type filter `_`",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "a-bb",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "a-bb",
+        error: "Unexpected `-` (did you mean `->`?)",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "a>bb",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "a>bb",
+        error: "Unexpected `>` (did you mean `->`?)",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "ab'",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "ab'",
+        error: "Unexpected `'`",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "a->",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "a->",
+        error: "Expected at least one item after `->`",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: '"p" <a>',
+        returned: [],
+        typeFilter: -1,
+        userQuery: '"p" <a>',
+        error: "Found generics without a path",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: '"p" a<a>',
+        returned: [],
+        typeFilter: -1,
+        userQuery: '"p" a<a>',
+        error: "You cannot have more than one element if you use quotes",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: 'a,<',
+        returned: [],
+        typeFilter: -1,
+        userQuery: 'a,<',
+        error: 'Found generics without a path',
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: 'aaaaa<>b',
+        returned: [],
+        typeFilter: -1,
+        userQuery: 'aaaaa<>b',
+        error: 'Expected `,`, ` `, `:` or `->`, found `b`',
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: 'fn:aaaaa<>b',
+        returned: [],
+        typeFilter: -1,
+        userQuery: 'fn:aaaaa<>b',
+        error: 'Expected `,`, ` ` or `->`, found `b`',
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: '->a<>b',
+        returned: [],
+        typeFilter: -1,
+        userQuery: '->a<>b',
+        error: 'Expected `,` or ` `, found `b`',
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: 'a<->',
+        returned: [],
+        typeFilter: -1,
+        userQuery: 'a<->',
+        error: 'Unexpected `-` after `<`',
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: 'a:: a',
+        returned: [],
+        typeFilter: -1,
+        userQuery: 'a:: a',
+        error: 'Paths cannot end with `::`',
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: 'a ::a',
+        returned: [],
+        typeFilter: -1,
+        userQuery: 'a ::a',
+        error: 'Paths cannot start with `::`',
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "a<a>:",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "a<a>:",
+        error: 'Unexpected `:`',
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "a<>:",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "a<>:",
+        error: 'Unexpected `<` in type filter',
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "a,:",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "a,:",
+        error: 'Unexpected `,` in type filter',
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "a<>  :",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "a<>  :",
+        error: 'Unexpected `<` in type filter',
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "mod : :",
+        returned: [],
+        typeFilter: -1,
+        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-filter.js b/src/test/rustdoc-js-std/parser-filter.js
new file mode 100644 (file)
index 0000000..e5a87a4
--- /dev/null
@@ -0,0 +1,43 @@
+const QUERY = ['fn:foo', 'enum : foo', 'macro<f>:foo'];
+
+const PARSED = [
+    {
+        elems: [{
+            name: "foo",
+            fullPath: ["foo"],
+            pathWithoutLast: [],
+            pathLast: "foo",
+            generics: [],
+        }],
+        foundElems: 1,
+        original: "fn:foo",
+        returned: [],
+        typeFilter: 5,
+        userQuery: "fn:foo",
+        error: null,
+    },
+    {
+        elems: [{
+            name: "foo",
+            fullPath: ["foo"],
+            pathWithoutLast: [],
+            pathLast: "foo",
+            generics: [],
+        }],
+        foundElems: 1,
+        original: "enum : foo",
+        returned: [],
+        typeFilter: 4,
+        userQuery: "enum : foo",
+        error: null,
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "macro<f>:foo",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "macro<f>:foo",
+        error: "Unexpected `:`",
+    },
+];
diff --git a/src/test/rustdoc-js-std/parser-generics.js b/src/test/rustdoc-js-std/parser-generics.js
new file mode 100644 (file)
index 0000000..0cf7f50
--- /dev/null
@@ -0,0 +1,62 @@
+const QUERY = ['A<B<C<D>,  E>', 'p<> u8', '"p"<a>'];
+
+const PARSED = [
+    {
+        elems: [],
+        foundElems: 0,
+        original: 'A<B<C<D>,  E>',
+        returned: [],
+        typeFilter: -1,
+        userQuery: 'a<b<c<d>,  e>',
+        error: 'Unexpected `<` after `<`',
+    },
+    {
+        elems: [
+            {
+                name: "p",
+                fullPath: ["p"],
+                pathWithoutLast: [],
+                pathLast: "p",
+                generics: [],
+            },
+            {
+                name: "u8",
+                fullPath: ["u8"],
+                pathWithoutLast: [],
+                pathLast: "u8",
+                generics: [],
+            },
+        ],
+        foundElems: 2,
+        original: "p<> u8",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "p<> u8",
+        error: null,
+    },
+    {
+        elems: [
+            {
+                name: "p",
+                fullPath: ["p"],
+                pathWithoutLast: [],
+                pathLast: "p",
+                generics: [
+                    {
+                        name: "a",
+                        fullPath: ["a"],
+                        pathWithoutLast: [],
+                        pathLast: "a",
+                        generics: [],
+                    },
+                ],
+            },
+        ],
+        foundElems: 1,
+        original: '"p"<a>',
+        returned: [],
+        typeFilter: -1,
+        userQuery: '"p"<a>',
+        error: null,
+    },
+];
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,
+    },
+];
diff --git a/src/test/rustdoc-js-std/parser-literal.js b/src/test/rustdoc-js-std/parser-literal.js
new file mode 100644 (file)
index 0000000..87b3baf
--- /dev/null
@@ -0,0 +1,27 @@
+const QUERY = ['R<P>'];
+
+const PARSED = [
+    {
+        elems: [{
+            name: "r",
+            fullPath: ["r"],
+            pathWithoutLast: [],
+            pathLast: "r",
+            generics: [
+                {
+                    name: "p",
+                    fullPath: ["p"],
+                    pathWithoutLast: [],
+                    pathLast: "p",
+                    generics: [],
+                },
+            ],
+        }],
+        foundElems: 1,
+        original: "R<P>",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "r<p>",
+        error: null,
+    }
+];
diff --git a/src/test/rustdoc-js-std/parser-paths.js b/src/test/rustdoc-js-std/parser-paths.js
new file mode 100644 (file)
index 0000000..9f823f9
--- /dev/null
@@ -0,0 +1,90 @@
+const QUERY = ['A::B', 'A::B,C',  'A::B<f>,C', 'mod::a'];
+
+const PARSED = [
+    {
+        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: [],
+            },
+            {
+                name: "c",
+                fullPath: ["c"],
+                pathWithoutLast: [],
+                pathLast: "c",
+                generics: [],
+            },
+        ],
+        foundElems: 2,
+        original: 'A::B,C',
+        returned: [],
+        typeFilter: -1,
+        userQuery: 'a::b,c',
+        error: null,
+    },
+    {
+        elems: [
+            {
+                name: "a::b",
+                fullPath: ["a", "b"],
+                pathWithoutLast: ["a"],
+                pathLast: "b",
+                generics: [
+                    {
+                        name: "f",
+                        fullPath: ["f"],
+                        pathWithoutLast: [],
+                        pathLast: "f",
+                        generics: [],
+                    },
+                ],
+            },
+            {
+                name: "c",
+                fullPath: ["c"],
+                pathWithoutLast: [],
+                pathLast: "c",
+                generics: [],
+            },
+        ],
+        foundElems: 2,
+        original: 'A::B<f>,C',
+        returned: [],
+        typeFilter: -1,
+        userQuery: 'a::b<f>,c',
+        error: null,
+    },
+    {
+        elems: [{
+            name: "mod::a",
+            fullPath: ["mod", "a"],
+            pathWithoutLast: ["mod"],
+            pathLast: "a",
+            generics: [],
+        }],
+        foundElems: 1,
+        original: "mod::a",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "mod::a",
+        error: null,
+    },
+];
diff --git a/src/test/rustdoc-js-std/parser-quote.js b/src/test/rustdoc-js-std/parser-quote.js
new file mode 100644 (file)
index 0000000..1e16c90
--- /dev/null
@@ -0,0 +1,87 @@
+const QUERY = [
+    '-> "p"',
+    '"p",',
+    '"p" -> a',
+    '"a" -> "p"',
+    '->"-"',
+    '"a',
+    '""',
+];
+
+const PARSED = [
+    {
+        elems: [],
+        foundElems: 1,
+        original: '-> "p"',
+        returned: [{
+            name: "p",
+            fullPath: ["p"],
+            pathWithoutLast: [],
+            pathLast: "p",
+            generics: [],
+        }],
+        typeFilter: -1,
+        userQuery: '-> "p"',
+        error: null,
+    },
+    {
+        elems: [{
+            name: "p",
+            fullPath: ["p"],
+            pathWithoutLast: [],
+            pathLast: "p",
+            generics: [],
+        }],
+        foundElems: 1,
+        original: '"p",',
+        returned: [],
+        typeFilter: -1,
+        userQuery: '"p",',
+        error: null,
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: '"p" -> a',
+        returned: [],
+        typeFilter: -1,
+        userQuery: '"p" -> a',
+        error: "You cannot have more than one element if you use quotes",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: '"a" -> "p"',
+        returned: [],
+        typeFilter: -1,
+        userQuery: '"a" -> "p"',
+        error: "Cannot have more than one literal search element",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: '->"-"',
+        returned: [],
+        typeFilter: -1,
+        userQuery: '->"-"',
+        error: 'Unexpected `-` in a string element',
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: '"a',
+        returned: [],
+        typeFilter: -1,
+        userQuery: '"a',
+        error: 'Unclosed `"`',
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: '""',
+        returned: [],
+        typeFilter: -1,
+        userQuery: '""',
+        error: 'Cannot have empty string element',
+    },
+];
diff --git a/src/test/rustdoc-js-std/parser-returned.js b/src/test/rustdoc-js-std/parser-returned.js
new file mode 100644 (file)
index 0000000..6fce17d
--- /dev/null
@@ -0,0 +1,99 @@
+const QUERY = [
+    "-> F<P>",
+    "-> P",
+    "->,a",
+    "aaaaa->a",
+    "-> !",
+];
+
+const PARSED = [
+    {
+        elems: [],
+        foundElems: 1,
+        original: "-> F<P>",
+        returned: [{
+            name: "f",
+            fullPath: ["f"],
+            pathWithoutLast: [],
+            pathLast: "f",
+            generics: [
+                {
+                    name: "p",
+                    fullPath: ["p"],
+                    pathWithoutLast: [],
+                    pathLast: "p",
+                    generics: [],
+                },
+            ],
+        }],
+        typeFilter: -1,
+        userQuery: "-> f<p>",
+        error: null,
+    },
+    {
+        elems: [],
+        foundElems: 1,
+        original: "-> P",
+        returned: [{
+            name: "p",
+            fullPath: ["p"],
+            pathWithoutLast: [],
+            pathLast: "p",
+            generics: [],
+        }],
+        typeFilter: -1,
+        userQuery: "-> p",
+        error: null,
+    },
+    {
+        elems: [],
+        foundElems: 1,
+        original: "->,a",
+        returned: [{
+            name: "a",
+            fullPath: ["a"],
+            pathWithoutLast: [],
+            pathLast: "a",
+            generics: [],
+        }],
+        typeFilter: -1,
+        userQuery: "->,a",
+        error: null,
+    },
+    {
+        elems: [{
+            name: "aaaaa",
+            fullPath: ["aaaaa"],
+            pathWithoutLast: [],
+            pathLast: "aaaaa",
+            generics: [],
+        }],
+        foundElems: 2,
+        original: "aaaaa->a",
+        returned: [{
+            name: "a",
+            fullPath: ["a"],
+            pathWithoutLast: [],
+            pathLast: "a",
+            generics: [],
+        }],
+        typeFilter: -1,
+        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-js-std/parser-separators.js b/src/test/rustdoc-js-std/parser-separators.js
new file mode 100644 (file)
index 0000000..5b7abdf
--- /dev/null
@@ -0,0 +1,206 @@
+// ignore-tidy-tab
+
+const QUERY = [
+    'aaaaaa    b',
+    'a b',
+    'a,b',
+    'a\tb',
+    'a<b c>',
+    'a<b,c>',
+    'a<b\tc>',
+];
+
+const PARSED = [
+    {
+        elems: [
+            {
+                name: 'aaaaaa',
+                fullPath: ['aaaaaa'],
+                pathWithoutLast: [],
+                pathLast: 'aaaaaa',
+                generics: [],
+            },
+            {
+                name: 'b',
+                fullPath: ['b'],
+                pathWithoutLast: [],
+                pathLast: 'b',
+                generics: [],
+            },
+        ],
+        foundElems: 2,
+        original: "aaaaaa      b",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "aaaaaa     b",
+        error: null,
+    },
+    {
+        elems: [
+            {
+                name: 'a',
+                fullPath: ['a'],
+                pathWithoutLast: [],
+                pathLast: 'a',
+                generics: [],
+            },
+            {
+                name: 'b',
+                fullPath: ['b'],
+                pathWithoutLast: [],
+                pathLast: 'b',
+                generics: [],
+            },
+        ],
+        foundElems: 2,
+        original: "a b",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "a b",
+        error: null,
+    },
+    {
+        elems: [
+            {
+                name: 'a',
+                fullPath: ['a'],
+                pathWithoutLast: [],
+                pathLast: 'a',
+                generics: [],
+            },
+            {
+                name: 'b',
+                fullPath: ['b'],
+                pathWithoutLast: [],
+                pathLast: 'b',
+                generics: [],
+            },
+        ],
+        foundElems: 2,
+        original: "a,b",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "a,b",
+        error: null,
+    },
+    {
+        elems: [
+            {
+                name: 'a',
+                fullPath: ['a'],
+                pathWithoutLast: [],
+                pathLast: 'a',
+                generics: [],
+            },
+            {
+                name: 'b',
+                fullPath: ['b'],
+                pathWithoutLast: [],
+                pathLast: 'b',
+                generics: [],
+            },
+        ],
+        foundElems: 2,
+        original: "a\tb",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "a\tb",
+        error: null,
+    },
+    {
+        elems: [
+            {
+                name: 'a',
+                fullPath: ['a'],
+                pathWithoutLast: [],
+                pathLast: 'a',
+                generics: [
+                    {
+                        name: 'b',
+                        fullPath: ['b'],
+                        pathWithoutLast: [],
+                        pathLast: 'b',
+                        generics: [],
+                    },
+                    {
+                        name: 'c',
+                        fullPath: ['c'],
+                        pathWithoutLast: [],
+                        pathLast: 'c',
+                        generics: [],
+                    },
+                ],
+            },
+        ],
+        foundElems: 1,
+        original: "a<b c>",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "a<b c>",
+        error: null,
+    },
+    {
+        elems: [
+            {
+                name: 'a',
+                fullPath: ['a'],
+                pathWithoutLast: [],
+                pathLast: 'a',
+                generics: [
+                    {
+                        name: 'b',
+                        fullPath: ['b'],
+                        pathWithoutLast: [],
+                        pathLast: 'b',
+                        generics: [],
+                    },
+                    {
+                        name: 'c',
+                        fullPath: ['c'],
+                        pathWithoutLast: [],
+                        pathLast: 'c',
+                        generics: [],
+                    },
+                ],
+            },
+        ],
+        foundElems: 1,
+        original: "a<b,c>",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "a<b,c>",
+        error: null,
+    },
+    {
+        elems: [
+            {
+                name: 'a',
+                fullPath: ['a'],
+                pathWithoutLast: [],
+                pathLast: 'a',
+                generics: [
+                    {
+                        name: 'b',
+                        fullPath: ['b'],
+                        pathWithoutLast: [],
+                        pathLast: 'b',
+                        generics: [],
+                    },
+                    {
+                        name: 'c',
+                        fullPath: ['c'],
+                        pathWithoutLast: [],
+                        pathLast: 'c',
+                        generics: [],
+                    },
+                ],
+            },
+        ],
+        foundElems: 1,
+        original: "a<b\tc>",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "a<b\tc>",
+        error: null,
+    },
+];
diff --git a/src/test/rustdoc-js-std/parser-weird-queries.js b/src/test/rustdoc-js-std/parser-weird-queries.js
new file mode 100644 (file)
index 0000000..a3d85ae
--- /dev/null
@@ -0,0 +1,123 @@
+// This test is mostly to check that the parser still kinda outputs something
+// (and doesn't enter an infinite loop!) even though the query is completely
+// invalid.
+const QUERY = [
+    'a b',
+    'a   b',
+    'a,b(c)',
+    'aaa,a',
+    ',,,,',
+    'mod    :',
+    'mod\t:',
+];
+
+const PARSED = [
+    {
+        elems: [
+            {
+                name: "a",
+                fullPath: ["a"],
+                pathWithoutLast: [],
+                pathLast: "a",
+                generics: [],
+            },
+            {
+                name: "b",
+                fullPath: ["b"],
+                pathWithoutLast: [],
+                pathLast: "b",
+                generics: [],
+            },
+        ],
+        foundElems: 2,
+        original: "a b",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "a b",
+        error: null,
+    },
+    {
+        elems: [
+            {
+                name: "a",
+                fullPath: ["a"],
+                pathWithoutLast: [],
+                pathLast: "a",
+                generics: [],
+            },
+            {
+                name: "b",
+                fullPath: ["b"],
+                pathWithoutLast: [],
+                pathLast: "b",
+                generics: [],
+            },
+        ],
+        foundElems: 2,
+        original: "a   b",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "a   b",
+        error: null,
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "a,b(c)",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "a,b(c)",
+        error: "Unexpected `(`",
+    },
+    {
+        elems: [
+            {
+                name: "aaa",
+                fullPath: ["aaa"],
+                pathWithoutLast: [],
+                pathLast: "aaa",
+                generics: [],
+            },
+            {
+                name: "a",
+                fullPath: ["a"],
+                pathWithoutLast: [],
+                pathLast: "a",
+                generics: [],
+            },
+        ],
+        foundElems: 2,
+        original: "aaa,a",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "aaa,a",
+        error: null,
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: ",,,,",
+        returned: [],
+        typeFilter: -1,
+        userQuery: ",,,,",
+        error: null,
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: 'mod    :',
+        returned: [],
+        typeFilter: 0,
+        userQuery: 'mod    :',
+        error: null,
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: 'mod\t:',
+        returned: [],
+        typeFilter: 0,
+        userQuery: 'mod\t:',
+        error: null,
+    },
+];
index 924129f86c8680214c07e2569cbea02aa2bc2a63..aec8484a41f6dcb6e27ad2cee6a0247163bdc4d3 100644 (file)
@@ -1,4 +1,7 @@
+// ignore-order
+
 const QUERY = '"error"';
+const FILTER_CRATE = 'std';
 
 const EXPECTED = {
     'others': [
@@ -6,7 +9,12 @@ const EXPECTED = {
         { 'path': 'std::fmt', 'name': 'Error' },
         { 'path': 'std::io', 'name': 'Error' },
     ],
-    'in_args': [],
+    'in_args': [
+        { 'path': 'std::fmt::Error', 'name': 'eq' },
+        { 'path': 'std::fmt::Error', 'name': 'cmp' },
+        { 'path': 'std::fmt::Error', 'name': 'partial_cmp' },
+
+    ],
     'returned': [
         { 'path': 'std::fmt::LowerExp', 'name': 'fmt' },
     ],
index 2c808143bae67fb434fda6307c5da81ef57d71c3..29609904b1957a52f893b9de8f097f796d399a49 100644 (file)
@@ -1,8 +1,8 @@
-const QUERY = 'struct:Vec';
+const QUERY = 'struct:VecD';
 
 const EXPECTED = {
     'others': [
-        { 'path': 'std::vec', 'name': 'Vec' },
         { 'path': 'std::collections', 'name': 'VecDeque' },
+        { 'path': 'std::vec', 'name': 'Vec' },
     ],
 };
index 3915ee7dc5d23196249c8499452744471076cfbb..25efbad26954003233d959692152f34888221bd7 100644 (file)
@@ -1,6 +1,7 @@
 // exact-check
 
 const QUERY = 'macro:print';
+const FILTER_CRATE = 'std';
 
 const EXPECTED = {
     'others': [
@@ -9,6 +10,8 @@ const EXPECTED = {
         { 'path': 'std', 'name': 'println' },
         { 'path': 'std', 'name': 'eprintln' },
         { 'path': 'std::pin', 'name': 'pin' },
-        { 'path': 'core::pin', 'name': 'pin' },
+        { 'path': 'std::future', 'name': 'join' },
+        { 'path': 'std', 'name': 'line' },
+        { 'path': 'std', 'name': 'write' },
     ],
 };
index e1a3256876bde15af94274c65d1ab29a71c6ce62..cd0e8e7b4a9eb41524adbb55fc8d9c931a8d20d4 100644 (file)
@@ -4,6 +4,6 @@ const EXPECTED = {
     'others': [
         { 'path': 'std::vec::Vec', 'name': 'new' },
         { 'path': 'std::vec::Vec', 'name': 'ne' },
-        { 'path': 'std::rc::Rc', 'name': 'ne' },
+        { 'path': 'alloc::vec::Vec', 'name': 'ne' },
     ],
 };
index 4b1e2e2970479d386c87370b03e783017937f588..e06047ba7606e78b8de5591ec8ecbbda03993a9d 100644 (file)
@@ -1,6 +1,6 @@
 // exact-check
 
-const QUERY = 'true';
+const QUERY = '"true"';
 
 const FILTER_CRATE = 'doc_alias_filter';
 
index ff188d5145801ad127793bf1094137b6cadb743f..7bb0cbe388fee1c8d7626b2d4aa74edd9ac80d10 100644 (file)
@@ -27,6 +27,7 @@ const QUERY = [
 
 const EXPECTED = [
     {
+        // StructItem
         'others': [
             {
                 'path': 'doc_alias',
@@ -38,6 +39,7 @@ const EXPECTED = [
         ],
     },
     {
+        // StructFieldItem
         'others': [
             {
                 'path': 'doc_alias::Struct',
@@ -49,6 +51,7 @@ const EXPECTED = [
         ],
     },
     {
+        // StructMethodItem
         'others': [
             {
                 'path': 'doc_alias::Struct',
@@ -76,6 +79,7 @@ const EXPECTED = [
         ],
     },
     {
+        // ImplTraitFunction
         'others': [
             {
                 'path': 'doc_alias::Struct',
@@ -87,6 +91,7 @@ const EXPECTED = [
         ],
     },
     {
+        // EnumItem
         'others': [
             {
                 'path': 'doc_alias',
@@ -98,6 +103,7 @@ const EXPECTED = [
         ],
     },
     {
+        // VariantItem
         'others': [
             {
                 'path': 'doc_alias::Enum',
@@ -109,6 +115,7 @@ const EXPECTED = [
         ],
     },
     {
+        // EnumMethodItem
         'others': [
             {
                 'path': 'doc_alias::Enum',
@@ -120,6 +127,7 @@ const EXPECTED = [
         ],
     },
     {
+        // TypedefItem
         'others': [
             {
                 'path': 'doc_alias',
@@ -131,6 +139,7 @@ const EXPECTED = [
         ],
     },
     {
+        // TraitItem
         'others': [
             {
                 'path': 'doc_alias',
@@ -142,6 +151,7 @@ const EXPECTED = [
         ],
     },
     {
+        // TraitTypeItem
         'others': [
             {
                 'path': 'doc_alias::Trait',
@@ -153,6 +163,7 @@ const EXPECTED = [
         ],
     },
     {
+        // AssociatedConstItem
         'others': [
             {
                 'path': 'doc_alias::Trait',
@@ -164,6 +175,7 @@ const EXPECTED = [
         ],
     },
     {
+        // TraitFunctionItem
         'others': [
             {
                 'path': 'doc_alias::Trait',
@@ -175,6 +187,7 @@ const EXPECTED = [
         ],
     },
     {
+        // FunctionItem
         'others': [
             {
                 'path': 'doc_alias',
@@ -186,6 +199,7 @@ const EXPECTED = [
         ],
     },
     {
+        // ModuleItem
         'others': [
             {
                 'path': 'doc_alias',
@@ -197,6 +211,7 @@ const EXPECTED = [
         ],
     },
     {
+        // ConstItem
         'others': [
             {
                 'path': 'doc_alias',
@@ -212,6 +227,7 @@ const EXPECTED = [
         ],
     },
     {
+        // StaticItem
         'others': [
             {
                 'path': 'doc_alias',
@@ -223,6 +239,7 @@ const EXPECTED = [
         ],
     },
     {
+        // UnionItem
         'others': [
             {
                 'path': 'doc_alias',
@@ -240,6 +257,7 @@ const EXPECTED = [
         ],
     },
     {
+        // UnionFieldItem
         'others': [
             {
                 'path': 'doc_alias::Union',
@@ -251,6 +269,7 @@ const EXPECTED = [
         ],
     },
     {
+        // UnionMethodItem
         'others': [
             {
                 'path': 'doc_alias::Union',
@@ -262,6 +281,7 @@ const EXPECTED = [
         ],
     },
     {
+        // MacroItem
         'others': [
             {
                 'path': 'doc_alias',
index 63a9ad5381244c635e80674ea8eafc11e04bd839..5e5ba7cd9ac8f55c35c4525e182390592ae6c335 100644 (file)
@@ -1,16 +1,18 @@
 // exact-check
 
 const QUERY = [
-    '"R<P>"',
+    'R<P>',
     '"P"',
     'P',
-    '"ExtraCreditStructMulti<ExtraCreditInnerMulti, ExtraCreditInnerMulti>"',
+    'ExtraCreditStructMulti<ExtraCreditInnerMulti, ExtraCreditInnerMulti>',
     'TraitCat',
     'TraitDog',
+    'Result<String>',
 ];
 
 const EXPECTED = [
     {
+        // R<P>
         'returned': [
             { 'path': 'generics', 'name': 'alef' },
         ],
@@ -19,6 +21,7 @@ const EXPECTED = [
         ],
     },
     {
+        // "P"
         'others': [
             { 'path': 'generics', 'name': 'P' },
         ],
@@ -30,29 +33,41 @@ const EXPECTED = [
         ],
     },
     {
+        // P
         'returned': [
             { 'path': 'generics', 'name': 'alef' },
-            { 'path': 'generics', 'name': 'bet' },
         ],
         'in_args': [
             { 'path': 'generics', 'name': 'alpha' },
-            { 'path': 'generics', 'name': 'beta' },
         ],
     },
     {
+        // "ExtraCreditStructMulti"<ExtraCreditInnerMulti, ExtraCreditInnerMulti>
         'in_args': [
             { 'path': 'generics', 'name': 'extracreditlabhomework' },
         ],
         'returned': [],
     },
     {
+        // TraitCat
         'in_args': [
             { 'path': 'generics', 'name': 'gamma' },
         ],
     },
     {
+        // TraitDog
         'in_args': [
             { 'path': 'generics', 'name': 'gamma' },
         ],
     },
+    {
+        // Result<String>
+        'others': [],
+        'returned': [
+            { 'path': 'generics', 'name': 'super_soup' },
+        ],
+        'in_args': [
+            { 'path': 'generics', 'name': 'super_soup' },
+        ],
+    },
 ];
index 5e11a6d6018856f75daaa7e73cc43fe7cd03764e..055c51c7ec5781f819196bbf9e1907b5ff61194b 100644 (file)
@@ -24,3 +24,5 @@ pub trait TraitCat {}
 pub trait TraitDog {}
 
 pub fn gamma<T: TraitCat + TraitDog>(t: T) {}
+
+pub fn super_soup(s: Result<String, i32>) -> Result<String, i32> { s }
index 9465e8e7ab99649bfff1c0a9fe6f64c3f267ca03..7a5156e81c4c875fbd0a5d58bb216ff0b7074b8e 100644 (file)
@@ -1,7 +1,7 @@
 // normalize-stderr-test: "nightly|beta|1\.[0-9][0-9]\.[0-9]" -> "$$CHANNEL"
+// check-pass
 #![deny(warnings)]
 
 //! Email me at <hello@localhost>.
-//~^ ERROR unknown disambiguator `hello`
 
 //! This should *not* warn: <hello@example.com>.
diff --git a/src/test/rustdoc-ui/intra-doc/email-address-localhost.stderr b/src/test/rustdoc-ui/intra-doc/email-address-localhost.stderr
deleted file mode 100644 (file)
index 1b07828..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-error: unknown disambiguator `hello`
-  --> $DIR/email-address-localhost.rs:4:18
-   |
-LL | //! Email me at <hello@localhost>.
-   |                  ^^^^^
-   |
-note: the lint level is defined here
-  --> $DIR/email-address-localhost.rs:2:9
-   |
-LL | #![deny(warnings)]
-   |         ^^^^^^^^
-   = note: `#[deny(rustdoc::broken_intra_doc_links)]` implied by `#[deny(warnings)]`
-   = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
-
-error: aborting due to previous error
-
index 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/early-unindent.rs b/src/test/rustdoc/early-unindent.rs
new file mode 100644 (file)
index 0000000..791a452
--- /dev/null
@@ -0,0 +1,26 @@
+// This is a regression for https://github.com/rust-lang/rust/issues/96079.
+
+#![crate_name = "foo"]
+
+pub mod app {
+    pub struct S;
+
+    impl S {
+        // @has 'foo/app/struct.S.html'
+        // @has - '//a[@href="../enums/enum.Foo.html#method.by_name"]' 'Foo::by_name'
+        /**
+        Doc comment hello! [`Foo::by_name`](`crate::enums::Foo::by_name`).
+        */
+        pub fn whatever(&self) {}
+    }
+}
+
+pub mod enums {
+    pub enum Foo {
+        Bar,
+    }
+
+    impl Foo {
+        pub fn by_name(&self) {}
+    }
+}
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() {}
diff --git a/src/test/rustdoc/where.SWhere_Simd_item-decl.html b/src/test/rustdoc/where.SWhere_Simd_item-decl.html
new file mode 100644 (file)
index 0000000..0133bca
--- /dev/null
@@ -0,0 +1 @@
+<div class="docblock item-decl"><pre class="rust struct"><code>pub struct Simd&lt;T&gt;(_) <br /><span class="where">where<br />&#160;&#160;&#160;&#160;T: <a class="trait" href="trait.MyTrait.html" title="trait foo::MyTrait">MyTrait</a></span>;</code></pre></div>
\ No newline at end of file
diff --git a/src/test/rustdoc/where.SWhere_TraitWhere_item-decl.html b/src/test/rustdoc/where.SWhere_TraitWhere_item-decl.html
new file mode 100644 (file)
index 0000000..54026ff
--- /dev/null
@@ -0,0 +1,3 @@
+<div class="docblock item-decl"><pre class="rust trait"><code>pub trait TraitWhere {
+    type <a href="#associatedtype.Item" class="associatedtype">Item</a>&lt;'a&gt;<br />&#160;&#160;&#160; <span class="where">where<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Self: 'a</span>;
+}</code></pre></div>
\ No newline at end of file
index 549cfff96cb6dc37e5c56aa7f06c99ff778e60dd..50a5722fbaff6926e5feec51c6ffd18d531bac5a 100644 (file)
@@ -1,3 +1,4 @@
+#![feature(generic_associated_types)]
 #![crate_name = "foo"]
 
 pub trait MyTrait { fn dummy(&self) { } }
@@ -19,6 +20,18 @@ pub fn delta() {}
 
 pub struct Echo<E>(E);
 
+// @has 'foo/struct.Simd.html'
+// @snapshot SWhere_Simd_item-decl - '//div[@class="docblock item-decl"]'
+pub struct Simd<T>([T; 1])
+where
+    T: MyTrait;
+
+// @has 'foo/trait.TraitWhere.html'
+// @snapshot SWhere_TraitWhere_item-decl - '//div[@class="docblock item-decl"]'
+pub trait TraitWhere {
+    type Item<'a> where Self: 'a;
+}
+
 // @has foo/struct.Echo.html '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
 //          "impl<E> MyTrait for Echo<E> where E: MyTrait"
 // @has foo/trait.MyTrait.html '//*[@id="implementors-list"]//h3[@class="code-header in-band"]' \
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()
+    );
 }
index 4c4ce8b5e9e493ecd6f22fcc9bd70a9d036b4038..272372ebedc1d01c5f716badcc5c7a6b2c08dffd 100644 (file)
@@ -29,13 +29,13 @@ fn main() {
         //~^ ERROR invalid register `rsp`: the stack pointer cannot be used as an operand
         asm!("", in("ip") foo);
         //~^ ERROR invalid register `ip`: the instruction pointer cannot be used as an operand
-        asm!("", in("k0") foo);
-        //~^ ERROR invalid register `k0`: the k0 AVX mask register cannot be used as an operand
 
         asm!("", in("st(2)") foo);
         //~^ ERROR register class `x87_reg` can only be used as a clobber, not as an input or output
         asm!("", in("mm0") foo);
         //~^ ERROR register class `mmx_reg` can only be used as a clobber, not as an input or output
+        asm!("", in("k0") foo);
+        //~^ ERROR register class `kreg0` can only be used as a clobber, not as an input or output
         asm!("", out("st(2)") _);
         asm!("", out("mm0") _);
         asm!("{}", in(x87_reg) foo);
index f8b024e1acd62c3b7d8891d4cc80ce558a312f63..84b8b5ec2850b77d81505c0b3754e3a20d4f2777 100644 (file)
@@ -64,24 +64,24 @@ error: invalid register `ip`: the instruction pointer cannot be used as an opera
 LL |         asm!("", in("ip") foo);
    |                  ^^^^^^^^^^^^
 
-error: invalid register `k0`: the k0 AVX mask register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:32:18
-   |
-LL |         asm!("", in("k0") foo);
-   |                  ^^^^^^^^^^^^
-
 error: register class `x87_reg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:35:18
+  --> $DIR/bad-reg.rs:33:18
    |
 LL |         asm!("", in("st(2)") foo);
    |                  ^^^^^^^^^^^^^^^
 
 error: register class `mmx_reg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:37:18
+  --> $DIR/bad-reg.rs:35:18
    |
 LL |         asm!("", in("mm0") foo);
    |                  ^^^^^^^^^^^^^
 
+error: register class `kreg0` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:37:18
+   |
+LL |         asm!("", in("k0") foo);
+   |                  ^^^^^^^^^^^^
+
 error: register class `x87_reg` can only be used as a clobber, not as an input or output
   --> $DIR/bad-reg.rs:41:20
    |
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 8b53408d758e110ef55992fc4f94c42390e4f5cd..d73772e5fa0d9b3616287e11efad261464f9dfbf 100644 (file)
@@ -7,5 +7,5 @@ fn g(_: impl Send) {}
 
 fn main() {
     g(issue_67893::run())
-    //~^ ERROR generator cannot be sent between threads safely
+    //~^ ERROR future cannot be sent between threads safely
 }
index 0aa0d5d7ccdde9c30840aaf7f6239a26d456412b..316b6d06f932ac1189cbbe6370beb920c259a178 100644 (file)
@@ -1,10 +1,22 @@
-error: generator cannot be sent between threads safely
+error: future cannot be sent between threads safely
   --> $DIR/issue-67893.rs:9:7
    |
 LL |     g(issue_67893::run())
-   |       ^^^^^^^^^^^^^^^^^^ generator is not `Send`
+   |       ^^^^^^^^^^^^^^^^^^ future is not `Send`
    |
    = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `MutexGuard<'_, ()>`
+note: future is not `Send` as this value is used across an await
+  --> $DIR/auxiliary/issue_67893.rs:9:26
+   |
+LL |     f(*x.lock().unwrap()).await;
+   |        ----------------- ^^^^^^ await occurs here, with `x.lock().unwrap()` maybe used later
+   |        |
+   |        has type `MutexGuard<'_, ()>` which is not `Send`
+note: `x.lock().unwrap()` is later dropped here
+  --> $DIR/auxiliary/issue_67893.rs:9:32
+   |
+LL |     f(*x.lock().unwrap()).await;
+   |                                ^
 note: required by a bound in `g`
   --> $DIR/issue-67893.rs:6:14
    |
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 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); };
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 8f92eeaffd19db4cf60f2a0e6a4a97e75c7025bb..f998c1187d810eb7f73e5631663bb5d7396cb69c 100644 (file)
@@ -13,7 +13,7 @@ error[E0107]: this trait takes 0 generic arguments but 1 generic argument was su
   --> $DIR/issue-87493.rs:8:8
    |
 LL |     T: MyTrait<Assoc == S::Assoc>,
-   |        ^^^^^^^------------------- help: remove these generics
+   |        ^^^^^^^ ----------------- help: replace the generic bound with the associated type: `Assoc = Assoc == S::Assoc`
    |        |
    |        expected 0 generic arguments
    |
index 111d243959a13257b9f9049be77ba4ad96f82ef2..b60bac541f4c815fe892d0a02d491a4cf4d72881 100644 (file)
@@ -119,27 +119,17 @@ LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::tran
                78 00 00 00 ff ff ff ff                         │ x.......
            }
 
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-enum.rs:92:1
+error[E0080]: evaluation of constant value failed
+  --> $DIR/ub-enum.rs:92:77
    |
 LL | const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(Ok)>.0.1: encountered a value of uninhabited type Never
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 4) {
-               00 00 00 00 00 00 00 00                         │ ........
-           }
+   |                                                                             ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
 
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-enum.rs:94:1
+error[E0080]: evaluation of constant value failed
+  --> $DIR/ub-enum.rs:94:77
    |
 LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(Ok)>.0.1: encountered a value of the never type `!`
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 4) {
-               00 00 00 00 00 00 00 00                         │ ........
-           }
+   |                                                                             ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
 
 error: aborting due to 13 previous errors
 
index eee132bae00bc4ab032b3b66ac497cc598c97ac8..1d81e2b3eed86564cf23f96ad99f702a69577dec 100644 (file)
@@ -119,27 +119,17 @@ LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::tran
                78 00 00 00 ff ff ff ff                         │ x.......
            }
 
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-enum.rs:92:1
+error[E0080]: evaluation of constant value failed
+  --> $DIR/ub-enum.rs:92:77
    |
 LL | const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(Ok)>.0.1: encountered a value of uninhabited type Never
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 4) {
-               00 00 00 00 00 00 00 00                         │ ........
-           }
+   |                                                                             ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
 
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-enum.rs:94:1
+error[E0080]: evaluation of constant value failed
+  --> $DIR/ub-enum.rs:94:77
    |
 LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(Ok)>.0.1: encountered a value of the never type `!`
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 4) {
-               00 00 00 00 00 00 00 00                         │ ........
-           }
+   |                                                                             ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
 
 error: aborting due to 13 previous errors
 
index e408d8ec072e318c6faa652c31204789affec2e3..86288685303cab71d3d733a3d6cfda0311fead9d 100644 (file)
@@ -90,9 +90,9 @@ enum UninhDiscriminant {
 // All variants are uninhabited but also have data.
 // Use `0` as constant to make behavior endianess-independent.
 const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) };
-//~^ ERROR is undefined behavior
+//~^ ERROR evaluation of constant value failed
 const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) };
-//~^ ERROR is undefined behavior
+//~^ ERROR evaluation of constant value failed
 
 fn main() {
 }
index 7dc1ec865af8a60a371ef1f4c1bd73d5aa0e2479..65ab1b02b3587d3cbbae56c1946f5e07c4db2f4e 100644 (file)
@@ -7,14 +7,14 @@ 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]: it is undefined behavior to use this value
-  --> $DIR/validate_uninhabited_zsts.rs:16:1
+  --> $DIR/validate_uninhabited_zsts.rs:23:1
    |
-LL | const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at [0]: encountered a value of uninhabited type Empty
+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
    |
    = 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) {}
@@ -31,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; 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::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
+note: enums with no variants have no valid value (in this struct field)
+  --> $DIR/validate_uninhabited_zsts.rs:16:22
+   |
+LL |     pub struct Empty(Void);
+   |                      ^^^^
 
 error: aborting due to 2 previous errors; 2 warnings emitted
 
index 7dc1ec865af8a60a371ef1f4c1bd73d5aa0e2479..65ab1b02b3587d3cbbae56c1946f5e07c4db2f4e 100644 (file)
@@ -7,14 +7,14 @@ 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]: it is undefined behavior to use this value
-  --> $DIR/validate_uninhabited_zsts.rs:16:1
+  --> $DIR/validate_uninhabited_zsts.rs:23:1
    |
-LL | const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at [0]: encountered a value of uninhabited type Empty
+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
    |
    = 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) {}
@@ -31,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; 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::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
+note: enums with no variants have no valid value (in this struct field)
+  --> $DIR/validate_uninhabited_zsts.rs:16:22
+   |
+LL |     pub struct Empty(Void);
+   |                      ^^^^
 
 error: aborting due to 2 previous errors; 2 warnings emitted
 
index 346504845561dc5144198bd3ee3881b0ceef390d..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];
+const BAR: [empty::Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
 //~^ ERROR it is undefined behavior to use this value
-//~| WARN the type `Empty` does not permit zero-initialization
+//~| 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 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/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 840700c9cc6d6526c76de8063a501e21ef27af36..d369fc2a5658b28e3d8ce41d9189084fa4460f89 100644 (file)
@@ -47,4 +47,14 @@ struct Baz<'a, 'b, 'c> {
     //~| HELP remove this lifetime argument
 }
 
+pub trait T {
+    type A;
+    type B;
+}
+
+fn trait_bound_generic<I: T<u8, u16>>(_i: I) {
+    //~^ ERROR this trait takes 0 generic arguments
+    //~| HELP replace the generic bounds with the associated types
+}
+
 fn main() {}
index c90f85df967413b9ffbeae9e271d320ade216124..5ca03b45d82b3851e294cc5d8d62b2fdc6747f41 100644 (file)
@@ -128,6 +128,22 @@ note: struct defined here, with 0 lifetime parameters
 LL | struct Quux<T>(T);
    |        ^^^^
 
-error: aborting due to 9 previous errors
+error[E0107]: this trait takes 0 generic arguments but 2 generic arguments were supplied
+  --> $DIR/E0107.rs:55:27
+   |
+LL | fn trait_bound_generic<I: T<u8, u16>>(_i: I) {
+   |                           ^ expected 0 generic arguments
+   |
+note: trait defined here, with 0 generic parameters
+  --> $DIR/E0107.rs:50:11
+   |
+LL | pub trait T {
+   |           ^
+help: replace the generic bounds with the associated types
+   |
+LL | fn trait_bound_generic<I: T<A = u8, B = u16>>(_i: I) {
+   |                             ~~~~~~  ~~~~~~~
+
+error: aborting due to 10 previous errors
 
 For more information about this error, try `rustc --explain E0107`.
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();
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 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 9988acbcb73e198918e324cee34336a730b42374..92305609c835c6248b50d13477d9fd0c0cec387a 100644 (file)
@@ -1,5 +1,6 @@
 // edition:2021
 // run-pass
+// compile-flags: -Zdrop-tracking
 
 #![feature(never_type)]
 
@@ -32,7 +33,7 @@ fn never() -> Never {
 }
 
 async fn includes_never(crash: bool, x: u32) -> u32 {
-    let mut result = async { x * x }.await;
+    let result = async { x * x }.await;
     if !crash {
         return result;
     }
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..aaeec920527edfbc43ee3ceacc0a107d6790567e 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,7 +83,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:35:8
+  --> $DIR/missing-bounds.rs:33:8
    |
 LL | struct E<B>(B);
    |        ^
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
+
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 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 9589b69491e251c19138f26223031e35b32eb66c..5a190649b63191436cd3db3ab939f774f32e4e34 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
@@ -82,10 +112,11 @@ 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
    |
+LL | fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static {
+   |                                 -- help: consider adding an explicit lifetime bound...: `T: 'static +`
+...
 LL |     x
-   |     ^
-   |
-   = help: consider adding an explicit lifetime bound `T: 'static`...
+   |     ^ ...so that the type `T` will meet its required lifetime bounds
 
 error: aborting due to 9 previous errors
 
index b1175a5952e592a7a575da8413050c2e18f3d29f..5328b077993c5ae2056c4c447e222467b492a56d 100644 (file)
@@ -1,10 +1,11 @@
 error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/type_parameters_captured.rs:10:5
    |
+LL | fn foo<T>(x: T) -> impl Any + 'static {
+   |        - help: consider adding an explicit lifetime bound...: `T: 'static`
+...
 LL |     x
-   |     ^
-   |
-   = help: consider adding an explicit lifetime bound `T: 'static`...
+   |     ^ ...so that the type `T` will meet its required lifetime bounds
 
 error: aborting due to previous error
 
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 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-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-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::<()>();
-}
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 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 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-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-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`.
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-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/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
+
index 5509226cb1cdd83c5c8eebcc6cae3673e52a9e53..422673b361a95b2ebcdd73de1a64b8f20b83033f 100644 (file)
@@ -1,10 +1,10 @@
 error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/issue_74400.rs:12:5
    |
+LL | fn g<T>(data: &[T]) {
+   |      - help: consider adding an explicit lifetime bound...: `T: 'static`
 LL |     f(data, identity)
-   |     ^^^^^^^^^^^^^^^^^
-   |
-   = help: consider adding an explicit lifetime bound `T: 'static`...
+   |     ^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
 
 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-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 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`.
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..b6856089a84f9f18abde1af4766d301da898b536 100644 (file)
@@ -36,6 +36,9 @@ LL | | }
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/propagate-from-trait-match.rs:32:36
    |
+LL |   fn supply<'a, T>(value: T)
+   |                 - help: consider adding an explicit lifetime bound...: `T: 'a`
+...
 LL |       establish_relationships(value, |value| {
    |  ____________________________________^
 LL | |
@@ -44,9 +47,7 @@ LL | |         // This function call requires that
 ...  |
 LL | |         require(value);
 LL | |     });
-   | |_____^
-   |
-   = help: consider adding an explicit lifetime bound `T: 'a`...
+   | |_____^ ...so that the type `T` will meet its required lifetime bounds
 
 error: aborting due to previous error
 
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..3d4cfc1610a6690757a8768e2e3249b11974756d 100644 (file)
@@ -1,18 +1,20 @@
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/impl-trait-outlives.rs:11:5
    |
+LL | fn no_region<'a, T>(x: Box<T>) -> impl Debug + 'a
+   |                  - help: consider adding an explicit lifetime bound...: `T: 'a`
+...
 LL |     x
-   |     ^
-   |
-   = help: consider adding an explicit lifetime bound `T: 'a`...
+   |     ^ ...so that the type `T` will meet its required lifetime bounds
 
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/impl-trait-outlives.rs:26:5
    |
+LL | fn wrong_region<'a, 'b, T>(x: Box<T>) -> impl Debug + 'a
+   |                         - help: consider adding an explicit lifetime bound...: `T: 'a`
+...
 LL |     x
-   |     ^
-   |
-   = help: consider adding an explicit lifetime bound `T: 'a`...
+   |     ^ ...so that the type `T` will meet its required lifetime bounds
 
 error: aborting due to 2 previous errors
 
index 9f0c60c1e1705a34424e546f32cc55a44bdb440f..cc5aa1eb11ec039c74e920ef179154efb7f0ca3c 100644 (file)
@@ -1,10 +1,10 @@
 error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/projection-implied-bounds.rs:30:18
    |
+LL | fn generic2<T: Iterator>(value: T) {
+   |             -- help: consider adding an explicit lifetime bound...: `T: 'static +`
 LL |     twice(value, |value_ref, item| invoke2(value_ref, item));
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: consider adding an explicit lifetime bound `T: 'static`...
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
 
 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..62db6dd845a28165709c3960c5f6540ae74cdbe5 100644 (file)
@@ -31,10 +31,11 @@ LL | | }
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/projection-one-region-closure.rs:45:29
    |
+LL | fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+   |                                  - help: consider adding an explicit lifetime bound...: `T: 'a`
+...
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
-   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: consider adding an explicit lifetime bound `T: 'a`...
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
 
 error: lifetime may not live long enough
   --> $DIR/projection-one-region-closure.rs:45:39
@@ -81,10 +82,11 @@ LL | | }
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/projection-one-region-closure.rs:56:29
    |
+LL | fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+   |                                   - help: consider adding an explicit lifetime bound...: `T: 'a`
+...
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
-   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: consider adding an explicit lifetime bound `T: 'a`...
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
 
 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..c51edb7868d7a8ef880c72ab02a77532cdae021f 100644 (file)
@@ -1,10 +1,11 @@
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/projection-where-clause-none.rs:16:5
    |
+LL | fn foo<'a, T>() -> &'a ()
+   |            - help: consider adding an explicit lifetime bound...: `T: 'a`
+...
 LL |     bar::<T::Output>()
-   |     ^^^^^^^^^^^^^^^^
-   |
-   = help: consider adding an explicit lifetime bound `T: 'a`...
+   |     ^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
 
 error: aborting due to previous error
 
index baf223b786b080709fd7ba3629f507d1f96f3d36..3e5e4868341edf613f176f1cf973fde0c61d3527 100644 (file)
@@ -52,10 +52,10 @@ LL | | }
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/ty-param-closure-approximate-lower-bound.rs:29:24
    |
+LL | fn generic_fail<'a, T>(cell: Cell<&'a ()>, value: T) {
+   |                     - help: consider adding an explicit lifetime bound...: `T: 'a`
 LL |     twice(cell, value, |a, b| invoke(a, b));
-   |                        ^^^^^^^^^^^^^^^^^^^
-   |
-   = help: consider adding an explicit lifetime bound `T: 'a`...
+   |                        ^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
 
 error: aborting due to previous error
 
index 88d73e7a729a92f5826d545af0bcf947c986f650..dc2f23b4fc8a33b8bcd4f4357b00fd5110334995 100644 (file)
@@ -29,18 +29,20 @@ LL | | }
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/ty-param-closure-outlives-from-return-type.rs:26:23
    |
+LL | fn no_region<'a, T>(x: Box<T>) -> Box<dyn Debug + 'a>
+   |                  - help: consider adding an explicit lifetime bound...: `T: 'a`
+...
 LL |     with_signature(x, |y| y)
-   |                       ^^^^^
-   |
-   = help: consider adding an explicit lifetime bound `T: 'a`...
+   |                       ^^^^^ ...so that the type `T` will meet its required lifetime bounds
 
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/ty-param-closure-outlives-from-return-type.rs:41:5
    |
+LL | fn wrong_region<'a, 'b, T>(x: Box<T>) -> Box<Debug + 'a>
+   |                         - help: consider adding an explicit lifetime bound...: `T: 'a`
+...
 LL |     x
-   |     ^
-   |
-   = help: consider adding an explicit lifetime bound `T: 'a`...
+   |     ^ ...so that the type `T` will meet its required lifetime bounds
 
 error: aborting due to 2 previous errors
 
index 5b175aac1e1cb774de1787b5ca8cdac6abbb2fd8..e9f728c77b34b9d0420906052b5b6650c56bf6ed 100644 (file)
@@ -37,6 +37,8 @@ LL | | }
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/ty-param-closure-outlives-from-where-clause.rs:27:26
    |
+LL |   fn no_region<'a, T>(a: Cell<&'a ()>, b: T) {
+   |                    - help: consider adding an explicit lifetime bound...: `T: 'a`
 LL |       with_signature(a, b, |x, y| {
    |  __________________________^
 LL | |
@@ -45,9 +47,7 @@ LL | |         // See `correct_region`, which explains the point of this
 ...  |
 LL | |         require(&x, &y)
 LL | |     })
-   | |_____^
-   |
-   = help: consider adding an explicit lifetime bound `T: 'a`...
+   | |_____^ ...so that the type `T` will meet its required lifetime bounds
 
 note: external requirements
   --> $DIR/ty-param-closure-outlives-from-where-clause.rs:43:26
@@ -121,15 +121,16 @@ LL | | }
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/ty-param-closure-outlives-from-where-clause.rs:64:26
    |
+LL |   fn wrong_region<'a, 'b, T>(a: Cell<&'a ()>, b: T)
+   |                           - help: consider adding an explicit lifetime bound...: `T: 'a`
+...
 LL |       with_signature(a, b, |x, y| {
    |  __________________________^
 LL | |
 LL | |         // See `correct_region`
 LL | |         require(&x, &y)
 LL | |     })
-   | |_____^
-   |
-   = help: consider adding an explicit lifetime bound `T: 'a`...
+   | |_____^ ...so that the type `T` will meet its required lifetime bounds
 
 note: external requirements
   --> $DIR/ty-param-closure-outlives-from-where-clause.rs:77:26
index 9a023a0e58e5f061efe3a2f517dbe947378ad663..a2e6a5d57cd6278891798e1640c6fd3f43268774 100644 (file)
@@ -1,10 +1,10 @@
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/ty-param-fn-body.rs:19:5
    |
+LL | fn region_static<'a, T>(cell: Cell<&'a usize>, t: T) {
+   |                      - help: consider adding an explicit lifetime bound...: `T: 'a`
 LL |     outlives(cell, t)
-   |     ^^^^^^^^^^^^^^^^^
-   |
-   = help: consider adding an explicit lifetime bound `T: 'a`...
+   |     ^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
 
 error: aborting due to previous error
 
index 8c8529620d57fd401b23b7e54693b49a7b9546d7..fce360dd54bfb28d84ca2f2efc7bd9525c1eea90 100644 (file)
@@ -1,18 +1,20 @@
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/ty-param-fn.rs:11:5
    |
+LL | fn no_region<'a, T>(x: Box<T>) -> Box<Debug + 'a>
+   |                  - help: consider adding an explicit lifetime bound...: `T: 'a`
+...
 LL |     x
-   |     ^
-   |
-   = help: consider adding an explicit lifetime bound `T: 'a`...
+   |     ^ ...so that the type `T` will meet its required lifetime bounds
 
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/ty-param-fn.rs:26:5
    |
+LL | fn wrong_region<'a, 'b, T>(x: Box<T>) -> Box<Debug + 'a>
+   |                         - help: consider adding an explicit lifetime bound...: `T: 'a`
+...
 LL |     x
-   |     ^
-   |
-   = help: consider adding an explicit lifetime bound `T: 'a`...
+   |     ^ ...so that the type `T` will meet its required lifetime bounds
 
 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/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 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/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..05ddc09b2d0b7a31a37969a18b48a571e671075f 100644 (file)
@@ -1,37 +1,46 @@
 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 | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
+   |             - help: consider adding an explicit lifetime bound...: `U: 'static`
 LL |     Box::new(B(&*v)) as Box<dyn X>
-   |     ^^^^^^^^
-   |
-   = help: consider adding an explicit lifetime bound `U: 'static`...
+   |     ^^^^^^^^ ...so that the type `U` will meet its required lifetime bounds
 
 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 | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
+   |             - help: consider adding an explicit lifetime bound...: `U: 'static`
 LL |     Box::new(B(&*v)) as Box<dyn X>
-   |     ^^^^^^^^^^^^^^^^
-   |
-   = help: consider adding an explicit lifetime bound `U: 'static`...
+   |     ^^^^^^^^^^^^^^^^ ...so that the type `U` will meet its required lifetime bounds
 
 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 | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
+   |             - help: consider adding an explicit lifetime bound...: `U: 'static`
 LL |     Box::new(B(&*v)) as Box<dyn X>
-   |     ^^^^^^^^^^^^^^^^
-   |
-   = help: consider adding an explicit lifetime bound `U: 'static`...
+   |     ^^^^^^^^^^^^^^^^ ...so that the type `U` will meet its required lifetime bounds
 
 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 +49,12 @@ 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 | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
+   |             - help: consider adding an explicit lifetime bound...: `U: 'static`
 LL |     Box::new(B(&*v)) as Box<dyn X>
-   |              ^^^^^^
-   |
-   = help: consider adding an explicit lifetime bound `U: 'static`...
+   |              ^^^^^^ ...so that the type `U` will meet its required lifetime bounds
 
 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..8b5a06b
--- /dev/null
@@ -0,0 +1,84 @@
+error[E0310]: the parameter type `T` may not live long enough
+  --> $DIR/regions-close-object-into-object-5.rs:21: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:13: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:21: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:21: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:13: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:21: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:13: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:21: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:21: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:21: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`.
index 7486e73e66ab31122bda6f9b0af5301668a2cc94..f4e3809e91613116378111caee1241f96ccdabbd 100644 (file)
@@ -1,29 +1,32 @@
 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 | 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>
-   |     ^^^^^^^^
-   |
-   = help: consider adding an explicit lifetime bound `T: 'static`...
+   |     ^^^^^^^^ ...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-object-into-object-5.rs:17:5
+  --> $DIR/regions-close-object-into-object-5.rs:21: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>
-   |     ^^^^^^^^^^^^^^^^
-   |
-   = help: consider adding an explicit lifetime bound `T: 'static`...
+   |     ^^^^^^^^^^^^^^^^ ...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-object-into-object-5.rs:17:5
+  --> $DIR/regions-close-object-into-object-5.rs:21: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>
-   |     ^^^^^^^^^^^^^^^^
-   |
-   = help: consider adding an explicit lifetime bound `T: 'static`...
+   |     ^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
 
 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 +35,13 @@ 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 | 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>
-   |              ^^^^^^
-   |
-   = help: consider adding an explicit lifetime bound `T: 'static`...
+   |              ^^^^^^ ...so that the type `T` will meet its required lifetime bounds
 
 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..41dc03e
--- /dev/null
@@ -0,0 +1,20 @@
+error[E0310]: the parameter type `A` may not live long enough
+  --> $DIR/regions-close-over-type-parameter-1.rs:15: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:24: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`.
index b576ae87011377d25a1a6f8c53a1554ef63fdc81..41dc03e86dd85ff4506b33958e3575e42ee6dc40 100644 (file)
@@ -1,18 +1,18 @@
 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 | 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>
-   |     ^^^^^^^^^^^
-   |
-   = help: consider adding an explicit lifetime bound `A: '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
+  --> $DIR/regions-close-over-type-parameter-1.rs:24: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>
-   |     ^^^^^^^^^^^
-   |
-   = help: consider adding an explicit lifetime bound `A: 'b`...
+   |     ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
 
 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..7e135c6
--- /dev/null
@@ -0,0 +1,40 @@
+error[E0310]: the parameter type `T` may not live long enough
+  --> $DIR/regions-close-param-into-object.rs:10: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:16: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:22: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:28: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`.
index 7bd7824f00a462ccebf0da80ebbc0aa95c385ccc..3fbc1022631152ba85f747b640ed4677855fdf5f 100644 (file)
@@ -1,34 +1,38 @@
 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 | fn p1<T>(v: T) -> Box<dyn X + 'static>
+   |       - help: consider adding an explicit lifetime bound...: `T: 'static`
+...
 LL |     Box::new(v)
-   |     ^^^^^^^^^^^
-   |
-   = help: consider adding an explicit lifetime bound `T: 'static`...
+   |     ^^^^^^^^^^^ ...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
+  --> $DIR/regions-close-param-into-object.rs:16: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)
-   |     ^^^^^^^^^^^
-   |
-   = help: consider adding an explicit lifetime bound `T: 'static`...
+   |     ^^^^^^^^^^^ ...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:18:5
+  --> $DIR/regions-close-param-into-object.rs:22: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)
-   |     ^^^^^^^^^^^
-   |
-   = help: consider adding an explicit lifetime bound `T: 'a`...
+   |     ^^^^^^^^^^^ ...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
+  --> $DIR/regions-close-param-into-object.rs:28: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)
-   |     ^^^^^^^^^^^
-   |
-   = help: consider adding an explicit lifetime bound `T: 'a`...
+   |     ^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
 
 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`.
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..ef68674
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0309]: the parameter type `T` may not live long enough
+  --> $DIR/regions-implied-bounds-projection-gap-1.rs:20: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`.
index 0f0f86dfcdd693c4221cd7010e357ac243282870..6d63de6d6bd95b5ccb0a686c0b14d56cecc9b191 100644 (file)
@@ -1,10 +1,11 @@
 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 | fn func<'x, T:Trait1<'x>>(t: &'x T::Foo)
+   |             -- help: consider adding an explicit lifetime bound...: `T: 'x +`
+LL | {
 LL |     wf::<&'x T>();
-   |     ^^^^^^^^^^^
-   |
-   = help: consider adding an explicit lifetime bound `T: 'x`...
+   |     ^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
 
 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..6a7e8ba
--- /dev/null
@@ -0,0 +1,31 @@
+error[E0309]: the parameter type `A` may not live long enough
+  --> $DIR/regions-infer-bound-from-trait.rs:37: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:16: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:41: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:16: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`.
index 1f7b34fc69962937095054765c206c8fed2dc255..4aa4b468eaa7237743314f72f9b3a04f1774349d 100644 (file)
@@ -1,18 +1,18 @@
 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 | fn bar1<'a,A>(x: Inv<'a>, a: A) {
+   |            - help: consider adding an explicit lifetime bound...: `A: 'a`
 LL |     check_bound(x, a)
-   |     ^^^^^^^^^^^^^^^^^
-   |
-   = help: consider adding an explicit lifetime bound `A: 'a`...
+   |     ^^^^^^^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
 
 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 | 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)
-   |     ^^^^^^^^^^^^^^^^^
-   |
-   = help: consider adding an explicit lifetime bound `A: 'a`...
+   |     ^^^^^^^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
 
 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`.
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..b37ce1e
--- /dev/null
@@ -0,0 +1,46 @@
+error[E0312]: lifetime of reference outlives lifetime of borrowed content...
+  --> $DIR/regions-static-bound.rs:10: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:9: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:16: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:16: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:19: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:19: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`.
index 699638c7ef9b23142eb303efdc02d3a00d14cf58..d228c42f9957921d1c4c720dea0ea24b03edaaba 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/regions-static-bound.rs:6:5
+  --> $DIR/regions-static-bound.rs:10:5
    |
 LL | fn static_id_wrong_way<'a>(t: &'a ()) -> &'static () where 'static: 'a {
    |                        -- lifetime `'a` defined here
@@ -7,7 +7,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:16:5
    |
 LL | fn error(u: &(), v: &()) {
    |          -  - let's call the lifetime of this reference `'1`
@@ -20,13 +20,13 @@ 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:19: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);
    |     ^^^^^^^^^^^^^^^^^^^^^^
    |     |
index a977a8b36d0563babb348b4eb1b7af78a5cd0f29..058b717c95daa38c9bae4b7d28254329ee33b0b5 100644 (file)
@@ -1,14 +1,24 @@
+// 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 }
 fn static_id_indirect<'a,'b>(t: &'a ()) -> &'static ()
     where 'a: 'b, 'b: 'static { t }
 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`.
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 6d389a1317a9fa2f4efa45870520388a9cc4b80d..364c8c8f7069e9e7a98b621ef5719bccde8c45d1 100644 (file)
@@ -1,5 +1,5 @@
 error: implementation of `FnOnce` is not general enough
-  --> $DIR/rfc1623.rs:36:8
+  --> $DIR/rfc1623.rs:32:8
    |
 LL |     f: &id,
    |        ^^^ implementation of `FnOnce` is not general enough
index f85b6ff8ff75b2a0431d8e43e50ce0fe97a4bb55..2eff4708547d80acac58f3492a104d421b1f7818 100644 (file)
@@ -1,63 +1,35 @@
 error[E0308]: mismatched types
-  --> $DIR/rfc1623.rs:29:35
+  --> $DIR/rfc1623.rs:32:8
    |
-LL |   static SOME_STRUCT: &SomeStruct = &SomeStruct {
-   |  ___________________________________^
-LL | |
-LL | |
-LL | |
-...  |
-LL | |
-LL | | };
-   | |_^ one type is more general than the other
+LL |     f: &id,
+   |        ^^^ one type is more general than the other
    |
    = note: expected type `for<'a, 'b> Fn<(&'a Foo<'b>,)>`
               found type `Fn<(&Foo<'_>,)>`
 
 error[E0308]: mismatched types
-  --> $DIR/rfc1623.rs:29:35
+  --> $DIR/rfc1623.rs:32:8
    |
-LL |   static SOME_STRUCT: &SomeStruct = &SomeStruct {
-   |  ___________________________________^
-LL | |
-LL | |
-LL | |
-...  |
-LL | |
-LL | | };
-   | |_^ one type is more general than the other
+LL |     f: &id,
+   |        ^^^ one type is more general than the other
    |
    = note: expected type `for<'a, 'b> Fn<(&'a Foo<'b>,)>`
               found type `Fn<(&Foo<'_>,)>`
 
 error: implementation of `FnOnce` is not general enough
-  --> $DIR/rfc1623.rs:29:35
+  --> $DIR/rfc1623.rs:32:8
    |
-LL |   static SOME_STRUCT: &SomeStruct = &SomeStruct {
-   |  ___________________________________^
-LL | |
-LL | |
-LL | |
-...  |
-LL | |
-LL | | };
-   | |_^ implementation of `FnOnce` is not general enough
+LL |     f: &id,
+   |        ^^^ implementation of `FnOnce` is not general enough
    |
    = note: `fn(&'2 Foo<'_>) -> &'2 Foo<'_> {id::<&'2 Foo<'_>>}` must implement `FnOnce<(&'1 Foo<'b>,)>`, for any lifetime `'1`...
    = note: ...but it actually implements `FnOnce<(&'2 Foo<'_>,)>`, for some specific lifetime `'2`
 
 error: implementation of `FnOnce` is not general enough
-  --> $DIR/rfc1623.rs:29:35
+  --> $DIR/rfc1623.rs:32:8
    |
-LL |   static SOME_STRUCT: &SomeStruct = &SomeStruct {
-   |  ___________________________________^
-LL | |
-LL | |
-LL | |
-...  |
-LL | |
-LL | | };
-   | |_^ implementation of `FnOnce` is not general enough
+LL |     f: &id,
+   |        ^^^ implementation of `FnOnce` is not general enough
    |
    = note: `fn(&Foo<'2>) -> &Foo<'2> {id::<&Foo<'2>>}` must implement `FnOnce<(&'a Foo<'1>,)>`, for any lifetime `'1`...
    = note: ...but it actually implements `FnOnce<(&Foo<'2>,)>`, for some specific lifetime `'2`
index 0e9d2140324256dbdcccab92e0fb3c9837ba5335..443da0aa955f982755b4300fc2732719984713ab 100644 (file)
@@ -27,14 +27,14 @@ fn id<T>(t: T) -> T {
 }
 
 static SOME_STRUCT: &SomeStruct = &SomeStruct {
-    //[nll]~^ ERROR mismatched types
-    //[nll]~| ERROR mismatched types
-    //[nll]~| ERROR implementation of `FnOnce` is not general enough
-    //[nll]~| ERROR implementation of `FnOnce` is not general enough
     foo: &Foo { bools: &[false, true] },
     bar: &Bar { bools: &[true, true] },
     f: &id,
     //[base]~^ ERROR implementation of `FnOnce` is not general enough
+    //[nll]~^^ ERROR mismatched types
+    //[nll]~| ERROR mismatched types
+    //[nll]~| ERROR implementation of `FnOnce` is not general enough
+    //[nll]~| ERROR implementation of `FnOnce` is not general enough
 };
 
 // very simple test for a 'static static with default lifetime
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]`
index d5645474891062e2a43bddacdcf8fbe0ab450e7f..f5c6f444317feb7cbc643dbb43b15e1647ec6f8b 100644 (file)
@@ -11,11 +11,11 @@ enum Void {}
 
 static VOID2: Void = unsafe { std::mem::transmute(()) }; //~ ERROR static of uninhabited type
 //~| WARN: previously accepted
-//~| ERROR undefined behavior to use this value
+//~| ERROR could not evaluate static initializer
 //~| WARN: type `Void` does not permit zero-initialization
 static NEVER2: Void = unsafe { std::mem::transmute(()) }; //~ ERROR static of uninhabited type
 //~| WARN: previously accepted
-//~| ERROR undefined behavior to use this value
+//~| ERROR could not evaluate static initializer
 //~| WARN: type `Void` does not permit zero-initialization
 
 fn main() {}
index c38cf10d6e648bfad53cb16009a3d2c4c5759329..1e0becb7d5aa87662c33250585821911f2962a78 100644 (file)
@@ -43,23 +43,17 @@ LL | static NEVER2: Void = unsafe { std::mem::transmute(()) };
    = note: for more information, see issue #74840 <https://github.com/rust-lang/rust/issues/74840>
    = note: uninhabited statics cannot be initialized, and any access would be an immediate error
 
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/uninhabited-static.rs:12:1
+error[E0080]: could not evaluate static initializer
+  --> $DIR/uninhabited-static.rs:12:31
    |
 LL | static VOID2: Void = unsafe { std::mem::transmute(()) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Void
-   |
-   = 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) {}
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
 
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/uninhabited-static.rs:16:1
+error[E0080]: could not evaluate static initializer
+  --> $DIR/uninhabited-static.rs:16:32
    |
 LL | static NEVER2: Void = unsafe { std::mem::transmute(()) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Void
-   |
-   = 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) {}
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
 
 warning: the type `Void` does not permit zero-initialization
   --> $DIR/uninhabited-static.rs:12:31
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 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
 
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 536494c73445ceeaf3a6113d0bbda805afd51626..d38d66c08853c44c3c5e40ac4971016ce5b92ebd 100644 (file)
@@ -1,6 +1,8 @@
 error[E0311]: the parameter type `T` may not live long enough
   --> $DIR/missing-lifetimes-in-signature-2.rs:20:5
    |
+LL |   fn func<T: Test>(foo: &Foo, t: T) {
+   |           -- help: consider adding an explicit lifetime bound...: `T: 'a +`
 LL | /     foo.bar(move |_| {
 LL | |
 LL | |         t.test();
@@ -12,6 +14,14 @@ 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 | |     });
+   | |______^
 
 error: aborting due to previous error
 
index 0ae629676fec7dfe4525a2fe36ab9403484a6e55..4a18e0a4f8bbdae43586fa01289f3277e01df8f3 100644 (file)
@@ -26,6 +26,9 @@ 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
    |
+LL |   fn bar<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+   |          - help: consider adding an explicit lifetime bound...: `G: 'a`
+...
 LL | /     move || {
 LL | |         *dest = g.get();
 LL | |     }
@@ -36,10 +39,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:32:5
+   |
+LL | /     move || {
+LL | |         *dest = g.get();
+LL | |     }
+   | |_____^
 
 error[E0311]: the parameter type `G` may not live long enough
   --> $DIR/missing-lifetimes-in-signature.rs:55:5
    |
+LL |   fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+   |              -- help: consider adding an explicit lifetime bound...: `G: 'b +`
+...
 LL | /     move || {
 LL | |         *dest = g.get();
 LL | |     }
@@ -50,10 +63,20 @@ note: the parameter type `G` must be valid for the anonymous lifetime defined he
    |
 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:55:5
+   |
+LL | /     move || {
+LL | |         *dest = g.get();
+LL | |     }
+   | |_____^
 
 error[E0311]: the parameter type `G` may not live long enough
   --> $DIR/missing-lifetimes-in-signature.rs:65:9
    |
+LL |       fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
+   |                  -- help: consider adding an explicit lifetime bound...: `G: 'c +`
+...
 LL | /         move || {
 LL | |             *dest = g.get();
 LL | |         }
@@ -64,10 +87,20 @@ note: the parameter type `G` must be valid for the anonymous lifetime defined he
    |
 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:65:9
+   |
+LL | /         move || {
+LL | |             *dest = g.get();
+LL | |         }
+   | |_________^
 
 error[E0311]: the parameter type `G` may not live long enough
   --> $DIR/missing-lifetimes-in-signature.rs:77:5
    |
+LL |   fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a
+   |              -- help: consider adding an explicit lifetime bound...: `G: 'b +`
+...
 LL | /     move || {
 LL | |         *dest = g.get();
 LL | |     }
@@ -78,6 +111,13 @@ note: the parameter type `G` must be valid for the anonymous lifetime defined he
    |
 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:77:5
+   |
+LL | /     move || {
+LL | |         *dest = g.get();
+LL | |     }
+   | |_____^
 
 error[E0621]: explicit lifetime required in the type of `dest`
   --> $DIR/missing-lifetimes-in-signature.rs:77:5
@@ -93,12 +133,13 @@ LL | |     }
 error[E0309]: the parameter type `G` may not live long enough
   --> $DIR/missing-lifetimes-in-signature.rs:89:5
    |
+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 | /     move || {
 LL | |         *dest = g.get();
 LL | |     }
-   | |_____^
-   |
-   = help: consider adding an explicit lifetime bound `G: 'a`...
+   | |_____^ ...so that the type `G` will meet its required lifetime bounds
 
 error: aborting due to 8 previous errors
 
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
 
diff --git a/src/test/ui/suggestions/pattern-struct-with-slice-vec-field.rs b/src/test/ui/suggestions/pattern-struct-with-slice-vec-field.rs
new file mode 100644 (file)
index 0000000..5b223a9
--- /dev/null
@@ -0,0 +1,35 @@
+use std::ops::Deref;
+
+struct Foo {
+    v: Vec<u32>,
+}
+
+struct Bar {
+    v: Vec<u32>,
+}
+
+impl Deref for Bar {
+    type Target = Vec<u32>;
+
+    fn deref(&self) -> &Self::Target {
+        &self.v
+    }
+}
+
+fn f(foo: &Foo) {
+    match foo {
+        Foo { v: [1, 2] } => {}
+        //~^ ERROR expected an array or slice, found `Vec<u32>
+        _ => {}
+    }
+}
+
+fn bar(bar: &Bar) {
+    match bar {
+        Bar { v: [1, 2] } => {}
+        //~^ ERROR expected an array or slice, found `Vec<u32>
+        _ => {}
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/pattern-struct-with-slice-vec-field.stderr b/src/test/ui/suggestions/pattern-struct-with-slice-vec-field.stderr
new file mode 100644 (file)
index 0000000..5b48a8b
--- /dev/null
@@ -0,0 +1,15 @@
+error[E0529]: expected an array or slice, found `Vec<u32>`
+  --> $DIR/pattern-struct-with-slice-vec-field.rs:21:18
+   |
+LL |         Foo { v: [1, 2] } => {}
+   |                  ^^^^^^ pattern cannot match with input type `Vec<u32>`
+
+error[E0529]: expected an array or slice, found `Vec<u32>`
+  --> $DIR/pattern-struct-with-slice-vec-field.rs:29:18
+   |
+LL |         Bar { v: [1, 2] } => {}
+   |                  ^^^^^^ pattern cannot match with input type `Vec<u32>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0529`.
index f4eb9813c1ac77f3fe19621fecfe149db2659b95..72354eaaee14722238109e763ec54448bcef449f 100644 (file)
@@ -1,10 +1,11 @@
 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);
-   |     ^^^^^^
-   |
-   = help: consider adding an explicit lifetime bound `impl Debug: 'static`...
+   |     ^^^^^^ ...so that the type `impl Debug` will meet its required lifetime bounds
 
 error: aborting due to previous error
 
index 5a158e5876a069a23049d6872a15ee22ca3a47ba..5409e32c436fbd9ff1e26dc88901e133362c55f3 100644 (file)
@@ -2,15 +2,17 @@ error[E0107]: this trait takes 2 generic arguments but 4 generic arguments were
   --> $DIR/use-type-argument-instead-of-assoc-type.rs:7:16
    |
 LL |     i: Box<dyn T<usize, usize, usize, usize, B=usize>>,
-   |                ^               ------------ help: remove these generic arguments
-   |                |
-   |                expected 2 generic arguments
+   |                ^ expected 2 generic arguments
    |
 note: trait defined here, with 2 generic parameters: `X`, `Y`
   --> $DIR/use-type-argument-instead-of-assoc-type.rs:1:11
    |
 LL | pub trait T<X, Y> {
    |           ^ -  -
+help: replace the generic bounds with the associated types
+   |
+LL |     i: Box<dyn T<usize, usize, A = usize, C = usize, B=usize>>,
+   |                                ~~~~~~~~~  ~~~~~~~~~
 
 error[E0191]: the value of the associated types `A` (from trait `T`), `C` (from trait `T`) must be specified
   --> $DIR/use-type-argument-instead-of-assoc-type.rs:7:16
@@ -23,11 +25,6 @@ LL |     type C;
 ...
 LL |     i: Box<dyn T<usize, usize, usize, usize, B=usize>>,
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ associated types `A`, `C` must be specified
-   |
-help: specify the associated types
-   |
-LL |     i: Box<dyn T<usize, usize, A = usize, C = usize, B=usize>>,
-   |                                ~~~~~~~~~  ~~~~~~~~~
 
 error: aborting due to 2 previous errors
 
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/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;
+}
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 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 db771d211322c8f53776a358d3e67c210c140468..a3b410c2cfb8c4946c53b40be46e6e828b4bf979 100644 (file)
@@ -19,10 +19,10 @@ 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
-   |     ^
-   |
-   = help: consider adding an explicit lifetime bound `T: 'static`...
+   |     ^ ...so that the type `T` will meet its required lifetime bounds
 
 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 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`.
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
 
diff --git a/src/test/ui/uninhabited/privately-uninhabited-mir-call.rs b/src/test/ui/uninhabited/privately-uninhabited-mir-call.rs
new file mode 100644 (file)
index 0000000..b37ec26
--- /dev/null
@@ -0,0 +1,29 @@
+// Verifies that MIR building for a call expression respects
+// privacy when checking if a call return type is uninhabited.
+
+pub mod widget {
+    enum Unimplemented {}
+    pub struct Widget(Unimplemented);
+
+    impl Widget {
+        pub fn new() -> Widget {
+            todo!();
+        }
+    }
+
+    pub fn f() {
+        let x: &mut u32;
+        Widget::new();
+        // Ok. Widget type returned from new is known to be uninhabited
+        // and the following code is considered unreachable.
+        *x = 1;
+    }
+}
+
+fn main() {
+    let y: &mut u32;
+    widget::Widget::new();
+    // Error. Widget type is not known to be uninhabited here,
+    // so the following code is considered reachable.
+    *y = 2; //~ ERROR use of possibly-uninitialized variable
+}
diff --git a/src/test/ui/uninhabited/privately-uninhabited-mir-call.stderr b/src/test/ui/uninhabited/privately-uninhabited-mir-call.stderr
new file mode 100644 (file)
index 0000000..fb19534
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0381]: use of possibly-uninitialized variable: `y`
+  --> $DIR/privately-uninhabited-mir-call.rs:28:5
+   |
+LL |     *y = 2;
+   |     ^^^^^^ use of possibly-uninitialized `y`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0381`.
index 33f762ccf63016a0f1f9a94c5bd3ec1614b18e7a..e7960960774fcdf54641b50b5c913cc4482f57bc 100644 (file)
@@ -1,11 +1,27 @@
 error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
-  --> $DIR/issue-45087-unreachable-unsafe.rs:6:5
+  --> $DIR/issue-45087-unreachable-unsafe.rs:7:5
    |
 LL |     *(1 as *mut u32) = 42;
    |     ^^^^^^^^^^^^^^^^^^^^^ dereference of raw pointer
    |
    = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
 
-error: aborting due to previous error
+error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
+  --> $DIR/issue-45087-unreachable-unsafe.rs:17:5
+   |
+LL |     *a = 1;
+   |     ^^^^^^ dereference of raw pointer
+   |
+   = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
+error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
+  --> $DIR/issue-45087-unreachable-unsafe.rs:29:5
+   |
+LL |     *b = 1;
+   |     ^^^^^^ dereference of raw pointer
+   |
+   = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0133`.
index 071cea8fbd78bd905a4f9cfea5951de842ad05a7..3e3da667c0b0883bb0636cc460c6e4dd0e8c4acc 100644 (file)
@@ -1,3 +1,4 @@
+// Verify that unreachable code undergoes unsafety checks.
 // revisions: mir thir
 // [thir]compile-flags: -Z thir-unsafeck
 
@@ -6,3 +7,25 @@ fn main() {
     *(1 as *mut u32) = 42;
     //~^ ERROR dereference of raw pointer is unsafe
 }
+
+fn panic() -> ! {
+    panic!();
+}
+
+fn f(a: *mut u32) {
+    panic();
+    *a = 1;
+    //~^ ERROR dereference of raw pointer is unsafe
+}
+
+enum Void {}
+
+fn uninhabited() -> Void {
+    panic!();
+}
+
+fn g(b: *mut u32) {
+    uninhabited();
+    *b = 1;
+    //~^ ERROR dereference of raw pointer is unsafe
+}
index 73a113652b8338b02f0388078f46b82beba22fca..e81adad45075054682737061ac3c3d64999b478a 100644 (file)
@@ -1,11 +1,27 @@
 error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
-  --> $DIR/issue-45087-unreachable-unsafe.rs:6:5
+  --> $DIR/issue-45087-unreachable-unsafe.rs:7:5
    |
 LL |     *(1 as *mut u32) = 42;
    |     ^^^^^^^^^^^^^^^^ dereference of raw pointer
    |
    = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
 
-error: aborting due to previous error
+error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
+  --> $DIR/issue-45087-unreachable-unsafe.rs:17:5
+   |
+LL |     *a = 1;
+   |     ^^ dereference of raw pointer
+   |
+   = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
+error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
+  --> $DIR/issue-45087-unreachable-unsafe.rs:29:5
+   |
+LL |     *b = 1;
+   |     ^^ dereference of raw pointer
+   |
+   = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0133`.
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/extern-loc-bad-loctype.rs b/src/test/ui/unused-crate-deps/extern-loc-bad-loctype.rs
deleted file mode 100644 (file)
index e69df03..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-// --extern-location with bad location type
-
-// aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar=badloc:in-the-test-file -Z unstable-options
-
-#![warn(unused_crate_dependencies)]
-
-fn main() {}
diff --git a/src/test/ui/unused-crate-deps/extern-loc-bad-loctype.stderr b/src/test/ui/unused-crate-deps/extern-loc-bad-loctype.stderr
deleted file mode 100644 (file)
index 12378f1..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-error: unknown location type `badloc`: use `raw` or `json`
-
diff --git a/src/test/ui/unused-crate-deps/extern-loc-defl-json.rs b/src/test/ui/unused-crate-deps/extern-loc-defl-json.rs
deleted file mode 100644 (file)
index a023f53..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-// Default extern location from name and path if one isn't specified
-
-// check-pass
-// aux-crate:bar=bar.rs
-// compile-flags:--error-format json
-
-#![warn(unused_crate_dependencies)]
-//~^ WARNING external crate `bar` unused in
-
-fn main() {}
diff --git a/src/test/ui/unused-crate-deps/extern-loc-defl-json.stderr b/src/test/ui/unused-crate-deps/extern-loc-defl-json.stderr
deleted file mode 100644 (file)
index cee3f6c..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-{"message":"external crate `bar` unused in `extern_loc_defl_json`: remove the dependency or add `use bar as _;`","code":{"code":"unused_crate_dependencies","explanation":null},"level":"warning","spans":[{"file_name":"$DIR/extern-loc-defl-json.rs","byte_start":146,"byte_end":146,"line_start":7,"line_end":7,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"the lint level is defined here","code":null,"level":"note","spans":[{"file_name":"$DIR/extern-loc-defl-json.rs","byte_start":154,"byte_end":179,"line_start":7,"line_end":7,"column_start":9,"column_end":34,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":9,"highlight_end":34}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":null},{"message":"remove unnecessary dependency `bar`","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"json extern location","code":null,"level":"help","spans":[],"children":[],"rendered":null,"tool_metadata":{"name":"bar"}}],"rendered":"warning: external crate `bar` unused in `extern_loc_defl_json`: remove the dependency or add `use bar as _;`
-  --> $DIR/extern-loc-defl-json.rs:7:1
-   |
-LL | #![warn(unused_crate_dependencies)]
-   | ^
-   |
-note: the lint level is defined here
-  --> $DIR/extern-loc-defl-json.rs:7:9
-   |
-LL | #![warn(unused_crate_dependencies)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
-   = help: remove unnecessary dependency `bar`
-
-"}
-{"message":"1 warning emitted","code":null,"level":"warning","spans":[],"children":[],"rendered":"warning: 1 warning emitted
-
-"}
diff --git a/src/test/ui/unused-crate-deps/extern-loc-json-bad-json.rs b/src/test/ui/unused-crate-deps/extern-loc-json-bad-json.rs
deleted file mode 100644 (file)
index aee6233..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-// --extern-location with a raw reference
-
-// aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar=json:[{"malformed -Z unstable-options
-
-#![warn(unused_crate_dependencies)]
-
-fn main() {}
diff --git a/src/test/ui/unused-crate-deps/extern-loc-json-bad-json.stderr b/src/test/ui/unused-crate-deps/extern-loc-json-bad-json.stderr
deleted file mode 100644 (file)
index 20d6063..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-error: `--extern-location`: malformed json location `[{"malformed`
-
diff --git a/src/test/ui/unused-crate-deps/extern-loc-json-json.rs b/src/test/ui/unused-crate-deps/extern-loc-json-json.rs
deleted file mode 100644 (file)
index c7988cd..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-// --extern-location with a raw reference
-
-// check-pass
-// aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar=json:{"key":123,"value":{}} --error-format json -Z unstable-options
-
-#![warn(unused_crate_dependencies)]
-//~^ WARNING external crate `bar` unused in
-
-fn main() {}
diff --git a/src/test/ui/unused-crate-deps/extern-loc-json-json.stderr b/src/test/ui/unused-crate-deps/extern-loc-json-json.stderr
deleted file mode 100644 (file)
index 001ec6a..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-{"message":"external crate `bar` unused in `extern_loc_json_json`: remove the dependency or add `use bar as _;`","code":{"code":"unused_crate_dependencies","explanation":null},"level":"warning","spans":[{"file_name":"$DIR/extern-loc-json-json.rs","byte_start":189,"byte_end":189,"line_start":7,"line_end":7,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"the lint level is defined here","code":null,"level":"note","spans":[{"file_name":"$DIR/extern-loc-json-json.rs","byte_start":197,"byte_end":222,"line_start":7,"line_end":7,"column_start":9,"column_end":34,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":9,"highlight_end":34}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":null},{"message":"remove unnecessary dependency `bar`","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"json extern location","code":null,"level":"help","spans":[],"children":[],"rendered":null,"tool_metadata":{"key":123,"value":{}}}],"rendered":"warning: external crate `bar` unused in `extern_loc_json_json`: remove the dependency or add `use bar as _;`
-  --> $DIR/extern-loc-json-json.rs:7:1
-   |
-LL | #![warn(unused_crate_dependencies)]
-   | ^
-   |
-note: the lint level is defined here
-  --> $DIR/extern-loc-json-json.rs:7:9
-   |
-LL | #![warn(unused_crate_dependencies)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
-   = help: remove unnecessary dependency `bar`
-
-"}
-{"message":"1 warning emitted","code":null,"level":"warning","spans":[],"children":[],"rendered":"warning: 1 warning emitted
-
-"}
diff --git a/src/test/ui/unused-crate-deps/extern-loc-json.rs b/src/test/ui/unused-crate-deps/extern-loc-json.rs
deleted file mode 100644 (file)
index c0d76c8..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-// --extern-location with a raw reference
-
-// check-pass
-// aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar=json:{"key":123,"value":{}} -Z unstable-options
-
-#![warn(unused_crate_dependencies)]
-//~^ WARNING external crate `bar` unused in
-
-fn main() {}
diff --git a/src/test/ui/unused-crate-deps/extern-loc-json.stderr b/src/test/ui/unused-crate-deps/extern-loc-json.stderr
deleted file mode 100644 (file)
index a6bbc0d..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-warning: external crate `bar` unused in `extern_loc_json`: remove the dependency or add `use bar as _;`
-  --> $DIR/extern-loc-json.rs:7:1
-   |
-LL | #![warn(unused_crate_dependencies)]
-   | ^
-   |
-note: the lint level is defined here
-  --> $DIR/extern-loc-json.rs:7:9
-   |
-LL | #![warn(unused_crate_dependencies)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
-   = help: remove unnecessary dependency `bar`
-
-warning: 1 warning emitted
-
diff --git a/src/test/ui/unused-crate-deps/extern-loc-missing-loc.rs b/src/test/ui/unused-crate-deps/extern-loc-missing-loc.rs
deleted file mode 100644 (file)
index 6ac5589..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-// --extern-location with a raw reference
-
-// aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar -Zunstable-options
-
-#![warn(unused_crate_dependencies)]
-
-fn main() {}
diff --git a/src/test/ui/unused-crate-deps/extern-loc-missing-loc.stderr b/src/test/ui/unused-crate-deps/extern-loc-missing-loc.stderr
deleted file mode 100644 (file)
index 4584fbf..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-error: `--extern-location`: specify location for extern crate `bar`
-
diff --git a/src/test/ui/unused-crate-deps/extern-loc-missing-loctype.rs b/src/test/ui/unused-crate-deps/extern-loc-missing-loctype.rs
deleted file mode 100644 (file)
index 3590b9c..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-// --extern-location with no type
-
-// aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar=missing-loc-type -Z unstable-options
-
-#![warn(unused_crate_dependencies)]
-
-fn main() {}
diff --git a/src/test/ui/unused-crate-deps/extern-loc-missing-loctype.stderr b/src/test/ui/unused-crate-deps/extern-loc-missing-loctype.stderr
deleted file mode 100644 (file)
index d0c36eb..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-error: unknown location type `missing-loc-type`: use `raw` or `json`
-
diff --git a/src/test/ui/unused-crate-deps/extern-loc-raw-json.rs b/src/test/ui/unused-crate-deps/extern-loc-raw-json.rs
deleted file mode 100644 (file)
index 64c3d77..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-// --extern-location with a raw reference
-
-// check-pass
-// aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar=raw:in-the-test-file --error-format json -Z unstable-options
-
-#![warn(unused_crate_dependencies)]
-//~^ WARNING external crate `bar` unused in
-
-fn main() {}
diff --git a/src/test/ui/unused-crate-deps/extern-loc-raw-json.stderr b/src/test/ui/unused-crate-deps/extern-loc-raw-json.stderr
deleted file mode 100644 (file)
index 4083bd5..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-{"message":"external crate `bar` unused in `extern_loc_raw_json`: remove the dependency or add `use bar as _;`","code":{"code":"unused_crate_dependencies","explanation":null},"level":"warning","spans":[{"file_name":"$DIR/extern-loc-raw-json.rs","byte_start":182,"byte_end":182,"line_start":7,"line_end":7,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"the lint level is defined here","code":null,"level":"note","spans":[{"file_name":"$DIR/extern-loc-raw-json.rs","byte_start":190,"byte_end":215,"line_start":7,"line_end":7,"column_start":9,"column_end":34,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":9,"highlight_end":34}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":null},{"message":"remove unnecessary dependency `bar` at `in-the-test-file`","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"raw extern location","code":null,"level":"help","spans":[{"file_name":"$DIR/extern-loc-raw-json.rs","byte_start":0,"byte_end":0,"line_start":1,"line_end":1,"column_start":1,"column_end":1,"is_primary":true,"text":[],"label":null,"suggested_replacement":"in-the-test-file","suggestion_applicability":"Unspecified","expansion":null}],"children":[],"rendered":null},{"message":"json extern location","code":null,"level":"help","spans":[],"children":[],"rendered":null,"tool_metadata":"in-the-test-file"}],"rendered":"warning: external crate `bar` unused in `extern_loc_raw_json`: remove the dependency or add `use bar as _;`
-  --> $DIR/extern-loc-raw-json.rs:7:1
-   |
-LL | #![warn(unused_crate_dependencies)]
-   | ^
-   |
-note: the lint level is defined here
-  --> $DIR/extern-loc-raw-json.rs:7:9
-   |
-LL | #![warn(unused_crate_dependencies)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
-   = help: remove unnecessary dependency `bar` at `in-the-test-file`
-
-"}
-{"message":"1 warning emitted","code":null,"level":"warning","spans":[],"children":[],"rendered":"warning: 1 warning emitted
-
-"}
diff --git a/src/test/ui/unused-crate-deps/extern-loc-raw-missing-loc.rs b/src/test/ui/unused-crate-deps/extern-loc-raw-missing-loc.rs
deleted file mode 100644 (file)
index a9e7afb..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-// --extern-location with a raw reference
-
-// aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar=raw -Z unstable-options
-
-#![warn(unused_crate_dependencies)]
-
-fn main() {}
diff --git a/src/test/ui/unused-crate-deps/extern-loc-raw-missing-loc.stderr b/src/test/ui/unused-crate-deps/extern-loc-raw-missing-loc.stderr
deleted file mode 100644 (file)
index 4b51266..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-error: `--extern-location`: missing `raw` location
-
diff --git a/src/test/ui/unused-crate-deps/extern-loc-raw.rs b/src/test/ui/unused-crate-deps/extern-loc-raw.rs
deleted file mode 100644 (file)
index 27d0975..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-// --extern-location with a raw reference
-
-// check-pass
-// aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar=raw:in-the-test-file -Z unstable-options
-
-#![warn(unused_crate_dependencies)]
-//~^ WARNING external crate `bar` unused in
-
-fn main() {}
diff --git a/src/test/ui/unused-crate-deps/extern-loc-raw.stderr b/src/test/ui/unused-crate-deps/extern-loc-raw.stderr
deleted file mode 100644 (file)
index 2cdd005..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-warning: external crate `bar` unused in `extern_loc_raw`: remove the dependency or add `use bar as _;`
-  --> $DIR/extern-loc-raw.rs:7:1
-   |
-LL | #![warn(unused_crate_dependencies)]
-   | ^
-   |
-note: the lint level is defined here
-  --> $DIR/extern-loc-raw.rs:7:9
-   |
-LL | #![warn(unused_crate_dependencies)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
-   = help: remove unnecessary dependency `bar` at `in-the-test-file`
-
-warning: 1 warning emitted
-
index 479f51bff464d61f1ee8aa324d4426d520e3d699..15833126bd6201ddda75e3b529eb26f8dc08473c 100644 (file)
@@ -5,7 +5,6 @@ LL | pub fn fib(n: u32) -> Vec<u32> {
    | ^
    |
    = note: requested on the command line with `-W unused-crate-dependencies`
-   = help: remove unnecessary dependency `bar`
 
 warning: 1 warning emitted
 
index 1142d156d0e96e507d863f77532d7f710075309c..c8c6c4507b0c51427136d656ba9de8cdbdcd3a43 100644 (file)
@@ -9,7 +9,6 @@ note: the lint level is defined here
    |
 LL | #![warn(unused_crate_dependencies)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
-   = help: remove unnecessary dependency `barbar`
 
 warning: 1 warning emitted
 
index 29667d9525cb4b266fc00b7783416079b9fd91cd..0d38315704b11fb25e6bc7be22774c0714d4f4d4 100644 (file)
@@ -9,7 +9,6 @@ note: the lint level is defined here
    |
 LL | #![warn(unused_crate_dependencies)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
-   = help: remove unnecessary dependency `bar`
 
 warning: 1 warning emitted
 
index 2c0c9215129866c593193ebfce314d02946ecea1..65956461d643928fa5a319c7ae533f3dc7e15ded 100644 (file)
@@ -5,7 +5,6 @@ LL | fn main() {}
    | ^
    |
    = note: requested on the command line with `-W unused-crate-dependencies`
-   = help: remove unnecessary dependency `bar`
 
 warning: 1 warning emitted
 
index 2cd49218f5ad85728a314ac64aebf715c5a1f4bd..ea675ba9a1eb184560f8379ea4571e2d2b1e9ec4 100644 (file)
@@ -5,7 +5,6 @@ LL | fn main() {}
    | ^
    |
    = note: requested on the command line with `-W unused-crate-dependencies`
-   = help: remove unnecessary dependency `bar`
 
 warning: 1 warning emitted
 
index dba5baf4345858c591517b24801902a062c399f8..edffc4ada3d77799e5a04eeafd9b2f843d29fc23 160000 (submodule)
@@ -1 +1 @@
-Subproject commit dba5baf4345858c591517b24801902a062c399f8
+Subproject commit edffc4ada3d77799e5a04eeafd9b2f843d29fc23
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 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 fc0483a929a7a1e93c3cded4003f6b2835ec2985..5816a95dcebffe63aa2a9410940e4c372a83260d 100644 (file)
@@ -10,7 +10,7 @@
 use rustc_ast::ast;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::ty;
+use rustc_middle::ty::{self, DefIdTree};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::def_id::CRATE_DEF_ID;
 use rustc_span::source_map::Span;
@@ -114,8 +114,8 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'_>) {
             hir::ItemKind::Fn(..) => {
                 // ignore main()
                 if it.ident.name == sym::main {
-                    let def_key = cx.tcx.hir().def_key(it.def_id);
-                    if def_key.parent == Some(hir::def_id::CRATE_DEF_INDEX) {
+                    let at_root = cx.tcx.local_parent(it.def_id) == Some(CRATE_DEF_ID);
+                    if at_root {
                         return;
                     }
                 }
index d29d07da7b0ffdcc8aa85a28443b6d8f1623357f..9c734221ebcea4989523b48545b88bb7e7916927 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;
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 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..74978720424d46e3f64f6970383b53c11c724e53 100644 (file)
@@ -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 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 8c1f28f14076887dcb110c0064beca87a8350c2b..f4e6c2a2bb288818bbad52cd3eaa7f4a89756dd1 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"),
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 1ef91e122775060acb1fbda2c9a366891af3ea89..a71a0083937671d79e16bfac4c7b8cab9c8ab9bb 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 1ef91e122775060acb1fbda2c9a366891af3ea89
+Subproject commit a71a0083937671d79e16bfac4c7b8cab9c8ab9bb
index dbf5cf9650c5f4f16098a2d11979b1bf423531c3..98d0f5dc656c17ac0cd4359630e5aba742d9b121 100644 (file)
@@ -58,7 +58,8 @@ function extractFunction(content, functionName) {
                 } while (pos < content.length && content[pos] !== '/' && content[pos - 1] !== '*');
 
             // Eat quoted strings
-            } else if (content[pos] === '"' || content[pos] === "'" || content[pos] === "`") {
+            } else if ((content[pos] === '"' || content[pos] === "'" || content[pos] === "`") &&
+                       (pos === 0 || content[pos - 1] !== '/')) {
                 stop = content[pos];
                 do {
                     if (content[pos] === '\\') {
@@ -84,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) {
@@ -125,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) {
@@ -161,6 +171,9 @@ function extractVariable(content, varName) {
         }
         content = content.slice(start + 1);
     }
+    if (kind === "let ") {
+        return extractVariable(content, varName, "const ");
+    }
     return null;
 }
 
@@ -269,8 +282,13 @@ function loadSearchJsAndIndex(searchJs, searchIndex, storageJs, crate) {
     // execQuery last parameter is built in buildIndex.
     // buildIndex requires the hashmap from search-index.
     var functionsToLoad = ["buildHrefAndPath", "pathSplitter", "levenshtein", "validateResult",
-                           "handleAliases", "getQuery", "buildIndex", "execQuery", "execSearch",
-                           "removeEmptyStringsFromArray"];
+                           "buildIndex", "execQuery", "parseQuery", "createQueryResults",
+                           "isWhitespace", "isSpecialStartCharacter", "isStopCharacter",
+                           "parseInput", "getItemsBefore", "getNextElem", "createQueryElement",
+                           "isReturnArrow", "isPathStart", "getStringElem", "newParsedQuery",
+                           "itemTypeFromName", "isEndCharacter", "isErrorCharacter",
+                           "isIdentCharacter", "isSeparatorCharacter", "getIdentEndPosition",
+                           "checkExtraTypeFilterCharacters", "isWhitespaceCharacter"];
 
     const functions = ["hasOwnPropertyRustdoc", "onEach"];
     ALIASES = {};
@@ -286,12 +304,99 @@ function loadSearchJsAndIndex(searchJs, searchIndex, storageJs, crate) {
     return [loaded, index];
 }
 
+// This function checks if `expected` has all the required fields needed for the checks.
+function checkNeededFields(fullPath, expected, error_text, queryName, position) {
+    let fieldsToCheck;
+    if (fullPath.length === 0) {
+        fieldsToCheck = [
+            "foundElems",
+            "original",
+            "returned",
+            "typeFilter",
+            "userQuery",
+            "error",
+        ];
+    } else if (fullPath.endsWith("elems") || fullPath.endsWith("generics")) {
+        fieldsToCheck = [
+            "name",
+            "fullPath",
+            "pathWithoutLast",
+            "pathLast",
+            "generics",
+        ];
+    } else {
+        fieldsToCheck = [];
+    }
+    for (var i = 0; i < fieldsToCheck.length; ++i) {
+        const field = fieldsToCheck[i];
+        if (!expected.hasOwnProperty(field)) {
+            let text = `${queryName}==> Mandatory key \`${field}\` is not present`;
+            if (fullPath.length > 0) {
+                text += ` in field \`${fullPath}\``;
+                if (position != null) {
+                    text += ` (position ${position})`;
+                }
+            }
+            error_text.push(text);
+        }
+    }
+}
+
+function valueCheck(fullPath, expected, result, error_text, queryName) {
+    if (Array.isArray(expected)) {
+        for (var i = 0; i < expected.length; ++i) {
+            checkNeededFields(fullPath, expected[i], error_text, queryName, i);
+            if (i >= result.length) {
+                error_text.push(`${queryName}==> EXPECTED has extra value in array from field ` +
+                    `\`${fullPath}\` (position ${i}): \`${JSON.stringify(expected[i])}\``);
+            } else {
+                valueCheck(fullPath + '[' + i + ']', expected[i], result[i], error_text, queryName);
+            }
+        }
+        for (; i < result.length; ++i) {
+            error_text.push(`${queryName}==> RESULT has extra value in array from field ` +
+                `\`${fullPath}\` (position ${i}): \`${JSON.stringify(result[i])}\` ` +
+                'compared to EXPECTED');
+        }
+    } else if (expected !== null && typeof expected !== "undefined" &&
+               expected.constructor == Object)
+    {
+        for (const key in expected) {
+            if (!expected.hasOwnProperty(key)) {
+                continue;
+            }
+            if (!result.hasOwnProperty(key)) {
+                error_text.push('==> Unknown key "' + key + '"');
+                break;
+            }
+            const obj_path = fullPath + (fullPath.length > 0 ? '.' : '') + key;
+            valueCheck(obj_path, expected[key], result[key], error_text, queryName);
+        }
+    } else {
+        expectedValue = JSON.stringify(expected);
+        resultValue = JSON.stringify(result);
+        if (expectedValue != resultValue) {
+            error_text.push(`${queryName}==> Different values for field \`${fullPath}\`:\n` +
+                `EXPECTED: \`${expectedValue}\`\nRESULT:   \`${resultValue}\``);
+        }
+    }
+}
+
+function runParser(query, expected, loaded, loadedFile, queryName) {
+    var error_text = [];
+    checkNeededFields("", expected, error_text, queryName, null);
+    if (error_text.length === 0) {
+        valueCheck('', expected, loaded.parseQuery(query), error_text, queryName);
+    }
+    return error_text;
+}
+
 function runSearch(query, expected, index, loaded, loadedFile, queryName) {
     const filter_crate = loadedFile.FILTER_CRATE;
     const ignore_order = loadedFile.ignore_order;
     const exact_check = loadedFile.exact_check;
 
-    var results = loaded.execSearch(loaded.getQuery(query), index, filter_crate);
+    var results = loaded.execQuery(loaded.parseQuery(query), index, filter_crate);
     var error_text = [];
 
     for (var key in expected) {
@@ -353,40 +458,75 @@ function checkResult(error_text, loadedFile, displaySuccess) {
     return 1;
 }
 
-function runChecks(testFile, loaded, index) {
-    var testFileContent = readFile(testFile) + 'exports.QUERY = QUERY;exports.EXPECTED = EXPECTED;';
-    if (testFileContent.indexOf("FILTER_CRATE") !== -1) {
-        testFileContent += "exports.FILTER_CRATE = FILTER_CRATE;";
-    } else {
-        testFileContent += "exports.FILTER_CRATE = null;";
-    }
-    var loadedFile = loadContent(testFileContent);
-
-    const expected = loadedFile.EXPECTED;
+function runCheck(loadedFile, key, callback) {
+    const expected = loadedFile[key];
     const query = loadedFile.QUERY;
 
     if (Array.isArray(query)) {
         if (!Array.isArray(expected)) {
             console.log("FAILED");
-            console.log("==> If QUERY variable is an array, EXPECTED should be an array too");
+            console.log(`==> If QUERY variable is an array, ${key} should be an array too`);
             return 1;
         } else if (query.length !== expected.length) {
             console.log("FAILED");
-            console.log("==> QUERY variable should have the same length as EXPECTED");
+            console.log(`==> QUERY variable should have the same length as ${key}`);
             return 1;
         }
         for (var i = 0; i < query.length; ++i) {
-            var error_text = runSearch(query[i], expected[i], index, loaded, loadedFile,
-                "[ query `" + query[i] + "`]");
+            var error_text = callback(query[i], expected[i], "[ query `" + query[i] + "`]");
             if (checkResult(error_text, loadedFile, false) !== 0) {
                 return 1;
             }
         }
         console.log("OK");
-        return 0;
+    } else {
+        var error_text = callback(query, expected, "");
+        if (checkResult(error_text, loadedFile, true) !== 0) {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+function runChecks(testFile, loaded, index) {
+    var checkExpected = false;
+    var checkParsed = false;
+    var testFileContent = readFile(testFile) + 'exports.QUERY = QUERY;';
+
+    if (testFileContent.indexOf("FILTER_CRATE") !== -1) {
+        testFileContent += "exports.FILTER_CRATE = FILTER_CRATE;";
+    } else {
+        testFileContent += "exports.FILTER_CRATE = null;";
+    }
+
+    if (testFileContent.indexOf("\nconst EXPECTED") !== -1) {
+        testFileContent += 'exports.EXPECTED = EXPECTED;';
+        checkExpected = true;
+    }
+    if (testFileContent.indexOf("\nconst PARSED") !== -1) {
+        testFileContent += 'exports.PARSED = PARSED;';
+        checkParsed = true;
+    }
+    if (!checkParsed && !checkExpected) {
+        console.log("FAILED");
+        console.log("==> At least `PARSED` or `EXPECTED` is needed!");
+        return 1;
+    }
+
+    const loadedFile = loadContent(testFileContent);
+    var res = 0;
+
+    if (checkExpected) {
+        res += runCheck(loadedFile, "EXPECTED", (query, expected, text) => {
+            return runSearch(query, expected, index, loaded, loadedFile, text);
+        });
+    }
+    if (checkParsed) {
+        res += runCheck(loadedFile, "PARSED", (query, expected, text) => {
+            return runParser(query, expected, loaded, loadedFile, text);
+        });
     }
-    var error_text = runSearch(query, expected, index, loaded, loadedFile, "");
-    return checkResult(error_text, loadedFile, true);
+    return res;
 }
 
 function load_files(doc_folder, resource_suffix, crate) {
index ea6e01e577c6bfd3fa56740ce8d72c1a9a1a42ef..3f776b70b14c771fdb1b36008b3850d50d478769 100644 (file)
@@ -42,6 +42,9 @@
     ("self_cell", "Apache-2.0"),      // rustc (fluent translations)
     // FIXME: this dependency violates the documentation comment above:
     ("fortanix-sgx-abi", "MPL-2.0"), // libstd but only for `sgx` target
+    ("dunce", "CC0-1.0"),            // cargo (dev dependency)
+    ("similar", "Apache-2.0"),       // cargo (dev dependency)
+    ("normalize-line-endings", "Apache-2.0"), // cargo (dev dependency)
 ];
 
 const EXCEPTIONS_CRANELIFT: &[(&str, &str)] = &[
index 63a8909c6627ab6b7fa97f1f6c7252b826b6828d..d823b412c5992518ee98d5b434e43201582a9a3c 100644 (file)
@@ -8,7 +8,7 @@
 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 ISSUES_ENTRY_LIMIT: usize = 2292;
 
 fn check_entries(path: &Path, bad: &mut bool) {
     let dirs = walkdir::WalkDir::new(&path.join("test/ui"))