]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #82244 - pickfire:patch-6, r=dtolnay
authorGuillaume Gomez <guillaume1.gomez@gmail.com>
Sat, 20 Feb 2021 19:37:01 +0000 (20:37 +0100)
committerGitHub <noreply@github.com>
Sat, 20 Feb 2021 19:37:01 +0000 (20:37 +0100)
Keep consistency in example for Stdin StdinLock

Stdin uses handle whereas StdinLock uses stdin_lock, changed it to handle.

396 files changed:
Cargo.lock
compiler/rustc_ast/src/ast.rs
compiler/rustc_ast/src/mut_visit.rs
compiler/rustc_ast/src/visit.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_ast_pretty/src/pprust/state.rs
compiler/rustc_builtin_macros/src/proc_macro_harness.rs
compiler/rustc_builtin_macros/src/standard_library_imports.rs
compiler/rustc_builtin_macros/src/test_harness.rs
compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
compiler/rustc_data_structures/src/profiling.rs
compiler/rustc_driver/src/args.rs
compiler/rustc_driver/src/lib.rs
compiler/rustc_error_codes/src/error_codes.rs
compiler/rustc_error_codes/src/error_codes/E0162.md
compiler/rustc_error_codes/src/error_codes/E0165.md
compiler/rustc_error_codes/src/error_codes/E0549.md [new file with mode: 0644]
compiler/rustc_errors/src/emitter.rs
compiler/rustc_expand/src/config.rs
compiler/rustc_expand/src/expand.rs
compiler/rustc_expand/src/module.rs
compiler/rustc_expand/src/mut_visit/tests.rs
compiler/rustc_expand/src/parse/tests.rs
compiler/rustc_hir/src/hir.rs
compiler/rustc_hir/src/lang_items.rs
compiler/rustc_incremental/src/persist/file_format.rs
compiler/rustc_incremental/src/persist/fs.rs
compiler/rustc_incremental/src/persist/load.rs
compiler/rustc_infer/src/infer/at.rs
compiler/rustc_infer/src/infer/canonical/query_response.rs
compiler/rustc_infer/src/infer/error_reporting/mod.rs
compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs
compiler/rustc_interface/src/passes.rs
compiler/rustc_lint/src/early.rs
compiler/rustc_lint/src/passes.rs
compiler/rustc_lint_defs/src/builtin.rs
compiler/rustc_metadata/src/rmeta/encoder.rs
compiler/rustc_middle/src/traits/mod.rs
compiler/rustc_middle/src/traits/select.rs
compiler/rustc_middle/src/traits/structural_impls.rs
compiler/rustc_middle/src/ty/codec.rs
compiler/rustc_middle/src/ty/diagnostics.rs
compiler/rustc_middle/src/ty/error.rs
compiler/rustc_middle/src/ty/mod.rs
compiler/rustc_middle/src/ty/print/pretty.rs
compiler/rustc_middle/src/ty/query/stats.rs
compiler/rustc_middle/src/ty/relate.rs
compiler/rustc_middle/src/ty/sty.rs
compiler/rustc_mir/src/const_eval/eval_queries.rs
compiler/rustc_mir/src/const_eval/machine.rs
compiler/rustc_mir/src/const_eval/mod.rs
compiler/rustc_mir/src/interpret/cast.rs
compiler/rustc_mir/src/interpret/eval_context.rs
compiler/rustc_mir/src/interpret/intern.rs
compiler/rustc_mir/src/interpret/intrinsics.rs
compiler/rustc_mir/src/interpret/intrinsics/caller_location.rs
compiler/rustc_mir/src/interpret/machine.rs
compiler/rustc_mir/src/interpret/operand.rs
compiler/rustc_mir/src/interpret/operator.rs
compiler/rustc_mir/src/interpret/place.rs
compiler/rustc_mir/src/interpret/step.rs
compiler/rustc_mir/src/interpret/terminator.rs
compiler/rustc_mir/src/interpret/traits.rs
compiler/rustc_mir/src/interpret/validity.rs
compiler/rustc_mir/src/interpret/visitor.rs
compiler/rustc_mir/src/transform/const_prop.rs
compiler/rustc_mir/src/transform/coverage/tests.rs
compiler/rustc_mir/src/util/generic_graphviz.rs
compiler/rustc_mir_build/src/thir/pattern/check_match.rs
compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
compiler/rustc_parse/src/parser/diagnostics.rs
compiler/rustc_parse/src/parser/expr.rs
compiler/rustc_parse/src/parser/item.rs
compiler/rustc_parse/src/parser/mod.rs
compiler/rustc_parse/src/parser/nonterminal.rs
compiler/rustc_parse/src/parser/pat.rs
compiler/rustc_parse/src/parser/stmt.rs
compiler/rustc_passes/src/check_const.rs
compiler/rustc_passes/src/hir_stats.rs
compiler/rustc_privacy/src/lib.rs
compiler/rustc_query_system/src/dep_graph/graph.rs
compiler/rustc_resolve/src/late.rs
compiler/rustc_resolve/src/lib.rs
compiler/rustc_session/src/session.rs
compiler/rustc_span/src/source_map.rs
compiler/rustc_span/src/source_map/tests.rs
compiler/rustc_span/src/symbol.rs
compiler/rustc_target/src/spec/mod.rs
compiler/rustc_target/src/spec/riscv32gc_unknown_linux_musl.rs [new file with mode: 0644]
compiler/rustc_target/src/spec/riscv64gc_unknown_linux_musl.rs [new file with mode: 0644]
compiler/rustc_trait_selection/src/autoderef.rs
compiler/rustc_trait_selection/src/traits/auto_trait.rs
compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
compiler/rustc_trait_selection/src/traits/fulfill.rs
compiler/rustc_trait_selection/src/traits/object_safety.rs
compiler/rustc_trait_selection/src/traits/project.rs
compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
compiler/rustc_trait_selection/src/traits/select/confirmation.rs
compiler/rustc_trait_selection/src/traits/select/mod.rs
compiler/rustc_traits/src/chalk/lowering.rs
compiler/rustc_ty_utils/src/instance.rs
compiler/rustc_typeck/src/astconv/generics.rs
compiler/rustc_typeck/src/astconv/mod.rs
compiler/rustc_typeck/src/check/check.rs
compiler/rustc_typeck/src/check/closure.rs
compiler/rustc_typeck/src/check/expr.rs
compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
compiler/rustc_typeck/src/check/method/suggest.rs
compiler/rustc_typeck/src/check/upvar.rs
compiler/rustc_typeck/src/coherence/mod.rs
compiler/rustc_typeck/src/constrained_generic_params.rs
library/core/src/hash/mod.rs
library/core/src/lib.rs
library/core/src/num/dec2flt/parse.rs
library/core/src/ops/deref.rs
library/core/src/ptr/const_ptr.rs
library/core/src/ptr/metadata.rs [new file with mode: 0644]
library/core/src/ptr/mod.rs
library/core/src/ptr/mut_ptr.rs
library/core/src/ptr/non_null.rs
library/core/src/result.rs
library/core/src/slice/mod.rs
library/core/tests/atomic.rs
library/core/tests/lib.rs
library/core/tests/ptr.rs
library/core/tests/result.rs
library/proc_macro/src/lib.rs
library/std/src/io/stdio.rs
library/std/src/lib.rs
library/std/src/sync/mutex.rs
library/std/src/sys/windows/ext/process.rs
library/std/src/sys/windows/process.rs
library/std/src/sys/windows/process/tests.rs
library/test/src/lib.rs
src/bootstrap/bin/main.rs
src/bootstrap/compile.rs
src/bootstrap/install.rs
src/bootstrap/util.rs
src/doc/rustc/src/platform-support.md
src/doc/rustdoc/src/command-line-arguments.md
src/librustdoc/clean/auto_trait.rs
src/librustdoc/clean/blanket_impl.rs
src/librustdoc/clean/inline.rs
src/librustdoc/clean/mod.rs
src/librustdoc/clean/types.rs
src/librustdoc/clean/utils.rs
src/librustdoc/core.rs
src/librustdoc/html/render/mod.rs
src/librustdoc/html/sources.rs
src/librustdoc/json/conversions.rs
src/librustdoc/json/mod.rs
src/librustdoc/lib.rs
src/librustdoc/passes/calculate_doc_coverage.rs
src/librustdoc/passes/check_code_block_syntax.rs
src/librustdoc/passes/collect_intra_doc_links.rs
src/librustdoc/passes/collect_trait_impls.rs
src/librustdoc/passes/doc_test_lints.rs
src/librustdoc/passes/html_tags.rs
src/librustdoc/passes/mod.rs
src/librustdoc/passes/non_autolinks.rs
src/librustdoc/passes/propagate_doc_cfg.rs
src/librustdoc/passes/strip_hidden.rs
src/librustdoc/passes/strip_priv_imports.rs
src/librustdoc/passes/strip_private.rs
src/librustdoc/passes/unindent_comments.rs
src/test/pretty/gat-bounds.rs
src/test/run-make/libtest-thread-limit/Makefile [new file with mode: 0644]
src/test/run-make/libtest-thread-limit/test.rs [new file with mode: 0644]
src/test/rustdoc-ui/commandline-argfile-badutf8.args [new file with mode: 0644]
src/test/rustdoc-ui/commandline-argfile-badutf8.rs [new file with mode: 0644]
src/test/rustdoc-ui/commandline-argfile-badutf8.stderr [new file with mode: 0644]
src/test/rustdoc-ui/commandline-argfile-missing.rs [new file with mode: 0644]
src/test/rustdoc-ui/commandline-argfile-missing.stderr [new file with mode: 0644]
src/test/rustdoc-ui/commandline-argfile.args [new file with mode: 0644]
src/test/rustdoc-ui/commandline-argfile.rs [new file with mode: 0644]
src/test/rustdoc/intra-doc/libstd-re-export.rs
src/test/rustdoc/sized_trait.rs [new file with mode: 0644]
src/test/ui/associated-types/associated-types-eq-hr.stderr
src/test/ui/associated-types/issue-21726.rs [new file with mode: 0644]
src/test/ui/associated-types/issue-22560.rs [new file with mode: 0644]
src/test/ui/associated-types/issue-22560.stderr [new file with mode: 0644]
src/test/ui/associated-types/issue-23595-2.rs [new file with mode: 0644]
src/test/ui/associated-types/issue-23595-2.stderr [new file with mode: 0644]
src/test/ui/associated-types/issue-24204.rs [new file with mode: 0644]
src/test/ui/associated-types/issue-43784-associated-type.rs [new file with mode: 0644]
src/test/ui/associated-types/issue-43784-associated-type.stderr [new file with mode: 0644]
src/test/ui/associated-types/project-defer-unification.rs [new file with mode: 0644]
src/test/ui/ast-json/ast-json-noexpand-output.stdout
src/test/ui/ast-json/ast-json-output.stdout
src/test/ui/async-await/generator-desc.rs [new file with mode: 0644]
src/test/ui/async-await/generator-desc.stderr [new file with mode: 0644]
src/test/ui/async-await/issue-77993-2.rs [new file with mode: 0644]
src/test/ui/async-await/issue-77993-2.stderr [new file with mode: 0644]
src/test/ui/async-await/issues/issue-78600.rs [new file with mode: 0644]
src/test/ui/async-await/issues/issue-78600.stderr [new file with mode: 0644]
src/test/ui/async-await/repeat_count_const_in_async_fn.rs [new file with mode: 0644]
src/test/ui/binding/if-let.rs
src/test/ui/cleanup-rvalue-during-if-and-while.rs [deleted file]
src/test/ui/closures/2229_closure_analysis/by_value.rs
src/test/ui/closures/2229_closure_analysis/by_value.stderr
src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-array-diagnostics.rs [new file with mode: 0644]
src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-array-diagnostics.stderr [new file with mode: 0644]
src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-single-variant-diagnostics.rs
src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-single-variant-diagnostics.stderr
src/test/ui/closures/2229_closure_analysis/move_closure.rs
src/test/ui/closures/2229_closure_analysis/move_closure.stderr
src/test/ui/closures/2229_closure_analysis/run_pass/move_closure.rs
src/test/ui/const-generics/const-param-shadowing.stderr
src/test/ui/const-generics/diagnostics.rs [new file with mode: 0644]
src/test/ui/const-generics/diagnostics.stderr [new file with mode: 0644]
src/test/ui/const-generics/dont-evaluate-array-len-on-err-1.rs [new file with mode: 0644]
src/test/ui/const-generics/dont-evaluate-array-len-on-err-1.stderr [new file with mode: 0644]
src/test/ui/const-generics/invalid-enum.rs
src/test/ui/const-generics/invalid-enum.stderr
src/test/ui/consts/issue-13837.rs [new file with mode: 0644]
src/test/ui/consts/issue-17718-references.rs [new file with mode: 0644]
src/test/ui/consts/issue-17718-references.stderr [new file with mode: 0644]
src/test/ui/consts/issue-32829.rs [new file with mode: 0644]
src/test/ui/consts/issue-32829.stderr [new file with mode: 0644]
src/test/ui/consts/issue-33537.rs [new file with mode: 0644]
src/test/ui/consts/rvalue-static-promotion.rs [new file with mode: 0644]
src/test/ui/consts/write-to-static-mut-in-static.rs [new file with mode: 0644]
src/test/ui/consts/write-to-static-mut-in-static.stderr [new file with mode: 0644]
src/test/ui/dotdotdot-expr.rs [deleted file]
src/test/ui/dotdotdot-expr.stderr [deleted file]
src/test/ui/emit-artifact-notifications.nll.stderr [deleted file]
src/test/ui/emit-artifact-notifications.polonius.stderr [deleted file]
src/test/ui/emit-artifact-notifications.rs [deleted file]
src/test/ui/emit-artifact-notifications.stderr [deleted file]
src/test/ui/emit-metadata-obj.rs [deleted file]
src/test/ui/expr-if-panic.rs [deleted file]
src/test/ui/expr/if/expr-if-panic-pass.rs [new file with mode: 0644]
src/test/ui/expr/if/if-let.rs
src/test/ui/expr/if/if-let.stderr
src/test/ui/expr/if/issue-4201.rs [new file with mode: 0644]
src/test/ui/expr/if/issue-4201.stderr [new file with mode: 0644]
src/test/ui/for-loop-while/cleanup-rvalue-during-if-and-while.rs [new file with mode: 0644]
src/test/ui/generator/auto-trait-regions.stderr
src/test/ui/generator/yield-outside-generator-issue-78653.rs [new file with mode: 0644]
src/test/ui/generator/yield-outside-generator-issue-78653.stderr [new file with mode: 0644]
src/test/ui/generic-associated-types/constraint-assoc-type-suggestion.rs [new file with mode: 0644]
src/test/ui/generic-associated-types/constraint-assoc-type-suggestion.stderr [new file with mode: 0644]
src/test/ui/generic-associated-types/generic-associated-type-bounds.rs [new file with mode: 0644]
src/test/ui/generic-associated-types/issue-76535.rs
src/test/ui/generic-associated-types/issue-76535.stderr
src/test/ui/generic-associated-types/issue-79422.rs
src/test/ui/generic-associated-types/issue-79422.stderr
src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.rs [new file with mode: 0644]
src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.stderr [new file with mode: 0644]
src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.rs [new file with mode: 0644]
src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.stderr [new file with mode: 0644]
src/test/ui/generic-associated-types/unsatified-item-lifetime-bound.rs [new file with mode: 0644]
src/test/ui/generic-associated-types/unsatified-item-lifetime-bound.stderr [new file with mode: 0644]
src/test/ui/hrtb/due-to-where-clause.stderr
src/test/ui/hrtb/hrtb-cache-issue-54302.stderr
src/test/ui/hrtb/hrtb-conflate-regions.stderr
src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.stderr
src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr
src/test/ui/hrtb/hrtb-just-for-static.stderr
src/test/ui/hrtb/hrtb-perfect-forwarding.nll.stderr
src/test/ui/hrtb/hrtb-perfect-forwarding.rs
src/test/ui/hrtb/hrtb-perfect-forwarding.stderr
src/test/ui/hrtb/issue-46989.stderr
src/test/ui/html-literals.rs [deleted file]
src/test/ui/hygiene/issue-40847.rs [new file with mode: 0644]
src/test/ui/issue-6157.rs [new file with mode: 0644]
src/test/ui/issues/issue-13837.rs [deleted file]
src/test/ui/issues/issue-17718-references.rs [deleted file]
src/test/ui/issues/issue-17718-references.stderr [deleted file]
src/test/ui/issues/issue-19991.rs
src/test/ui/issues/issue-20616-3.rs [deleted file]
src/test/ui/issues/issue-20616-3.stderr [deleted file]
src/test/ui/issues/issue-21726.rs [deleted file]
src/test/ui/issues/issue-22560.rs [deleted file]
src/test/ui/issues/issue-22560.stderr [deleted file]
src/test/ui/issues/issue-23595-2.rs [deleted file]
src/test/ui/issues/issue-23595-2.stderr [deleted file]
src/test/ui/issues/issue-24204.rs [deleted file]
src/test/ui/issues/issue-31924-non-snake-ffi.rs [deleted file]
src/test/ui/issues/issue-32829.rs [deleted file]
src/test/ui/issues/issue-32829.stderr [deleted file]
src/test/ui/issues/issue-33537.rs [deleted file]
src/test/ui/issues/issue-40847.rs [deleted file]
src/test/ui/issues/issue-4201.rs [deleted file]
src/test/ui/issues/issue-4201.stderr [deleted file]
src/test/ui/issues/issue-43784-associated-type.rs [deleted file]
src/test/ui/issues/issue-43784-associated-type.stderr [deleted file]
src/test/ui/issues/issue-44406.rs [deleted file]
src/test/ui/issues/issue-44406.stderr [deleted file]
src/test/ui/issues/issue-49040.stderr
src/test/ui/issues/issue-54302-cases.stderr
src/test/ui/issues/issue-54302.stderr
src/test/ui/issues/issue-55731.stderr
src/test/ui/issues/issue-57843.nll.stderr
src/test/ui/issues/issue-57843.rs
src/test/ui/issues/issue-57843.stderr
src/test/ui/issues/issue-6157.rs [deleted file]
src/test/ui/issues/issue-77993-2.rs [deleted file]
src/test/ui/issues/issue-77993-2.stderr [deleted file]
src/test/ui/lifetimes/issue-79187.rs
src/test/ui/lifetimes/issue-79187.stderr
src/test/ui/lint/issue-31924-non-snake-ffi.rs [new file with mode: 0644]
src/test/ui/macros/html-literals.rs [new file with mode: 0644]
src/test/ui/mismatched_types/closure-arg-type-mismatch.rs
src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr
src/test/ui/old-suffixes-are-really-forbidden.rs [deleted file]
src/test/ui/old-suffixes-are-really-forbidden.stderr [deleted file]
src/test/ui/one-tuple.rs [deleted file]
src/test/ui/or-patterns/feature-gate-or_patterns.stderr
src/test/ui/or-patterns/fn-param-wrap-parens.fixed
src/test/ui/or-patterns/fn-param-wrap-parens.rs
src/test/ui/or-patterns/fn-param-wrap-parens.stderr
src/test/ui/or-patterns/multiple-pattern-typo.rs
src/test/ui/or-patterns/multiple-pattern-typo.stderr
src/test/ui/or-patterns/or-patterns-syntactic-fail.rs
src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr
src/test/ui/or-patterns/remove-leading-vert.fixed
src/test/ui/or-patterns/remove-leading-vert.rs
src/test/ui/or-patterns/remove-leading-vert.stderr
src/test/ui/parser/dotdotdot-expr.rs [new file with mode: 0644]
src/test/ui/parser/dotdotdot-expr.stderr [new file with mode: 0644]
src/test/ui/parser/issue-20616-3.rs [new file with mode: 0644]
src/test/ui/parser/issue-20616-3.stderr [new file with mode: 0644]
src/test/ui/parser/issue-44406.rs [new file with mode: 0644]
src/test/ui/parser/issue-44406.stderr [new file with mode: 0644]
src/test/ui/parser/old-suffixes-are-really-forbidden.rs [new file with mode: 0644]
src/test/ui/parser/old-suffixes-are-really-forbidden.stderr [new file with mode: 0644]
src/test/ui/parser/struct-literal-variant-in-if.rs [new file with mode: 0644]
src/test/ui/parser/struct-literal-variant-in-if.stderr [new file with mode: 0644]
src/test/ui/partialeq_help.stderr
src/test/ui/pattern/usefulness/deny-irrefutable-let-patterns.rs
src/test/ui/pattern/usefulness/deny-irrefutable-let-patterns.stderr
src/test/ui/project-defer-unification.rs [deleted file]
src/test/ui/range_inclusive_gate.rs [deleted file]
src/test/ui/regions-fn-subtyping-return-static-fail.nll.stderr [deleted file]
src/test/ui/regions-fn-subtyping-return-static-fail.rs [deleted file]
src/test/ui/regions-fn-subtyping-return-static-fail.stderr [deleted file]
src/test/ui/regions/regions-fn-subtyping-return-static-fail.nll.stderr [new file with mode: 0644]
src/test/ui/regions/regions-fn-subtyping-return-static-fail.rs [new file with mode: 0644]
src/test/ui/regions/regions-fn-subtyping-return-static-fail.stderr [new file with mode: 0644]
src/test/ui/repeat_count_const_in_async_fn.rs [deleted file]
src/test/ui/resolve/issue-82156.rs [new file with mode: 0644]
src/test/ui/resolve/issue-82156.stderr [new file with mode: 0644]
src/test/ui/rfc-2294-if-let-guard/warns.rs
src/test/ui/rfc-2294-if-let-guard/warns.stderr
src/test/ui/rfc1623.rs
src/test/ui/rfc1623.stderr
src/test/ui/rmeta/emit-artifact-notifications.nll.stderr [new file with mode: 0644]
src/test/ui/rmeta/emit-artifact-notifications.polonius.stderr [new file with mode: 0644]
src/test/ui/rmeta/emit-artifact-notifications.rs [new file with mode: 0644]
src/test/ui/rmeta/emit-artifact-notifications.stderr [new file with mode: 0644]
src/test/ui/rmeta/emit-metadata-obj.rs [new file with mode: 0644]
src/test/ui/rvalue-static-promotion.rs [deleted file]
src/test/ui/span/issue-81800.rs [new file with mode: 0644]
src/test/ui/span/issue-81800.stderr [new file with mode: 0644]
src/test/ui/specialization/deafult-associated-type-bound-2.stderr
src/test/ui/stability-attribute/stability-attribute-sanity.stderr
src/test/ui/struct-literal-variant-in-if.rs [deleted file]
src/test/ui/struct-literal-variant-in-if.stderr [deleted file]
src/test/ui/structs-enums/type-sizes.rs [new file with mode: 0644]
src/test/ui/suggestions/auxiliary/issue-81839.rs [new file with mode: 0644]
src/test/ui/suggestions/issue-81839.rs [new file with mode: 0644]
src/test/ui/suggestions/issue-81839.stderr [new file with mode: 0644]
src/test/ui/suggestions/match-prev-arm-needing-semi.stderr
src/test/ui/suggestions/suggest-change-mut.rs
src/test/ui/suggestions/suggest-change-mut.stderr
src/test/ui/traits/suggest-where-clause.stderr
src/test/ui/tuple/one-tuple.rs [new file with mode: 0644]
src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.nll.stderr
src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs
src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr
src/test/ui/type-id-higher-rank.rs [deleted file]
src/test/ui/type-sizes.rs [deleted file]
src/test/ui/unboxed-closures/issue-30906.nll.stderr
src/test/ui/unboxed-closures/issue-30906.rs
src/test/ui/unboxed-closures/issue-30906.stderr
src/test/ui/unboxed-closures/type-id-higher-rank.rs [new file with mode: 0644]
src/test/ui/where-clauses/where-for-self-2.stderr
src/test/ui/while-let.rs
src/test/ui/while-let.stderr
src/test/ui/write-to-static-mut-in-static.rs [deleted file]
src/test/ui/write-to-static-mut-in-static.stderr [deleted file]
src/tools/cargo
src/tools/clippy/clippy_lints/src/loops.rs
src/tools/clippy/clippy_lints/src/utils/ast_utils.rs
src/tools/tidy/src/ui_tests.rs

index c1011c0f479cbd158455ac6686fd354c95441d67..9f43f5a8b36b22ab54ff5b7bb2f74010fd82f40b 100644 (file)
@@ -285,7 +285,7 @@ checksum = "81a18687293a1546b67c246452202bbbf143d239cb43494cc163da14979082da"
 
 [[package]]
 name = "cargo"
-version = "0.52.0"
+version = "0.53.0"
 dependencies = [
  "anyhow",
  "atty",
index cd0ad2b0150bec5a91f190aa07ee977e22f83ae8..3550055ac10d3ce384cdc312df57e50a8394e231 100644 (file)
@@ -486,8 +486,8 @@ pub struct WhereEqPredicate {
 
 #[derive(Clone, Encodable, Decodable, Debug)]
 pub struct Crate {
-    pub module: Mod,
     pub attrs: Vec<Attribute>,
+    pub items: Vec<P<Item>>,
     pub span: Span,
     /// The order of items in the HIR is unrelated to the order of
     /// items in the AST. However, we generate proc macro harnesses
@@ -2299,21 +2299,22 @@ pub fn span(&self) -> Span {
     }
 }
 
-/// Module declaration.
-///
-/// E.g., `mod foo;` or `mod foo { .. }`.
+#[derive(Clone, PartialEq, Encodable, Decodable, Debug)]
+pub enum Inline {
+    Yes,
+    No,
+}
+
+/// Module item kind.
 #[derive(Clone, Encodable, Decodable, Debug)]
-pub struct Mod {
-    /// A span from the first token past `{` to the last token until `}`.
-    /// For `mod foo;`, the inner span ranges from the first token
-    /// to the last token in the external file.
-    pub inner: Span,
-    /// `unsafe` keyword accepted syntactically for macro DSLs, but not
-    /// semantically by Rust.
-    pub unsafety: Unsafe,
-    pub items: Vec<P<Item>>,
-    /// `true` for `mod foo { .. }`; `false` for `mod foo;`.
-    pub inline: bool,
+pub enum ModKind {
+    /// Module with inlined definition `mod foo { ... }`,
+    /// or with definition outlined to a separate file `mod foo;` and already loaded from it.
+    /// The inner span is from the first token past `{` to the last token until `}`,
+    /// or from the first to the last token in the loaded file.
+    Loaded(Vec<P<Item>>, Inline, Span),
+    /// Module with definition outlined to a separate file `mod foo;` but not yet loaded from it.
+    Unloaded,
 }
 
 /// Foreign module declaration.
@@ -2710,7 +2711,9 @@ pub enum ItemKind {
     /// A module declaration (`mod`).
     ///
     /// E.g., `mod foo;` or `mod foo { .. }`.
-    Mod(Mod),
+    /// `unsafe` keyword on modules is accepted syntactically for macro DSLs, but not
+    /// semantically by Rust.
+    Mod(Unsafe, ModKind),
     /// An external module (`extern`).
     ///
     /// E.g., `extern {}` or `extern "C" {}`.
index 024d9687f311940710bac84eb21f04f908aa8383..c286738811ca13c27648c1da000c6ed5f72bb64b 100644 (file)
@@ -170,10 +170,6 @@ fn visit_ty_constraint(&mut self, t: &mut AssocTyConstraint) {
         noop_visit_ty_constraint(t, self);
     }
 
-    fn visit_mod(&mut self, m: &mut Mod) {
-        noop_visit_mod(m, self);
-    }
-
     fn visit_foreign_mod(&mut self, nm: &mut ForeignMod) {
         noop_visit_foreign_mod(nm, self);
     }
@@ -917,7 +913,13 @@ pub fn noop_visit_item_kind<T: MutVisitor>(kind: &mut ItemKind, vis: &mut T) {
             vis.visit_generics(generics);
             visit_opt(body, |body| vis.visit_block(body));
         }
-        ItemKind::Mod(m) => vis.visit_mod(m),
+        ItemKind::Mod(_unsafety, mod_kind) => match mod_kind {
+            ModKind::Loaded(items, _inline, inner_span) => {
+                vis.visit_span(inner_span);
+                items.flat_map_in_place(|item| vis.flat_map_item(item));
+            }
+            ModKind::Unloaded => {}
+        },
         ItemKind::ForeignMod(nm) => vis.visit_foreign_mod(nm),
         ItemKind::GlobalAsm(_ga) => {}
         ItemKind::TyAlias(box TyAliasKind(_, generics, bounds, ty)) => {
@@ -998,14 +1000,10 @@ pub fn noop_visit_fn_header<T: MutVisitor>(header: &mut FnHeader, vis: &mut T) {
     vis.visit_asyncness(asyncness);
 }
 
-pub fn noop_visit_mod<T: MutVisitor>(module: &mut Mod, vis: &mut T) {
-    let Mod { inner, unsafety: _, items, inline: _ } = module;
-    vis.visit_span(inner);
-    items.flat_map_in_place(|item| vis.flat_map_item(item));
-}
-
+// FIXME: Avoid visiting the crate as a `Mod` item, flat map only the inner items if possible,
+// or make crate visiting first class if necessary.
 pub fn noop_visit_crate<T: MutVisitor>(krate: &mut Crate, vis: &mut T) {
-    visit_clobber(krate, |Crate { module, attrs, span, proc_macros }| {
+    visit_clobber(krate, |Crate { attrs, items, span, proc_macros }| {
         let item_vis =
             Visibility { kind: VisibilityKind::Public, span: span.shrink_to_lo(), tokens: None };
         let item = P(Item {
@@ -1014,19 +1012,20 @@ pub fn noop_visit_crate<T: MutVisitor>(krate: &mut Crate, vis: &mut T) {
             id: DUMMY_NODE_ID,
             vis: item_vis,
             span,
-            kind: ItemKind::Mod(module),
+            kind: ItemKind::Mod(Unsafe::No, ModKind::Loaded(items, Inline::Yes, span)),
             tokens: None,
         });
         let items = vis.flat_map_item(item);
 
         let len = items.len();
         if len == 0 {
-            let module = Mod { inner: span, unsafety: Unsafe::No, items: vec![], inline: true };
-            Crate { module, attrs: vec![], span, proc_macros }
+            Crate { attrs: vec![], items: vec![], span, proc_macros }
         } else if len == 1 {
             let Item { attrs, span, kind, .. } = items.into_iter().next().unwrap().into_inner();
             match kind {
-                ItemKind::Mod(module) => Crate { module, attrs, span, proc_macros },
+                ItemKind::Mod(_, ModKind::Loaded(items, ..)) => {
+                    Crate { attrs, items, span, proc_macros }
+                }
                 _ => panic!("visitor converted a module to not a module"),
             }
         } else {
index c37d4cd9f79365a4be8e7197ede66e56d7d37678..32b9dd46baef446dc6b2f78d88e6393de49f4133 100644 (file)
@@ -74,7 +74,7 @@ pub fn ctxt(&self) -> Option<FnCtxt> {
 /// Each method of the `Visitor` trait is a hook to be potentially
 /// overridden. Each method's default implementation recursively visits
 /// the substructure of the input via the corresponding `walk` method;
-/// e.g., the `visit_mod` method by default calls `visit::walk_mod`.
+/// e.g., the `visit_item` method by default calls `visit::walk_item`.
 ///
 /// If you want to ensure that your code handles every variant
 /// explicitly, you need to override each method. (And you also need
@@ -87,9 +87,6 @@ fn visit_name(&mut self, _span: Span, _name: Symbol) {
     fn visit_ident(&mut self, ident: Ident) {
         walk_ident(self, ident);
     }
-    fn visit_mod(&mut self, m: &'ast Mod, _s: Span, _attrs: &[Attribute], _n: NodeId) {
-        walk_mod(self, m);
-    }
     fn visit_foreign_item(&mut self, i: &'ast ForeignItem) {
         walk_foreign_item(self, i)
     }
@@ -238,14 +235,10 @@ pub fn walk_ident<'a, V: Visitor<'a>>(visitor: &mut V, ident: Ident) {
 }
 
 pub fn walk_crate<'a, V: Visitor<'a>>(visitor: &mut V, krate: &'a Crate) {
-    visitor.visit_mod(&krate.module, krate.span, &krate.attrs, CRATE_NODE_ID);
+    walk_list!(visitor, visit_item, &krate.items);
     walk_list!(visitor, visit_attribute, &krate.attrs);
 }
 
-pub fn walk_mod<'a, V: Visitor<'a>>(visitor: &mut V, module: &'a Mod) {
-    walk_list!(visitor, visit_item, &module.items);
-}
-
 pub fn walk_local<'a, V: Visitor<'a>>(visitor: &mut V, local: &'a Local) {
     for attr in local.attrs.iter() {
         visitor.visit_attribute(attr);
@@ -297,7 +290,12 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
             let kind = FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, body.as_deref());
             visitor.visit_fn(kind, item.span, item.id)
         }
-        ItemKind::Mod(ref module) => visitor.visit_mod(module, item.span, &item.attrs, item.id),
+        ItemKind::Mod(_unsafety, ref mod_kind) => match mod_kind {
+            ModKind::Loaded(items, _inline, _inner_span) => {
+                walk_list!(visitor, visit_item, items)
+            }
+            ModKind::Unloaded => {}
+        },
         ItemKind::ForeignMod(ref foreign_module) => {
             walk_list!(visitor, visit_foreign_item, &foreign_module.items);
         }
index cad2a21d1a4a7190e43687fc7c5f7c3f137fe0b0..8b740b77740892d875b3df8d64640a07f25578e3 100644 (file)
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::Span;
 use rustc_target::spec::abi;
-
 use smallvec::{smallvec, SmallVec};
-use std::collections::BTreeSet;
 use tracing::debug;
 
+use std::mem;
+
 pub(super) struct ItemLowerer<'a, 'lowering, 'hir> {
     pub(super) lctx: &'a mut LoweringContext<'lowering, 'hir>,
 }
@@ -34,25 +34,6 @@ fn with_trait_impl_ref(&mut self, impl_ref: &Option<TraitRef>, f: impl FnOnce(&m
 }
 
 impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> {
-    fn visit_mod(&mut self, m: &'a Mod, _s: Span, _attrs: &[Attribute], n: NodeId) {
-        let def_id = self.lctx.lower_node_id(n).expect_owner();
-
-        self.lctx.modules.insert(
-            def_id,
-            hir::ModuleItems {
-                items: BTreeSet::new(),
-                trait_items: BTreeSet::new(),
-                impl_items: BTreeSet::new(),
-                foreign_items: BTreeSet::new(),
-            },
-        );
-
-        let old = self.lctx.current_module;
-        self.lctx.current_module = def_id;
-        visit::walk_mod(self, m);
-        self.lctx.current_module = old;
-    }
-
     fn visit_item(&mut self, item: &'a Item) {
         let mut item_hir_id = None;
         self.lctx.with_hir_id_owner(item.id, |lctx| {
@@ -67,10 +48,18 @@ fn visit_item(&mut self, item: &'a Item) {
         if let Some(hir_id) = item_hir_id {
             self.lctx.with_parent_item_lifetime_defs(hir_id, |this| {
                 let this = &mut ItemLowerer { lctx: this };
-                if let ItemKind::Impl(box ImplKind { ref of_trait, .. }) = item.kind {
-                    this.with_trait_impl_ref(of_trait, |this| visit::walk_item(this, item));
-                } else {
-                    visit::walk_item(this, item);
+                match item.kind {
+                    ItemKind::Mod(..) => {
+                        let def_id = this.lctx.lower_node_id(item.id).expect_owner();
+                        let old_current_module =
+                            mem::replace(&mut this.lctx.current_module, def_id);
+                        visit::walk_item(this, item);
+                        this.lctx.current_module = old_current_module;
+                    }
+                    ItemKind::Impl(box ImplKind { ref of_trait, .. }) => {
+                        this.with_trait_impl_ref(of_trait, |this| visit::walk_item(this, item));
+                    }
+                    _ => visit::walk_item(this, item),
                 }
             });
         }
@@ -94,13 +83,13 @@ fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
                 let hir_item = lctx.lower_trait_item(item);
                 let id = hir_item.trait_item_id();
                 lctx.trait_items.insert(id, hir_item);
-                lctx.modules.get_mut(&lctx.current_module).unwrap().trait_items.insert(id);
+                lctx.modules.entry(lctx.current_module).or_default().trait_items.insert(id);
             }
             AssocCtxt::Impl => {
                 let hir_item = lctx.lower_impl_item(item);
                 let id = hir_item.impl_item_id();
                 lctx.impl_items.insert(id, hir_item);
-                lctx.modules.get_mut(&lctx.current_module).unwrap().impl_items.insert(id);
+                lctx.modules.entry(lctx.current_module).or_default().impl_items.insert(id);
             }
         });
 
@@ -113,7 +102,7 @@ fn visit_foreign_item(&mut self, item: &'a ForeignItem) {
             let hir_item = lctx.lower_foreign_item(item);
             let id = hir_item.foreign_item_id();
             lctx.foreign_items.insert(id, hir_item);
-            lctx.modules.get_mut(&lctx.current_module).unwrap().foreign_items.insert(id);
+            lctx.modules.entry(lctx.current_module).or_default().foreign_items.insert(id);
         });
 
         visit::walk_foreign_item(self, item);
@@ -157,7 +146,7 @@ fn without_in_scope_lifetime_defs<T>(
         &mut self,
         f: impl FnOnce(&mut LoweringContext<'_, '_>) -> T,
     ) -> T {
-        let old_in_scope_lifetimes = std::mem::replace(&mut self.in_scope_lifetimes, vec![]);
+        let old_in_scope_lifetimes = mem::replace(&mut self.in_scope_lifetimes, vec![]);
 
         // this vector is only used when walking over impl headers,
         // input types, and the like, and should not be non-empty in
@@ -172,12 +161,10 @@ fn without_in_scope_lifetime_defs<T>(
         res
     }
 
-    pub(super) fn lower_mod(&mut self, m: &Mod) -> hir::Mod<'hir> {
+    pub(super) fn lower_mod(&mut self, items: &[P<Item>], inner: Span) -> hir::Mod<'hir> {
         hir::Mod {
-            inner: m.inner,
-            item_ids: self
-                .arena
-                .alloc_from_iter(m.items.iter().flat_map(|x| self.lower_item_id(x))),
+            inner,
+            item_ids: self.arena.alloc_from_iter(items.iter().flat_map(|x| self.lower_item_id(x))),
         }
     }
 
@@ -327,7 +314,12 @@ fn lower_item_kind(
                     hir::ItemKind::Fn(sig, generics, body_id)
                 })
             }
-            ItemKind::Mod(ref m) => hir::ItemKind::Mod(self.lower_mod(m)),
+            ItemKind::Mod(_, ref mod_kind) => match mod_kind {
+                ModKind::Loaded(items, _, inner_span) => {
+                    hir::ItemKind::Mod(self.lower_mod(items, *inner_span))
+                }
+                ModKind::Unloaded => panic!("`mod` items should have been loaded by now"),
+            },
             ItemKind::ForeignMod(ref fm) => {
                 if fm.abi.is_none() {
                     self.maybe_lint_missing_abi(span, id, abi::Abi::C);
index 9d0b2cd5c675d0667d7fe2ad75447158b0554aea..05b417effd491688e9782633fc90e3c3f4a6c706 100644 (file)
@@ -560,7 +560,7 @@ fn visit_ty(&mut self, t: &'tcx Ty) {
         visit::walk_crate(&mut MiscCollector { lctx: &mut self }, c);
         visit::walk_crate(&mut item::ItemLowerer { lctx: &mut self }, c);
 
-        let module = self.lower_mod(&c.module);
+        let module = self.lower_mod(&c.items, c.span);
         let attrs = self.lower_attrs(&c.attrs);
         let body_ids = body_ids(&self.bodies);
         let proc_macros =
@@ -608,7 +608,7 @@ fn visit_ty(&mut self, t: &'tcx Ty) {
     fn insert_item(&mut self, item: hir::Item<'hir>) -> hir::ItemId {
         let id = hir::ItemId { def_id: item.def_id };
         self.items.insert(id, item);
-        self.modules.get_mut(&self.current_module).unwrap().items.insert(id);
+        self.modules.entry(self.current_module).or_default().items.insert(id);
         id
     }
 
index 8defd91c688d7b241b215784073dfd24b77bf682..563bcda51906575cefaf6602b1553caa42bba11e 100644 (file)
@@ -1054,12 +1054,14 @@ fn visit_item(&mut self, item: &'a Item) {
                 walk_list!(self, visit_attribute, &item.attrs);
                 return;
             }
-            ItemKind::Mod(Mod { inline, unsafety, .. }) => {
+            ItemKind::Mod(unsafety, ref mod_kind) => {
                 if let Unsafe::Yes(span) = unsafety {
                     self.err_handler().span_err(span, "module cannot be declared unsafe");
                 }
                 // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
-                if !inline && !self.session.contains_name(&item.attrs, sym::path) {
+                if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _))
+                    && !self.session.contains_name(&item.attrs, sym::path)
+                {
                     self.check_mod_file_item_asciionly(item.ident);
                 }
             }
index 2971fa435c8dce47ed19909012968a019d2b6657..fb7e0d3450fde5a0f1b1cf422838fa73a4d37574 100644 (file)
@@ -20,10 +20,6 @@ fn visit_ident(&mut self, ident: Ident) {
         self.count += 1;
         walk_ident(self, ident);
     }
-    fn visit_mod(&mut self, m: &Mod, _s: Span, _a: &[Attribute], _n: NodeId) {
-        self.count += 1;
-        walk_mod(self, m)
-    }
     fn visit_foreign_item(&mut self, i: &ForeignItem) {
         self.count += 1;
         walk_foreign_item(self, i)
index 180402c24fb7b683611035901908df1f34766962..82f6e936b766eb041a8bc4458abab9fd25d56772 100644 (file)
@@ -9,7 +9,7 @@
 use rustc_ast::util::comments::{gather_comments, Comment, CommentStyle};
 use rustc_ast::util::parser::{self, AssocOp, Fixity};
 use rustc_ast::{self as ast, BlockCheckMode, PatKind, RangeEnd, RangeSyntax};
-use rustc_ast::{GenericArg, MacArgs};
+use rustc_ast::{GenericArg, MacArgs, ModKind};
 use rustc_ast::{GenericBound, SelfKind, TraitBoundModifier};
 use rustc_ast::{InlineAsmOperand, InlineAsmRegOrRegClass};
 use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
@@ -87,7 +87,6 @@ pub struct State<'a> {
     pub s: pp::Printer,
     comments: Option<Comments<'a>>,
     ann: &'a (dyn PpAnn + 'a),
-    is_expanded: bool,
 }
 
 crate const INDENT_UNIT: usize = 4;
@@ -103,12 +102,8 @@ pub fn print_crate<'a>(
     is_expanded: bool,
     edition: Edition,
 ) -> String {
-    let mut s = State {
-        s: pp::mk_printer(),
-        comments: Some(Comments::new(sm, filename, input)),
-        ann,
-        is_expanded,
-    };
+    let mut s =
+        State { s: pp::mk_printer(), comments: Some(Comments::new(sm, filename, input)), ann };
 
     if is_expanded && !krate.attrs.iter().any(|attr| attr.has_name(sym::no_core)) {
         // We need to print `#![no_std]` (and its feature gate) so that
@@ -132,7 +127,10 @@ pub fn print_crate<'a>(
         }
     }
 
-    s.print_mod(&krate.module, &krate.attrs);
+    s.print_inner_attributes(&krate.attrs);
+    for item in &krate.items {
+        s.print_item(item);
+    }
     s.print_remaining_comments();
     s.ann.post(&mut s, AnnNode::Crate(krate));
     s.s.eof()
@@ -853,7 +851,7 @@ fn print_generic_args(&mut self, args: &ast::GenericArgs, colons_before_params:
 
 impl<'a> State<'a> {
     pub fn new() -> State<'a> {
-        State { s: pp::mk_printer(), comments: None, ann: &NoAnn, is_expanded: false }
+        State { s: pp::mk_printer(), comments: None, ann: &NoAnn }
     }
 
     // Synthesizes a comment that was not textually present in the original source
@@ -891,13 +889,6 @@ pub fn synth_comment(&mut self, text: String) {
         self.commasep_cmnt(b, exprs, |s, e| s.print_expr(e), |e| e.span)
     }
 
-    pub fn print_mod(&mut self, _mod: &ast::Mod, attrs: &[ast::Attribute]) {
-        self.print_inner_attributes(attrs);
-        for item in &_mod.items {
-            self.print_item(item);
-        }
-    }
-
     crate fn print_foreign_mod(&mut self, nmod: &ast::ForeignMod, attrs: &[ast::Attribute]) {
         self.print_inner_attributes(attrs);
         for item in &nmod.items {
@@ -914,6 +905,7 @@ pub fn print_opt_lifetime(&mut self, lifetime: &Option<ast::Lifetime>) {
 
     pub fn print_assoc_constraint(&mut self, constraint: &ast::AssocTyConstraint) {
         self.print_ident(constraint.ident);
+        constraint.gen_args.as_ref().map(|args| self.print_generic_args(args, false));
         self.s.space();
         match &constraint.kind {
             ast::AssocTyConstraintKind::Equality { ty } => {
@@ -1138,23 +1130,29 @@ fn print_associated_type(
                 let body = body.as_deref();
                 self.print_fn_full(sig, item.ident, gen, &item.vis, def, body, &item.attrs);
             }
-            ast::ItemKind::Mod(ref _mod) => {
+            ast::ItemKind::Mod(unsafety, ref mod_kind) => {
                 self.head(self.to_string(|s| {
                     s.print_visibility(&item.vis);
-                    s.print_unsafety(_mod.unsafety);
+                    s.print_unsafety(unsafety);
                     s.word("mod");
                 }));
                 self.print_ident(item.ident);
 
-                if _mod.inline || self.is_expanded {
-                    self.nbsp();
-                    self.bopen();
-                    self.print_mod(_mod, &item.attrs);
-                    self.bclose(item.span);
-                } else {
-                    self.s.word(";");
-                    self.end(); // end inner head-block
-                    self.end(); // end outer head-block
+                match mod_kind {
+                    ModKind::Loaded(items, ..) => {
+                        self.nbsp();
+                        self.bopen();
+                        self.print_inner_attributes(&item.attrs);
+                        for item in items {
+                            self.print_item(item);
+                        }
+                        self.bclose(item.span);
+                    }
+                    ModKind::Unloaded => {
+                        self.s.word(";");
+                        self.end(); // end inner head-block
+                        self.end(); // end outer head-block
+                    }
                 }
             }
             ast::ItemKind::ForeignMod(ref nmod) => {
index 7582d9805390ec24295c9792a35c76bb3c0f4797..71bbae1161b4bebcef863c749dde5e5f53697b2b 100644 (file)
@@ -91,7 +91,7 @@ pub fn inject(
     }
 
     let decls = mk_decls(&mut krate, &mut cx, &macros);
-    krate.module.items.push(decls);
+    krate.items.push(decls);
 
     krate
 }
index 91566ec1ef24540323c9769cbd2f88e3fad78fed..3a81d076dc52fdbd6ea2db324bdc90bee7cc40f0 100644 (file)
@@ -44,7 +44,7 @@ pub fn inject(
     // .rev() to preserve ordering above in combination with insert(0, ...)
     for &name in names.iter().rev() {
         let ident = if rust_2018 { Ident::new(name, span) } else { Ident::new(name, call_site) };
-        krate.module.items.insert(
+        krate.items.insert(
             0,
             cx.item(
                 span,
@@ -79,7 +79,7 @@ pub fn inject(
         })),
     );
 
-    krate.module.items.insert(0, use_item);
+    krate.items.insert(0, use_item);
 
     krate
 }
index 4ac22be3c275d508077f12dbe7620dd5b60b34c3..28e8259784387078e064de865d09c7c62e8cb286 100644 (file)
@@ -1,10 +1,10 @@
 // Code that generates a test runner to run all the tests in a crate
 
 use rustc_ast as ast;
-use rustc_ast::attr;
 use rustc_ast::entry::EntryPointType;
 use rustc_ast::mut_visit::{ExpectOne, *};
 use rustc_ast::ptr::P;
+use rustc_ast::{attr, ModKind};
 use rustc_expand::base::{ExtCtxt, ResolverExpand};
 use rustc_expand::expand::{AstFragment, ExpansionConfig};
 use rustc_feature::Features;
@@ -89,7 +89,7 @@ fn visit_crate(&mut self, c: &mut ast::Crate) {
         noop_visit_crate(c, self);
 
         // Create a main function to run our tests
-        c.module.items.push(mk_main(&mut self.cx));
+        c.items.push(mk_main(&mut self.cx));
     }
 
     fn flat_map_item(&mut self, i: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
@@ -103,9 +103,9 @@ fn visit_crate(&mut self, c: &mut ast::Crate) {
 
         // We don't want to recurse into anything other than mods, since
         // mods or tests inside of functions will break things
-        if let ast::ItemKind::Mod(mut module) = item.kind {
+        if let ast::ItemKind::Mod(..) = item.kind {
             let tests = mem::take(&mut self.tests);
-            noop_visit_mod(&mut module, self);
+            noop_visit_item_kind(&mut item.kind, self);
             let mut tests = mem::replace(&mut self.tests, tests);
 
             if !tests.is_empty() {
@@ -113,8 +113,12 @@ fn visit_crate(&mut self, c: &mut ast::Crate) {
                     if item.id == ast::DUMMY_NODE_ID { ast::CRATE_NODE_ID } else { item.id };
                 // Create an identifier that will hygienically resolve the test
                 // case name, even in another module.
+                let inner_span = match item.kind {
+                    ast::ItemKind::Mod(_, ModKind::Loaded(.., span)) => span,
+                    _ => unreachable!(),
+                };
                 let expn_id = self.cx.ext_cx.resolver.expansion_for_ast_pass(
-                    module.inner,
+                    inner_span,
                     AstPass::TestHarness,
                     &[],
                     Some(parent),
@@ -126,7 +130,6 @@ fn visit_crate(&mut self, c: &mut ast::Crate) {
                 }
                 self.cx.test_cases.extend(tests);
             }
-            item.kind = ast::ItemKind::Mod(module);
         }
         smallvec![P(item)]
     }
index f1eae605da0181b12967dea276510702b23f894c..ea59e1831188b82bca2bb0db58037f9d3c1bcba9 100644 (file)
@@ -320,6 +320,8 @@ pub fn compute_per_local_var_debug_info(
     ) -> Option<IndexVec<mir::Local, Vec<PerLocalVarDebugInfo<'tcx, Bx::DIVariable>>>> {
         let full_debug_info = self.cx.sess().opts.debuginfo == DebugInfo::Full;
 
+        let target_is_msvc = self.cx.sess().target.is_like_msvc;
+
         if !full_debug_info && self.cx.sess().fewer_names() {
             return None;
         }
@@ -341,11 +343,29 @@ pub fn compute_per_local_var_debug_info(
                             && var.source_info.scope == mir::OUTERMOST_SOURCE_SCOPE
                         {
                             let arg_index = place.local.index() - 1;
-
-                            // FIXME(eddyb) shouldn't `ArgumentVariable` indices be
-                            // offset in closures to account for the hidden environment?
-                            // Also, is this `+ 1` needed at all?
-                            VariableKind::ArgumentVariable(arg_index + 1)
+                            if target_is_msvc {
+                                // Rust compiler decomposes every &str or slice argument into two components:
+                                // a pointer to the memory address where the data is stored and a usize representing
+                                // the length of the str (or slice). These components will later be used to reconstruct
+                                // the original argument inside the body of the function that owns it (see the
+                                // definition of debug_introduce_local for more details).
+                                //
+                                // Since the original argument is declared inside a function rather than being passed
+                                // in as an argument, it must be marked as a LocalVariable for MSVC debuggers to visualize
+                                // its data correctly. (See issue #81894 for an in-depth description of the problem).
+                                match *var_ty.kind() {
+                                    ty::Ref(_, inner_type, _) => match *inner_type.kind() {
+                                        ty::Slice(_) | ty::Str => VariableKind::LocalVariable,
+                                        _ => VariableKind::ArgumentVariable(arg_index + 1),
+                                    },
+                                    _ => VariableKind::ArgumentVariable(arg_index + 1),
+                                }
+                            } else {
+                                // FIXME(eddyb) shouldn't `ArgumentVariable` indices be
+                                // offset in closures to account for the hidden environment?
+                                // Also, is this `+ 1` needed at all?
+                                VariableKind::ArgumentVariable(arg_index + 1)
+                            }
                         } else {
                             VariableKind::LocalVariable
                         };
index f0b413c795e9c7d6c61bf57e21e991e1e876329c..51f851dc9469fe10dc0a07fea8d21e20c8a71b4a 100644 (file)
@@ -608,7 +608,7 @@ pub fn print_time_passes_entry(
         (None, None) => String::new(),
     };
 
-    println!("time: {:>7}{}\t{}", duration_to_secs_str(dur), mem_string, what);
+    eprintln!("time: {:>7}{}\t{}", duration_to_secs_str(dur), mem_string, what);
 }
 
 // Hack up our own formatting for the duration to make it easier for scripts
index 4f2febf04b135acf54afa8009bd74a46d42a1705..01338359f1af1d063ddc3d16130fc221a31657f4 100644 (file)
@@ -3,7 +3,7 @@
 use std::fs;
 use std::io;
 
-pub fn arg_expand(arg: String) -> Result<Vec<String>, Error> {
+fn arg_expand(arg: String) -> Result<Vec<String>, Error> {
     if let Some(path) = arg.strip_prefix('@') {
         let file = match fs::read_to_string(path) {
             Ok(file) => file,
@@ -18,6 +18,20 @@ pub fn arg_expand(arg: String) -> Result<Vec<String>, Error> {
     }
 }
 
+pub fn arg_expand_all(at_args: &[String]) -> Vec<String> {
+    let mut args = Vec::new();
+    for arg in at_args {
+        match arg_expand(arg.clone()) {
+            Ok(arg) => args.extend(arg),
+            Err(err) => rustc_session::early_error(
+                rustc_session::config::ErrorOutputType::default(),
+                &format!("Failed to load argument file: {}", err),
+            ),
+        }
+    }
+    args
+}
+
 #[derive(Debug)]
 pub enum Error {
     Utf8Error(Option<String>),
index 8295e88f75ac70779d3d3c763f0ebecc5a129c19..cad5a87bb134663ad329c360df5a442709356ecb 100644 (file)
@@ -55,7 +55,7 @@
 use std::str;
 use std::time::Instant;
 
-mod args;
+pub mod args;
 pub mod pretty;
 
 /// Exit status code used for successful compilation and help output.
@@ -188,16 +188,8 @@ fn run_compiler(
         Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>,
     >,
 ) -> interface::Result<()> {
-    let mut args = Vec::new();
-    for arg in at_args {
-        match args::arg_expand(arg.clone()) {
-            Ok(arg) => args.extend(arg),
-            Err(err) => early_error(
-                ErrorOutputType::default(),
-                &format!("Failed to load argument file: {}", err),
-            ),
-        }
-    }
+    let args = args::arg_expand_all(at_args);
+
     let diagnostic_output = emitter.map_or(DiagnosticOutput::Default, DiagnosticOutput::Raw);
     let matches = match handle_options(&args) {
         Some(matches) => matches,
index 8944711f38f4f68819bfcca193e2ef079a22c209..c4330694504c34e53a04f257bce6b2c66adcc6e0 100644 (file)
 E0545: include_str!("./error_codes/E0545.md"),
 E0546: include_str!("./error_codes/E0546.md"),
 E0547: include_str!("./error_codes/E0547.md"),
+E0549: include_str!("./error_codes/E0549.md"),
 E0550: include_str!("./error_codes/E0550.md"),
 E0551: include_str!("./error_codes/E0551.md"),
 E0552: include_str!("./error_codes/E0552.md"),
 //  E0540, // multiple rustc_deprecated attributes
     E0544, // multiple stability levels
 //  E0548, // replaced with a generic attribute input check
-    // rustc_deprecated attribute must be paired with either stable or unstable
-    // attribute
-    E0549,
     E0553, // multiple rustc_const_unstable attributes
 //  E0555, // replaced with a generic attribute input check
 //  E0558, // replaced with a generic attribute input check
index 98146147f3950da35f564707003d7e5701d64745..0161c9325c2111e573d91a609bfa8a102fe608b2 100644 (file)
@@ -1,6 +1,6 @@
 #### Note: this error code is no longer emitted by the compiler.
 
-An if-let pattern attempts to match the pattern, and enters the body if the
+An `if let` pattern attempts to match the pattern, and enters the body if the
 match was successful. If the match is irrefutable (when it cannot fail to
 match), use a regular `let`-binding instead. For instance:
 
index 92243db455015404b2aa836aba97009f5b4e6072..7bcd6c0cbf379fe8a0b09bd6b7d0930001ffb389 100644 (file)
@@ -1,6 +1,6 @@
 #### Note: this error code is no longer emitted by the compiler.
 
-A while-let pattern attempts to match the pattern, and enters the body if the
+A `while let` pattern attempts to match the pattern, and enters the body if the
 match was successful. If the match is irrefutable (when it cannot fail to
 match), use a regular `let`-binding inside a `loop` instead. For instance:
 
diff --git a/compiler/rustc_error_codes/src/error_codes/E0549.md b/compiler/rustc_error_codes/src/error_codes/E0549.md
new file mode 100644 (file)
index 0000000..d4b78e7
--- /dev/null
@@ -0,0 +1,37 @@
+A `rustc_deprecated` attribute wasn't paired with a `stable`/`unstable`
+attribute.
+
+Erroneous code example:
+
+```compile_fail,E0549
+#![feature(staged_api)]
+#![stable(since = "1.0.0", feature = "test")]
+
+#[rustc_deprecated(
+    since = "1.0.1",
+    reason = "explanation for deprecation"
+)] // invalid
+fn _deprecated_fn() {}
+```
+
+To fix this issue, you need to add also an attribute `stable` or `unstable`.
+Example:
+
+```
+#![feature(staged_api)]
+#![stable(since = "1.0.0", feature = "test")]
+
+#[stable(since = "1.0.0", feature = "test")]
+#[rustc_deprecated(
+    since = "1.0.1",
+    reason = "explanation for deprecation"
+)] // ok!
+fn _deprecated_fn() {}
+```
+
+See the [How Rust is Made and “Nightly Rust”][how-rust-made-nightly] appendix
+of the Book and the [Stability attributes][stability-attributes] section of the
+Rustc Dev Guide for more details.
+
+[how-rust-made-nightly]: https://doc.rust-lang.org/book/appendix-07-nightly-rust.html
+[stability-attributes]: https://rustc-dev-guide.rust-lang.org/stability.html
index ea62e21523028e3223fde03bc4098feb14fbb9f2..42c3d5e48fe86f040e041389c932e83504234c59 100644 (file)
@@ -1713,7 +1713,18 @@ fn emit_messages_default(
         let max_line_num_len = if self.ui_testing {
             ANONYMIZED_LINE_NUM.len()
         } else {
-            self.get_max_line_num(span, children).to_string().len()
+            // Instead of using .to_string().len(), we iteratively count the
+            // number of digits to avoid allocation. This strategy has sizable
+            // performance gains over the old string strategy.
+            let mut n = self.get_max_line_num(span, children);
+            let mut num_digits = 0;
+            loop {
+                num_digits += 1;
+                n /= 10;
+                if n == 0 {
+                    break num_digits;
+                }
+            }
         };
 
         match self.emit_message_default(span, message, code, level, max_line_num_len, false) {
index b07bce94870c1c9bdd33cbf4e11916abf178108f..ad04fa9a95816b64e5c7cb88613f90c6835aa3b1 100644 (file)
@@ -209,7 +209,7 @@ pub fn features(sess: &Session, mut krate: ast::Crate) -> (ast::Crate, Features)
         None => {
             // The entire crate is unconfigured.
             krate.attrs = Vec::new();
-            krate.module.items = Vec::new();
+            krate.items = Vec::new();
             Features::default()
         }
         Some(attrs) => {
index c5d0927760b6aed29d47466426f40ce7c7a2e3f8..5a4737842f0af0e4e0a26fee4c01a5f03853a69b 100644 (file)
@@ -12,8 +12,8 @@
 use rustc_ast::token;
 use rustc_ast::tokenstream::TokenStream;
 use rustc_ast::visit::{self, AssocCtxt, Visitor};
-use rustc_ast::{AttrItem, AttrStyle, Block, ItemKind, LitKind, MacArgs};
-use rustc_ast::{MacCallStmt, MacStmtStyle, MetaItemKind, NestedMetaItem};
+use rustc_ast::{AttrItem, AttrStyle, Block, Inline, ItemKind, LitKind, MacArgs};
+use rustc_ast::{MacCallStmt, MacStmtStyle, MetaItemKind, ModKind, NestedMetaItem};
 use rustc_ast::{NodeId, PatKind, Path, StmtKind, Unsafe};
 use rustc_ast_pretty::pprust;
 use rustc_attr::{self as attr, is_builtin_attr, HasAttrs};
@@ -22,7 +22,7 @@
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{Applicability, PResult};
 use rustc_feature::Features;
-use rustc_parse::parser::{AttemptLocalParseRecovery, ForceCollect, Parser};
+use rustc_parse::parser::{AttemptLocalParseRecovery, ForceCollect, GateOr, Parser, RecoverComma};
 use rustc_parse::validate_attr;
 use rustc_session::lint::builtin::UNUSED_DOC_COMMENTS;
 use rustc_session::lint::BuiltinLintDiagnostics;
@@ -350,6 +350,8 @@ pub fn new(cx: &'a mut ExtCtxt<'b>, monotonic: bool) -> Self {
         MacroExpander { cx, monotonic }
     }
 
+    // FIXME: Avoid visiting the crate as a `Mod` item,
+    // make crate a first class expansion target instead.
     pub fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate {
         let mut module = ModuleData {
             mod_path: vec![Ident::from_str(&self.cx.ecfg.crate_name)],
@@ -362,12 +364,13 @@ pub fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate {
         self.cx.root_path = module.directory.clone();
         self.cx.current_expansion.module = Rc::new(module);
 
-        let orig_mod_span = krate.module.inner;
-
         let krate_item = AstFragment::Items(smallvec![P(ast::Item {
             attrs: krate.attrs,
             span: krate.span,
-            kind: ast::ItemKind::Mod(krate.module),
+            kind: ast::ItemKind::Mod(
+                Unsafe::No,
+                ModKind::Loaded(krate.items, Inline::Yes, krate.span)
+            ),
             ident: Ident::invalid(),
             id: ast::DUMMY_NODE_ID,
             vis: ast::Visibility {
@@ -379,28 +382,22 @@ pub fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate {
         })]);
 
         match self.fully_expand_fragment(krate_item).make_items().pop().map(P::into_inner) {
-            Some(ast::Item { attrs, kind: ast::ItemKind::Mod(module), .. }) => {
+            Some(ast::Item {
+                attrs,
+                kind: ast::ItemKind::Mod(_, ModKind::Loaded(items, ..)),
+                ..
+            }) => {
                 krate.attrs = attrs;
-                krate.module = module;
+                krate.items = items;
             }
             None => {
                 // Resolution failed so we return an empty expansion
                 krate.attrs = vec![];
-                krate.module = ast::Mod {
-                    inner: orig_mod_span,
-                    unsafety: Unsafe::No,
-                    items: vec![],
-                    inline: true,
-                };
+                krate.items = vec![];
             }
             Some(ast::Item { span, kind, .. }) => {
                 krate.attrs = vec![];
-                krate.module = ast::Mod {
-                    inner: orig_mod_span,
-                    unsafety: Unsafe::No,
-                    items: vec![],
-                    inline: true,
-                };
+                krate.items = vec![];
                 self.cx.span_err(
                     span,
                     &format!(
@@ -814,7 +811,9 @@ struct GateProcMacroInput<'a> {
         impl<'ast, 'a> Visitor<'ast> for GateProcMacroInput<'a> {
             fn visit_item(&mut self, item: &'ast ast::Item) {
                 match &item.kind {
-                    ast::ItemKind::Mod(module) if !module.inline => {
+                    ast::ItemKind::Mod(_, mod_kind)
+                        if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _)) =>
+                    {
                         feature_err(
                             self.parse_sess,
                             sym::proc_macro_hygiene,
@@ -914,7 +913,9 @@ pub fn parse_ast_fragment<'a>(
             }
         }
         AstFragmentKind::Ty => AstFragment::Ty(this.parse_ty()?),
-        AstFragmentKind::Pat => AstFragment::Pat(this.parse_pat(None)?),
+        AstFragmentKind::Pat => {
+            AstFragment::Pat(this.parse_pat_allow_top_alt(None, GateOr::Yes, RecoverComma::No)?)
+        }
         AstFragmentKind::Arms
         | AstFragmentKind::Fields
         | AstFragmentKind::FieldPats
@@ -1269,52 +1270,47 @@ fn visit_block(&mut self, block: &mut P<Block>) {
                     _ => unreachable!(),
                 })
             }
-            ast::ItemKind::Mod(ref mut old_mod @ ast::Mod { .. }) if ident != Ident::invalid() => {
+            ast::ItemKind::Mod(_, ref mut mod_kind) if ident != Ident::invalid() => {
                 let sess = &self.cx.sess.parse_sess;
                 let orig_ownership = self.cx.current_expansion.directory_ownership;
                 let mut module = (*self.cx.current_expansion.module).clone();
 
                 let pushed = &mut false; // Record `parse_external_mod` pushing so we can pop.
                 let dir = Directory { ownership: orig_ownership, path: module.directory };
-                let Directory { ownership, path } = if old_mod.inline {
-                    // Inline `mod foo { ... }`, but we still need to push directories.
-                    item.attrs = attrs;
-                    push_directory(&self.cx.sess, ident, &item.attrs, dir)
-                } else {
-                    // We have an outline `mod foo;` so we need to parse the file.
-                    let (new_mod, dir) = parse_external_mod(
-                        &self.cx.sess,
-                        ident,
-                        span,
-                        old_mod.unsafety,
-                        dir,
-                        &mut attrs,
-                        pushed,
-                    );
-
-                    let krate = ast::Crate {
-                        span: new_mod.inner,
-                        module: new_mod,
-                        attrs,
-                        proc_macros: vec![],
-                    };
-                    if let Some(extern_mod_loaded) = self.cx.extern_mod_loaded {
-                        extern_mod_loaded(&krate, ident);
+                let Directory { ownership, path } = match mod_kind {
+                    ModKind::Loaded(_, Inline::Yes, _) => {
+                        // Inline `mod foo { ... }`, but we still need to push directories.
+                        item.attrs = attrs;
+                        push_directory(&self.cx.sess, ident, &item.attrs, dir)
+                    }
+                    ModKind::Loaded(_, Inline::No, _) => {
+                        panic!("`mod` item is loaded from a file for the second time")
                     }
+                    ModKind::Unloaded => {
+                        // We have an outline `mod foo;` so we need to parse the file.
+                        let (items, inner_span, dir) =
+                            parse_external_mod(&self.cx.sess, ident, span, dir, &mut attrs, pushed);
+
+                        let krate =
+                            ast::Crate { attrs, items, span: inner_span, proc_macros: vec![] };
+                        if let Some(extern_mod_loaded) = self.cx.extern_mod_loaded {
+                            extern_mod_loaded(&krate, ident);
+                        }
 
-                    *old_mod = krate.module;
-                    item.attrs = krate.attrs;
-                    // File can have inline attributes, e.g., `#![cfg(...)]` & co. => Reconfigure.
-                    item = match self.configure(item) {
-                        Some(node) => node,
-                        None => {
-                            if *pushed {
-                                sess.included_mod_stack.borrow_mut().pop();
+                        *mod_kind = ModKind::Loaded(krate.items, Inline::No, inner_span);
+                        item.attrs = krate.attrs;
+                        // File can have inline attributes, e.g., `#![cfg(...)]` & co. => Reconfigure.
+                        item = match self.configure(item) {
+                            Some(node) => node,
+                            None => {
+                                if *pushed {
+                                    sess.included_mod_stack.borrow_mut().pop();
+                                }
+                                return Default::default();
                             }
-                            return Default::default();
-                        }
-                    };
-                    dir
+                        };
+                        dir
+                    }
                 };
 
                 // Set the module info before we flat map.
index 171cb3fa8e6e920088095fb7a085a0adfaab62cc..076d3b02be93fb45b565a17e4ac8cd6dec12074e 100644 (file)
@@ -1,4 +1,5 @@
-use rustc_ast::{token, Attribute, Mod, Unsafe};
+use rustc_ast::ptr::P;
+use rustc_ast::{token, Attribute, Item};
 use rustc_errors::{struct_span_err, PResult};
 use rustc_parse::new_parser_from_file;
 use rustc_session::parse::ParseSess;
@@ -42,11 +43,10 @@ pub struct ModulePathSuccess {
     sess: &Session,
     id: Ident,
     span: Span, // The span to blame on errors.
-    unsafety: Unsafe,
     Directory { mut ownership, path }: Directory,
     attrs: &mut Vec<Attribute>,
     pop_mod_stack: &mut bool,
-) -> (Mod, Directory) {
+) -> (Vec<P<Item>>, Span, Directory) {
     // We bail on the first error, but that error does not cause a fatal error... (1)
     let result: PResult<'_, _> = try {
         // Extract the file path and the new ownership.
@@ -62,26 +62,22 @@ pub struct ModulePathSuccess {
 
         // Actually parse the external file as a module.
         let mut parser = new_parser_from_file(&sess.parse_sess, &mp.path, Some(span));
-        let mut module = parser.parse_mod(&token::Eof, unsafety)?;
-        module.0.inline = false;
-        module
+        let (mut inner_attrs, items, inner_span) = parser.parse_mod(&token::Eof)?;
+        attrs.append(&mut inner_attrs);
+        (items, inner_span)
     };
     // (1) ...instead, we return a dummy module.
-    let (module, mut new_attrs) = result.map_err(|mut err| err.emit()).unwrap_or_else(|_| {
-        let module = Mod { inner: Span::default(), unsafety, items: Vec::new(), inline: false };
-        (module, Vec::new())
-    });
-    attrs.append(&mut new_attrs);
+    let (items, inner_span) = result.map_err(|mut err| err.emit()).unwrap_or_default();
 
-    // Extract the directory path for submodules of `module`.
-    let path = sess.source_map().span_to_unmapped_path(module.inner);
+    // Extract the directory path for submodules of  the module.
+    let path = sess.source_map().span_to_unmapped_path(inner_span);
     let mut path = match path {
         FileName::Real(name) => name.into_local_path(),
         other => PathBuf::from(other.to_string()),
     };
     path.pop();
 
-    (module, Directory { ownership, path })
+    (items, inner_span, Directory { ownership, path })
 }
 
 fn error_on_circular_module<'a>(
index be0300bad98bd1aa5f7274d001134a1f051fac17..7e7155ad27876bff0571d97c42305eb518be8ade 100644 (file)
@@ -7,8 +7,8 @@
 use rustc_span::with_default_session_globals;
 
 // This version doesn't care about getting comments or doc-strings in.
-fn fake_print_crate(s: &mut pprust::State<'_>, krate: &ast::Crate) {
-    s.print_mod(&krate.module, &krate.attrs)
+fn print_crate_items(krate: &ast::Crate) -> String {
+    krate.items.iter().map(|i| pprust::item_to_string(i)).collect::<Vec<_>>().join(" ")
 }
 
 // Change every identifier to "zz".
@@ -46,7 +46,7 @@ fn ident_transformation() {
         assert_pred!(
             matches_codepattern,
             "matches_codepattern",
-            pprust::to_string(|s| fake_print_crate(s, &krate)),
+            print_crate_items(&krate),
             "#[zz]mod zz{fn zz(zz:zz,zz:zz){zz!(zz,zz,zz);zz;zz}}".to_string()
         );
     })
@@ -66,7 +66,7 @@ fn ident_transformation_in_defs() {
         assert_pred!(
             matches_codepattern,
             "matches_codepattern",
-            pprust::to_string(|s| fake_print_crate(s, &krate)),
+            print_crate_items(&krate),
             "macro_rules! zz{(zz$zz:zz$(zz $zz:zz)zz+=>(zz$(zz$zz$zz)+))}".to_string()
         );
     })
index f4fcaf5c0a4520184d243935606355dee2d8a2db..56f25ffdb0187cf7bc4ea2a8f8c3ea7c17d25898 100644 (file)
@@ -309,8 +309,8 @@ fn out_of_line_mod() {
         .unwrap()
         .unwrap();
 
-        if let ast::ItemKind::Mod(ref m) = item.kind {
-            assert!(m.items.len() == 2);
+        if let ast::ItemKind::Mod(_, ref mod_kind) = item.kind {
+            assert!(matches!(mod_kind, ast::ModKind::Loaded(items, ..) if items.len() == 2));
         } else {
             panic!();
         }
index 6ac1c570cfe1b794ca61ffd92ead4495ad20c969..4df8c44e62b38a0506cb89cce4bca53ef3c21d94 100644 (file)
@@ -1,3 +1,4 @@
+// ignore-tidy-filelength
 use crate::def::{DefKind, Namespace, Res};
 use crate::def_id::DefId;
 crate use crate::hir_id::HirId;
@@ -615,7 +616,7 @@ pub struct WhereEqPredicate<'hir> {
     pub rhs_ty: &'hir Ty<'hir>,
 }
 
-#[derive(Encodable, Debug, HashStable_Generic)]
+#[derive(Default, Encodable, Debug, HashStable_Generic)]
 pub struct ModuleItems {
     // Use BTreeSets here so items are in the same order as in the
     // list of all items in Crate
@@ -1280,7 +1281,7 @@ pub fn generator_kind(&self) -> Option<GeneratorKind> {
 }
 
 /// The type of source expression that caused this generator to be created.
-#[derive(Clone, PartialEq, Eq, HashStable_Generic, Encodable, Decodable, Debug, Copy)]
+#[derive(Clone, PartialEq, Eq, Hash, HashStable_Generic, Encodable, Decodable, Debug, Copy)]
 pub enum GeneratorKind {
     /// An explicit `async` block or the body of an async function.
     Async(AsyncGeneratorKind),
@@ -1298,12 +1299,21 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     }
 }
 
+impl GeneratorKind {
+    pub fn descr(&self) -> &'static str {
+        match self {
+            GeneratorKind::Async(ask) => ask.descr(),
+            GeneratorKind::Gen => "generator",
+        }
+    }
+}
+
 /// In the case of a generator created as part of an async construct,
 /// which kind of async construct caused it to be created?
 ///
 /// This helps error messages but is also used to drive coercions in
 /// type-checking (see #60424).
-#[derive(Clone, PartialEq, Eq, HashStable_Generic, Encodable, Decodable, Debug, Copy)]
+#[derive(Clone, PartialEq, Eq, Hash, HashStable_Generic, Encodable, Decodable, Debug, Copy)]
 pub enum AsyncGeneratorKind {
     /// An explicit `async` block written by the user.
     Block,
@@ -1325,6 +1335,16 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     }
 }
 
+impl AsyncGeneratorKind {
+    pub fn descr(&self) -> &'static str {
+        match self {
+            AsyncGeneratorKind::Block => "`async` block",
+            AsyncGeneratorKind::Closure => "`async` closure body",
+            AsyncGeneratorKind::Fn => "`async fn` body",
+        }
+    }
+}
+
 #[derive(Copy, Clone, Debug)]
 pub enum BodyOwnerKind {
     /// Functions and methods.
index 26ce30cb51177944f4632f2cd62954459657ddf7..03524569ce7a9f726fc581dd5cffee3aefda03de 100644 (file)
@@ -201,6 +201,10 @@ pub fn extract<'a, F>(check_name: F, attrs: &'a [ast::Attribute]) -> Option<(Sym
     // The associated item of `trait DiscriminantKind`.
     Discriminant,            sym::discriminant_type,   discriminant_type,          Target::AssocTy;
 
+    PointeeTrait,            sym::pointee_trait,       pointee_trait,              Target::Trait;
+    Metadata,                sym::metadata_type,       metadata_type,              Target::AssocTy;
+    DynMetadata,             sym::dyn_metadata,        dyn_metadata,               Target::Struct;
+
     Freeze,                  sym::freeze,              freeze_trait,               Target::Trait;
 
     Drop,                    sym::drop,                drop_trait,                 Target::Trait;
@@ -238,6 +242,7 @@ pub fn extract<'a, F>(check_name: F, attrs: &'a [ast::Attribute]) -> Option<(Sym
 
     Deref,                   sym::deref,               deref_trait,                Target::Trait;
     DerefMut,                sym::deref_mut,           deref_mut_trait,            Target::Trait;
+    DerefTarget,             sym::deref_target,        deref_target,               Target::AssocTy;
     Receiver,                sym::receiver,            receiver_trait,             Target::Trait;
 
     Fn,                      kw::Fn,                   fn_trait,                   Target::Trait;
index 087f83c24754a1e18258cf746ab5f9eca293789b..374a9eb41e5c72be10ab654acc630b304649d21e 100644 (file)
@@ -109,7 +109,7 @@ fn report_format_mismatch(report_incremental_info: bool, file: &Path, message: &
     debug!("read_file: {}", message);
 
     if report_incremental_info {
-        println!(
+        eprintln!(
             "[incremental] ignoring cache artifact `{}`: {}",
             file.file_name().unwrap().to_string_lossy(),
             message
index 7a1976bed4b3baed456375a50f5f64c1531f22b5..c7a6c1195c5033cef24a587f55c5e098d0530567 100644 (file)
@@ -440,12 +440,12 @@ fn copy_files(sess: &Session, target_dir: &Path, source_dir: &Path) -> Result<bo
     }
 
     if sess.opts.debugging_opts.incremental_info {
-        println!(
+        eprintln!(
             "[incremental] session directory: \
                   {} files hard-linked",
             files_linked
         );
-        println!(
+        eprintln!(
             "[incremental] session directory: \
                  {} files copied",
             files_copied
index 0add0c5aa268ed23f060a0877b25229f2a473ca4..2b5649bb0594f57de4d749f630278bb4026c8288 100644 (file)
@@ -170,7 +170,7 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
 
                 if prev_commandline_args_hash != expected_hash {
                     if report_incremental_info {
-                        println!(
+                        eprintln!(
                             "[incremental] completely ignoring cache because of \
                                     differing commandline arguments"
                         );
index a7749d33b7c1389edcd874c10151ac8403d17da7..11ee8fb17ad1b4abc01175e138d765b28e192bb1 100644 (file)
@@ -55,6 +55,7 @@ pub fn at(
 
 pub trait ToTrace<'tcx>: Relate<'tcx> + Copy {
     fn to_trace(
+        tcx: TyCtxt<'tcx>,
         cause: &ObligationCause<'tcx>,
         a_is_expected: bool,
         a: Self,
@@ -178,7 +179,7 @@ pub fn trace_exp<T>(self, a_is_expected: bool, a: T, b: T) -> Trace<'a, 'tcx>
     where
         T: ToTrace<'tcx>,
     {
-        let trace = ToTrace::to_trace(self.cause, a_is_expected, a, b);
+        let trace = ToTrace::to_trace(self.infcx.tcx, self.cause, a_is_expected, a, b);
         Trace { at: self, trace, a_is_expected }
     }
 }
@@ -251,6 +252,7 @@ pub fn glb<T>(self, a: T, b: T) -> InferResult<'tcx, T>
 
 impl<'tcx> ToTrace<'tcx> for Ty<'tcx> {
     fn to_trace(
+        _: TyCtxt<'tcx>,
         cause: &ObligationCause<'tcx>,
         a_is_expected: bool,
         a: Self,
@@ -262,6 +264,7 @@ fn to_trace(
 
 impl<'tcx> ToTrace<'tcx> for ty::Region<'tcx> {
     fn to_trace(
+        _: TyCtxt<'tcx>,
         cause: &ObligationCause<'tcx>,
         a_is_expected: bool,
         a: Self,
@@ -273,6 +276,7 @@ fn to_trace(
 
 impl<'tcx> ToTrace<'tcx> for &'tcx Const<'tcx> {
     fn to_trace(
+        _: TyCtxt<'tcx>,
         cause: &ObligationCause<'tcx>,
         a_is_expected: bool,
         a: Self,
@@ -284,6 +288,7 @@ fn to_trace(
 
 impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> {
     fn to_trace(
+        _: TyCtxt<'tcx>,
         cause: &ObligationCause<'tcx>,
         a_is_expected: bool,
         a: Self,
@@ -298,6 +303,7 @@ fn to_trace(
 
 impl<'tcx> ToTrace<'tcx> for ty::PolyTraitRef<'tcx> {
     fn to_trace(
+        _: TyCtxt<'tcx>,
         cause: &ObligationCause<'tcx>,
         a_is_expected: bool,
         a: Self,
@@ -309,3 +315,20 @@ fn to_trace(
         }
     }
 }
+
+impl<'tcx> ToTrace<'tcx> for ty::ProjectionTy<'tcx> {
+    fn to_trace(
+        tcx: TyCtxt<'tcx>,
+        cause: &ObligationCause<'tcx>,
+        a_is_expected: bool,
+        a: Self,
+        b: Self,
+    ) -> TypeTrace<'tcx> {
+        let a_ty = tcx.mk_projection(a.item_def_id, a.substs);
+        let b_ty = tcx.mk_projection(b.item_def_id, b.substs);
+        TypeTrace {
+            cause: cause.clone(),
+            values: Types(ExpectedFound::new(a_is_expected, a_ty, b_ty)),
+        }
+    }
+}
index 074c9252481aa5bd709d8cd4306addc194b84b56..2ec9b9e0be4a81ef810a8231d18b5fc103380fd8 100644 (file)
@@ -507,12 +507,7 @@ fn unify_query_response_substitution_guess<R>(
 
         // Unify the original value for each variable with the value
         // taken from `query_response` (after applying `result_subst`).
-        Ok(self.unify_canonical_vars(
-            cause,
-            param_env,
-            original_values,
-            substituted_query_response,
-        )?)
+        self.unify_canonical_vars(cause, param_env, original_values, substituted_query_response)
     }
 
     /// Converts the region constraints resulting from a query into an
index 63f8a7293d899d020687dc5ee69ae00af930f4d1..9e55f7e558999db7703079092bb32d78912683d9 100644 (file)
@@ -1509,7 +1509,7 @@ fn add_labels_for_types(
 
         impl<'tcx> ty::fold::TypeVisitor<'tcx> for OpaqueTypesVisitor<'tcx> {
             fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
-                if let Some((kind, def_id)) = TyCategory::from_ty(t) {
+                if let Some((kind, def_id)) = TyCategory::from_ty(self.tcx, t) {
                     let span = self.tcx.def_span(def_id);
                     // Avoid cluttering the output when the "found" and error span overlap:
                     //
@@ -1582,11 +1582,11 @@ enum Mismatch<'a> {
         };
         if let Some((expected, found)) = expected_found {
             let expected_label = match exp_found {
-                Mismatch::Variable(ef) => ef.expected.prefix_string(),
+                Mismatch::Variable(ef) => ef.expected.prefix_string(self.tcx),
                 Mismatch::Fixed(s) => s.into(),
             };
             let found_label = match exp_found {
-                Mismatch::Variable(ef) => ef.found.prefix_string(),
+                Mismatch::Variable(ef) => ef.found.prefix_string(self.tcx),
                 Mismatch::Fixed(s) => s.into(),
             };
             let exp_found = match exp_found {
@@ -2489,7 +2489,7 @@ fn as_requirement_str(&self) -> &'static str {
 pub enum TyCategory {
     Closure,
     Opaque,
-    Generator,
+    Generator(hir::GeneratorKind),
     Foreign,
 }
 
@@ -2498,16 +2498,18 @@ fn descr(&self) -> &'static str {
         match self {
             Self::Closure => "closure",
             Self::Opaque => "opaque type",
-            Self::Generator => "generator",
+            Self::Generator(gk) => gk.descr(),
             Self::Foreign => "foreign type",
         }
     }
 
-    pub fn from_ty(ty: Ty<'_>) -> Option<(Self, DefId)> {
+    pub fn from_ty(tcx: TyCtxt<'_>, ty: Ty<'_>) -> Option<(Self, DefId)> {
         match *ty.kind() {
             ty::Closure(def_id, _) => Some((Self::Closure, def_id)),
             ty::Opaque(def_id, _) => Some((Self::Opaque, def_id)),
-            ty::Generator(def_id, ..) => Some((Self::Generator, def_id)),
+            ty::Generator(def_id, ..) => {
+                Some((Self::Generator(tcx.generator_kind(def_id).unwrap()), def_id))
+            }
             ty::Foreign(def_id) => Some((Self::Foreign, def_id)),
             _ => None,
         }
index cb783847fd1cf463fbc28aefbf9e426874036849..d533e267fd702856ad1ca3a3e467fd0cd0fc8274 100644 (file)
@@ -383,7 +383,7 @@ pub fn extract_inference_diagnostics_data(
                 InferenceDiagnosticsData {
                     name: s,
                     span: None,
-                    kind: UnderspecifiedArgKind::Type { prefix: ty.prefix_string() },
+                    kind: UnderspecifiedArgKind::Type { prefix: ty.prefix_string(self.tcx) },
                     parent: None,
                 }
             }
index cc8f1816bc3f4a10ac6fccef165ce0fc55937a70..0599c78ebfd079295788debc9d11bf4123a2a54a 100644 (file)
@@ -43,7 +43,7 @@ fn tcx(&self) -> TyCtxt<'tcx> {
         self.infcx.tcx
     }
 
-    pub fn try_report_from_nll(&self) -> Option<DiagnosticBuilder<'cx>> {
+    pub fn try_report_from_nll(&self) -> Option<DiagnosticBuilder<'tcx>> {
         // Due to the improved diagnostics returned by the MIR borrow checker, only a subset of
         // the nice region errors are required when running under the MIR borrow checker.
         self.try_report_named_anon_conflict().or_else(|| self.try_report_placeholder_conflict())
index e3c613b1d6a12876cf5066a97d9ec09a7e8d90de..2f622231a081ed07a562725b4e4baa6902388e07 100644 (file)
@@ -9,7 +9,7 @@
 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
     /// When given a `ConcreteFailure` for a function with parameters containing a named region and
     /// an anonymous region, emit an descriptive diagnostic error.
-    pub(super) fn try_report_named_anon_conflict(&self) -> Option<DiagnosticBuilder<'a>> {
+    pub(super) fn try_report_named_anon_conflict(&self) -> Option<DiagnosticBuilder<'tcx>> {
         let (span, sub, sup) = self.regions()?;
 
         debug!(
index e8e0326d978658bdb88d06751832b1c005527311..4aecc2f40b8741599ee61e8966ff1de700dd8344 100644 (file)
@@ -16,7 +16,7 @@
 impl NiceRegionError<'me, 'tcx> {
     /// When given a `ConcreteFailure` for a function with arguments containing a named region and
     /// an anonymous region, emit a descriptive diagnostic error.
-    pub(super) fn try_report_placeholder_conflict(&self) -> Option<DiagnosticBuilder<'me>> {
+    pub(super) fn try_report_placeholder_conflict(&self) -> Option<DiagnosticBuilder<'tcx>> {
         match &self.error {
             ///////////////////////////////////////////////////////////////////////////
             // NB. The ordering of cases in this match is very
@@ -30,157 +30,153 @@ pub(super) fn try_report_placeholder_conflict(&self) -> Option<DiagnosticBuilder
             Some(RegionResolutionError::SubSupConflict(
                 vid,
                 _,
-                SubregionOrigin::Subtype(box TypeTrace {
-                    cause,
-                    values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
-                }),
+                SubregionOrigin::Subtype(box TypeTrace { cause, values }),
                 sub_placeholder @ ty::RePlaceholder(_),
                 _,
                 sup_placeholder @ ty::RePlaceholder(_),
-            )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
+            )) => self.try_report_trait_placeholder_mismatch(
                 Some(self.tcx().mk_region(ty::ReVar(*vid))),
                 cause,
                 Some(sub_placeholder),
                 Some(sup_placeholder),
-                expected.def_id,
-                expected.substs,
-                found.substs,
-            )),
+                values,
+            ),
 
             Some(RegionResolutionError::SubSupConflict(
                 vid,
                 _,
-                SubregionOrigin::Subtype(box TypeTrace {
-                    cause,
-                    values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
-                }),
+                SubregionOrigin::Subtype(box TypeTrace { cause, values }),
                 sub_placeholder @ ty::RePlaceholder(_),
                 _,
                 _,
-            )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
+            )) => self.try_report_trait_placeholder_mismatch(
                 Some(self.tcx().mk_region(ty::ReVar(*vid))),
                 cause,
                 Some(sub_placeholder),
                 None,
-                expected.def_id,
-                expected.substs,
-                found.substs,
-            )),
+                values,
+            ),
 
             Some(RegionResolutionError::SubSupConflict(
                 vid,
                 _,
-                SubregionOrigin::Subtype(box TypeTrace {
-                    cause,
-                    values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
-                }),
+                SubregionOrigin::Subtype(box TypeTrace { cause, values }),
                 _,
                 _,
                 sup_placeholder @ ty::RePlaceholder(_),
-            )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
+            )) => self.try_report_trait_placeholder_mismatch(
                 Some(self.tcx().mk_region(ty::ReVar(*vid))),
                 cause,
                 None,
                 Some(*sup_placeholder),
-                expected.def_id,
-                expected.substs,
-                found.substs,
-            )),
+                values,
+            ),
 
             Some(RegionResolutionError::SubSupConflict(
                 vid,
                 _,
                 _,
                 _,
-                SubregionOrigin::Subtype(box TypeTrace {
-                    cause,
-                    values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
-                }),
+                SubregionOrigin::Subtype(box TypeTrace { cause, values }),
                 sup_placeholder @ ty::RePlaceholder(_),
-            )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
+            )) => self.try_report_trait_placeholder_mismatch(
                 Some(self.tcx().mk_region(ty::ReVar(*vid))),
                 cause,
                 None,
                 Some(*sup_placeholder),
-                expected.def_id,
-                expected.substs,
-                found.substs,
-            )),
+                values,
+            ),
 
             Some(RegionResolutionError::UpperBoundUniverseConflict(
                 vid,
                 _,
                 _,
-                SubregionOrigin::Subtype(box TypeTrace {
-                    cause,
-                    values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
-                }),
+                SubregionOrigin::Subtype(box TypeTrace { cause, values }),
                 sup_placeholder @ ty::RePlaceholder(_),
-            )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
+            )) => self.try_report_trait_placeholder_mismatch(
                 Some(self.tcx().mk_region(ty::ReVar(*vid))),
                 cause,
                 None,
                 Some(*sup_placeholder),
-                expected.def_id,
-                expected.substs,
-                found.substs,
-            )),
+                values,
+            ),
 
             Some(RegionResolutionError::ConcreteFailure(
-                SubregionOrigin::Subtype(box TypeTrace {
-                    cause,
-                    values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
-                }),
+                SubregionOrigin::Subtype(box TypeTrace { cause, values }),
                 sub_region @ ty::RePlaceholder(_),
                 sup_region @ ty::RePlaceholder(_),
-            )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
+            )) => self.try_report_trait_placeholder_mismatch(
                 None,
                 cause,
                 Some(*sub_region),
                 Some(*sup_region),
-                expected.def_id,
-                expected.substs,
-                found.substs,
-            )),
+                values,
+            ),
 
             Some(RegionResolutionError::ConcreteFailure(
-                SubregionOrigin::Subtype(box TypeTrace {
-                    cause,
-                    values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
-                }),
+                SubregionOrigin::Subtype(box TypeTrace { cause, values }),
                 sub_region @ ty::RePlaceholder(_),
                 sup_region,
-            )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
-                Some(sup_region),
+            )) => self.try_report_trait_placeholder_mismatch(
+                (!sup_region.has_name()).then_some(sup_region),
                 cause,
-                Some(*sub_region),
+                Some(sub_region),
                 None,
-                expected.def_id,
-                expected.substs,
-                found.substs,
-            )),
+                values,
+            ),
 
             Some(RegionResolutionError::ConcreteFailure(
-                SubregionOrigin::Subtype(box TypeTrace {
-                    cause,
-                    values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
-                }),
+                SubregionOrigin::Subtype(box TypeTrace { cause, values }),
                 sub_region,
                 sup_region @ ty::RePlaceholder(_),
-            )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
-                Some(sub_region),
+            )) => self.try_report_trait_placeholder_mismatch(
+                (!sub_region.has_name()).then_some(sub_region),
                 cause,
                 None,
-                Some(*sup_region),
-                expected.def_id,
-                expected.substs,
-                found.substs,
-            )),
+                Some(sup_region),
+                values,
+            ),
 
             _ => None,
         }
     }
 
+    fn try_report_trait_placeholder_mismatch(
+        &self,
+        vid: Option<ty::Region<'tcx>>,
+        cause: &ObligationCause<'tcx>,
+        sub_placeholder: Option<ty::Region<'tcx>>,
+        sup_placeholder: Option<ty::Region<'tcx>>,
+        value_pairs: &ValuePairs<'tcx>,
+    ) -> Option<DiagnosticBuilder<'tcx>> {
+        let (expected_substs, found_substs, trait_def_id) = match value_pairs {
+            ValuePairs::TraitRefs(ExpectedFound { expected, found })
+                if expected.def_id == found.def_id =>
+            {
+                (expected.substs, found.substs, expected.def_id)
+            }
+            ValuePairs::PolyTraitRefs(ExpectedFound { expected, found })
+                if expected.def_id() == found.def_id() =>
+            {
+                // It's possible that the placeholders come from a binder
+                // outside of this value pair. Use `no_bound_vars` as a
+                // simple heuristic for that.
+                (expected.no_bound_vars()?.substs, found.no_bound_vars()?.substs, expected.def_id())
+            }
+            _ => return None,
+        };
+
+        Some(self.report_trait_placeholder_mismatch(
+            vid,
+            cause,
+            sub_placeholder,
+            sup_placeholder,
+            trait_def_id,
+            expected_substs,
+            found_substs,
+        ))
+    }
+
     // error[E0308]: implementation of `Foo` does not apply to enough lifetimes
     //   --> /home/nmatsakis/tmp/foo.rs:12:5
     //    |
@@ -190,7 +186,8 @@ pub(super) fn try_report_placeholder_conflict(&self) -> Option<DiagnosticBuilder
     //    = note: Due to a where-clause on the function `all`,
     //    = note: `T` must implement `...` for any two lifetimes `'1` and `'2`.
     //    = note: However, the type `T` only implements `...` for some specific lifetime `'2`.
-    fn try_report_placeholders_trait(
+    #[instrument(level = "debug", skip(self))]
+    fn report_trait_placeholder_mismatch(
         &self,
         vid: Option<ty::Region<'tcx>>,
         cause: &ObligationCause<'tcx>,
@@ -199,28 +196,13 @@ fn try_report_placeholders_trait(
         trait_def_id: DefId,
         expected_substs: SubstsRef<'tcx>,
         actual_substs: SubstsRef<'tcx>,
-    ) -> DiagnosticBuilder<'me> {
-        debug!(
-            "try_report_placeholders_trait(\
-             vid={:?}, \
-             sub_placeholder={:?}, \
-             sup_placeholder={:?}, \
-             trait_def_id={:?}, \
-             expected_substs={:?}, \
-             actual_substs={:?})",
-            vid, sub_placeholder, sup_placeholder, trait_def_id, expected_substs, actual_substs
-        );
-
+    ) -> DiagnosticBuilder<'tcx> {
         let span = cause.span(self.tcx());
         let msg = format!(
             "implementation of `{}` is not general enough",
             self.tcx().def_path_str(trait_def_id),
         );
         let mut err = self.tcx().sess.struct_span_err(span, &msg);
-        err.span_label(
-            self.tcx().def_span(trait_def_id),
-            format!("trait `{}` defined here", self.tcx().def_path_str(trait_def_id)),
-        );
 
         let leading_ellipsis = if let ObligationCauseCode::ItemObligation(def_id) = cause.code {
             err.span_label(span, "doesn't satisfy where-clause");
@@ -285,17 +267,13 @@ fn try_report_placeholders_trait(
 
         let any_self_ty_has_vid = actual_self_ty_has_vid || expected_self_ty_has_vid;
 
-        debug!("try_report_placeholders_trait: actual_has_vid={:?}", actual_has_vid);
-        debug!("try_report_placeholders_trait: expected_has_vid={:?}", expected_has_vid);
-        debug!("try_report_placeholders_trait: has_sub={:?}", has_sub);
-        debug!("try_report_placeholders_trait: has_sup={:?}", has_sup);
         debug!(
-            "try_report_placeholders_trait: actual_self_ty_has_vid={:?}",
-            actual_self_ty_has_vid
-        );
-        debug!(
-            "try_report_placeholders_trait: expected_self_ty_has_vid={:?}",
-            expected_self_ty_has_vid
+            ?actual_has_vid,
+            ?expected_has_vid,
+            ?has_sub,
+            ?has_sup,
+            ?actual_self_ty_has_vid,
+            ?expected_self_ty_has_vid,
         );
 
         self.explain_actual_impl_that_was_found(
@@ -388,6 +366,8 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
             value: trait_ref,
         };
 
+        let same_self_type = actual_trait_ref.self_ty() == expected_trait_ref.self_ty();
+
         let mut expected_trait_ref = highlight_trait_ref(expected_trait_ref);
         expected_trait_ref.highlight.maybe_highlighting_region(sub_placeholder, has_sub);
         expected_trait_ref.highlight.maybe_highlighting_region(sup_placeholder, has_sup);
@@ -403,7 +383,42 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                 }
             };
 
-            let mut note = if passive_voice {
+            let mut note = if same_self_type {
+                let mut self_ty = expected_trait_ref.map(|tr| tr.self_ty());
+                self_ty.highlight.maybe_highlighting_region(vid, actual_has_vid);
+
+                if self_ty.value.is_closure()
+                    && self
+                        .tcx()
+                        .fn_trait_kind_from_lang_item(expected_trait_ref.value.def_id)
+                        .is_some()
+                {
+                    let closure_sig = self_ty.map(|closure| {
+                        if let ty::Closure(_, substs) = closure.kind() {
+                            self.tcx().signature_unclosure(
+                                substs.as_closure().sig(),
+                                rustc_hir::Unsafety::Normal,
+                            )
+                        } else {
+                            bug!("type is not longer closure");
+                        }
+                    });
+
+                    format!(
+                        "{}closure with signature `{}` must implement `{}`",
+                        if leading_ellipsis { "..." } else { "" },
+                        closure_sig,
+                        expected_trait_ref.map(|tr| tr.print_only_trait_path()),
+                    )
+                } else {
+                    format!(
+                        "{}`{}` must implement `{}`",
+                        if leading_ellipsis { "..." } else { "" },
+                        self_ty,
+                        expected_trait_ref.map(|tr| tr.print_only_trait_path()),
+                    )
+                }
+            } else if passive_voice {
                 format!(
                     "{}`{}` would have to be implemented for the type `{}`",
                     if leading_ellipsis { "..." } else { "" },
@@ -449,7 +464,12 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                 None => true,
             };
 
-            let mut note = if passive_voice {
+            let mut note = if same_self_type {
+                format!(
+                    "...but it actually implements `{}`",
+                    actual_trait_ref.map(|tr| tr.print_only_trait_path()),
+                )
+            } else if passive_voice {
                 format!(
                     "...but `{}` is actually implemented for the type `{}`",
                     actual_trait_ref.map(|tr| tr.print_only_trait_path()),
index 544da4cd9aa7d44cd6f9df777b659011358932f0..ed5061125ba9ee7fa165efbb9ef004b563b3e17e 100644 (file)
@@ -64,8 +64,8 @@ pub fn parse<'a>(sess: &'a Session, input: &Input) -> PResult<'a, ast::Crate> {
     }
 
     if sess.opts.debugging_opts.input_stats {
-        println!("Lines of code:             {}", sess.source_map().count_lines());
-        println!("Pre-expansion node count:  {}", count_nodes(&krate));
+        eprintln!("Lines of code:             {}", sess.source_map().count_lines());
+        eprintln!("Pre-expansion node count:  {}", count_nodes(&krate));
     }
 
     if let Some(ref s) = sess.opts.debugging_opts.show_span {
@@ -394,7 +394,7 @@ fn configure_and_expand_inner<'a>(
     // Done with macro expansion!
 
     if sess.opts.debugging_opts.input_stats {
-        println!("Post-expansion node count: {}", count_nodes(&krate));
+        eprintln!("Post-expansion node count: {}", count_nodes(&krate));
     }
 
     if sess.opts.debugging_opts.hir_stats {
index 231edf442eb00c0175ba695cbd12fe36c74fc125..cc3bf4095fdef300fc8d3c7e1cb7aad65bf4eaf7 100644 (file)
@@ -188,13 +188,6 @@ fn visit_ident(&mut self, ident: Ident) {
         run_early_pass!(self, check_ident, ident);
     }
 
-    fn visit_mod(&mut self, m: &'a ast::Mod, s: Span, _a: &[ast::Attribute], n: ast::NodeId) {
-        run_early_pass!(self, check_mod, m, s, n);
-        self.check_id(n);
-        ast_visit::walk_mod(self, m);
-        run_early_pass!(self, check_mod_post, m, s, n);
-    }
-
     fn visit_local(&mut self, l: &'a ast::Local) {
         self.with_lint_attrs(l.id, &l.attrs, |cx| {
             run_early_pass!(cx, check_local, l);
index 828f283d2a95a71f7f5d7686d95a5072410c075e..ffbed3a0aff2d111ad897e81ad520085622e26f6 100644 (file)
@@ -160,8 +160,6 @@ macro_rules! early_lint_methods {
             fn check_ident(a: Ident);
             fn check_crate(a: &ast::Crate);
             fn check_crate_post(a: &ast::Crate);
-            fn check_mod(a: &ast::Mod, b: Span, c: ast::NodeId);
-            fn check_mod_post(a: &ast::Mod, b: Span, c: ast::NodeId);
             fn check_foreign_item(a: &ast::ForeignItem);
             fn check_foreign_item_post(a: &ast::ForeignItem);
             fn check_item(a: &ast::Item);
index f0a5ea150b71941e1619d509ae32978771147a50..686d09dd7fcb4478e53fcc98ec42d404f1f81059 100644 (file)
 }
 
 declare_lint! {
-    /// The `irrefutable_let_patterns` lint detects detects [irrefutable
-    /// patterns] in [if-let] and [while-let] statements.
-    ///
-    ///
+    /// The `irrefutable_let_patterns` lint detects [irrefutable patterns]
+    /// in [`if let`]s, [`while let`]s, and `if let` guards.
     ///
     /// ### Example
     ///
-    /// ```rust
+    /// ```
     /// if let _ = 123 {
     ///     println!("always runs!");
     /// }
     /// ### Explanation
     ///
     /// There usually isn't a reason to have an irrefutable pattern in an
-    /// if-let or while-let statement, because the pattern will always match
+    /// `if let` or `while let` statement, because the pattern will always match
     /// successfully. A [`let`] or [`loop`] statement will suffice. However,
     /// when generating code with a macro, forbidding irrefutable patterns
     /// would require awkward workarounds in situations where the macro
     /// See [RFC 2086] for more details.
     ///
     /// [irrefutable patterns]: https://doc.rust-lang.org/reference/patterns.html#refutability
-    /// [if-let]: https://doc.rust-lang.org/reference/expressions/if-expr.html#if-let-expressions
-    /// [while-let]: https://doc.rust-lang.org/reference/expressions/loop-expr.html#predicate-pattern-loops
+    /// [`if let`]: https://doc.rust-lang.org/reference/expressions/if-expr.html#if-let-expressions
+    /// [`while let`]: https://doc.rust-lang.org/reference/expressions/loop-expr.html#predicate-pattern-loops
     /// [`let`]: https://doc.rust-lang.org/reference/statements.html#let-statements
     /// [`loop`]: https://doc.rust-lang.org/reference/expressions/loop-expr.html#infinite-loops
     /// [RFC 2086]: https://github.com/rust-lang/rfcs/blob/master/text/2086-allow-if-let-irrefutables.md
     pub IRREFUTABLE_LET_PATTERNS,
     Warn,
-    "detects irrefutable patterns in if-let and while-let statements"
+    "detects irrefutable patterns in `if let` and `while let` statements"
 }
 
 declare_lint! {
index 3314385dbf0a3499ae39111c65b1b1c68d34793c..61265d7204c0b2773814a709f72fa4272597c8f4 100644 (file)
@@ -695,23 +695,23 @@ fn encode_crate_root(&mut self) -> Lazy<CrateRoot<'tcx>> {
                 }
             }
 
-            println!("metadata stats:");
-            println!("             dep bytes: {}", dep_bytes);
-            println!("     lib feature bytes: {}", lib_feature_bytes);
-            println!("       lang item bytes: {}", lang_item_bytes);
-            println!(" diagnostic item bytes: {}", diagnostic_item_bytes);
-            println!("          native bytes: {}", native_lib_bytes);
-            println!("      source_map bytes: {}", source_map_bytes);
-            println!("            impl bytes: {}", impl_bytes);
-            println!("    exp. symbols bytes: {}", exported_symbols_bytes);
-            println!("  def-path table bytes: {}", def_path_table_bytes);
-            println!(" proc-macro-data-bytes: {}", proc_macro_data_bytes);
-            println!("             mir bytes: {}", mir_bytes);
-            println!("            item bytes: {}", item_bytes);
-            println!("           table bytes: {}", tables_bytes);
-            println!("         hygiene bytes: {}", hygiene_bytes);
-            println!("            zero bytes: {}", zero_bytes);
-            println!("           total bytes: {}", total_bytes);
+            eprintln!("metadata stats:");
+            eprintln!("             dep bytes: {}", dep_bytes);
+            eprintln!("     lib feature bytes: {}", lib_feature_bytes);
+            eprintln!("       lang item bytes: {}", lang_item_bytes);
+            eprintln!(" diagnostic item bytes: {}", diagnostic_item_bytes);
+            eprintln!("          native bytes: {}", native_lib_bytes);
+            eprintln!("      source_map bytes: {}", source_map_bytes);
+            eprintln!("            impl bytes: {}", impl_bytes);
+            eprintln!("    exp. symbols bytes: {}", exported_symbols_bytes);
+            eprintln!("  def-path table bytes: {}", def_path_table_bytes);
+            eprintln!(" proc-macro-data-bytes: {}", proc_macro_data_bytes);
+            eprintln!("             mir bytes: {}", mir_bytes);
+            eprintln!("            item bytes: {}", item_bytes);
+            eprintln!("           table bytes: {}", tables_bytes);
+            eprintln!("         hygiene bytes: {}", hygiene_bytes);
+            eprintln!("            zero bytes: {}", zero_bytes);
+            eprintln!("           total bytes: {}", total_bytes);
         }
 
         root
index f34ee22860259e1953a2b5437f556c934db113cc..9deeaf462d65d41b451e0d27c3c4cf4068ac614c 100644 (file)
@@ -479,6 +479,9 @@ pub enum ImplSource<'tcx, N> {
     /// ImplSource for a builtin `DeterminantKind` trait implementation.
     DiscriminantKind(ImplSourceDiscriminantKindData),
 
+    /// ImplSource for a builtin `Pointee` trait implementation.
+    Pointee(ImplSourcePointeeData),
+
     /// ImplSource automatically generated for a generator.
     Generator(ImplSourceGeneratorData<'tcx, N>),
 
@@ -497,7 +500,8 @@ pub fn nested_obligations(self) -> Vec<N> {
             ImplSource::Generator(c) => c.nested,
             ImplSource::Object(d) => d.nested,
             ImplSource::FnPointer(d) => d.nested,
-            ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) => Vec::new(),
+            ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
+            | ImplSource::Pointee(ImplSourcePointeeData) => Vec::new(),
             ImplSource::TraitAlias(d) => d.nested,
         }
     }
@@ -512,7 +516,8 @@ pub fn borrow_nested_obligations(&self) -> &[N] {
             ImplSource::Generator(c) => &c.nested[..],
             ImplSource::Object(d) => &d.nested[..],
             ImplSource::FnPointer(d) => &d.nested[..],
-            ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) => &[],
+            ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
+            | ImplSource::Pointee(ImplSourcePointeeData) => &[],
             ImplSource::TraitAlias(d) => &d.nested[..],
         }
     }
@@ -557,6 +562,9 @@ pub fn map<M, F>(self, f: F) -> ImplSource<'tcx, M>
             ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) => {
                 ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
             }
+            ImplSource::Pointee(ImplSourcePointeeData) => {
+                ImplSource::Pointee(ImplSourcePointeeData)
+            }
             ImplSource::TraitAlias(d) => ImplSource::TraitAlias(ImplSourceTraitAliasData {
                 alias_def_id: d.alias_def_id,
                 substs: d.substs,
@@ -635,6 +643,9 @@ pub struct ImplSourceFnPointerData<'tcx, N> {
 #[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
 pub struct ImplSourceDiscriminantKindData;
 
+#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
+pub struct ImplSourcePointeeData;
+
 #[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
 pub struct ImplSourceTraitAliasData<'tcx, N> {
     pub alias_def_id: DefId,
index e056240f9415045ae2f18f600a9ea62f5dec8f71..ab085175762ab2409a2d4e05b630a5f2ea515ec7 100644 (file)
@@ -125,6 +125,9 @@ pub enum SelectionCandidate<'tcx> {
     /// Builtin implementation of `DiscriminantKind`.
     DiscriminantKindCandidate,
 
+    /// Builtin implementation of `Pointee`.
+    PointeeCandidate,
+
     TraitAliasCandidate(DefId),
 
     /// Matching `dyn Trait` with a supertrait of `Trait`. The index is the
index 5a17d38c73460bacbb994669ba118171ed4050d8..4f978e63630440561e43fb5c0d4473f0c3d2a69a 100644 (file)
@@ -19,6 +19,8 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 
             super::ImplSource::DiscriminantKind(ref d) => write!(f, "{:?}", d),
 
+            super::ImplSource::Pointee(ref d) => write!(f, "{:?}", d),
+
             super::ImplSource::Object(ref d) => write!(f, "{:?}", d),
 
             super::ImplSource::Param(ref n, ct) => {
@@ -110,4 +112,5 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 TrivialTypeFoldableAndLiftImpls! {
     super::IfExpressionCause,
     super::ImplSourceDiscriminantKindData,
+    super::ImplSourcePointeeData,
 }
index 0dad5df48551ed115ffac2137ca775eab3516efb..73ad87a9ef219149776dcc5fd76c6c60507f781c 100644 (file)
@@ -253,7 +253,7 @@ impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for SubstsRef<'tcx> {
     fn decode(decoder: &mut D) -> Result<Self, D::Error> {
         let len = decoder.read_usize()?;
         let tcx = decoder.tcx();
-        Ok(tcx.mk_substs((0..len).map(|_| Decodable::decode(decoder)))?)
+        tcx.mk_substs((0..len).map(|_| Decodable::decode(decoder)))
     }
 }
 
@@ -314,7 +314,7 @@ fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
 impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for ty::List<Ty<'tcx>> {
     fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
         let len = decoder.read_usize()?;
-        Ok(decoder.tcx().mk_type_list((0..len).map(|_| Decodable::decode(decoder)))?)
+        decoder.tcx().mk_type_list((0..len).map(|_| Decodable::decode(decoder)))
     }
 }
 
@@ -323,9 +323,7 @@ impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D>
 {
     fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
         let len = decoder.read_usize()?;
-        Ok(decoder
-            .tcx()
-            .mk_poly_existential_predicates((0..len).map(|_| Decodable::decode(decoder)))?)
+        decoder.tcx().mk_poly_existential_predicates((0..len).map(|_| Decodable::decode(decoder)))
     }
 }
 
index 3b7dc25b6cf50ccfb13189e4abca68eeec2a61e3..f41bb7e6d6350945d172f565e6851340cb90c457 100644 (file)
@@ -75,6 +75,36 @@ pub fn is_suggestable(&self) -> bool {
     }
 }
 
+pub fn suggest_arbitrary_trait_bound(
+    generics: &hir::Generics<'_>,
+    err: &mut DiagnosticBuilder<'_>,
+    param_name: &str,
+    constraint: &str,
+) -> bool {
+    let param = generics.params.iter().find(|p| p.name.ident().as_str() == param_name);
+    match (param, param_name) {
+        (Some(_), "Self") => return false,
+        _ => {}
+    }
+    // Suggest a where clause bound for a non-type paremeter.
+    let (action, prefix) = if generics.where_clause.predicates.is_empty() {
+        ("introducing a", " where ")
+    } else {
+        ("extending the", ", ")
+    };
+    err.span_suggestion_verbose(
+        generics.where_clause.tail_span_for_suggestion(),
+        &format!(
+            "consider {} `where` bound, but there might be an alternative better way to express \
+             this requirement",
+            action,
+        ),
+        format!("{}{}: {}", prefix, param_name, constraint),
+        Applicability::MaybeIncorrect,
+    );
+    true
+}
+
 /// Suggest restricting a type param with a new bound.
 pub fn suggest_constraining_type_param(
     tcx: TyCtxt<'_>,
index a6db2e3aa2886c6d02bbfe9c36711a2d33eccff4..bf315c81588a902ceec75e7987964ba0af7ed0a6 100644 (file)
@@ -1,5 +1,6 @@
 use crate::traits::{ObligationCause, ObligationCauseCode};
 use crate::ty::diagnostics::suggest_constraining_type_param;
+use crate::ty::print::{FmtPrinter, Printer};
 use crate::ty::{self, BoundRegionKind, Region, Ty, TyCtxt};
 use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect};
 use rustc_errors::{pluralize, DiagnosticBuilder};
@@ -269,7 +270,7 @@ pub fn sort_string(&self, tcx: TyCtxt<'_>) -> Cow<'static, str> {
                 }
             }
             ty::Closure(..) => "closure".into(),
-            ty::Generator(..) => "generator".into(),
+            ty::Generator(def_id, ..) => tcx.generator_kind(def_id).unwrap().descr().into(),
             ty::GeneratorWitness(..) => "generator witness".into(),
             ty::Tuple(..) => "tuple".into(),
             ty::Infer(ty::TyVar(_)) => "inferred type".into(),
@@ -287,7 +288,7 @@ pub fn sort_string(&self, tcx: TyCtxt<'_>) -> Cow<'static, str> {
         }
     }
 
-    pub fn prefix_string(&self) -> Cow<'static, str> {
+    pub fn prefix_string(&self, tcx: TyCtxt<'_>) -> Cow<'static, str> {
         match *self.kind() {
             ty::Infer(_)
             | ty::Error(_)
@@ -313,7 +314,7 @@ pub fn prefix_string(&self) -> Cow<'static, str> {
             ty::FnPtr(_) => "fn pointer".into(),
             ty::Dynamic(..) => "trait object".into(),
             ty::Closure(..) => "closure".into(),
-            ty::Generator(..) => "generator".into(),
+            ty::Generator(def_id, ..) => tcx.generator_kind(def_id).unwrap().descr().into(),
             ty::GeneratorWitness(..) => "generator witness".into(),
             ty::Tuple(..) => "tuple".into(),
             ty::Placeholder(..) => "higher-ranked type".into(),
@@ -405,14 +406,22 @@ pub fn note_and_explain_type_err(
                         {
                             // Synthesize the associated type restriction `Add<Output = Expected>`.
                             // FIXME: extract this logic for use in other diagnostics.
-                            let trait_ref = proj.trait_ref(self);
+                            let (trait_ref, assoc_substs) = proj.trait_ref_and_own_substs(self);
                             let path =
                                 self.def_path_str_with_substs(trait_ref.def_id, trait_ref.substs);
                             let item_name = self.item_name(proj.item_def_id);
+                            let item_args = self.format_generic_args(assoc_substs);
+
                             let path = if path.ends_with('>') {
-                                format!("{}, {} = {}>", &path[..path.len() - 1], item_name, p)
+                                format!(
+                                    "{}, {}{} = {}>",
+                                    &path[..path.len() - 1],
+                                    item_name,
+                                    item_args,
+                                    p
+                                )
                             } else {
-                                format!("{}<{} = {}>", path, item_name, p)
+                                format!("{}<{}{} = {}>", path, item_name, item_args, p)
                             };
                             note = !suggest_constraining_type_param(
                                 self,
@@ -561,7 +570,7 @@ fn suggest_constraint(
         ty: Ty<'tcx>,
     ) -> bool {
         let assoc = self.associated_item(proj_ty.item_def_id);
-        let trait_ref = proj_ty.trait_ref(self);
+        let (trait_ref, assoc_substs) = proj_ty.trait_ref_and_own_substs(self);
         if let Some(item) = self.hir().get_if_local(body_owner_def_id) {
             if let Some(hir_generics) = item.generics() {
                 // Get the `DefId` for the type parameter corresponding to `A` in `<A as T>::Foo`.
@@ -595,6 +604,7 @@ fn suggest_constraint(
                             &trait_ref,
                             pred.bounds,
                             &assoc,
+                            assoc_substs,
                             ty,
                             msg,
                         ) {
@@ -612,6 +622,7 @@ fn suggest_constraint(
                             &trait_ref,
                             param.bounds,
                             &assoc,
+                            assoc_substs,
                             ty,
                             msg,
                         );
@@ -697,6 +708,7 @@ fn expected_projection(
                 db,
                 self.def_span(def_id),
                 &assoc,
+                proj_ty.trait_ref_and_own_substs(self).1,
                 values.found,
                 &msg,
             ) {
@@ -861,6 +873,7 @@ fn constrain_generic_bound_associated_type_structured_suggestion(
         trait_ref: &ty::TraitRef<'tcx>,
         bounds: hir::GenericBounds<'_>,
         assoc: &ty::AssocItem,
+        assoc_substs: &[ty::GenericArg<'tcx>],
         ty: Ty<'tcx>,
         msg: &str,
     ) -> bool {
@@ -870,7 +883,12 @@ fn constrain_generic_bound_associated_type_structured_suggestion(
                 // Relate the type param against `T` in `<A as T>::Foo`.
                 ptr.trait_ref.trait_def_id() == Some(trait_ref.def_id)
                     && self.constrain_associated_type_structured_suggestion(
-                        db, ptr.span, assoc, ty, msg,
+                        db,
+                        ptr.span,
+                        assoc,
+                        assoc_substs,
+                        ty,
+                        msg,
                     )
             }
             _ => false,
@@ -884,6 +902,7 @@ fn constrain_associated_type_structured_suggestion(
         db: &mut DiagnosticBuilder<'_>,
         span: Span,
         assoc: &ty::AssocItem,
+        assoc_substs: &[ty::GenericArg<'tcx>],
         ty: Ty<'tcx>,
         msg: &str,
     ) -> bool {
@@ -895,11 +914,20 @@ fn constrain_associated_type_structured_suggestion(
                 let span = Span::new(pos, pos, span.ctxt());
                 (span, format!(", {} = {}", assoc.ident, ty))
             } else {
-                (span.shrink_to_hi(), format!("<{} = {}>", assoc.ident, ty))
+                let item_args = self.format_generic_args(assoc_substs);
+                (span.shrink_to_hi(), format!("<{}{} = {}>", assoc.ident, item_args, ty))
             };
             db.span_suggestion_verbose(span, msg, sugg, MaybeIncorrect);
             return true;
         }
         false
     }
+
+    fn format_generic_args(self, args: &[ty::GenericArg<'tcx>]) -> String {
+        let mut item_args = String::new();
+        FmtPrinter::new(self, &mut item_args, hir::def::Namespace::TypeNS)
+            .path_generic_args(Ok, args)
+            .expect("could not write to `String`.");
+        item_args
+    }
 }
index babab005edb2b3a85c7dd53644b012b00635069a..b7f62437fa5a86379a79f1728eb076100a914599 100644 (file)
@@ -1289,8 +1289,22 @@ pub fn item_def_id(&self) -> DefId {
         self.skip_binder().projection_ty.item_def_id
     }
 
+    /// Returns the `DefId` of the trait of the associated item being projected.
     #[inline]
-    pub fn to_poly_trait_ref(&self, tcx: TyCtxt<'tcx>) -> PolyTraitRef<'tcx> {
+    pub fn trait_def_id(&self, tcx: TyCtxt<'tcx>) -> DefId {
+        self.skip_binder().projection_ty.trait_def_id(tcx)
+    }
+
+    #[inline]
+    pub fn projection_self_ty(&self) -> Binder<Ty<'tcx>> {
+        self.map_bound(|predicate| predicate.projection_ty.self_ty())
+    }
+
+    /// Get the [PolyTraitRef] required for this projection to be well formed.
+    /// Note that for generic associated types the predicates of the associated
+    /// type also need to be checked.
+    #[inline]
+    pub fn required_poly_trait_ref(&self, tcx: TyCtxt<'tcx>) -> PolyTraitRef<'tcx> {
         // Note: unlike with `TraitRef::to_poly_trait_ref()`,
         // `self.0.trait_ref` is permitted to have escaping regions.
         // This is because here `self` has a `Binder` and so does our
index 286041a7c548bc20670fcc72292deb0f93c819ce..53c164d44b3e159cb772dc31129a90d68663ff4e 100644 (file)
@@ -607,7 +607,7 @@ fn pretty_print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error>
                     return Ok(self);
                 }
 
-                return Ok(with_no_queries(|| {
+                return with_no_queries(|| {
                     let def_key = self.tcx().def_key(def_id);
                     if let Some(name) = def_key.disambiguated_data.data.get_opt_name() {
                         p!(write("{}", name));
@@ -649,7 +649,7 @@ fn pretty_print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error>
                         p!(" Sized");
                     }
                     Ok(self)
-                })?);
+                });
             }
             ty::Str => p!("str"),
             ty::Generator(did, substs, movability) => {
@@ -1018,7 +1018,7 @@ fn pretty_print_const_scalar(
                 p!(write("{:?}", char::try_from(int).unwrap()))
             }
             // Raw pointers
-            (Scalar::Int(int), ty::RawPtr(_)) => {
+            (Scalar::Int(int), ty::RawPtr(_) | ty::FnPtr(_)) => {
                 let data = int.assert_bits(self.tcx().data_layout.pointer_size);
                 self = self.typed_value(
                     |mut this| {
@@ -1030,15 +1030,18 @@ fn pretty_print_const_scalar(
                 )?;
             }
             (Scalar::Ptr(ptr), ty::FnPtr(_)) => {
-                // FIXME: this can ICE when the ptr is dangling or points to a non-function.
-                // We should probably have a helper method to share code with the "Byte strings"
+                // FIXME: We should probably have a helper method to share code with the "Byte strings"
                 // printing above (which also has to handle pointers to all sorts of things).
-                let instance = self.tcx().global_alloc(ptr.alloc_id).unwrap_fn();
-                self = self.typed_value(
-                    |this| this.print_value_path(instance.def_id(), instance.substs),
-                    |this| this.print_type(ty),
-                    " as ",
-                )?;
+                match self.tcx().get_global_alloc(ptr.alloc_id) {
+                    Some(GlobalAlloc::Function(instance)) => {
+                        self = self.typed_value(
+                            |this| this.print_value_path(instance.def_id(), instance.substs),
+                            |this| this.print_type(ty),
+                            " as ",
+                        )?;
+                    }
+                    _ => self = self.pretty_print_const_pointer(ptr, ty, print_ty)?,
+                }
             }
             // For function type zsts just printing the path is enough
             (Scalar::Int(int), ty::FnDef(d, s)) if int == ScalarInt::ZST => {
index c885a10f8059524040b4d33a8f86c46bb37eba10..29ec9c132a89c0b6e6c7761558ff9772dbf8a364 100644 (file)
@@ -67,29 +67,29 @@ pub fn print_stats(tcx: TyCtxt<'_>) {
     if cfg!(debug_assertions) {
         let hits: usize = queries.iter().map(|s| s.cache_hits).sum();
         let results: usize = queries.iter().map(|s| s.entry_count).sum();
-        println!("\nQuery cache hit rate: {}", hits as f64 / (hits + results) as f64);
+        eprintln!("\nQuery cache hit rate: {}", hits as f64 / (hits + results) as f64);
     }
 
     let mut query_key_sizes = queries.clone();
     query_key_sizes.sort_by_key(|q| q.key_size);
-    println!("\nLarge query keys:");
+    eprintln!("\nLarge query keys:");
     for q in query_key_sizes.iter().rev().filter(|q| q.key_size > 8) {
-        println!("   {} - {} x {} - {}", q.name, q.key_size, q.entry_count, q.key_type);
+        eprintln!("   {} - {} x {} - {}", q.name, q.key_size, q.entry_count, q.key_type);
     }
 
     let mut query_value_sizes = queries.clone();
     query_value_sizes.sort_by_key(|q| q.value_size);
-    println!("\nLarge query values:");
+    eprintln!("\nLarge query values:");
     for q in query_value_sizes.iter().rev().filter(|q| q.value_size > 8) {
-        println!("   {} - {} x {} - {}", q.name, q.value_size, q.entry_count, q.value_type);
+        eprintln!("   {} - {} x {} - {}", q.name, q.value_size, q.entry_count, q.value_type);
     }
 
     if cfg!(debug_assertions) {
         let mut query_cache_hits = queries.clone();
         query_cache_hits.sort_by_key(|q| q.cache_hits);
-        println!("\nQuery cache hits:");
+        eprintln!("\nQuery cache hits:");
         for q in query_cache_hits.iter().rev() {
-            println!(
+            eprintln!(
                 "   {} - {} ({}%)",
                 q.name,
                 q.cache_hits,
@@ -100,19 +100,19 @@ pub fn print_stats(tcx: TyCtxt<'_>) {
 
     let mut query_value_count = queries.clone();
     query_value_count.sort_by_key(|q| q.entry_count);
-    println!("\nQuery value count:");
+    eprintln!("\nQuery value count:");
     for q in query_value_count.iter().rev() {
-        println!("   {} - {}", q.name, q.entry_count);
+        eprintln!("   {} - {}", q.name, q.entry_count);
     }
 
     let mut def_id_density: Vec<_> =
         queries.iter().filter(|q| q.local_def_id_keys.is_some()).collect();
     def_id_density.sort_by_key(|q| q.local_def_id_keys.unwrap());
-    println!("\nLocal DefId density:");
+    eprintln!("\nLocal DefId density:");
     let total = tcx.hir().definitions().def_index_count() as f64;
     for q in def_id_density.iter().rev() {
         let local = q.local_def_id_keys.unwrap();
-        println!("   {} - {} = ({}%)", q.name, local, (local as f64 * 100.0) / total);
+        eprintln!("   {} - {} = ({}%)", q.name, local, (local as f64 * 100.0) / total);
     }
 }
 
index 293b3c6b0470a923a8214ab0ba2193568017fbe9..315e5d63d2bb3f4e77641a4c719b5af051e1295a 100644 (file)
@@ -154,7 +154,7 @@ pub fn relate_substs<R: TypeRelation<'tcx>>(
         relation.relate_with_variance(variance, a, b)
     });
 
-    Ok(tcx.mk_substs(params)?)
+    tcx.mk_substs(params)
 }
 
 impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> {
@@ -647,7 +647,7 @@ fn relate<R: TypeRelation<'tcx>>(
                 _ => Err(TypeError::ExistentialMismatch(expected_found(relation, a, b))),
             }
         });
-        Ok(tcx.mk_poly_existential_predicates(v)?)
+        tcx.mk_poly_existential_predicates(v)
     }
 }
 
index 04cc4db0bcf649a822ec27d0d92d0f5523f4d5d0..bbf64c69d83bd399f2ccb57e6cb3dbe465869693 100644 (file)
@@ -17,7 +17,7 @@
 use rustc_hir::def_id::DefId;
 use rustc_index::vec::Idx;
 use rustc_macros::HashStable;
-use rustc_span::symbol::{kw, Ident, Symbol};
+use rustc_span::symbol::{kw, Symbol};
 use rustc_target::abi::VariantIdx;
 use rustc_target::spec::abi;
 use std::borrow::Cow;
@@ -1112,36 +1112,35 @@ pub struct ProjectionTy<'tcx> {
 }
 
 impl<'tcx> ProjectionTy<'tcx> {
-    /// Construct a `ProjectionTy` by searching the trait from `trait_ref` for the
-    /// associated item named `item_name`.
-    pub fn from_ref_and_name(
-        tcx: TyCtxt<'_>,
-        trait_ref: ty::TraitRef<'tcx>,
-        item_name: Ident,
-    ) -> ProjectionTy<'tcx> {
-        let item_def_id = tcx
-            .associated_items(trait_ref.def_id)
-            .find_by_name_and_kind(tcx, item_name, ty::AssocKind::Type, trait_ref.def_id)
-            .unwrap()
-            .def_id;
+    pub fn trait_def_id(&self, tcx: TyCtxt<'tcx>) -> DefId {
+        tcx.associated_item(self.item_def_id).container.id()
+    }
 
-        ProjectionTy { substs: trait_ref.substs, item_def_id }
+    /// Extracts the underlying trait reference and own substs from this projection.
+    /// For example, if this is a projection of `<T as StreamingIterator>::Item<'a>`,
+    /// then this function would return a `T: Iterator` trait reference and `['a]` as the own substs
+    pub fn trait_ref_and_own_substs(
+        &self,
+        tcx: TyCtxt<'tcx>,
+    ) -> (ty::TraitRef<'tcx>, &'tcx [ty::GenericArg<'tcx>]) {
+        let def_id = tcx.associated_item(self.item_def_id).container.id();
+        let trait_generics = tcx.generics_of(def_id);
+        (
+            ty::TraitRef { def_id, substs: self.substs.truncate_to(tcx, trait_generics) },
+            &self.substs[trait_generics.count()..],
+        )
     }
 
     /// Extracts the underlying trait reference from this projection.
     /// For example, if this is a projection of `<T as Iterator>::Item`,
     /// then this function would return a `T: Iterator` trait reference.
+    ///
+    /// WARNING: This will drop the substs for generic associated types
+    /// consider calling [Self::trait_ref_and_own_substs] to get those
+    /// as well.
     pub fn trait_ref(&self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> {
-        // FIXME: This method probably shouldn't exist at all, since it's not
-        // clear what this method really intends to do. Be careful when
-        // using this method since the resulting TraitRef additionally
-        // contains the substs for the assoc_item, which strictly speaking
-        // is not correct
-        let def_id = tcx.associated_item(self.item_def_id).container.id();
-        // Include substitutions for generic arguments of associated types
-        let assoc_item = tcx.associated_item(self.item_def_id);
-        let substs_assoc_item = self.substs.truncate_to(tcx, tcx.generics_of(assoc_item.def_id));
-        ty::TraitRef { def_id, substs: substs_assoc_item }
+        let def_id = self.trait_def_id(tcx);
+        ty::TraitRef { def_id, substs: self.substs.truncate_to(tcx, tcx.generics_of(def_id)) }
     }
 
     pub fn self_ty(&self) -> Ty<'tcx> {
@@ -1493,12 +1492,11 @@ impl<'tcx> ExistentialProjection<'tcx> {
     /// For example, if this is a projection of `exists T. <T as Iterator>::Item == X`,
     /// then this function would return a `exists T. T: Iterator` existential trait
     /// reference.
-    pub fn trait_ref(&self, tcx: TyCtxt<'_>) -> ty::ExistentialTraitRef<'tcx> {
-        // FIXME(generic_associated_types): substs is the substs of the
-        // associated type, which should be truncated to get the correct substs
-        // for the trait.
+    pub fn trait_ref(&self, tcx: TyCtxt<'tcx>) -> ty::ExistentialTraitRef<'tcx> {
         let def_id = tcx.associated_item(self.item_def_id).container.id();
-        ty::ExistentialTraitRef { def_id, substs: self.substs }
+        let subst_count = tcx.generics_of(def_id).count() - 1;
+        let substs = tcx.intern_substs(&self.substs[..subst_count]);
+        ty::ExistentialTraitRef { def_id, substs }
     }
 
     pub fn with_self_ty(
@@ -1517,6 +1515,20 @@ pub fn with_self_ty(
             ty: self.ty,
         }
     }
+
+    pub fn erase_self_ty(
+        tcx: TyCtxt<'tcx>,
+        projection_predicate: ty::ProjectionPredicate<'tcx>,
+    ) -> Self {
+        // Assert there is a Self.
+        projection_predicate.projection_ty.substs.type_at(0);
+
+        Self {
+            item_def_id: projection_predicate.projection_ty.item_def_id,
+            substs: tcx.intern_substs(&projection_predicate.projection_ty.substs[1..]),
+            ty: projection_predicate.ty,
+        }
+    }
 }
 
 impl<'tcx> PolyExistentialProjection<'tcx> {
@@ -2133,6 +2145,54 @@ pub fn discriminant_ty(&'tcx self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
         }
     }
 
+    /// Returns the type of metadata for (potentially fat) pointers to this type.
+    pub fn ptr_metadata_ty(&'tcx self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
+        // FIXME: should this normalize?
+        let tail = tcx.struct_tail_without_normalization(self);
+        match tail.kind() {
+            // Sized types
+            ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
+            | ty::Uint(_)
+            | ty::Int(_)
+            | ty::Bool
+            | ty::Float(_)
+            | ty::FnDef(..)
+            | ty::FnPtr(_)
+            | ty::RawPtr(..)
+            | ty::Char
+            | ty::Ref(..)
+            | ty::Generator(..)
+            | ty::GeneratorWitness(..)
+            | ty::Array(..)
+            | ty::Closure(..)
+            | ty::Never
+            | ty::Error(_)
+            | ty::Foreign(..)
+            // If returned by `struct_tail_without_normalization` this is a unit struct
+            // without any fields, or not a struct, and therefore is Sized.
+            | ty::Adt(..)
+            // If returned by `struct_tail_without_normalization` this is the empty tuple,
+            // a.k.a. unit type, which is Sized
+            | ty::Tuple(..) => tcx.types.unit,
+
+            ty::Str | ty::Slice(_) => tcx.types.usize,
+            ty::Dynamic(..) => {
+                let dyn_metadata = tcx.lang_items().dyn_metadata().unwrap();
+                tcx.type_of(dyn_metadata).subst(tcx, &[tail.into()])
+            },
+
+            ty::Projection(_)
+            | ty::Param(_)
+            | ty::Opaque(..)
+            | ty::Infer(ty::TyVar(_))
+            | ty::Bound(..)
+            | ty::Placeholder(..)
+            | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
+                bug!("`ptr_metadata_ty` applied to unexpected type: {:?}", tail)
+            }
+        }
+    }
+
     /// When we create a closure, we record its kind (i.e., what trait
     /// it implements) into its `ClosureSubsts` using a type
     /// parameter. This is kind of a phantom type, except that the
index 0f1c2b87426b53b4251ffeeae8ecfd95c902b862..de898460368b8427a73b178b9ae651372f00743f 100644 (file)
@@ -56,7 +56,7 @@ fn eval_body_using_ecx<'mir, 'tcx>(
     ecx.push_stack_frame(
         cid.instance,
         body,
-        Some(ret.into()),
+        Some(&ret.into()),
         StackPopCleanup::None { cleanup: false },
     )?;
 
@@ -72,7 +72,7 @@ fn eval_body_using_ecx<'mir, 'tcx>(
             None => InternKind::Constant,
         }
     };
-    intern_const_alloc_recursive(ecx, intern_kind, ret)?;
+    intern_const_alloc_recursive(ecx, intern_kind, &ret)?;
 
     debug!("eval_body_using_ecx done: {:?}", *ret);
     Ok(ret)
@@ -105,7 +105,7 @@ pub(super) fn mk_eval_cx<'mir, 'tcx>(
 /// type system.
 pub(super) fn op_to_const<'tcx>(
     ecx: &CompileTimeEvalContext<'_, 'tcx>,
-    op: OpTy<'tcx>,
+    op: &OpTy<'tcx>,
 ) -> ConstValue<'tcx> {
     // We do not have value optimizations for everything.
     // Only scalars and slices, since they are very common.
@@ -137,7 +137,7 @@ pub(super) fn op_to_const<'tcx>(
         op.try_as_mplace(ecx)
     };
 
-    let to_const_value = |mplace: MPlaceTy<'_>| match mplace.ptr {
+    let to_const_value = |mplace: &MPlaceTy<'_>| match mplace.ptr {
         Scalar::Ptr(ptr) => {
             let alloc = ecx.tcx.global_alloc(ptr.alloc_id).unwrap_memory();
             ConstValue::ByRef { alloc, offset: ptr.offset }
@@ -155,12 +155,12 @@ pub(super) fn op_to_const<'tcx>(
         }
     };
     match immediate {
-        Ok(mplace) => to_const_value(mplace),
+        Ok(ref mplace) => to_const_value(mplace),
         // see comment on `let try_as_immediate` above
         Err(imm) => match *imm {
             Immediate::Scalar(x) => match x {
                 ScalarMaybeUninit::Scalar(s) => ConstValue::Scalar(s),
-                ScalarMaybeUninit::Uninit => to_const_value(op.assert_mem_place(ecx)),
+                ScalarMaybeUninit::Uninit => to_const_value(&op.assert_mem_place(ecx)),
             },
             Immediate::ScalarPair(a, b) => {
                 let (data, start) = match a.check_init().unwrap() {
@@ -201,7 +201,7 @@ fn turn_into_const_value<'tcx>(
         "the `eval_to_const_value_raw` query should not be used for statics, use `eval_to_allocation` instead"
     );
     // Turn this into a proper constant.
-    op_to_const(&ecx, mplace.into())
+    op_to_const(&ecx, &mplace.into())
 }
 
 pub fn eval_to_const_value_raw_provider<'tcx>(
@@ -348,7 +348,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
                         Some(_) => CtfeValidationMode::Regular, // a `static`
                         None => CtfeValidationMode::Const { inner, allow_static_ptrs: false },
                     };
-                    ecx.const_validate_operand(mplace.into(), path, &mut ref_tracking, mode)?;
+                    ecx.const_validate_operand(&mplace.into(), path, &mut ref_tracking, mode)?;
                     inner = true;
                 }
             };
index 8e75481e323c54cf652fec9c9e9ada23d2cbd270..61785a52729d5d091b4f98f9d8347cbd4e66c7b3 100644 (file)
@@ -39,8 +39,8 @@ fn hook_panic_fn(
             // &str
             assert!(args.len() == 1);
 
-            let msg_place = self.deref_operand(args[0])?;
-            let msg = Symbol::intern(self.read_str(msg_place)?);
+            let msg_place = self.deref_operand(&args[0])?;
+            let msg = Symbol::intern(self.read_str(&msg_place)?);
             let span = self.find_closest_untracked_caller_location();
             let (file, line, col) = self.location_triple_for_span(span);
             Err(ConstEvalErrKind::Panic { msg, file, line, col }.into())
@@ -222,7 +222,7 @@ fn find_mir_or_eval_fn(
         instance: ty::Instance<'tcx>,
         _abi: Abi,
         args: &[OpTy<'tcx>],
-        _ret: Option<(PlaceTy<'tcx>, mir::BasicBlock)>,
+        _ret: Option<(&PlaceTy<'tcx>, mir::BasicBlock)>,
         _unwind: Option<mir::BasicBlock>, // unwinding is not supported in consts
     ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> {
         debug!("find_mir_or_eval_fn: {:?}", instance);
@@ -262,7 +262,7 @@ fn call_intrinsic(
         ecx: &mut InterpCx<'mir, 'tcx, Self>,
         instance: ty::Instance<'tcx>,
         args: &[OpTy<'tcx>],
-        ret: Option<(PlaceTy<'tcx>, mir::BasicBlock)>,
+        ret: Option<(&PlaceTy<'tcx>, mir::BasicBlock)>,
         _unwind: Option<mir::BasicBlock>,
     ) -> InterpResult<'tcx> {
         // Shared intrinsics.
@@ -284,8 +284,8 @@ fn call_intrinsic(
         };
         match intrinsic_name {
             sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => {
-                let a = ecx.read_immediate(args[0])?.to_scalar()?;
-                let b = ecx.read_immediate(args[1])?.to_scalar()?;
+                let a = ecx.read_immediate(&args[0])?.to_scalar()?;
+                let b = ecx.read_immediate(&args[1])?.to_scalar()?;
                 let cmp = if intrinsic_name == sym::ptr_guaranteed_eq {
                     ecx.guaranteed_eq(a, b)
                 } else {
@@ -294,8 +294,8 @@ fn call_intrinsic(
                 ecx.write_scalar(Scalar::from_bool(cmp), dest)?;
             }
             sym::const_allocate => {
-                let size = ecx.read_scalar(args[0])?.to_machine_usize(ecx)?;
-                let align = ecx.read_scalar(args[1])?.to_machine_usize(ecx)?;
+                let size = ecx.read_scalar(&args[0])?.to_machine_usize(ecx)?;
+                let align = ecx.read_scalar(&args[1])?.to_machine_usize(ecx)?;
 
                 let align = match Align::from_bytes(align) {
                     Ok(a) => a,
@@ -330,7 +330,7 @@ fn assert_panic(
         use rustc_middle::mir::AssertKind::*;
         // Convert `AssertKind<Operand>` to `AssertKind<Scalar>`.
         let eval_to_int =
-            |op| ecx.read_immediate(ecx.eval_operand(op, None)?).map(|x| x.to_const_int());
+            |op| ecx.read_immediate(&ecx.eval_operand(op, None)?).map(|x| x.to_const_int());
         let err = match msg {
             BoundsCheck { ref len, ref index } => {
                 let len = eval_to_int(len)?;
@@ -358,15 +358,15 @@ fn ptr_to_int(_mem: &Memory<'mir, 'tcx, Self>, _ptr: Pointer) -> InterpResult<'t
     fn binary_ptr_op(
         _ecx: &InterpCx<'mir, 'tcx, Self>,
         _bin_op: mir::BinOp,
-        _left: ImmTy<'tcx>,
-        _right: ImmTy<'tcx>,
+        _left: &ImmTy<'tcx>,
+        _right: &ImmTy<'tcx>,
     ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> {
         Err(ConstEvalErrKind::NeedsRfc("pointer arithmetic or comparison".to_string()).into())
     }
 
     fn box_alloc(
         _ecx: &mut InterpCx<'mir, 'tcx, Self>,
-        _dest: PlaceTy<'tcx>,
+        _dest: &PlaceTy<'tcx>,
     ) -> InterpResult<'tcx> {
         Err(ConstEvalErrKind::NeedsRfc("heap allocations via `box` keyword".to_string()).into())
     }
index 9dd2a8592a7e0a0d5d47110727e2de5df73db714..a4e1cd2faa3c0244f0c1238d2c787e1b85e3e3ee 100644 (file)
@@ -29,7 +29,7 @@ pub(crate) fn const_caller_location(
     let mut ecx = mk_eval_cx(tcx, DUMMY_SP, ty::ParamEnv::reveal_all(), false);
 
     let loc_place = ecx.alloc_caller_location(file, line, col);
-    if intern_const_alloc_recursive(&mut ecx, InternKind::Constant, loc_place).is_err() {
+    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(loc_place.ptr)
@@ -55,8 +55,8 @@ pub(crate) fn destructure_const<'tcx>(
             return mir::DestructuredConst { variant: None, fields: &[] };
         }
         ty::Adt(def, _) => {
-            let variant = ecx.read_discriminant(op).unwrap().1;
-            let down = ecx.operand_downcast(op, variant).unwrap();
+            let variant = ecx.read_discriminant(&op).unwrap().1;
+            let down = ecx.operand_downcast(&op, variant).unwrap();
             (def.variants[variant].fields.len(), Some(variant), down)
         }
         ty::Tuple(substs) => (substs.len(), None, op),
@@ -64,8 +64,8 @@ pub(crate) fn destructure_const<'tcx>(
     };
 
     let fields_iter = (0..field_count).map(|i| {
-        let field_op = ecx.operand_field(down, i).unwrap();
-        let val = op_to_const(&ecx, field_op);
+        let field_op = ecx.operand_field(&down, i).unwrap();
+        let val = op_to_const(&ecx, &field_op);
         ty::Const::from_value(tcx, val, field_op.layout.ty)
     });
     let fields = tcx.arena.alloc_from_iter(fields_iter);
@@ -81,7 +81,7 @@ pub(crate) fn deref_const<'tcx>(
     trace!("deref_const: {:?}", val);
     let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false);
     let op = ecx.const_to_op(val, None).unwrap();
-    let mplace = ecx.deref_operand(op).unwrap();
+    let mplace = ecx.deref_operand(&op).unwrap();
     if let Scalar::Ptr(ptr) = mplace.ptr {
         assert_eq!(
             ecx.memory.get_raw(ptr.alloc_id).unwrap().mutability,
@@ -106,5 +106,5 @@ pub(crate) fn deref_const<'tcx>(
         },
     };
 
-    tcx.mk_const(ty::Const { val: ty::ConstKind::Value(op_to_const(&ecx, mplace.into())), ty })
+    tcx.mk_const(ty::Const { val: ty::ConstKind::Value(op_to_const(&ecx, &mplace.into())), ty })
 }
index 128d8cff95e6b321719e66197a9e1b2f4c7a1c0c..2d9e6df0ab86073729c3d9892369191761cc4cc9 100644 (file)
 impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     pub fn cast(
         &mut self,
-        src: OpTy<'tcx, M::PointerTag>,
+        src: &OpTy<'tcx, M::PointerTag>,
         cast_kind: CastKind,
         cast_ty: Ty<'tcx>,
-        dest: PlaceTy<'tcx, M::PointerTag>,
+        dest: &PlaceTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx> {
         use rustc_middle::mir::CastKind::*;
         // FIXME: In which cases should we trigger UB when the source is uninit?
@@ -32,7 +32,7 @@ pub fn cast(
 
             Misc => {
                 let src = self.read_immediate(src)?;
-                let res = self.misc_cast(src, cast_ty)?;
+                let res = self.misc_cast(&src, cast_ty)?;
                 self.write_immediate(res, dest)?;
             }
 
@@ -107,7 +107,7 @@ pub fn cast(
 
     fn misc_cast(
         &self,
-        src: ImmTy<'tcx, M::PointerTag>,
+        src: &ImmTy<'tcx, M::PointerTag>,
         cast_ty: Ty<'tcx>,
     ) -> InterpResult<'tcx, Immediate<M::PointerTag>> {
         use rustc_middle::ty::TyKind::*;
@@ -158,13 +158,13 @@ fn misc_cast(
             let dest_layout = self.layout_of(cast_ty)?;
             if dest_layout.size == src.layout.size {
                 // Thin or fat pointer that just hast the ptr kind of target type changed.
-                return Ok(*src);
+                return Ok(**src);
             } else {
                 // Casting the metadata away from a fat ptr.
                 assert_eq!(src.layout.size, 2 * self.memory.pointer_size());
                 assert_eq!(dest_layout.size, self.memory.pointer_size());
                 assert!(src.layout.ty.is_unsafe_ptr());
-                return match *src {
+                return match **src {
                     Immediate::ScalarPair(data, _) => Ok(data.into()),
                     Immediate::Scalar(..) => span_bug!(
                         self.cur_span(),
@@ -259,8 +259,8 @@ fn cast_from_float<F>(&self, f: F, dest_ty: Ty<'tcx>) -> Scalar<M::PointerTag>
 
     fn unsize_into_ptr(
         &mut self,
-        src: OpTy<'tcx, M::PointerTag>,
-        dest: PlaceTy<'tcx, M::PointerTag>,
+        src: &OpTy<'tcx, M::PointerTag>,
+        dest: &PlaceTy<'tcx, M::PointerTag>,
         // The pointee types
         source_ty: Ty<'tcx>,
         cast_ty: Ty<'tcx>,
@@ -300,9 +300,9 @@ fn unsize_into_ptr(
 
     fn unsize_into(
         &mut self,
-        src: OpTy<'tcx, M::PointerTag>,
+        src: &OpTy<'tcx, M::PointerTag>,
         cast_ty: TyAndLayout<'tcx>,
-        dest: PlaceTy<'tcx, M::PointerTag>,
+        dest: &PlaceTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx> {
         trace!("Unsizing {:?} of type {} into {:?}", *src, src.layout.ty, cast_ty.ty);
         match (&src.layout.ty.kind(), &cast_ty.ty.kind()) {
@@ -340,9 +340,9 @@ fn unsize_into(
                     let src_field = self.operand_field(src, i)?;
                     let dst_field = self.place_field(dest, i)?;
                     if src_field.layout.ty == cast_ty_field.ty {
-                        self.copy_op(src_field, dst_field)?;
+                        self.copy_op(&src_field, &dst_field)?;
                     } else {
-                        self.unsize_into(src_field, cast_ty_field, dst_field)?;
+                        self.unsize_into(&src_field, cast_ty_field, &dst_field)?;
                     }
                 }
                 Ok(())
index 7e9594dd6bfd77fdb502e993edc8cc64cfd26ab5..1ba87358b1c3d4b9bd7df15726d3feed6044cd4c 100644 (file)
@@ -548,8 +548,8 @@ pub fn layout_of_local(
     /// This can fail to provide an answer for extern types.
     pub(super) fn size_and_align_of(
         &self,
-        metadata: MemPlaceMeta<M::PointerTag>,
-        layout: TyAndLayout<'tcx>,
+        metadata: &MemPlaceMeta<M::PointerTag>,
+        layout: &TyAndLayout<'tcx>,
     ) -> InterpResult<'tcx, Option<(Size, Align)>> {
         if !layout.is_unsized() {
             return Ok(Some((layout.size, layout.align.abi)));
@@ -577,24 +577,25 @@ pub(super) fn size_and_align_of(
                 // the last field).  Can't have foreign types here, how would we
                 // adjust alignment and size for them?
                 let field = layout.field(self, layout.fields.count() - 1)?;
-                let (unsized_size, unsized_align) = match self.size_and_align_of(metadata, field)? {
-                    Some(size_and_align) => size_and_align,
-                    None => {
-                        // A field with extern type.  If this field is at offset 0, we behave
-                        // like the underlying extern type.
-                        // FIXME: Once we have made decisions for how to handle size and alignment
-                        // of `extern type`, this should be adapted.  It is just a temporary hack
-                        // to get some code to work that probably ought to work.
-                        if sized_size == Size::ZERO {
-                            return Ok(None);
-                        } else {
-                            span_bug!(
-                                self.cur_span(),
-                                "Fields cannot be extern types, unless they are at offset 0"
-                            )
+                let (unsized_size, unsized_align) =
+                    match self.size_and_align_of(metadata, &field)? {
+                        Some(size_and_align) => size_and_align,
+                        None => {
+                            // A field with extern type.  If this field is at offset 0, we behave
+                            // like the underlying extern type.
+                            // FIXME: Once we have made decisions for how to handle size and alignment
+                            // of `extern type`, this should be adapted.  It is just a temporary hack
+                            // to get some code to work that probably ought to work.
+                            if sized_size == Size::ZERO {
+                                return Ok(None);
+                            } else {
+                                span_bug!(
+                                    self.cur_span(),
+                                    "Fields cannot be extern types, unless they are at offset 0"
+                                )
+                            }
                         }
-                    }
-                };
+                    };
 
                 // FIXME (#26403, #27023): We should be adding padding
                 // to `sized_size` (to accommodate the `unsized_align`
@@ -645,16 +646,16 @@ pub(super) fn size_and_align_of(
     #[inline]
     pub fn size_and_align_of_mplace(
         &self,
-        mplace: MPlaceTy<'tcx, M::PointerTag>,
+        mplace: &MPlaceTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx, Option<(Size, Align)>> {
-        self.size_and_align_of(mplace.meta, mplace.layout)
+        self.size_and_align_of(&mplace.meta, &mplace.layout)
     }
 
     pub fn push_stack_frame(
         &mut self,
         instance: ty::Instance<'tcx>,
         body: &'mir mir::Body<'tcx>,
-        return_place: Option<PlaceTy<'tcx, M::PointerTag>>,
+        return_place: Option<&PlaceTy<'tcx, M::PointerTag>>,
         return_to_block: StackPopCleanup,
     ) -> InterpResult<'tcx> {
         // first push a stack frame so we have access to the local substs
@@ -662,7 +663,7 @@ pub fn push_stack_frame(
             body,
             loc: Err(body.span), // Span used for errors caused during preamble.
             return_to_block,
-            return_place,
+            return_place: return_place.copied(),
             // empty local array, we fill it in below, after we are inside the stack frame and
             // all methods actually know about the frame
             locals: IndexVec::new(),
@@ -777,10 +778,10 @@ pub(super) fn pop_stack_frame(&mut self, unwinding: bool) -> InterpResult<'tcx>
 
         if !unwinding {
             // Copy the return value to the caller's stack frame.
-            if let Some(return_place) = frame.return_place {
+            if let Some(ref return_place) = frame.return_place {
                 let op = self.access_local(&frame, mir::RETURN_PLACE, None)?;
-                self.copy_op_transmute(op, return_place)?;
-                trace!("{:?}", self.dump_place(*return_place));
+                self.copy_op_transmute(&op, return_place)?;
+                trace!("{:?}", self.dump_place(**return_place));
             } else {
                 throw_ub!(Unreachable);
             }
index 7993d4847a744d9e019205b0725f89fa38950008..59438661cac7d3dbe1f180bcf7b67f5fcc66b42c 100644 (file)
@@ -167,7 +167,7 @@ fn ecx(&self) -> &InterpCx<'mir, 'tcx, M> {
 
     fn visit_aggregate(
         &mut self,
-        mplace: MPlaceTy<'tcx>,
+        mplace: &MPlaceTy<'tcx>,
         fields: impl Iterator<Item = InterpResult<'tcx, Self::V>>,
     ) -> InterpResult<'tcx> {
         // ZSTs cannot contain pointers, so we can skip them.
@@ -191,14 +191,14 @@ fn visit_aggregate(
         self.walk_aggregate(mplace, fields)
     }
 
-    fn visit_value(&mut self, mplace: MPlaceTy<'tcx>) -> InterpResult<'tcx> {
+    fn visit_value(&mut self, mplace: &MPlaceTy<'tcx>) -> InterpResult<'tcx> {
         // Handle Reference types, as these are the only relocations supported by const eval.
         // Raw pointers (and boxes) are handled by the `leftover_relocations` logic.
         let tcx = self.ecx.tcx;
         let ty = mplace.layout.ty;
         if let ty::Ref(_, referenced_ty, ref_mutability) = *ty.kind() {
-            let value = self.ecx.read_immediate(mplace.into())?;
-            let mplace = self.ecx.ref_to_mplace(value)?;
+            let value = self.ecx.read_immediate(&(*mplace).into())?;
+            let mplace = self.ecx.ref_to_mplace(&value)?;
             assert_eq!(mplace.layout.ty, referenced_ty);
             // Handle trait object vtables.
             if let ty::Dynamic(..) =
@@ -296,7 +296,7 @@ pub enum InternKind {
 pub fn intern_const_alloc_recursive<M: CompileTimeMachine<'mir, 'tcx, const_eval::MemoryKind>>(
     ecx: &mut InterpCx<'mir, 'tcx, M>,
     intern_kind: InternKind,
-    ret: MPlaceTy<'tcx>,
+    ret: &MPlaceTy<'tcx>,
 ) -> Result<(), ErrorReported>
 where
     'tcx: 'mir,
@@ -328,7 +328,7 @@ pub fn intern_const_alloc_recursive<M: CompileTimeMachine<'mir, 'tcx, const_eval
         Some(ret.layout.ty),
     );
 
-    ref_tracking.track((ret, base_intern_mode), || ());
+    ref_tracking.track((*ret, base_intern_mode), || ());
 
     while let Some(((mplace, mode), _)) = ref_tracking.todo.pop() {
         let res = InternVisitor {
@@ -338,7 +338,7 @@ pub fn intern_const_alloc_recursive<M: CompileTimeMachine<'mir, 'tcx, const_eval
             leftover_allocations,
             inside_unsafe_cell: false,
         }
-        .visit_value(mplace);
+        .visit_value(&mplace);
         // We deliberately *ignore* interpreter errors here.  When there is a problem, the remaining
         // references are "leftover"-interned, and later validation will show a proper error
         // and point at the right part of the value causing the problem.
@@ -435,11 +435,11 @@ pub(crate) fn intern_with_temp_alloc(
         layout: TyAndLayout<'tcx>,
         f: impl FnOnce(
             &mut InterpCx<'mir, 'tcx, M>,
-            MPlaceTy<'tcx, M::PointerTag>,
+            &MPlaceTy<'tcx, M::PointerTag>,
         ) -> InterpResult<'tcx, ()>,
     ) -> InterpResult<'tcx, &'tcx Allocation> {
         let dest = self.allocate(layout, MemoryKind::Stack);
-        f(self, dest)?;
+        f(self, &dest)?;
         let ptr = dest.ptr.assert_ptr();
         assert_eq!(ptr.offset, Size::ZERO);
         let mut alloc = self.memory.alloc_map.remove(&ptr.alloc_id).unwrap().1;
index f4309c9cd9572d11e62f1eabc758cb78d1bd59b6..c4039f2f15e940b5f41c7b082a5e07f07ebf46ce 100644 (file)
@@ -115,7 +115,7 @@ pub fn emulate_intrinsic(
         &mut self,
         instance: ty::Instance<'tcx>,
         args: &[OpTy<'tcx, M::PointerTag>],
-        ret: Option<(PlaceTy<'tcx, M::PointerTag>, mir::BasicBlock)>,
+        ret: Option<(&PlaceTy<'tcx, M::PointerTag>, mir::BasicBlock)>,
     ) -> InterpResult<'tcx, bool> {
         let substs = instance.substs;
         let intrinsic_name = self.tcx.item_name(instance.def_id());
@@ -143,9 +143,9 @@ pub fn emulate_intrinsic(
             sym::min_align_of_val | sym::size_of_val => {
                 // Avoid `deref_operand` -- this is not a deref, the ptr does not have to be
                 // dereferencable!
-                let place = self.ref_to_mplace(self.read_immediate(args[0])?)?;
+                let place = self.ref_to_mplace(&self.read_immediate(&args[0])?)?;
                 let (size, align) = self
-                    .size_and_align_of_mplace(place)?
+                    .size_and_align_of_mplace(&place)?
                     .ok_or_else(|| err_unsup_format!("`extern type` does not have known layout"))?;
 
                 let result = match intrinsic_name {
@@ -177,7 +177,7 @@ pub fn emulate_intrinsic(
                     self.tcx.const_eval_global_id(self.param_env, gid, Some(self.tcx.span))?;
                 let const_ = ty::Const { val: ty::ConstKind::Value(val), ty };
                 let val = self.const_to_op(&const_, None)?;
-                self.copy_op(val, dest)?;
+                self.copy_op(&val, dest)?;
             }
 
             sym::ctpop
@@ -189,7 +189,7 @@ pub fn emulate_intrinsic(
             | sym::bitreverse => {
                 let ty = substs.type_at(0);
                 let layout_of = self.layout_of(ty)?;
-                let val = self.read_scalar(args[0])?.check_init()?;
+                let val = self.read_scalar(&args[0])?.check_init()?;
                 let bits = self.force_bits(val, layout_of.size)?;
                 let kind = match layout_of.abi {
                     Abi::Scalar(ref scalar) => scalar.value,
@@ -212,22 +212,25 @@ pub fn emulate_intrinsic(
                 self.write_scalar(out_val, dest)?;
             }
             sym::add_with_overflow | sym::sub_with_overflow | sym::mul_with_overflow => {
-                let lhs = self.read_immediate(args[0])?;
-                let rhs = self.read_immediate(args[1])?;
+                let lhs = self.read_immediate(&args[0])?;
+                let rhs = self.read_immediate(&args[1])?;
                 let bin_op = match intrinsic_name {
                     sym::add_with_overflow => BinOp::Add,
                     sym::sub_with_overflow => BinOp::Sub,
                     sym::mul_with_overflow => BinOp::Mul,
                     _ => bug!("Already checked for int ops"),
                 };
-                self.binop_with_overflow(bin_op, lhs, rhs, dest)?;
+                self.binop_with_overflow(bin_op, &lhs, &rhs, dest)?;
             }
             sym::saturating_add | sym::saturating_sub => {
-                let l = self.read_immediate(args[0])?;
-                let r = self.read_immediate(args[1])?;
+                let l = self.read_immediate(&args[0])?;
+                let r = self.read_immediate(&args[1])?;
                 let is_add = intrinsic_name == sym::saturating_add;
-                let (val, overflowed, _ty) =
-                    self.overflowing_binary_op(if is_add { BinOp::Add } else { BinOp::Sub }, l, r)?;
+                let (val, overflowed, _ty) = self.overflowing_binary_op(
+                    if is_add { BinOp::Add } else { BinOp::Sub },
+                    &l,
+                    &r,
+                )?;
                 let val = if overflowed {
                     let num_bits = l.layout.size.bits();
                     if l.layout.abi.is_signed() {
@@ -269,8 +272,8 @@ pub fn emulate_intrinsic(
                 self.write_scalar(val, dest)?;
             }
             sym::discriminant_value => {
-                let place = self.deref_operand(args[0])?;
-                let discr_val = self.read_discriminant(place.into())?.0;
+                let place = self.deref_operand(&args[0])?;
+                let discr_val = self.read_discriminant(&place.into())?.0;
                 self.write_scalar(discr_val, dest)?;
             }
             sym::unchecked_shl
@@ -280,8 +283,8 @@ pub fn emulate_intrinsic(
             | sym::unchecked_mul
             | sym::unchecked_div
             | sym::unchecked_rem => {
-                let l = self.read_immediate(args[0])?;
-                let r = self.read_immediate(args[1])?;
+                let l = self.read_immediate(&args[0])?;
+                let r = self.read_immediate(&args[1])?;
                 let bin_op = match intrinsic_name {
                     sym::unchecked_shl => BinOp::Shl,
                     sym::unchecked_shr => BinOp::Shr,
@@ -292,7 +295,7 @@ pub fn emulate_intrinsic(
                     sym::unchecked_rem => BinOp::Rem,
                     _ => bug!("Already checked for int ops"),
                 };
-                let (val, overflowed, _ty) = self.overflowing_binary_op(bin_op, l, r)?;
+                let (val, overflowed, _ty) = self.overflowing_binary_op(bin_op, &l, &r)?;
                 if overflowed {
                     let layout = self.layout_of(substs.type_at(0))?;
                     let r_val = self.force_bits(r.to_scalar()?, layout.size)?;
@@ -308,9 +311,9 @@ pub fn emulate_intrinsic(
                 // rotate_left: (X << (S % BW)) | (X >> ((BW - S) % BW))
                 // rotate_right: (X << ((BW - S) % BW)) | (X >> (S % BW))
                 let layout = self.layout_of(substs.type_at(0))?;
-                let val = self.read_scalar(args[0])?.check_init()?;
+                let val = self.read_scalar(&args[0])?.check_init()?;
                 let val_bits = self.force_bits(val, layout.size)?;
-                let raw_shift = self.read_scalar(args[1])?.check_init()?;
+                let raw_shift = self.read_scalar(&args[1])?.check_init()?;
                 let raw_shift_bits = self.force_bits(raw_shift, layout.size)?;
                 let width_bits = u128::from(layout.size.bits());
                 let shift_bits = raw_shift_bits % width_bits;
@@ -327,15 +330,15 @@ pub fn emulate_intrinsic(
             sym::copy | sym::copy_nonoverlapping => {
                 let elem_ty = instance.substs.type_at(0);
                 let elem_layout = self.layout_of(elem_ty)?;
-                let count = self.read_scalar(args[2])?.to_machine_usize(self)?;
+                let count = self.read_scalar(&args[2])?.to_machine_usize(self)?;
                 let elem_align = elem_layout.align.abi;
 
                 let size = elem_layout.size.checked_mul(count, self).ok_or_else(|| {
                     err_ub_format!("overflow computing total size of `{}`", intrinsic_name)
                 })?;
-                let src = self.read_scalar(args[0])?.check_init()?;
+                let src = self.read_scalar(&args[0])?.check_init()?;
                 let src = self.memory.check_ptr_access(src, size, elem_align)?;
-                let dest = self.read_scalar(args[1])?.check_init()?;
+                let dest = self.read_scalar(&args[1])?.check_init()?;
                 let dest = self.memory.check_ptr_access(dest, size, elem_align)?;
 
                 if let (Some(src), Some(dest)) = (src, dest) {
@@ -348,16 +351,16 @@ pub fn emulate_intrinsic(
                 }
             }
             sym::offset => {
-                let ptr = self.read_scalar(args[0])?.check_init()?;
-                let offset_count = self.read_scalar(args[1])?.to_machine_isize(self)?;
+                let ptr = self.read_scalar(&args[0])?.check_init()?;
+                let offset_count = self.read_scalar(&args[1])?.to_machine_isize(self)?;
                 let pointee_ty = substs.type_at(0);
 
                 let offset_ptr = self.ptr_offset_inbounds(ptr, pointee_ty, offset_count)?;
                 self.write_scalar(offset_ptr, dest)?;
             }
             sym::arith_offset => {
-                let ptr = self.read_scalar(args[0])?.check_init()?;
-                let offset_count = self.read_scalar(args[1])?.to_machine_isize(self)?;
+                let ptr = self.read_scalar(&args[0])?.check_init()?;
+                let offset_count = self.read_scalar(&args[1])?.to_machine_isize(self)?;
                 let pointee_ty = substs.type_at(0);
 
                 let pointee_size = i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap();
@@ -366,8 +369,8 @@ pub fn emulate_intrinsic(
                 self.write_scalar(offset_ptr, dest)?;
             }
             sym::ptr_offset_from => {
-                let a = self.read_immediate(args[0])?.to_scalar()?;
-                let b = self.read_immediate(args[1])?.to_scalar()?;
+                let a = self.read_immediate(&args[0])?.to_scalar()?;
+                let b = self.read_immediate(&args[1])?.to_scalar()?;
 
                 // Special case: if both scalars are *equal integers*
                 // and not NULL, we pretend there is an allocation of size 0 right there,
@@ -406,16 +409,16 @@ pub fn emulate_intrinsic(
                     let a_offset = ImmTy::from_uint(a.offset.bytes(), usize_layout);
                     let b_offset = ImmTy::from_uint(b.offset.bytes(), usize_layout);
                     let (val, _overflowed, _ty) =
-                        self.overflowing_binary_op(BinOp::Sub, a_offset, b_offset)?;
+                        self.overflowing_binary_op(BinOp::Sub, &a_offset, &b_offset)?;
                     let pointee_layout = self.layout_of(substs.type_at(0))?;
                     let val = ImmTy::from_scalar(val, isize_layout);
                     let size = ImmTy::from_int(pointee_layout.size.bytes(), isize_layout);
-                    self.exact_div(val, size, dest)?;
+                    self.exact_div(&val, &size, dest)?;
                 }
             }
 
             sym::transmute => {
-                self.copy_op_transmute(args[0], dest)?;
+                self.copy_op_transmute(&args[0], dest)?;
             }
             sym::assert_inhabited => {
                 let ty = instance.substs.type_at(0);
@@ -434,9 +437,9 @@ pub fn emulate_intrinsic(
                 }
             }
             sym::simd_insert => {
-                let index = u64::from(self.read_scalar(args[1])?.to_u32()?);
-                let elem = args[2];
-                let input = args[0];
+                let index = u64::from(self.read_scalar(&args[1])?.to_u32()?);
+                let elem = &args[2];
+                let input = &args[0];
                 let (len, e_ty) = input.layout.ty.simd_size_and_type(*self.tcx);
                 assert!(
                     index < len,
@@ -458,12 +461,12 @@ pub fn emulate_intrinsic(
 
                 for i in 0..len {
                     let place = self.place_index(dest, i)?;
-                    let value = if i == index { elem } else { self.operand_index(input, i)? };
-                    self.copy_op(value, place)?;
+                    let value = if i == index { *elem } else { self.operand_index(input, i)? };
+                    self.copy_op(&value, &place)?;
                 }
             }
             sym::simd_extract => {
-                let index = u64::from(self.read_scalar(args[1])?.to_u32()?);
+                let index = u64::from(self.read_scalar(&args[1])?.to_u32()?);
                 let (len, e_ty) = args[0].layout.ty.simd_size_and_type(*self.tcx);
                 assert!(
                     index < len,
@@ -477,14 +480,14 @@ pub fn emulate_intrinsic(
                     "Return type `{}` must match vector element type `{}`",
                     dest.layout.ty, e_ty
                 );
-                self.copy_op(self.operand_index(args[0], index)?, dest)?;
+                self.copy_op(&self.operand_index(&args[0], index)?, dest)?;
             }
             sym::likely | sym::unlikely => {
                 // These just return their argument
-                self.copy_op(args[0], dest)?;
+                self.copy_op(&args[0], dest)?;
             }
             sym::assume => {
-                let cond = self.read_scalar(args[0])?.check_init()?.to_bool()?;
+                let cond = self.read_scalar(&args[0])?.check_init()?.to_bool()?;
                 if !cond {
                     throw_ub_format!("`assume` intrinsic called with `false`");
                 }
@@ -492,21 +495,21 @@ pub fn emulate_intrinsic(
             _ => return Ok(false),
         }
 
-        trace!("{:?}", self.dump_place(*dest));
+        trace!("{:?}", self.dump_place(**dest));
         self.go_to_block(ret);
         Ok(true)
     }
 
     pub fn exact_div(
         &mut self,
-        a: ImmTy<'tcx, M::PointerTag>,
-        b: ImmTy<'tcx, M::PointerTag>,
-        dest: PlaceTy<'tcx, M::PointerTag>,
+        a: &ImmTy<'tcx, M::PointerTag>,
+        b: &ImmTy<'tcx, M::PointerTag>,
+        dest: &PlaceTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx> {
         // Performs an exact division, resulting in undefined behavior where
         // `x % y != 0` or `y == 0` or `x == T::MIN && y == -1`.
         // First, check x % y != 0 (or if that computation overflows).
-        let (res, overflow, _ty) = self.overflowing_binary_op(BinOp::Rem, a, b)?;
+        let (res, overflow, _ty) = self.overflowing_binary_op(BinOp::Rem, &a, &b)?;
         if overflow || res.assert_bits(a.layout.size) != 0 {
             // Then, check if `b` is -1, which is the "MIN / -1" case.
             let minus1 = Scalar::from_int(-1, dest.layout.size);
@@ -518,7 +521,7 @@ pub fn exact_div(
             }
         }
         // `Rem` says this is all right, so we can let `Div` do its job.
-        self.binop_ignore_overflow(BinOp::Div, a, b, dest)
+        self.binop_ignore_overflow(BinOp::Div, &a, &b, dest)
     }
 
     /// Offsets a pointer by some multiple of its type, returning an error if the pointer leaves its
index 5c917f00d157bd9080c52c9443f275d25f48c08b..4dfdc08b875c04fee49a5dbf11e9a1d414d3b849 100644 (file)
@@ -92,11 +92,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         let location = self.allocate(loc_layout, MemoryKind::CallerLocation);
 
         // Initialize fields.
-        self.write_immediate(file.to_ref(), self.mplace_field(location, 0).unwrap().into())
+        self.write_immediate(file.to_ref(), &self.mplace_field(&location, 0).unwrap().into())
             .expect("writing to memory we just allocated cannot fail");
-        self.write_scalar(line, self.mplace_field(location, 1).unwrap().into())
+        self.write_scalar(line, &self.mplace_field(&location, 1).unwrap().into())
             .expect("writing to memory we just allocated cannot fail");
-        self.write_scalar(col, self.mplace_field(location, 2).unwrap().into())
+        self.write_scalar(col, &self.mplace_field(&location, 2).unwrap().into())
             .expect("writing to memory we just allocated cannot fail");
 
         location
index 53ac62d435187c63d97932a2c895670af7cdb1a4..65869f956397f16ab79a89e5e5d5867bd4dc68f6 100644 (file)
@@ -157,7 +157,7 @@ fn find_mir_or_eval_fn(
         instance: ty::Instance<'tcx>,
         abi: Abi,
         args: &[OpTy<'tcx, Self::PointerTag>],
-        ret: Option<(PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>,
+        ret: Option<(&PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>,
         unwind: Option<mir::BasicBlock>,
     ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>>;
 
@@ -168,7 +168,7 @@ fn call_extra_fn(
         fn_val: Self::ExtraFnVal,
         abi: Abi,
         args: &[OpTy<'tcx, Self::PointerTag>],
-        ret: Option<(PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>,
+        ret: Option<(&PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>,
         unwind: Option<mir::BasicBlock>,
     ) -> InterpResult<'tcx>;
 
@@ -178,7 +178,7 @@ fn call_intrinsic(
         ecx: &mut InterpCx<'mir, 'tcx, Self>,
         instance: ty::Instance<'tcx>,
         args: &[OpTy<'tcx, Self::PointerTag>],
-        ret: Option<(PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>,
+        ret: Option<(&PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>,
         unwind: Option<mir::BasicBlock>,
     ) -> InterpResult<'tcx>;
 
@@ -200,14 +200,14 @@ fn abort(_ecx: &mut InterpCx<'mir, 'tcx, Self>, _msg: String) -> InterpResult<'t
     fn binary_ptr_op(
         ecx: &InterpCx<'mir, 'tcx, Self>,
         bin_op: mir::BinOp,
-        left: ImmTy<'tcx, Self::PointerTag>,
-        right: ImmTy<'tcx, Self::PointerTag>,
+        left: &ImmTy<'tcx, Self::PointerTag>,
+        right: &ImmTy<'tcx, Self::PointerTag>,
     ) -> InterpResult<'tcx, (Scalar<Self::PointerTag>, bool, Ty<'tcx>)>;
 
     /// Heap allocations via the `box` keyword.
     fn box_alloc(
         ecx: &mut InterpCx<'mir, 'tcx, Self>,
-        dest: PlaceTy<'tcx, Self::PointerTag>,
+        dest: &PlaceTy<'tcx, Self::PointerTag>,
     ) -> InterpResult<'tcx>;
 
     /// Called to read the specified `local` from the `frame`.
@@ -327,7 +327,7 @@ fn after_static_mem_initialized(
     fn retag(
         _ecx: &mut InterpCx<'mir, 'tcx, Self>,
         _kind: mir::RetagKind,
-        _place: PlaceTy<'tcx, Self::PointerTag>,
+        _place: &PlaceTy<'tcx, Self::PointerTag>,
     ) -> InterpResult<'tcx> {
         Ok(())
     }
@@ -420,7 +420,7 @@ fn call_extra_fn(
         fn_val: !,
         _abi: Abi,
         _args: &[OpTy<$tcx>],
-        _ret: Option<(PlaceTy<$tcx>, mir::BasicBlock)>,
+        _ret: Option<(&PlaceTy<$tcx>, mir::BasicBlock)>,
         _unwind: Option<mir::BasicBlock>,
     ) -> InterpResult<$tcx> {
         match fn_val {}
index 88236458a213a134843ffa9c7aeca7adfe3cc930..46ecd33cc5b35d76826c38e8bf67289dd468d608 100644 (file)
@@ -32,6 +32,9 @@ pub enum Immediate<Tag = ()> {
     ScalarPair(ScalarMaybeUninit<Tag>, ScalarMaybeUninit<Tag>),
 }
 
+#[cfg(target_arch = "x86_64")]
+rustc_data_structures::static_assert_size!(Immediate, 56);
+
 impl<Tag> From<ScalarMaybeUninit<Tag>> for Immediate<Tag> {
     #[inline(always)]
     fn from(val: ScalarMaybeUninit<Tag>) -> Self {
@@ -92,6 +95,9 @@ pub struct ImmTy<'tcx, Tag = ()> {
     pub layout: TyAndLayout<'tcx>,
 }
 
+#[cfg(target_arch = "x86_64")]
+rustc_data_structures::static_assert_size!(ImmTy<'_>, 72);
+
 impl<Tag: Copy> std::fmt::Display for ImmTy<'tcx, Tag> {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         /// Helper function for printing a scalar to a FmtPrinter
@@ -106,7 +112,7 @@ fn p<'a, 'tcx, F: std::fmt::Write, Tag>(
                 }
                 ScalarMaybeUninit::Uninit => cx.typed_value(
                     |mut this| {
-                        this.write_str("{uninit ")?;
+                        this.write_str("uninit ")?;
                         Ok(this)
                     },
                     |this| this.print_type(ty),
@@ -156,6 +162,9 @@ pub struct OpTy<'tcx, Tag = ()> {
     pub layout: TyAndLayout<'tcx>,
 }
 
+#[cfg(target_arch = "x86_64")]
+rustc_data_structures::static_assert_size!(OpTy<'_, ()>, 80);
+
 impl<'tcx, Tag> std::ops::Deref for OpTy<'tcx, Tag> {
     type Target = Operand<Tag>;
     #[inline(always)]
@@ -171,6 +180,13 @@ fn from(mplace: MPlaceTy<'tcx, Tag>) -> Self {
     }
 }
 
+impl<'tcx, Tag: Copy> From<&'_ MPlaceTy<'tcx, Tag>> for OpTy<'tcx, Tag> {
+    #[inline(always)]
+    fn from(mplace: &MPlaceTy<'tcx, Tag>) -> Self {
+        OpTy { op: Operand::Indirect(**mplace), layout: mplace.layout }
+    }
+}
+
 impl<'tcx, Tag> From<ImmTy<'tcx, Tag>> for OpTy<'tcx, Tag> {
     #[inline(always)]
     fn from(val: ImmTy<'tcx, Tag>) -> Self {
@@ -222,7 +238,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     #[inline]
     pub fn force_op_ptr(
         &self,
-        op: OpTy<'tcx, M::PointerTag>,
+        op: &OpTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
         match op.try_as_mplace(self) {
             Ok(mplace) => Ok(self.force_mplace_ptr(mplace)?.into()),
@@ -234,7 +250,7 @@ pub fn force_op_ptr(
     /// Returns `None` if the layout does not permit loading this as a value.
     fn try_read_immediate_from_mplace(
         &self,
-        mplace: MPlaceTy<'tcx, M::PointerTag>,
+        mplace: &MPlaceTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx, Option<ImmTy<'tcx, M::PointerTag>>> {
         if mplace.layout.is_unsized() {
             // Don't touch unsized
@@ -295,14 +311,14 @@ fn try_read_immediate_from_mplace(
     /// in a `Immediate`, not on which data is stored there currently.
     pub(crate) fn try_read_immediate(
         &self,
-        src: OpTy<'tcx, M::PointerTag>,
+        src: &OpTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx, Result<ImmTy<'tcx, M::PointerTag>, MPlaceTy<'tcx, M::PointerTag>>> {
         Ok(match src.try_as_mplace(self) {
-            Ok(mplace) => {
+            Ok(ref mplace) => {
                 if let Some(val) = self.try_read_immediate_from_mplace(mplace)? {
                     Ok(val)
                 } else {
-                    Err(mplace)
+                    Err(*mplace)
                 }
             }
             Err(val) => Ok(val),
@@ -313,7 +329,7 @@ pub(crate) fn try_read_immediate(
     #[inline(always)]
     pub fn read_immediate(
         &self,
-        op: OpTy<'tcx, M::PointerTag>,
+        op: &OpTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx, ImmTy<'tcx, M::PointerTag>> {
         if let Ok(imm) = self.try_read_immediate(op)? {
             Ok(imm)
@@ -325,13 +341,13 @@ pub fn read_immediate(
     /// Read a scalar from a place
     pub fn read_scalar(
         &self,
-        op: OpTy<'tcx, M::PointerTag>,
+        op: &OpTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx, ScalarMaybeUninit<M::PointerTag>> {
         Ok(self.read_immediate(op)?.to_scalar_or_uninit())
     }
 
     // Turn the wide MPlace into a string (must already be dereferenced!)
-    pub fn read_str(&self, mplace: MPlaceTy<'tcx, M::PointerTag>) -> InterpResult<'tcx, &str> {
+    pub fn read_str(&self, mplace: &MPlaceTy<'tcx, M::PointerTag>) -> InterpResult<'tcx, &str> {
         let len = mplace.len(self)?;
         let bytes = self.memory.read_bytes(mplace.ptr, Size::from_bytes(len))?;
         let str = std::str::from_utf8(bytes).map_err(|err| err_ub!(InvalidStr(err)))?;
@@ -341,11 +357,11 @@ pub fn read_str(&self, mplace: MPlaceTy<'tcx, M::PointerTag>) -> InterpResult<'t
     /// Projection functions
     pub fn operand_field(
         &self,
-        op: OpTy<'tcx, M::PointerTag>,
+        op: &OpTy<'tcx, M::PointerTag>,
         field: usize,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
         let base = match op.try_as_mplace(self) {
-            Ok(mplace) => {
+            Ok(ref mplace) => {
                 // We can reuse the mplace field computation logic for indirect operands.
                 let field = self.mplace_field(mplace, field)?;
                 return Ok(field.into());
@@ -379,7 +395,7 @@ pub fn operand_field(
 
     pub fn operand_index(
         &self,
-        op: OpTy<'tcx, M::PointerTag>,
+        op: &OpTy<'tcx, M::PointerTag>,
         index: u64,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
         if let Ok(index) = usize::try_from(index) {
@@ -388,28 +404,28 @@ pub fn operand_index(
         } else {
             // Indexing into a big array. This must be an mplace.
             let mplace = op.assert_mem_place(self);
-            Ok(self.mplace_index(mplace, index)?.into())
+            Ok(self.mplace_index(&mplace, index)?.into())
         }
     }
 
     pub fn operand_downcast(
         &self,
-        op: OpTy<'tcx, M::PointerTag>,
+        op: &OpTy<'tcx, M::PointerTag>,
         variant: VariantIdx,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
         // Downcasts only change the layout
         Ok(match op.try_as_mplace(self) {
-            Ok(mplace) => self.mplace_downcast(mplace, variant)?.into(),
+            Ok(ref mplace) => self.mplace_downcast(mplace, variant)?.into(),
             Err(..) => {
                 let layout = op.layout.for_variant(self, variant);
-                OpTy { layout, ..op }
+                OpTy { layout, ..*op }
             }
         })
     }
 
     pub fn operand_projection(
         &self,
-        base: OpTy<'tcx, M::PointerTag>,
+        base: &OpTy<'tcx, M::PointerTag>,
         proj_elem: mir::PlaceElem<'tcx>,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
         use rustc_middle::mir::ProjectionElem::*;
@@ -421,7 +437,7 @@ pub fn operand_projection(
                 // The rest should only occur as mplace, we do not use Immediates for types
                 // allowing such operations.  This matches place_projection forcing an allocation.
                 let mplace = base.assert_mem_place(self);
-                self.mplace_projection(mplace, proj_elem)?.into()
+                self.mplace_projection(&mplace, proj_elem)?.into()
             }
         })
     }
@@ -453,9 +469,9 @@ pub fn access_local(
     #[inline(always)]
     pub fn place_to_op(
         &self,
-        place: PlaceTy<'tcx, M::PointerTag>,
+        place: &PlaceTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
-        let op = match *place {
+        let op = match **place {
             Place::Ptr(mplace) => Operand::Indirect(mplace),
             Place::Local { frame, local } => {
                 *self.access_local(&self.stack()[frame], local, None)?
@@ -480,7 +496,7 @@ pub fn eval_place_to_op(
         let op = place
             .projection
             .iter()
-            .try_fold(base_op, |op, elem| self.operand_projection(op, elem))?;
+            .try_fold(base_op, |op, elem| self.operand_projection(&op, elem))?;
 
         trace!("eval_place_to_op: got {:?}", *op);
         // Sanity-check the type we ended up with.
@@ -590,7 +606,7 @@ pub(super) fn eval_operands(
     /// Read discriminant, return the runtime value as well as the variant index.
     pub fn read_discriminant(
         &self,
-        op: OpTy<'tcx, M::PointerTag>,
+        op: &OpTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx, (Scalar<M::PointerTag>, VariantIdx)> {
         trace!("read_discriminant_value {:#?}", op.layout);
         // Get type and layout of the discriminant.
@@ -636,7 +652,7 @@ pub fn read_discriminant(
         let tag_layout = self.layout_of(tag_scalar_layout.value.to_int_ty(*self.tcx))?;
 
         // Read tag and sanity-check `tag_layout`.
-        let tag_val = self.read_immediate(self.operand_field(op, tag_field)?)?;
+        let tag_val = self.read_immediate(&self.operand_field(op, tag_field)?)?;
         assert_eq!(tag_layout.size, tag_val.layout.size);
         assert_eq!(tag_layout.abi.is_signed(), tag_val.layout.abi.is_signed());
         let tag_val = tag_val.to_scalar()?;
@@ -690,7 +706,7 @@ pub fn read_discriminant(
                         let tag_val = ImmTy::from_uint(tag_bits, tag_layout);
                         let niche_start_val = ImmTy::from_uint(niche_start, tag_layout);
                         let variant_index_relative_val =
-                            self.binary_op(mir::BinOp::Sub, tag_val, niche_start_val)?;
+                            self.binary_op(mir::BinOp::Sub, &tag_val, &niche_start_val)?;
                         let variant_index_relative = variant_index_relative_val
                             .to_scalar()?
                             .assert_bits(tag_val.layout.size);
index f5081655015b479027e4ddc63d856f7ee21b0fcb..3737f8781c7ae2a333dc02cfd9405717f4eeabaa 100644 (file)
@@ -14,11 +14,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     pub fn binop_with_overflow(
         &mut self,
         op: mir::BinOp,
-        left: ImmTy<'tcx, M::PointerTag>,
-        right: ImmTy<'tcx, M::PointerTag>,
-        dest: PlaceTy<'tcx, M::PointerTag>,
+        left: &ImmTy<'tcx, M::PointerTag>,
+        right: &ImmTy<'tcx, M::PointerTag>,
+        dest: &PlaceTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx> {
-        let (val, overflowed, ty) = self.overflowing_binary_op(op, left, right)?;
+        let (val, overflowed, ty) = self.overflowing_binary_op(op, &left, &right)?;
         debug_assert_eq!(
             self.tcx.intern_tup(&[ty, self.tcx.types.bool]),
             dest.layout.ty,
@@ -34,9 +34,9 @@ pub fn binop_with_overflow(
     pub fn binop_ignore_overflow(
         &mut self,
         op: mir::BinOp,
-        left: ImmTy<'tcx, M::PointerTag>,
-        right: ImmTy<'tcx, M::PointerTag>,
-        dest: PlaceTy<'tcx, M::PointerTag>,
+        left: &ImmTy<'tcx, M::PointerTag>,
+        right: &ImmTy<'tcx, M::PointerTag>,
+        dest: &PlaceTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx> {
         let (val, _overflowed, ty) = self.overflowing_binary_op(op, left, right)?;
         assert_eq!(ty, dest.layout.ty, "type mismatch for result of {:?}", op);
@@ -269,8 +269,8 @@ fn binary_int_op(
     pub fn overflowing_binary_op(
         &self,
         bin_op: mir::BinOp,
-        left: ImmTy<'tcx, M::PointerTag>,
-        right: ImmTy<'tcx, M::PointerTag>,
+        left: &ImmTy<'tcx, M::PointerTag>,
+        right: &ImmTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx, (Scalar<M::PointerTag>, bool, Ty<'tcx>)> {
         trace!(
             "Running binary op {:?}: {:?} ({:?}), {:?} ({:?})",
@@ -347,8 +347,8 @@ pub fn overflowing_binary_op(
     pub fn binary_op(
         &self,
         bin_op: mir::BinOp,
-        left: ImmTy<'tcx, M::PointerTag>,
-        right: ImmTy<'tcx, M::PointerTag>,
+        left: &ImmTy<'tcx, M::PointerTag>,
+        right: &ImmTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx, ImmTy<'tcx, M::PointerTag>> {
         let (val, _overflow, ty) = self.overflowing_binary_op(bin_op, left, right)?;
         Ok(ImmTy::from_scalar(val, self.layout_of(ty)?))
@@ -359,7 +359,7 @@ pub fn binary_op(
     pub fn overflowing_unary_op(
         &self,
         un_op: mir::UnOp,
-        val: ImmTy<'tcx, M::PointerTag>,
+        val: &ImmTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx, (Scalar<M::PointerTag>, bool, Ty<'tcx>)> {
         use rustc_middle::mir::UnOp::*;
 
@@ -409,7 +409,7 @@ pub fn overflowing_unary_op(
     pub fn unary_op(
         &self,
         un_op: mir::UnOp,
-        val: ImmTy<'tcx, M::PointerTag>,
+        val: &ImmTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx, ImmTy<'tcx, M::PointerTag>> {
         let (val, _overflow, ty) = self.overflowing_unary_op(un_op, val)?;
         Ok(ImmTy::from_scalar(val, self.layout_of(ty)?))
index efde7fe6948c28e973e1f01153af95aa29dd5cf3..392f739e84fd6dfb2429fc05d7bd9cc9f6f3ab9b 100644 (file)
@@ -33,6 +33,9 @@ pub enum MemPlaceMeta<Tag = ()> {
     Poison,
 }
 
+#[cfg(target_arch = "x86_64")]
+rustc_data_structures::static_assert_size!(MemPlaceMeta, 24);
+
 impl<Tag> MemPlaceMeta<Tag> {
     pub fn unwrap_meta(self) -> Scalar<Tag> {
         match self {
@@ -71,6 +74,9 @@ pub struct MemPlace<Tag = ()> {
     pub meta: MemPlaceMeta<Tag>,
 }
 
+#[cfg(target_arch = "x86_64")]
+rustc_data_structures::static_assert_size!(MemPlace, 56);
+
 #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable)]
 pub enum Place<Tag = ()> {
     /// A place referring to a value allocated in the `Memory` system.
@@ -81,12 +87,18 @@ pub enum Place<Tag = ()> {
     Local { frame: usize, local: mir::Local },
 }
 
+#[cfg(target_arch = "x86_64")]
+rustc_data_structures::static_assert_size!(Place, 64);
+
 #[derive(Copy, Clone, Debug)]
 pub struct PlaceTy<'tcx, Tag = ()> {
     place: Place<Tag>, // Keep this private; it helps enforce invariants.
     pub layout: TyAndLayout<'tcx>,
 }
 
+#[cfg(target_arch = "x86_64")]
+rustc_data_structures::static_assert_size!(PlaceTy<'_>, 80);
+
 impl<'tcx, Tag> std::ops::Deref for PlaceTy<'tcx, Tag> {
     type Target = Place<Tag>;
     #[inline(always)]
@@ -102,6 +114,9 @@ pub struct MPlaceTy<'tcx, Tag = ()> {
     pub layout: TyAndLayout<'tcx>,
 }
 
+#[cfg(target_arch = "x86_64")]
+rustc_data_structures::static_assert_size!(MPlaceTy<'_>, 72);
+
 impl<'tcx, Tag> std::ops::Deref for MPlaceTy<'tcx, Tag> {
     type Target = MemPlace<Tag>;
     #[inline(always)]
@@ -168,7 +183,7 @@ pub fn offset(
     }
 }
 
-impl<'tcx, Tag> MPlaceTy<'tcx, Tag> {
+impl<'tcx, Tag: Copy> MPlaceTy<'tcx, Tag> {
     /// Produces a MemPlace that works for ZST but nothing else
     #[inline]
     pub fn dangling(layout: TyAndLayout<'tcx>, cx: &impl HasDataLayout) -> Self {
@@ -180,13 +195,13 @@ pub fn dangling(layout: TyAndLayout<'tcx>, cx: &impl HasDataLayout) -> Self {
 
     /// Replace ptr tag, maintain vtable tag (if any)
     #[inline]
-    pub fn replace_tag(self, new_tag: Tag) -> Self {
+    pub fn replace_tag(&self, new_tag: Tag) -> Self {
         MPlaceTy { mplace: self.mplace.replace_tag(new_tag), layout: self.layout }
     }
 
     #[inline]
     pub fn offset(
-        self,
+        &self,
         offset: Size,
         meta: MemPlaceMeta<Tag>,
         layout: TyAndLayout<'tcx>,
@@ -201,7 +216,7 @@ fn from_aligned_ptr(ptr: Pointer<Tag>, layout: TyAndLayout<'tcx>) -> Self {
     }
 
     #[inline]
-    pub(super) fn len(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> {
+    pub(super) fn len(&self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> {
         if self.layout.is_unsized() {
             // We need to consult `meta` metadata
             match self.layout.ty.kind() {
@@ -219,7 +234,7 @@ pub(super) fn len(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> {
     }
 
     #[inline]
-    pub(super) fn vtable(self) -> Scalar<Tag> {
+    pub(super) fn vtable(&self) -> Scalar<Tag> {
         match self.layout.ty.kind() {
             ty::Dynamic(..) => self.mplace.meta.unwrap_meta(),
             _ => bug!("vtable not supported on type {:?}", self.layout.ty),
@@ -233,10 +248,10 @@ impl<'tcx, Tag: Debug + Copy> OpTy<'tcx, Tag> {
     /// Note: do not call `as_ref` on the resulting place. This function should only be used to
     /// read from the resulting mplace, not to get its address back.
     pub fn try_as_mplace(
-        self,
+        &self,
         cx: &impl HasDataLayout,
     ) -> Result<MPlaceTy<'tcx, Tag>, ImmTy<'tcx, Tag>> {
-        match *self {
+        match **self {
             Operand::Indirect(mplace) => Ok(MPlaceTy { mplace, layout: self.layout }),
             Operand::Immediate(_) if self.layout.is_zst() => {
                 Ok(MPlaceTy::dangling(self.layout, cx))
@@ -248,7 +263,7 @@ pub fn try_as_mplace(
     #[inline(always)]
     /// Note: do not call `as_ref` on the resulting place. This function should only be used to
     /// read from the resulting mplace, not to get its address back.
-    pub fn assert_mem_place(self, cx: &impl HasDataLayout) -> MPlaceTy<'tcx, Tag> {
+    pub fn assert_mem_place(&self, cx: &impl HasDataLayout) -> MPlaceTy<'tcx, Tag> {
         self.try_as_mplace(cx).unwrap()
     }
 }
@@ -288,12 +303,12 @@ impl<'mir, 'tcx: 'mir, Tag, M> InterpCx<'mir, 'tcx, M>
     /// Generally prefer `deref_operand`.
     pub fn ref_to_mplace(
         &self,
-        val: ImmTy<'tcx, M::PointerTag>,
+        val: &ImmTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
         let pointee_type =
             val.layout.ty.builtin_deref(true).expect("`ref_to_mplace` called on non-ptr type").ty;
         let layout = self.layout_of(pointee_type)?;
-        let (ptr, meta) = match *val {
+        let (ptr, meta) = match **val {
             Immediate::Scalar(ptr) => (ptr.check_init()?, MemPlaceMeta::None),
             Immediate::ScalarPair(ptr, meta) => {
                 (ptr.check_init()?, MemPlaceMeta::Meta(meta.check_init()?))
@@ -316,11 +331,11 @@ pub fn ref_to_mplace(
     /// will always be a MemPlace.  Lives in `place.rs` because it creates a place.
     pub fn deref_operand(
         &self,
-        src: OpTy<'tcx, M::PointerTag>,
+        src: &OpTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
         let val = self.read_immediate(src)?;
         trace!("deref to {} on {:?}", val.layout.ty, *val);
-        let place = self.ref_to_mplace(val)?;
+        let place = self.ref_to_mplace(&val)?;
         self.mplace_access_checked(place, None)
     }
 
@@ -333,7 +348,7 @@ pub fn deref_operand(
     #[inline]
     pub(super) fn check_mplace_access(
         &self,
-        place: MPlaceTy<'tcx, M::PointerTag>,
+        place: &MPlaceTy<'tcx, M::PointerTag>,
         size: Option<Size>,
     ) -> InterpResult<'tcx, Option<Pointer<M::PointerTag>>> {
         let size = size.unwrap_or_else(|| {
@@ -355,13 +370,13 @@ pub fn mplace_access_checked(
         force_align: Option<Align>,
     ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
         let (size, align) = self
-            .size_and_align_of_mplace(place)?
+            .size_and_align_of_mplace(&place)?
             .unwrap_or((place.layout.size, place.layout.align.abi));
         assert!(place.mplace.align <= align, "dynamic alignment less strict than static one?");
         // Check (stricter) dynamic alignment, unless forced otherwise.
         place.mplace.align = force_align.unwrap_or(align);
         // When dereferencing a pointer, it must be non-NULL, aligned, and live.
-        if let Some(ptr) = self.check_mplace_access(place, Some(size))? {
+        if let Some(ptr) = self.check_mplace_access(&place, Some(size))? {
             place.mplace.ptr = ptr.into();
         }
         Ok(place)
@@ -386,7 +401,7 @@ pub(super) fn force_mplace_ptr(
     #[inline(always)]
     pub fn mplace_field(
         &self,
-        base: MPlaceTy<'tcx, M::PointerTag>,
+        base: &MPlaceTy<'tcx, M::PointerTag>,
         field: usize,
     ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
         let offset = base.layout.fields.offset(field);
@@ -397,7 +412,7 @@ pub fn mplace_field(
             // Re-use parent metadata to determine dynamic field layout.
             // With custom DSTS, this *will* execute user-defined code, but the same
             // happens at run-time so that's okay.
-            let align = match self.size_and_align_of(base.meta, field_layout)? {
+            let align = match self.size_and_align_of(&base.meta, &field_layout)? {
                 Some((_, align)) => align,
                 None if offset == Size::ZERO => {
                     // An extern type at offset 0, we fall back to its static alignment.
@@ -427,7 +442,7 @@ pub fn mplace_field(
     #[inline(always)]
     pub fn mplace_index(
         &self,
-        base: MPlaceTy<'tcx, M::PointerTag>,
+        base: &MPlaceTy<'tcx, M::PointerTag>,
         index: u64,
     ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
         // Not using the layout method because we want to compute on u64
@@ -457,8 +472,8 @@ pub fn mplace_index(
     // same by repeatedly calling `mplace_array`.
     pub(super) fn mplace_array_fields(
         &self,
-        base: MPlaceTy<'tcx, Tag>,
-    ) -> InterpResult<'tcx, impl Iterator<Item = InterpResult<'tcx, MPlaceTy<'tcx, Tag>>> + 'tcx>
+        base: &'a MPlaceTy<'tcx, Tag>,
+    ) -> InterpResult<'tcx, impl Iterator<Item = InterpResult<'tcx, MPlaceTy<'tcx, Tag>>> + 'a>
     {
         let len = base.len(self)?; // also asserts that we have a type where this makes sense
         let stride = match base.layout.fields {
@@ -473,7 +488,7 @@ pub(super) fn mplace_array_fields(
 
     fn mplace_subslice(
         &self,
-        base: MPlaceTy<'tcx, M::PointerTag>,
+        base: &MPlaceTy<'tcx, M::PointerTag>,
         from: u64,
         to: u64,
         from_end: bool,
@@ -518,30 +533,30 @@ fn mplace_subslice(
 
     pub(super) fn mplace_downcast(
         &self,
-        base: MPlaceTy<'tcx, M::PointerTag>,
+        base: &MPlaceTy<'tcx, M::PointerTag>,
         variant: VariantIdx,
     ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
         // Downcasts only change the layout
         assert!(!base.meta.has_meta());
-        Ok(MPlaceTy { layout: base.layout.for_variant(self, variant), ..base })
+        Ok(MPlaceTy { layout: base.layout.for_variant(self, variant), ..*base })
     }
 
     /// Project into an mplace
     pub(super) fn mplace_projection(
         &self,
-        base: MPlaceTy<'tcx, M::PointerTag>,
+        base: &MPlaceTy<'tcx, M::PointerTag>,
         proj_elem: mir::PlaceElem<'tcx>,
     ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
         use rustc_middle::mir::ProjectionElem::*;
         Ok(match proj_elem {
             Field(field, _) => self.mplace_field(base, field.index())?,
             Downcast(_, variant) => self.mplace_downcast(base, variant)?,
-            Deref => self.deref_operand(base.into())?,
+            Deref => self.deref_operand(&base.into())?,
 
             Index(local) => {
                 let layout = self.layout_of(self.tcx.types.usize)?;
                 let n = self.access_local(self.frame(), local, Some(layout))?;
-                let n = self.read_scalar(n)?;
+                let n = self.read_scalar(&n)?;
                 let n = u64::try_from(
                     self.force_bits(n.check_init()?, self.tcx.data_layout.pointer_size)?,
                 )
@@ -577,37 +592,37 @@ pub(super) fn mplace_projection(
     /// into the field of a local `ScalarPair`, we have to first allocate it.
     pub fn place_field(
         &mut self,
-        base: PlaceTy<'tcx, M::PointerTag>,
+        base: &PlaceTy<'tcx, M::PointerTag>,
         field: usize,
     ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
         // FIXME: We could try to be smarter and avoid allocation for fields that span the
         // entire place.
         let mplace = self.force_allocation(base)?;
-        Ok(self.mplace_field(mplace, field)?.into())
+        Ok(self.mplace_field(&mplace, field)?.into())
     }
 
     pub fn place_index(
         &mut self,
-        base: PlaceTy<'tcx, M::PointerTag>,
+        base: &PlaceTy<'tcx, M::PointerTag>,
         index: u64,
     ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
         let mplace = self.force_allocation(base)?;
-        Ok(self.mplace_index(mplace, index)?.into())
+        Ok(self.mplace_index(&mplace, index)?.into())
     }
 
     pub fn place_downcast(
         &self,
-        base: PlaceTy<'tcx, M::PointerTag>,
+        base: &PlaceTy<'tcx, M::PointerTag>,
         variant: VariantIdx,
     ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
         // Downcast just changes the layout
         Ok(match base.place {
             Place::Ptr(mplace) => {
-                self.mplace_downcast(MPlaceTy { mplace, layout: base.layout }, variant)?.into()
+                self.mplace_downcast(&MPlaceTy { mplace, layout: base.layout }, variant)?.into()
             }
             Place::Local { .. } => {
                 let layout = base.layout.for_variant(self, variant);
-                PlaceTy { layout, ..base }
+                PlaceTy { layout, ..*base }
             }
         })
     }
@@ -615,19 +630,19 @@ pub fn place_downcast(
     /// Projects into a place.
     pub fn place_projection(
         &mut self,
-        base: PlaceTy<'tcx, M::PointerTag>,
+        base: &PlaceTy<'tcx, M::PointerTag>,
         &proj_elem: &mir::ProjectionElem<mir::Local, Ty<'tcx>>,
     ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
         use rustc_middle::mir::ProjectionElem::*;
         Ok(match proj_elem {
             Field(field, _) => self.place_field(base, field.index())?,
             Downcast(_, variant) => self.place_downcast(base, variant)?,
-            Deref => self.deref_operand(self.place_to_op(base)?)?.into(),
+            Deref => self.deref_operand(&self.place_to_op(base)?)?.into(),
             // For the other variants, we have to force an allocation.
             // This matches `operand_projection`.
             Subslice { .. } | ConstantIndex { .. } | Index(_) => {
                 let mplace = self.force_allocation(base)?;
-                self.mplace_projection(mplace, proj_elem)?.into()
+                self.mplace_projection(&mplace, proj_elem)?.into()
             }
         })
     }
@@ -645,7 +660,7 @@ pub fn eval_place(
         };
 
         for elem in place.projection.iter() {
-            place_ty = self.place_projection(place_ty, &elem)?
+            place_ty = self.place_projection(&place_ty, &elem)?
         }
 
         trace!("{:?}", self.dump_place(place_ty.place));
@@ -666,7 +681,7 @@ pub fn eval_place(
     pub fn write_scalar(
         &mut self,
         val: impl Into<ScalarMaybeUninit<M::PointerTag>>,
-        dest: PlaceTy<'tcx, M::PointerTag>,
+        dest: &PlaceTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx> {
         self.write_immediate(Immediate::Scalar(val.into()), dest)
     }
@@ -676,13 +691,13 @@ pub fn write_scalar(
     pub fn write_immediate(
         &mut self,
         src: Immediate<M::PointerTag>,
-        dest: PlaceTy<'tcx, M::PointerTag>,
+        dest: &PlaceTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx> {
         self.write_immediate_no_validate(src, dest)?;
 
         if M::enforce_validity(self) {
             // Data got changed, better make sure it matches the type!
-            self.validate_operand(self.place_to_op(dest)?)?;
+            self.validate_operand(&self.place_to_op(dest)?)?;
         }
 
         Ok(())
@@ -693,13 +708,13 @@ pub fn write_immediate(
     pub fn write_immediate_to_mplace(
         &mut self,
         src: Immediate<M::PointerTag>,
-        dest: MPlaceTy<'tcx, M::PointerTag>,
+        dest: &MPlaceTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx> {
         self.write_immediate_to_mplace_no_validate(src, dest)?;
 
         if M::enforce_validity(self) {
             // Data got changed, better make sure it matches the type!
-            self.validate_operand(dest.into())?;
+            self.validate_operand(&dest.into())?;
         }
 
         Ok(())
@@ -711,7 +726,7 @@ pub fn write_immediate_to_mplace(
     fn write_immediate_no_validate(
         &mut self,
         src: Immediate<M::PointerTag>,
-        dest: PlaceTy<'tcx, M::PointerTag>,
+        dest: &PlaceTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx> {
         if cfg!(debug_assertions) {
             // This is a very common path, avoid some checks in release mode
@@ -754,7 +769,7 @@ fn write_immediate_no_validate(
         let dest = MPlaceTy { mplace, layout: dest.layout };
 
         // This is already in memory, write there.
-        self.write_immediate_to_mplace_no_validate(src, dest)
+        self.write_immediate_to_mplace_no_validate(src, &dest)
     }
 
     /// Write an immediate to memory.
@@ -763,7 +778,7 @@ fn write_immediate_no_validate(
     fn write_immediate_to_mplace_no_validate(
         &mut self,
         value: Immediate<M::PointerTag>,
-        dest: MPlaceTy<'tcx, M::PointerTag>,
+        dest: &MPlaceTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx> {
         // Note that it is really important that the type here is the right one, and matches the
         // type things are read at. In case `src_val` is a `ScalarPair`, we don't do any magic here
@@ -828,14 +843,14 @@ fn write_immediate_to_mplace_no_validate(
     #[inline(always)]
     pub fn copy_op(
         &mut self,
-        src: OpTy<'tcx, M::PointerTag>,
-        dest: PlaceTy<'tcx, M::PointerTag>,
+        src: &OpTy<'tcx, M::PointerTag>,
+        dest: &PlaceTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx> {
         self.copy_op_no_validate(src, dest)?;
 
         if M::enforce_validity(self) {
             // Data got changed, better make sure it matches the type!
-            self.validate_operand(self.place_to_op(dest)?)?;
+            self.validate_operand(&self.place_to_op(dest)?)?;
         }
 
         Ok(())
@@ -847,8 +862,8 @@ pub fn copy_op(
     /// right type.
     fn copy_op_no_validate(
         &mut self,
-        src: OpTy<'tcx, M::PointerTag>,
-        dest: PlaceTy<'tcx, M::PointerTag>,
+        src: &OpTy<'tcx, M::PointerTag>,
+        dest: &PlaceTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx> {
         // We do NOT compare the types for equality, because well-typed code can
         // actually "transmute" `&mut T` to `&T` in an assignment without a cast.
@@ -888,10 +903,10 @@ fn copy_op_no_validate(
         assert_eq!(src.meta, dest.meta, "Can only copy between equally-sized instances");
 
         let src = self
-            .check_mplace_access(src, Some(size))
+            .check_mplace_access(&src, Some(size))
             .expect("places should be checked on creation");
         let dest = self
-            .check_mplace_access(dest, Some(size))
+            .check_mplace_access(&dest, Some(size))
             .expect("places should be checked on creation");
         let (src_ptr, dest_ptr) = match (src, dest) {
             (Some(src_ptr), Some(dest_ptr)) => (src_ptr, dest_ptr),
@@ -906,8 +921,8 @@ fn copy_op_no_validate(
     /// have the same size.
     pub fn copy_op_transmute(
         &mut self,
-        src: OpTy<'tcx, M::PointerTag>,
-        dest: PlaceTy<'tcx, M::PointerTag>,
+        src: &OpTy<'tcx, M::PointerTag>,
+        dest: &PlaceTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx> {
         if mir_assign_valid_types(*self.tcx, self.param_env, src.layout, dest.layout) {
             // Fast path: Just use normal `copy_op`
@@ -944,12 +959,12 @@ pub fn copy_op_transmute(
         let dest = self.force_allocation(dest)?;
         self.copy_op_no_validate(
             src,
-            PlaceTy::from(MPlaceTy { mplace: *dest, layout: src.layout }),
+            &PlaceTy::from(MPlaceTy { mplace: *dest, layout: src.layout }),
         )?;
 
         if M::enforce_validity(self) {
             // Data got changed, better make sure it matches the type!
-            self.validate_operand(dest.into())?;
+            self.validate_operand(&dest.into())?;
         }
 
         Ok(())
@@ -965,7 +980,7 @@ pub fn copy_op_transmute(
     /// version.
     pub fn force_allocation_maybe_sized(
         &mut self,
-        place: PlaceTy<'tcx, M::PointerTag>,
+        place: &PlaceTy<'tcx, M::PointerTag>,
         meta: MemPlaceMeta<M::PointerTag>,
     ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::PointerTag>, Option<Size>)> {
         let (mplace, size) = match place.place {
@@ -981,7 +996,7 @@ pub fn force_allocation_maybe_sized(
                             self.layout_of_local(&self.stack()[frame], local, None)?;
                         // We also need to support unsized types, and hence cannot use `allocate`.
                         let (size, align) = self
-                            .size_and_align_of(meta, local_layout)?
+                            .size_and_align_of(&meta, &local_layout)?
                             .expect("Cannot allocate for non-dyn-sized type");
                         let ptr = self.memory.allocate(size, align, MemoryKind::Stack);
                         let mplace = MemPlace { ptr: ptr.into(), align, meta };
@@ -990,7 +1005,7 @@ pub fn force_allocation_maybe_sized(
                             // We don't have to validate as we can assume the local
                             // was already valid for its type.
                             let mplace = MPlaceTy { mplace, layout: local_layout };
-                            self.write_immediate_to_mplace_no_validate(value, mplace)?;
+                            self.write_immediate_to_mplace_no_validate(value, &mplace)?;
                         }
                         // Now we can call `access_mut` again, asserting it goes well,
                         // and actually overwrite things.
@@ -1010,7 +1025,7 @@ pub fn force_allocation_maybe_sized(
     #[inline(always)]
     pub fn force_allocation(
         &mut self,
-        place: PlaceTy<'tcx, M::PointerTag>,
+        place: &PlaceTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
         Ok(self.force_allocation_maybe_sized(place, MemPlaceMeta::None)?.0)
     }
@@ -1046,7 +1061,7 @@ pub fn allocate_str(
     pub fn write_discriminant(
         &mut self,
         variant_index: VariantIdx,
-        dest: PlaceTy<'tcx, M::PointerTag>,
+        dest: &PlaceTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx> {
         // Layout computation excludes uninhabited variants from consideration
         // therefore there's no way to represent those variants in the given layout.
@@ -1077,7 +1092,7 @@ pub fn write_discriminant(
                 let tag_val = size.truncate(discr_val);
 
                 let tag_dest = self.place_field(dest, tag_field)?;
-                self.write_scalar(Scalar::from_uint(tag_val, size), tag_dest)?;
+                self.write_scalar(Scalar::from_uint(tag_val, size), &tag_dest)?;
             }
             Variants::Multiple {
                 tag_encoding:
@@ -1103,12 +1118,12 @@ pub fn write_discriminant(
                         ImmTy::from_uint(variant_index_relative, tag_layout);
                     let tag_val = self.binary_op(
                         mir::BinOp::Add,
-                        variant_index_relative_val,
-                        niche_start_val,
+                        &variant_index_relative_val,
+                        &niche_start_val,
                     )?;
                     // Write result.
                     let niche_dest = self.place_field(dest, tag_field)?;
-                    self.write_immediate(*tag_val, niche_dest)?;
+                    self.write_immediate(*tag_val, &niche_dest)?;
                 }
             }
         }
@@ -1131,7 +1146,7 @@ pub fn raw_const_to_mplace(
     /// Also return some more information so drop doesn't have to run the same code twice.
     pub(super) fn unpack_dyn_trait(
         &self,
-        mplace: MPlaceTy<'tcx, M::PointerTag>,
+        mplace: &MPlaceTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx, (ty::Instance<'tcx>, MPlaceTy<'tcx, M::PointerTag>)> {
         let vtable = mplace.vtable(); // also sanity checks the type
         let (instance, ty) = self.read_drop_type_from_vtable(vtable)?;
@@ -1145,7 +1160,7 @@ pub(super) fn unpack_dyn_trait(
             assert_eq!(align, layout.align.abi);
         }
 
-        let mplace = MPlaceTy { mplace: MemPlace { meta: MemPlaceMeta::None, ..*mplace }, layout };
+        let mplace = MPlaceTy { mplace: MemPlace { meta: MemPlaceMeta::None, ..**mplace }, layout };
         Ok((instance, mplace))
     }
 }
index fbc72ad8adc9656c3fbf2f51d7888fab76ceecc0..64d7c8ef2c719daa16d3e11e8e77f188f5d3ba1c 100644 (file)
@@ -90,7 +90,7 @@ pub fn step(&mut self) -> InterpResult<'tcx, bool> {
 
             SetDiscriminant { place, variant_index } => {
                 let dest = self.eval_place(**place)?;
-                self.write_discriminant(*variant_index, dest)?;
+                self.write_discriminant(*variant_index, &dest)?;
             }
 
             // Mark locals as alive
@@ -110,7 +110,7 @@ pub fn step(&mut self) -> InterpResult<'tcx, bool> {
             // Stacked Borrows.
             Retag(kind, place) => {
                 let dest = self.eval_place(**place)?;
-                M::retag(self, *kind, dest)?;
+                M::retag(self, *kind, &dest)?;
             }
 
             // Statements we do not track.
@@ -156,45 +156,45 @@ pub fn eval_rvalue_into_place(
             ThreadLocalRef(did) => {
                 let id = M::thread_local_static_alloc_id(self, did)?;
                 let val = self.global_base_pointer(id.into())?;
-                self.write_scalar(val, dest)?;
+                self.write_scalar(val, &dest)?;
             }
 
             Use(ref operand) => {
                 // Avoid recomputing the layout
                 let op = self.eval_operand(operand, Some(dest.layout))?;
-                self.copy_op(op, dest)?;
+                self.copy_op(&op, &dest)?;
             }
 
             BinaryOp(bin_op, ref left, ref right) => {
                 let layout = binop_left_homogeneous(bin_op).then_some(dest.layout);
-                let left = self.read_immediate(self.eval_operand(left, layout)?)?;
+                let left = self.read_immediate(&self.eval_operand(left, layout)?)?;
                 let layout = binop_right_homogeneous(bin_op).then_some(left.layout);
-                let right = self.read_immediate(self.eval_operand(right, layout)?)?;
-                self.binop_ignore_overflow(bin_op, left, right, dest)?;
+                let right = self.read_immediate(&self.eval_operand(right, layout)?)?;
+                self.binop_ignore_overflow(bin_op, &left, &right, &dest)?;
             }
 
             CheckedBinaryOp(bin_op, ref left, ref right) => {
                 // Due to the extra boolean in the result, we can never reuse the `dest.layout`.
-                let left = self.read_immediate(self.eval_operand(left, None)?)?;
+                let left = self.read_immediate(&self.eval_operand(left, None)?)?;
                 let layout = binop_right_homogeneous(bin_op).then_some(left.layout);
-                let right = self.read_immediate(self.eval_operand(right, layout)?)?;
-                self.binop_with_overflow(bin_op, left, right, dest)?;
+                let right = self.read_immediate(&self.eval_operand(right, layout)?)?;
+                self.binop_with_overflow(bin_op, &left, &right, &dest)?;
             }
 
             UnaryOp(un_op, ref operand) => {
                 // The operand always has the same type as the result.
-                let val = self.read_immediate(self.eval_operand(operand, Some(dest.layout))?)?;
-                let val = self.unary_op(un_op, val)?;
+                let val = self.read_immediate(&self.eval_operand(operand, Some(dest.layout))?)?;
+                let val = self.unary_op(un_op, &val)?;
                 assert_eq!(val.layout, dest.layout, "layout mismatch for result of {:?}", un_op);
-                self.write_immediate(*val, dest)?;
+                self.write_immediate(*val, &dest)?;
             }
 
             Aggregate(ref kind, ref operands) => {
                 let (dest, active_field_index) = match **kind {
                     mir::AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => {
-                        self.write_discriminant(variant_index, dest)?;
+                        self.write_discriminant(variant_index, &dest)?;
                         if adt_def.is_enum() {
-                            (self.place_downcast(dest, variant_index)?, active_field_index)
+                            (self.place_downcast(&dest, variant_index)?, active_field_index)
                         } else {
                             (dest, active_field_index)
                         }
@@ -207,21 +207,21 @@ pub fn eval_rvalue_into_place(
                     // Ignore zero-sized fields.
                     if !op.layout.is_zst() {
                         let field_index = active_field_index.unwrap_or(i);
-                        let field_dest = self.place_field(dest, field_index)?;
-                        self.copy_op(op, field_dest)?;
+                        let field_dest = self.place_field(&dest, field_index)?;
+                        self.copy_op(&op, &field_dest)?;
                     }
                 }
             }
 
             Repeat(ref operand, _) => {
                 let op = self.eval_operand(operand, None)?;
-                let dest = self.force_allocation(dest)?;
+                let dest = self.force_allocation(&dest)?;
                 let length = dest.len(self)?;
 
-                if let Some(first_ptr) = self.check_mplace_access(dest, None)? {
+                if let Some(first_ptr) = self.check_mplace_access(&dest, None)? {
                     // Write the first.
-                    let first = self.mplace_field(dest, 0)?;
-                    self.copy_op(op, first.into())?;
+                    let first = self.mplace_field(&dest, 0)?;
+                    self.copy_op(&op, &first.into())?;
 
                     if length > 1 {
                         let elem_size = first.layout.size;
@@ -242,23 +242,23 @@ pub fn eval_rvalue_into_place(
             Len(place) => {
                 // FIXME(CTFE): don't allow computing the length of arrays in const eval
                 let src = self.eval_place(place)?;
-                let mplace = self.force_allocation(src)?;
+                let mplace = self.force_allocation(&src)?;
                 let len = mplace.len(self)?;
-                self.write_scalar(Scalar::from_machine_usize(len, self), dest)?;
+                self.write_scalar(Scalar::from_machine_usize(len, self), &dest)?;
             }
 
             AddressOf(_, place) | Ref(_, _, place) => {
                 let src = self.eval_place(place)?;
-                let place = self.force_allocation(src)?;
+                let place = self.force_allocation(&src)?;
                 if place.layout.size.bytes() > 0 {
                     // definitely not a ZST
                     assert!(place.ptr.is_ptr(), "non-ZST places should be normalized to `Pointer`");
                 }
-                self.write_immediate(place.to_ref(), dest)?;
+                self.write_immediate(place.to_ref(), &dest)?;
             }
 
             NullaryOp(mir::NullOp::Box, _) => {
-                M::box_alloc(self, dest)?;
+                M::box_alloc(self, &dest)?;
             }
 
             NullaryOp(mir::NullOp::SizeOf, ty) => {
@@ -272,19 +272,19 @@ pub fn eval_rvalue_into_place(
                     );
                     throw_inval!(SizeOfUnsizedType(ty));
                 }
-                self.write_scalar(Scalar::from_machine_usize(layout.size.bytes(), self), dest)?;
+                self.write_scalar(Scalar::from_machine_usize(layout.size.bytes(), self), &dest)?;
             }
 
             Cast(cast_kind, ref operand, cast_ty) => {
                 let src = self.eval_operand(operand, None)?;
                 let cast_ty = self.subst_from_current_frame_and_normalize_erasing_regions(cast_ty);
-                self.cast(src, cast_kind, cast_ty, dest)?;
+                self.cast(&src, cast_kind, cast_ty, &dest)?;
             }
 
             Discriminant(place) => {
                 let op = self.eval_place_to_op(place, None)?;
-                let discr_val = self.read_discriminant(op)?.0;
-                self.write_scalar(discr_val, dest)?;
+                let discr_val = self.read_discriminant(&op)?.0;
+                self.write_scalar(discr_val, &dest)?;
             }
         }
 
index 575667f9a95258e17b6b17f4cb72643e4b0db861..0807949a2d91beed6efc23ba86b7b8ddbf76a058 100644 (file)
@@ -25,7 +25,7 @@ pub(super) fn eval_terminator(
             Goto { target } => self.go_to_block(target),
 
             SwitchInt { ref discr, ref targets, switch_ty } => {
-                let discr = self.read_immediate(self.eval_operand(discr, None)?)?;
+                let discr = self.read_immediate(&self.eval_operand(discr, None)?)?;
                 trace!("SwitchInt({:?})", *discr);
                 assert_eq!(discr.layout.ty, switch_ty);
 
@@ -38,8 +38,8 @@ pub(super) fn eval_terminator(
                     let res = self
                         .overflowing_binary_op(
                             mir::BinOp::Eq,
-                            discr,
-                            ImmTy::from_uint(const_int, discr.layout),
+                            &discr,
+                            &ImmTy::from_uint(const_int, discr.layout),
                         )?
                         .0;
                     if res.to_bool()? {
@@ -58,7 +58,7 @@ pub(super) fn eval_terminator(
                 let (fn_val, abi) = match *func.layout.ty.kind() {
                     ty::FnPtr(sig) => {
                         let caller_abi = sig.abi();
-                        let fn_ptr = self.read_scalar(func)?.check_init()?;
+                        let fn_ptr = self.read_scalar(&func)?.check_init()?;
                         let fn_val = self.memory.get_fn(fn_ptr)?;
                         (fn_val, caller_abi)
                     }
@@ -78,8 +78,12 @@ pub(super) fn eval_terminator(
                     ),
                 };
                 let args = self.eval_operands(args)?;
+                let dest_place;
                 let ret = match destination {
-                    Some((dest, ret)) => Some((self.eval_place(dest)?, ret)),
+                    Some((dest, ret)) => {
+                        dest_place = self.eval_place(dest)?;
+                        Some((&dest_place, ret))
+                    }
                     None => None,
                 };
                 self.eval_fn_call(fn_val, abi, &args[..], ret, *cleanup)?;
@@ -96,12 +100,12 @@ pub(super) fn eval_terminator(
                 trace!("TerminatorKind::drop: {:?}, type {}", place, ty);
 
                 let instance = Instance::resolve_drop_in_place(*self.tcx, ty);
-                self.drop_in_place(place, instance, target, unwind)?;
+                self.drop_in_place(&place, instance, target, unwind)?;
             }
 
             Assert { ref cond, expected, ref msg, target, cleanup } => {
                 let cond_val =
-                    self.read_immediate(self.eval_operand(cond, None)?)?.to_scalar()?.to_bool()?;
+                    self.read_immediate(&self.eval_operand(cond, None)?)?.to_scalar()?.to_bool()?;
                 if expected == cond_val {
                     self.go_to_block(target);
                 } else {
@@ -180,7 +184,7 @@ fn pass_argument(
         &mut self,
         rust_abi: bool,
         caller_arg: &mut impl Iterator<Item = OpTy<'tcx, M::PointerTag>>,
-        callee_arg: PlaceTy<'tcx, M::PointerTag>,
+        callee_arg: &PlaceTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx> {
         if rust_abi && callee_arg.layout.is_zst() {
             // Nothing to do.
@@ -202,7 +206,7 @@ fn pass_argument(
             )
         }
         // We allow some transmutes here
-        self.copy_op_transmute(caller_arg, callee_arg)
+        self.copy_op_transmute(&caller_arg, callee_arg)
     }
 
     /// Call this function -- pushing the stack frame and initializing the arguments.
@@ -211,7 +215,7 @@ fn eval_fn_call(
         fn_val: FnVal<'tcx, M::ExtraFnVal>,
         caller_abi: Abi,
         args: &[OpTy<'tcx, M::PointerTag>],
-        ret: Option<(PlaceTy<'tcx, M::PointerTag>, mir::BasicBlock)>,
+        ret: Option<(&PlaceTy<'tcx, M::PointerTag>, mir::BasicBlock)>,
         unwind: Option<mir::BasicBlock>,
     ) -> InterpResult<'tcx> {
         trace!("eval_fn_call: {:#?}", fn_val);
@@ -314,7 +318,7 @@ fn eval_fn_call(
                     let caller_args: Cow<'_, [OpTy<'tcx, M::PointerTag>]> =
                         if caller_abi == Abi::RustCall && !args.is_empty() {
                             // Untuple
-                            let (&untuple_arg, args) = args.split_last().unwrap();
+                            let (untuple_arg, args) = args.split_last().unwrap();
                             trace!("eval_fn_call: Will pass last argument by untupling");
                             Cow::from(
                                 args.iter()
@@ -344,12 +348,12 @@ fn eval_fn_call(
                         if Some(local) == body.spread_arg {
                             // Must be a tuple
                             for i in 0..dest.layout.fields.count() {
-                                let dest = self.place_field(dest, i)?;
-                                self.pass_argument(rust_abi, &mut caller_iter, dest)?;
+                                let dest = self.place_field(&dest, i)?;
+                                self.pass_argument(rust_abi, &mut caller_iter, &dest)?;
                             }
                         } else {
                             // Normal argument
-                            self.pass_argument(rust_abi, &mut caller_iter, dest)?;
+                            self.pass_argument(rust_abi, &mut caller_iter, &dest)?;
                         }
                     }
                     // Now we should have no more caller args
@@ -397,7 +401,7 @@ fn eval_fn_call(
                 let receiver_place = match args[0].layout.ty.builtin_deref(true) {
                     Some(_) => {
                         // Built-in pointer.
-                        self.deref_operand(args[0])?
+                        self.deref_operand(&args[0])?
                     }
                     None => {
                         // Unsized self.
@@ -426,7 +430,7 @@ fn eval_fn_call(
 
     fn drop_in_place(
         &mut self,
-        place: PlaceTy<'tcx, M::PointerTag>,
+        place: &PlaceTy<'tcx, M::PointerTag>,
         instance: ty::Instance<'tcx>,
         target: mir::BasicBlock,
         unwind: Option<mir::BasicBlock>,
@@ -440,7 +444,7 @@ fn drop_in_place(
         let (instance, place) = match place.layout.ty.kind() {
             ty::Dynamic(..) => {
                 // Dropping a trait object.
-                self.unpack_dyn_trait(place)?
+                self.unpack_dyn_trait(&place)?
             }
             _ => (instance, place),
         };
@@ -457,7 +461,7 @@ fn drop_in_place(
             FnVal::Instance(instance),
             Abi::Rust,
             &[arg.into()],
-            Some((dest.into(), target)),
+            Some((&dest.into(), target)),
             unwind,
         )
     }
index 09ce6bc0fb754b18c09183f8f651ff4084db1651..50603bdd45b40b873d31cb39ddd7fd2052155eeb 100644 (file)
@@ -118,7 +118,7 @@ pub fn get_vtable_slot(
             .get_raw(vtable_slot.alloc_id)?
             .read_ptr_sized(self, vtable_slot)?
             .check_init()?;
-        Ok(self.memory.get_fn(fn_ptr)?)
+        self.memory.get_fn(fn_ptr)
     }
 
     /// Returns the drop fn instance as well as the actual dynamic type.
index ce803c0d485f1b20a585a2ea101f881b185e1342..2d2799f81e392ffd4e3770e36f16138c6be9783d 100644 (file)
@@ -378,7 +378,7 @@ fn check_wide_ptr_meta(
     /// Check a reference or `Box`.
     fn check_safe_pointer(
         &mut self,
-        value: OpTy<'tcx, M::PointerTag>,
+        value: &OpTy<'tcx, M::PointerTag>,
         kind: &str,
     ) -> InterpResult<'tcx> {
         let value = try_validation!(
@@ -389,7 +389,7 @@ fn check_safe_pointer(
         // Handle wide pointers.
         // Check metadata early, for better diagnostics
         let place = try_validation!(
-            self.ecx.ref_to_mplace(value),
+            self.ecx.ref_to_mplace(&value),
             self.path,
             err_ub!(InvalidUninitBytes(None)) => { "uninitialized {}", kind },
         );
@@ -398,7 +398,7 @@ fn check_safe_pointer(
         }
         // Make sure this is dereferenceable and all.
         let size_and_align = try_validation!(
-            self.ecx.size_and_align_of_mplace(place),
+            self.ecx.size_and_align_of_mplace(&place),
             self.path,
             err_ub!(InvalidMeta(msg)) => { "invalid {} metadata: {}", kind, msg },
         );
@@ -494,7 +494,7 @@ fn check_safe_pointer(
 
     fn read_scalar(
         &self,
-        op: OpTy<'tcx, M::PointerTag>,
+        op: &OpTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx, ScalarMaybeUninit<M::PointerTag>> {
         Ok(try_validation!(
             self.ecx.read_scalar(op),
@@ -507,7 +507,7 @@ fn read_scalar(
     /// at that type.  Return `true` if the type is indeed primitive.
     fn try_visit_primitive(
         &mut self,
-        value: OpTy<'tcx, M::PointerTag>,
+        value: &OpTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx, bool> {
         // Go over all the primitive types
         let ty = value.layout.ty;
@@ -555,7 +555,7 @@ fn try_visit_primitive(
                 // actually enforce the strict rules for raw pointers (mostly because
                 // that lets us re-use `ref_to_mplace`).
                 let place = try_validation!(
-                    self.ecx.read_immediate(value).and_then(|i| self.ecx.ref_to_mplace(i)),
+                    self.ecx.read_immediate(value).and_then(|ref i| self.ecx.ref_to_mplace(i)),
                     self.path,
                     err_ub!(InvalidUninitBytes(None)) => { "uninitialized raw pointer" },
                     err_unsup!(ReadPointerAsBytes) => { "part of a pointer" } expected { "a proper pointer or integer value" },
@@ -634,7 +634,7 @@ fn try_visit_primitive(
 
     fn visit_scalar(
         &mut self,
-        op: OpTy<'tcx, M::PointerTag>,
+        op: &OpTy<'tcx, M::PointerTag>,
         scalar_layout: &Scalar,
     ) -> InterpResult<'tcx> {
         let value = self.read_scalar(op)?;
@@ -708,7 +708,7 @@ fn ecx(&self) -> &InterpCx<'mir, 'tcx, M> {
 
     fn read_discriminant(
         &mut self,
-        op: OpTy<'tcx, M::PointerTag>,
+        op: &OpTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx, VariantIdx> {
         self.with_elem(PathElem::EnumTag, move |this| {
             Ok(try_validation!(
@@ -728,9 +728,9 @@ fn read_discriminant(
     #[inline]
     fn visit_field(
         &mut self,
-        old_op: OpTy<'tcx, M::PointerTag>,
+        old_op: &OpTy<'tcx, M::PointerTag>,
         field: usize,
-        new_op: OpTy<'tcx, M::PointerTag>,
+        new_op: &OpTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx> {
         let elem = self.aggregate_field_path_elem(old_op.layout, field);
         self.with_elem(elem, move |this| this.visit_value(new_op))
@@ -739,9 +739,9 @@ fn visit_field(
     #[inline]
     fn visit_variant(
         &mut self,
-        old_op: OpTy<'tcx, M::PointerTag>,
+        old_op: &OpTy<'tcx, M::PointerTag>,
         variant_id: VariantIdx,
-        new_op: OpTy<'tcx, M::PointerTag>,
+        new_op: &OpTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx> {
         let name = match old_op.layout.ty.kind() {
             ty::Adt(adt, _) => PathElem::Variant(adt.variants[variant_id].ident.name),
@@ -755,14 +755,14 @@ fn visit_variant(
     #[inline(always)]
     fn visit_union(
         &mut self,
-        _op: OpTy<'tcx, M::PointerTag>,
+        _op: &OpTy<'tcx, M::PointerTag>,
         _fields: NonZeroUsize,
     ) -> InterpResult<'tcx> {
         Ok(())
     }
 
     #[inline]
-    fn visit_value(&mut self, op: OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> {
+    fn visit_value(&mut self, op: &OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> {
         trace!("visit_value: {:?}, {:?}", *op, op.layout);
 
         // Check primitive types -- the leafs of our recursive descend.
@@ -819,7 +819,7 @@ fn visit_value(&mut self, op: OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> {
 
     fn visit_aggregate(
         &mut self,
-        op: OpTy<'tcx, M::PointerTag>,
+        op: &OpTy<'tcx, M::PointerTag>,
         fields: impl Iterator<Item = InterpResult<'tcx, Self::V>>,
     ) -> InterpResult<'tcx> {
         match op.layout.ty.kind() {
@@ -921,7 +921,7 @@ fn visit_aggregate(
 impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     fn validate_operand_internal(
         &self,
-        op: OpTy<'tcx, M::PointerTag>,
+        op: &OpTy<'tcx, M::PointerTag>,
         path: Vec<PathElem>,
         ref_tracking: Option<&mut RefTracking<MPlaceTy<'tcx, M::PointerTag>, Vec<PathElem>>>,
         ctfe_mode: Option<CtfeValidationMode>,
@@ -932,10 +932,10 @@ fn validate_operand_internal(
         let mut visitor = ValidityVisitor { path, ref_tracking, ctfe_mode, ecx: self };
 
         // Try to cast to ptr *once* instead of all the time.
-        let op = self.force_op_ptr(op).unwrap_or(op);
+        let op = self.force_op_ptr(&op).unwrap_or(*op);
 
         // Run it.
-        match visitor.visit_value(op) {
+        match visitor.visit_value(&op) {
             Ok(()) => Ok(()),
             // Pass through validation failures.
             Err(err) if matches!(err.kind(), err_ub!(ValidationFailure { .. })) => Err(err),
@@ -963,7 +963,7 @@ fn validate_operand_internal(
     #[inline(always)]
     pub fn const_validate_operand(
         &self,
-        op: OpTy<'tcx, M::PointerTag>,
+        op: &OpTy<'tcx, M::PointerTag>,
         path: Vec<PathElem>,
         ref_tracking: &mut RefTracking<MPlaceTy<'tcx, M::PointerTag>, Vec<PathElem>>,
         ctfe_mode: CtfeValidationMode,
@@ -975,7 +975,7 @@ pub fn const_validate_operand(
     /// `op` is assumed to cover valid memory if it is an indirect operand.
     /// It will error if the bits at the destination do not match the ones described by the layout.
     #[inline(always)]
-    pub fn validate_operand(&self, op: OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> {
+    pub fn validate_operand(&self, op: &OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> {
         self.validate_operand_internal(op, vec![], None, None)
     }
 }
index 097b9ae6ca1cd43c53ecd2f5965265bf7234304d..32edca6f3dff9629ce15ede2cea11c8f811a4abb 100644 (file)
@@ -18,21 +18,25 @@ pub trait Value<'mir, 'tcx, M: Machine<'mir, 'tcx>>: Copy {
     fn layout(&self) -> TyAndLayout<'tcx>;
 
     /// Makes this into an `OpTy`.
-    fn to_op(self, ecx: &InterpCx<'mir, 'tcx, M>) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>>;
+    fn to_op(&self, ecx: &InterpCx<'mir, 'tcx, M>)
+    -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>>;
 
     /// Creates this from an `MPlaceTy`.
     fn from_mem_place(mplace: MPlaceTy<'tcx, M::PointerTag>) -> Self;
 
     /// Projects to the given enum variant.
     fn project_downcast(
-        self,
+        &self,
         ecx: &InterpCx<'mir, 'tcx, M>,
         variant: VariantIdx,
     ) -> InterpResult<'tcx, Self>;
 
     /// Projects to the n-th field.
-    fn project_field(self, ecx: &InterpCx<'mir, 'tcx, M>, field: usize)
-    -> InterpResult<'tcx, Self>;
+    fn project_field(
+        &self,
+        ecx: &InterpCx<'mir, 'tcx, M>,
+        field: usize,
+    ) -> InterpResult<'tcx, Self>;
 }
 
 // Operands and memory-places are both values.
@@ -45,10 +49,10 @@ fn layout(&self) -> TyAndLayout<'tcx> {
 
     #[inline(always)]
     fn to_op(
-        self,
+        &self,
         _ecx: &InterpCx<'mir, 'tcx, M>,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
-        Ok(self)
+        Ok(*self)
     }
 
     #[inline(always)]
@@ -58,7 +62,7 @@ fn from_mem_place(mplace: MPlaceTy<'tcx, M::PointerTag>) -> Self {
 
     #[inline(always)]
     fn project_downcast(
-        self,
+        &self,
         ecx: &InterpCx<'mir, 'tcx, M>,
         variant: VariantIdx,
     ) -> InterpResult<'tcx, Self> {
@@ -67,7 +71,7 @@ fn project_downcast(
 
     #[inline(always)]
     fn project_field(
-        self,
+        &self,
         ecx: &InterpCx<'mir, 'tcx, M>,
         field: usize,
     ) -> InterpResult<'tcx, Self> {
@@ -85,10 +89,10 @@ fn layout(&self) -> TyAndLayout<'tcx> {
 
     #[inline(always)]
     fn to_op(
-        self,
+        &self,
         _ecx: &InterpCx<'mir, 'tcx, M>,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
-        Ok(self.into())
+        Ok((*self).into())
     }
 
     #[inline(always)]
@@ -98,7 +102,7 @@ fn from_mem_place(mplace: MPlaceTy<'tcx, M::PointerTag>) -> Self {
 
     #[inline(always)]
     fn project_downcast(
-        self,
+        &self,
         ecx: &InterpCx<'mir, 'tcx, M>,
         variant: VariantIdx,
     ) -> InterpResult<'tcx, Self> {
@@ -107,7 +111,7 @@ fn project_downcast(
 
     #[inline(always)]
     fn project_field(
-        self,
+        &self,
         ecx: &InterpCx<'mir, 'tcx, M>,
         field: usize,
     ) -> InterpResult<'tcx, Self> {
@@ -129,7 +133,7 @@ fn ecx(&$($mutability)? self)
             #[inline(always)]
             fn read_discriminant(
                 &mut self,
-                op: OpTy<'tcx, M::PointerTag>,
+                op: &OpTy<'tcx, M::PointerTag>,
             ) -> InterpResult<'tcx, VariantIdx> {
                 Ok(self.ecx().read_discriminant(op)?.1)
             }
@@ -137,13 +141,13 @@ fn read_discriminant(
             // Recursive actions, ready to be overloaded.
             /// Visits the given value, dispatching as appropriate to more specialized visitors.
             #[inline(always)]
-            fn visit_value(&mut self, v: Self::V) -> InterpResult<'tcx>
+            fn visit_value(&mut self, v: &Self::V) -> InterpResult<'tcx>
             {
                 self.walk_value(v)
             }
             /// Visits the given value as a union. No automatic recursion can happen here.
             #[inline(always)]
-            fn visit_union(&mut self, _v: Self::V, _fields: NonZeroUsize) -> InterpResult<'tcx>
+            fn visit_union(&mut self, _v: &Self::V, _fields: NonZeroUsize) -> InterpResult<'tcx>
             {
                 Ok(())
             }
@@ -153,7 +157,7 @@ fn visit_union(&mut self, _v: Self::V, _fields: NonZeroUsize) -> InterpResult<'t
             #[inline(always)]
             fn visit_aggregate(
                 &mut self,
-                v: Self::V,
+                v: &Self::V,
                 fields: impl Iterator<Item=InterpResult<'tcx, Self::V>>,
             ) -> InterpResult<'tcx> {
                 self.walk_aggregate(v, fields)
@@ -167,9 +171,9 @@ fn visit_aggregate(
             #[inline(always)]
             fn visit_field(
                 &mut self,
-                _old_val: Self::V,
+                _old_val: &Self::V,
                 _field: usize,
-                new_val: Self::V,
+                new_val: &Self::V,
             ) -> InterpResult<'tcx> {
                 self.visit_value(new_val)
             }
@@ -179,9 +183,9 @@ fn visit_field(
             #[inline(always)]
             fn visit_variant(
                 &mut self,
-                _old_val: Self::V,
+                _old_val: &Self::V,
                 _variant: VariantIdx,
-                new_val: Self::V,
+                new_val: &Self::V,
             ) -> InterpResult<'tcx> {
                 self.visit_value(new_val)
             }
@@ -189,16 +193,16 @@ fn visit_variant(
             // Default recursors. Not meant to be overloaded.
             fn walk_aggregate(
                 &mut self,
-                v: Self::V,
+                v: &Self::V,
                 fields: impl Iterator<Item=InterpResult<'tcx, Self::V>>,
             ) -> InterpResult<'tcx> {
                 // Now iterate over it.
                 for (idx, field_val) in fields.enumerate() {
-                    self.visit_field(v, idx, field_val?)?;
+                    self.visit_field(v, idx, &field_val?)?;
                 }
                 Ok(())
             }
-            fn walk_value(&mut self, v: Self::V) -> InterpResult<'tcx>
+            fn walk_value(&mut self, v: &Self::V) -> InterpResult<'tcx>
             {
                 trace!("walk_value: type: {}", v.layout().ty);
 
@@ -208,10 +212,10 @@ fn walk_value(&mut self, v: Self::V) -> InterpResult<'tcx>
                     ty::Dynamic(..) => {
                         // immediate trait objects are not a thing
                         let dest = v.to_op(self.ecx())?.assert_mem_place(self.ecx());
-                        let inner = self.ecx().unpack_dyn_trait(dest)?.1;
+                        let inner = self.ecx().unpack_dyn_trait(&dest)?.1;
                         trace!("walk_value: dyn object layout: {:#?}", inner.layout);
                         // recurse with the inner type
-                        return self.visit_field(v, 0, Value::from_mem_place(inner));
+                        return self.visit_field(&v, 0, &Value::from_mem_place(inner));
                     },
                     // Slices do not need special handling here: they have `Array` field
                     // placement with length 0, so we enter the `Array` case below which
@@ -241,7 +245,7 @@ fn walk_value(&mut self, v: Self::V) -> InterpResult<'tcx>
                         // Now we can go over all the fields.
                         // This uses the *run-time length*, i.e., if we are a slice,
                         // the dynamic info from the metadata is used.
-                        let iter = self.ecx().mplace_array_fields(mplace)?
+                        let iter = self.ecx().mplace_array_fields(&mplace)?
                             .map(|f| f.and_then(|f| {
                                 Ok(Value::from_mem_place(f))
                             }));
@@ -254,11 +258,11 @@ fn walk_value(&mut self, v: Self::V) -> InterpResult<'tcx>
                     // with *its* fields.
                     Variants::Multiple { .. } => {
                         let op = v.to_op(self.ecx())?;
-                        let idx = self.read_discriminant(op)?;
+                        let idx = self.read_discriminant(&op)?;
                         let inner = v.project_downcast(self.ecx(), idx)?;
                         trace!("walk_value: variant layout: {:#?}", inner.layout());
                         // recurse with the inner type
-                        self.visit_variant(v, idx, inner)
+                        self.visit_variant(v, idx, &inner)
                     }
                     // For single-variant layouts, we already did anything there is to do.
                     Variants::Single { .. } => Ok(())
index d0a23e1359c700c63a1cc65af32049a6feefbf29..5384dbcb8a6a17eff9d37b355c6307b3621a60bc 100644 (file)
@@ -197,7 +197,7 @@ fn find_mir_or_eval_fn(
         _instance: ty::Instance<'tcx>,
         _abi: Abi,
         _args: &[OpTy<'tcx>],
-        _ret: Option<(PlaceTy<'tcx>, BasicBlock)>,
+        _ret: Option<(&PlaceTy<'tcx>, BasicBlock)>,
         _unwind: Option<BasicBlock>,
     ) -> InterpResult<'tcx, Option<&'mir Body<'tcx>>> {
         Ok(None)
@@ -207,7 +207,7 @@ fn call_intrinsic(
         _ecx: &mut InterpCx<'mir, 'tcx, Self>,
         _instance: ty::Instance<'tcx>,
         _args: &[OpTy<'tcx>],
-        _ret: Option<(PlaceTy<'tcx>, BasicBlock)>,
+        _ret: Option<(&PlaceTy<'tcx>, BasicBlock)>,
         _unwind: Option<BasicBlock>,
     ) -> InterpResult<'tcx> {
         throw_machine_stop_str!("calling intrinsics isn't supported in ConstProp")
@@ -228,8 +228,8 @@ fn ptr_to_int(_mem: &Memory<'mir, 'tcx, Self>, _ptr: Pointer) -> InterpResult<'t
     fn binary_ptr_op(
         _ecx: &InterpCx<'mir, 'tcx, Self>,
         _bin_op: BinOp,
-        _left: ImmTy<'tcx>,
-        _right: ImmTy<'tcx>,
+        _left: &ImmTy<'tcx>,
+        _right: &ImmTy<'tcx>,
     ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> {
         // We can't do this because aliasing of memory can differ between const eval and llvm
         throw_machine_stop_str!("pointer arithmetic or comparisons aren't supported in ConstProp")
@@ -237,7 +237,7 @@ fn binary_ptr_op(
 
     fn box_alloc(
         _ecx: &mut InterpCx<'mir, 'tcx, Self>,
-        _dest: PlaceTy<'tcx>,
+        _dest: &PlaceTy<'tcx>,
     ) -> InterpResult<'tcx> {
         throw_machine_stop_str!("can't const prop heap allocations")
     }
@@ -392,12 +392,12 @@ fn new(
             .filter(|ret_layout| {
                 !ret_layout.is_zst() && ret_layout.size < Size::from_bytes(MAX_ALLOC_LIMIT)
             })
-            .map(|ret_layout| ecx.allocate(ret_layout, MemoryKind::Stack));
+            .map(|ret_layout| ecx.allocate(ret_layout, MemoryKind::Stack).into());
 
         ecx.push_stack_frame(
             Instance::new(def_id, substs),
             dummy_body,
-            ret.map(Into::into),
+            ret.as_ref(),
             StackPopCleanup::None { cleanup: false },
         )
         .expect("failed to push initial stack frame");
@@ -426,7 +426,7 @@ fn get_const(&self, place: Place<'tcx>) -> Option<OpTy<'tcx>> {
 
         // Try to read the local as an immediate so that if it is representable as a scalar, we can
         // handle it as such, but otherwise, just return the value as is.
-        Some(match self.ecx.try_read_immediate(op) {
+        Some(match self.ecx.try_read_immediate(&op) {
             Ok(Ok(imm)) => imm.into(),
             _ => op,
         })
@@ -548,8 +548,8 @@ fn check_unary_op(
         source_info: SourceInfo,
     ) -> Option<()> {
         if let (val, true) = self.use_ecx(|this| {
-            let val = this.ecx.read_immediate(this.ecx.eval_operand(arg, None)?)?;
-            let (_res, overflow, _ty) = this.ecx.overflowing_unary_op(op, val)?;
+            let val = this.ecx.read_immediate(&this.ecx.eval_operand(arg, None)?)?;
+            let (_res, overflow, _ty) = this.ecx.overflowing_unary_op(op, &val)?;
             Ok((val, overflow))
         })? {
             // `AssertKind` only has an `OverflowNeg` variant, so make sure that is
@@ -573,8 +573,8 @@ fn check_binary_op(
         right: &Operand<'tcx>,
         source_info: SourceInfo,
     ) -> Option<()> {
-        let r = self.use_ecx(|this| this.ecx.read_immediate(this.ecx.eval_operand(right, None)?));
-        let l = self.use_ecx(|this| this.ecx.read_immediate(this.ecx.eval_operand(left, None)?));
+        let r = self.use_ecx(|this| this.ecx.read_immediate(&this.ecx.eval_operand(right, None)?));
+        let l = self.use_ecx(|this| this.ecx.read_immediate(&this.ecx.eval_operand(left, None)?));
         // Check for exceeding shifts *even if* we cannot evaluate the LHS.
         if op == BinOp::Shr || op == BinOp::Shl {
             let r = r?;
@@ -609,7 +609,7 @@ fn check_binary_op(
             }
         }
 
-        if let (Some(l), Some(r)) = (l, r) {
+        if let (Some(l), Some(r)) = (&l, &r) {
             // The remaining operators are handled through `overflowing_binary_op`.
             if self.use_ecx(|this| {
                 let (_res, overflow, _ty) = this.ecx.overflowing_binary_op(op, l, r)?;
@@ -630,7 +630,7 @@ fn propagate_operand(&mut self, operand: &mut Operand<'tcx>) {
         match *operand {
             Operand::Copy(l) | Operand::Move(l) => {
                 if let Some(value) = self.get_const(l) {
-                    if self.should_const_prop(value) {
+                    if self.should_const_prop(&value) {
                         // FIXME(felix91gr): this code only handles `Scalar` cases.
                         // For now, we're not handling `ScalarPair` cases because
                         // doing so here would require a lot of code duplication.
@@ -745,7 +745,7 @@ fn eval_rvalue_with_identities(
                     let r = this.ecx.eval_operand(right, None);
 
                     let const_arg = match (l, r) {
-                        (Ok(x), Err(_)) | (Err(_), Ok(x)) => this.ecx.read_immediate(x)?,
+                        (Ok(ref x), Err(_)) | (Err(_), Ok(ref x)) => this.ecx.read_immediate(x)?,
                         (Err(e), Err(_)) => return Err(e),
                         (Ok(_), Ok(_)) => {
                             this.ecx.eval_rvalue_into_place(rvalue, place)?;
@@ -760,14 +760,14 @@ fn eval_rvalue_with_identities(
                     match op {
                         BinOp::BitAnd => {
                             if arg_value == 0 {
-                                this.ecx.write_immediate(*const_arg, dest)?;
+                                this.ecx.write_immediate(*const_arg, &dest)?;
                             }
                         }
                         BinOp::BitOr => {
                             if arg_value == const_arg.layout.size.truncate(u128::MAX)
                                 || (const_arg.layout.ty.is_bool() && arg_value == 1)
                             {
-                                this.ecx.write_immediate(*const_arg, dest)?;
+                                this.ecx.write_immediate(*const_arg, &dest)?;
                             }
                         }
                         BinOp::Mul => {
@@ -777,9 +777,9 @@ fn eval_rvalue_with_identities(
                                         const_arg.to_scalar()?.into(),
                                         Scalar::from_bool(false).into(),
                                     );
-                                    this.ecx.write_immediate(val, dest)?;
+                                    this.ecx.write_immediate(val, &dest)?;
                                 } else {
-                                    this.ecx.write_immediate(*const_arg, dest)?;
+                                    this.ecx.write_immediate(*const_arg, &dest)?;
                                 }
                             }
                         }
@@ -809,7 +809,7 @@ fn operand_from_scalar(&self, scalar: Scalar, ty: Ty<'tcx>, span: Span) -> Opera
     fn replace_with_const(
         &mut self,
         rval: &mut Rvalue<'tcx>,
-        value: OpTy<'tcx>,
+        value: &OpTy<'tcx>,
         source_info: SourceInfo,
     ) {
         if let Rvalue::Use(Operand::Constant(c)) = rval {
@@ -902,7 +902,7 @@ fn replace_with_const(
     }
 
     /// Returns `true` if and only if this `op` should be const-propagated into.
-    fn should_const_prop(&mut self, op: OpTy<'tcx>) -> bool {
+    fn should_const_prop(&mut self, op: &OpTy<'tcx>) -> bool {
         let mir_opt_level = self.tcx.sess.opts.debugging_opts.mir_opt_level;
 
         if mir_opt_level == 0 {
@@ -913,7 +913,7 @@ fn should_const_prop(&mut self, op: OpTy<'tcx>) -> bool {
             return false;
         }
 
-        match *op {
+        match **op {
             interpret::Operand::Immediate(Immediate::Scalar(ScalarMaybeUninit::Scalar(s))) => {
                 s.is_bits()
             }
@@ -1094,7 +1094,7 @@ fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Locatio
                 // This will return None if the above `const_prop` invocation only "wrote" a
                 // type whose creation requires no write. E.g. a generator whose initial state
                 // consists solely of uninitialized memory (so it doesn't capture any locals).
-                if let Some(value) = self.get_const(place) {
+                if let Some(ref value) = self.get_const(place) {
                     if self.should_const_prop(value) {
                         trace!("replacing {:?} with {:?}", rval, value);
                         self.replace_with_const(rval, value, source_info);
@@ -1177,10 +1177,10 @@ fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Loca
         self.super_terminator(terminator, location);
         match &mut terminator.kind {
             TerminatorKind::Assert { expected, ref msg, ref mut cond, .. } => {
-                if let Some(value) = self.eval_operand(&cond, source_info) {
+                if let Some(ref value) = self.eval_operand(&cond, source_info) {
                     trace!("assertion on {:?} should be {:?}", value, expected);
                     let expected = ScalarMaybeUninit::from(Scalar::from_bool(*expected));
-                    let value_const = self.ecx.read_scalar(value).unwrap();
+                    let value_const = self.ecx.read_scalar(&value).unwrap();
                     if expected != value_const {
                         enum DbgVal<T> {
                             Val(T),
@@ -1198,9 +1198,9 @@ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
                             // This can be `None` if the lhs wasn't const propagated and we just
                             // triggered the assert on the value of the rhs.
                             match self.eval_operand(op, source_info) {
-                                Some(op) => {
-                                    DbgVal::Val(self.ecx.read_immediate(op).unwrap().to_const_int())
-                                }
+                                Some(op) => DbgVal::Val(
+                                    self.ecx.read_immediate(&op).unwrap().to_const_int(),
+                                ),
                                 None => DbgVal::Underscore,
                             }
                         };
index d36f1b8e5f6705e92e5c472c3fe1e6cc5bf82ba1..7a9bfaad88367528bb9544684c2d51828f80259a 100644 (file)
@@ -327,7 +327,7 @@ macro_rules! assert_successors {
 fn test_covgraph_goto_switchint() {
     let mir_body = goto_switchint();
     if false {
-        println!("basic_blocks = {}", debug_basic_blocks(&mir_body));
+        eprintln!("basic_blocks = {}", debug_basic_blocks(&mir_body));
     }
     let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body);
     print_coverage_graphviz("covgraph_goto_switchint ", &mir_body, &basic_coverage_blocks);
@@ -583,11 +583,11 @@ fn test_find_loop_backedges_none() {
     let mir_body = goto_switchint();
     let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body);
     if false {
-        println!(
+        eprintln!(
             "basic_coverage_blocks = {:?}",
             basic_coverage_blocks.iter_enumerated().collect::<Vec<_>>()
         );
-        println!("successors = {:?}", basic_coverage_blocks.successors);
+        eprintln!("successors = {:?}", basic_coverage_blocks.successors);
     }
     let backedges = graph::find_loop_backedges(&basic_coverage_blocks);
     assert_eq!(
index fd55a4dfc4c9223f5b68fef6e1a83748867174d5..fd41e2822663209dad7601b9e66f0ff7c1031bf7 100644 (file)
@@ -6,8 +6,8 @@
 pub struct GraphvizWriter<
     'a,
     G: graph::DirectedGraph + graph::WithSuccessors + graph::WithStartNode + graph::WithNumNodes,
-    NodeContentFn: Fn(<G as rustc_data_structures::graph::DirectedGraph>::Node) -> Vec<String>,
-    EdgeLabelsFn: Fn(<G as rustc_data_structures::graph::DirectedGraph>::Node) -> Vec<String>,
+    NodeContentFn: Fn(<G as graph::DirectedGraph>::Node) -> Vec<String>,
+    EdgeLabelsFn: Fn(<G as graph::DirectedGraph>::Node) -> Vec<String>,
 > {
     graph: &'a G,
     is_subgraph: bool,
@@ -20,8 +20,8 @@ pub struct GraphvizWriter<
 impl<
     'a,
     G: graph::DirectedGraph + graph::WithSuccessors + graph::WithStartNode + graph::WithNumNodes,
-    NodeContentFn: Fn(<G as rustc_data_structures::graph::DirectedGraph>::Node) -> Vec<String>,
-    EdgeLabelsFn: Fn(<G as rustc_data_structures::graph::DirectedGraph>::Node) -> Vec<String>,
+    NodeContentFn: Fn(<G as graph::DirectedGraph>::Node) -> Vec<String>,
+    EdgeLabelsFn: Fn(<G as graph::DirectedGraph>::Node) -> Vec<String>,
 > GraphvizWriter<'a, G, NodeContentFn, EdgeLabelsFn>
 {
     pub fn new(
index 6ec602ff59b9ce2ad8e32fbe7b81933572b70e53..fdecbb9478808f9323233fff3147754d3aba2dce 100644 (file)
@@ -366,14 +366,31 @@ fn unreachable_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, catchall: Option<
 }
 
 fn irrefutable_let_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, source: hir::MatchSource) {
-    tcx.struct_span_lint_hir(IRREFUTABLE_LET_PATTERNS, id, span, |lint| {
-        let msg = match source {
-            hir::MatchSource::IfLetDesugar { .. } => "irrefutable if-let pattern",
-            hir::MatchSource::WhileLetDesugar => "irrefutable while-let pattern",
-            hir::MatchSource::IfLetGuardDesugar => "irrefutable if-let guard",
-            _ => bug!(),
-        };
-        lint.build(msg).emit()
+    tcx.struct_span_lint_hir(IRREFUTABLE_LET_PATTERNS, id, span, |lint| match source {
+        hir::MatchSource::IfLetDesugar { .. } => {
+            let mut diag = lint.build("irrefutable `if let` pattern");
+            diag.note("this pattern will always match, so the `if let` is useless");
+            diag.help("consider replacing the `if let` with a `let`");
+            diag.emit()
+        }
+        hir::MatchSource::WhileLetDesugar => {
+            let mut diag = lint.build("irrefutable `while let` pattern");
+            diag.note("this pattern will always match, so the loop will never exit");
+            diag.help("consider instead using a `loop { ... }` with a `let` inside it");
+            diag.emit()
+        }
+        hir::MatchSource::IfLetGuardDesugar => {
+            let mut diag = lint.build("irrefutable `if let` guard pattern");
+            diag.note("this pattern will always match, so the guard is useless");
+            diag.help("consider removing the guard and adding a `let` inside the match arm");
+            diag.emit()
+        }
+        _ => {
+            bug!(
+                "expected `if let`, `while let`, or `if let` guard HIR match source, found {:?}",
+                source,
+            )
+        }
     });
 }
 
@@ -387,7 +404,7 @@ fn check_if_let_guard<'p, 'tcx>(
     report_arm_reachability(&cx, &report, hir::MatchSource::IfLetGuardDesugar);
 
     if report.non_exhaustiveness_witnesses.is_empty() {
-        // The match is exhaustive, i.e. the if let pattern is irrefutable.
+        // The match is exhaustive, i.e. the `if let` pattern is irrefutable.
         irrefutable_let_pattern(cx.tcx, pat.span, pat_id, hir::MatchSource::IfLetGuardDesugar)
     }
 }
index 010fe4fd524d4d966bbd2207081023cc60e6a63d..38b7e50d78672699c524bbebaa9e1b81cb2020d4 100644 (file)
 
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::sync::OnceCell;
 
 use rustc_arena::TypedArena;
 use rustc_hir::def_id::DefId;
 use smallvec::{smallvec, SmallVec};
 use std::fmt;
 use std::iter::{FromIterator, IntoIterator};
+use std::lazy::OnceCell;
 
 crate struct MatchCheckCtxt<'a, 'tcx> {
     crate tcx: TyCtxt<'tcx>,
index 5512e849c451d014783f2ed47531bfd9cdb95505..0f49386dec07b083e80293934094cc9b14437159 100644 (file)
@@ -1654,7 +1654,7 @@ pub(super) fn parameter_without_type(
     }
 
     pub(super) fn recover_arg_parse(&mut self) -> PResult<'a, (P<ast::Pat>, P<ast::Ty>)> {
-        let pat = self.parse_pat(Some("argument name"))?;
+        let pat = self.parse_pat_no_top_alt(Some("argument name"))?;
         self.expect(&token::Colon)?;
         let ty = self.parse_ty()?;
 
index 20430ece05b06b3874d98920c98296e7c0a38dd7..fa05df6805f51ee280573077614ce5366193f4bf 100644 (file)
@@ -513,7 +513,7 @@ macro_rules! make_it {
             token::Ident(..) if this.is_mistaken_not_ident_negation() => {
                 make_it!(this, attrs, |this, _| this.recover_not_expr(lo))
             }
-            _ => return this.parse_dot_or_call_expr(Some(attrs.into())),
+            _ => return this.parse_dot_or_call_expr(Some(attrs)),
         }
     }
 
@@ -1726,7 +1726,7 @@ fn parse_fn_block_param(&mut self) -> PResult<'a, Param> {
         let lo = self.token.span;
         let attrs = self.parse_outer_attributes()?;
         self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
-            let pat = this.parse_pat(PARAM_EXPECTED)?;
+            let pat = this.parse_pat_no_top_alt(PARAM_EXPECTED)?;
             let ty = if this.eat(&token::Colon) {
                 this.parse_ty()?
             } else {
@@ -1803,7 +1803,7 @@ fn parse_cond_expr(&mut self) -> PResult<'a, P<Expr>> {
     /// The `let` token has already been eaten.
     fn parse_let_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
         let lo = self.prev_token.span;
-        let pat = self.parse_top_pat(GateOr::No, RecoverComma::Yes)?;
+        let pat = self.parse_pat_allow_top_alt(None, GateOr::No, RecoverComma::Yes)?;
         self.expect(&token::Eq)?;
         let expr = self.with_res(self.restrictions | Restrictions::NO_STRUCT_LITERAL, |this| {
             this.parse_assoc_expr_with(1 + prec_let_scrutinee_needs_par(), None.into())
@@ -1866,7 +1866,7 @@ fn parse_for_expr(
             _ => None,
         };
 
-        let pat = self.parse_top_pat(GateOr::Yes, RecoverComma::Yes)?;
+        let pat = self.parse_pat_allow_top_alt(None, GateOr::Yes, RecoverComma::Yes)?;
         if !self.eat_keyword(kw::In) {
             self.error_missing_in_for_loop();
         }
@@ -1977,7 +1977,7 @@ pub(super) fn parse_arm(&mut self) -> PResult<'a, Arm> {
         let attrs = self.parse_outer_attributes()?;
         self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
             let lo = this.token.span;
-            let pat = this.parse_top_pat(GateOr::No, RecoverComma::Yes)?;
+            let pat = this.parse_pat_allow_top_alt(None, GateOr::No, RecoverComma::Yes)?;
             let guard = if this.eat_keyword(kw::If) {
                 let if_span = this.prev_token.span;
                 let cond = this.parse_expr()?;
index cdea82f50ede488610ac573bb9cbc1c18d0f79d2..0f907859a19a681d90ff554360a7cad0efc1e622 100644 (file)
 impl<'a> Parser<'a> {
     /// Parses a source module as a crate. This is the main entry point for the parser.
     pub fn parse_crate_mod(&mut self) -> PResult<'a, ast::Crate> {
-        let lo = self.token.span;
-        let (module, attrs) = self.parse_mod(&token::Eof, Unsafe::No)?;
-        let span = lo.to(self.token.span);
+        let (attrs, items, span) = self.parse_mod(&token::Eof)?;
         let proc_macros = Vec::new(); // Filled in by `proc_macro_harness::inject()`.
-        Ok(ast::Crate { attrs, module, span, proc_macros })
+        Ok(ast::Crate { attrs, items, span, proc_macros })
     }
 
     /// Parses a `mod <foo> { ... }` or `mod <foo>;` item.
@@ -37,35 +35,26 @@ fn parse_item_mod(&mut self, attrs: &mut Vec<Attribute>) -> PResult<'a, ItemInfo
         let unsafety = self.parse_unsafety();
         self.expect_keyword(kw::Mod)?;
         let id = self.parse_ident()?;
-        let (module, mut inner_attrs) = if self.eat(&token::Semi) {
-            (Mod { inner: Span::default(), unsafety, items: Vec::new(), inline: false }, Vec::new())
+        let mod_kind = if self.eat(&token::Semi) {
+            ModKind::Unloaded
         } else {
             self.expect(&token::OpenDelim(token::Brace))?;
-            self.parse_mod(&token::CloseDelim(token::Brace), unsafety)?
+            let (mut inner_attrs, items, inner_span) =
+                self.parse_mod(&token::CloseDelim(token::Brace))?;
+            attrs.append(&mut inner_attrs);
+            ModKind::Loaded(items, Inline::Yes, inner_span)
         };
-        attrs.append(&mut inner_attrs);
-        Ok((id, ItemKind::Mod(module)))
+        Ok((id, ItemKind::Mod(unsafety, mod_kind)))
     }
 
     /// Parses the contents of a module (inner attributes followed by module items).
     pub fn parse_mod(
         &mut self,
         term: &TokenKind,
-        unsafety: Unsafe,
-    ) -> PResult<'a, (Mod, Vec<Attribute>)> {
+    ) -> PResult<'a, (Vec<Attribute>, Vec<P<Item>>, Span)> {
         let lo = self.token.span;
         let attrs = self.parse_inner_attributes()?;
-        let module = self.parse_mod_items(term, lo, unsafety)?;
-        Ok((module, attrs))
-    }
 
-    /// Given a termination token, parses all of the items in a module.
-    fn parse_mod_items(
-        &mut self,
-        term: &TokenKind,
-        inner_lo: Span,
-        unsafety: Unsafe,
-    ) -> PResult<'a, Mod> {
         let mut items = vec![];
         while let Some(item) = self.parse_item(ForceCollect::No)? {
             items.push(item);
@@ -82,9 +71,7 @@ fn parse_mod_items(
             }
         }
 
-        let hi = if self.token.span.is_dummy() { inner_lo } else { self.prev_token.span };
-
-        Ok(Mod { inner: inner_lo.to(hi), unsafety, items, inline: true })
+        Ok((attrs, items, lo.to(self.prev_token.span)))
     }
 }
 
index 18013f1250bdba70f5317434895909d5303a3bd0..ace4134b1f698362872b2dc204f079ce488685c2 100644 (file)
@@ -14,6 +14,7 @@
 pub use attr_wrapper::AttrWrapper;
 pub use diagnostics::AttemptLocalParseRecovery;
 use diagnostics::Error;
+pub use pat::{GateOr, RecoverComma};
 pub use path::PathStyle;
 
 use rustc_ast::ptr::P;
index 40dd938f000e371f8d75bd71f1f79b9d80e76d17..a84ae5151442d8c9f0c6c5c1d5b53bebe45612c2 100644 (file)
@@ -120,9 +120,9 @@ pub fn parse_nonterminal(&mut self, kind: NonterminalKind) -> PResult<'a, Nonter
             },
             NonterminalKind::Pat2018 { .. } | NonterminalKind::Pat2021 { .. } => {
                 token::NtPat(self.collect_tokens_no_attrs(|this| match kind {
-                    NonterminalKind::Pat2018 { .. } => this.parse_pat(None),
+                    NonterminalKind::Pat2018 { .. } => this.parse_pat_no_top_alt(None),
                     NonterminalKind::Pat2021 { .. } => {
-                        this.parse_top_pat(GateOr::Yes, RecoverComma::No)
+                        this.parse_pat_allow_top_alt(None, GateOr::Yes, RecoverComma::No)
                     }
                     _ => unreachable!(),
                 })?)
index 317ef84742c2168cd8f9056403d5baa341ab1eec..8874548da784df87e2bd16dae267174620fb40e0 100644 (file)
 
 /// Whether or not an or-pattern should be gated when occurring in the current context.
 #[derive(PartialEq, Clone, Copy)]
-pub(super) enum GateOr {
+pub enum GateOr {
     Yes,
     No,
 }
 
 /// Whether or not to recover a `,` when parsing or-patterns.
 #[derive(PartialEq, Copy, Clone)]
-pub(super) enum RecoverComma {
+pub enum RecoverComma {
     Yes,
     No,
 }
@@ -37,80 +37,57 @@ impl<'a> Parser<'a> {
     /// Corresponds to `pat<no_top_alt>` in RFC 2535 and does not admit or-patterns
     /// at the top level. Used when parsing the parameters of lambda expressions,
     /// functions, function pointers, and `pat` macro fragments.
-    pub fn parse_pat(&mut self, expected: Expected) -> PResult<'a, P<Pat>> {
+    pub fn parse_pat_no_top_alt(&mut self, expected: Expected) -> PResult<'a, P<Pat>> {
         self.parse_pat_with_range_pat(true, expected)
     }
 
-    /// Entry point to the main pattern parser.
+    /// Parses a pattern.
+    ///
     /// Corresponds to `top_pat` in RFC 2535 and allows or-pattern at the top level.
-    pub(super) fn parse_top_pat(
+    /// Used for parsing patterns in all cases when `pat<no_top_alt>` is not used.
+    ///
+    /// Note that after the FCP in <https://github.com/rust-lang/rust/issues/81415>,
+    /// a leading vert is allowed in nested or-patterns, too. This allows us to
+    /// simplify the grammar somewhat.
+    pub fn parse_pat_allow_top_alt(
         &mut self,
+        expected: Expected,
         gate_or: GateOr,
         rc: RecoverComma,
     ) -> PResult<'a, P<Pat>> {
         // Allow a '|' before the pats (RFCs 1925, 2530, and 2535).
-        let gated_leading_vert = self.eat_or_separator(None) && gate_or == GateOr::Yes;
-        let leading_vert_span = self.prev_token.span;
-
-        // Parse the possibly-or-pattern.
-        let pat = self.parse_pat_with_or(None, gate_or, rc)?;
-
-        // If we parsed a leading `|` which should be gated,
-        // and no other gated or-pattern has been parsed thus far,
-        // then we should really gate the leading `|`.
-        // This complicated procedure is done purely for diagnostics UX.
-        if gated_leading_vert && self.sess.gated_spans.is_ungated(sym::or_patterns) {
-            self.sess.gated_spans.gate(sym::or_patterns, leading_vert_span);
-        }
-
-        Ok(pat)
-    }
-
-    /// Parse the pattern for a function or function pointer parameter.
-    /// Special recovery is provided for or-patterns and leading `|`.
-    pub(super) fn parse_fn_param_pat(&mut self) -> PResult<'a, P<Pat>> {
-        self.recover_leading_vert(None, "not allowed in a parameter pattern");
-        let pat = self.parse_pat_with_or(PARAM_EXPECTED, GateOr::No, RecoverComma::No)?;
-
-        if let PatKind::Or(..) = &pat.kind {
-            self.ban_illegal_fn_param_or_pat(&pat);
-        }
-
-        Ok(pat)
-    }
+        let leading_vert_span =
+            if self.eat_or_separator(None) { Some(self.prev_token.span) } else { None };
 
-    /// Ban `A | B` immediately in a parameter pattern and suggest wrapping in parens.
-    fn ban_illegal_fn_param_or_pat(&self, pat: &Pat) {
-        let msg = "wrap the pattern in parenthesis";
-        let fix = format!("({})", pprust::pat_to_string(pat));
-        self.struct_span_err(pat.span, "an or-pattern parameter must be wrapped in parenthesis")
-            .span_suggestion(pat.span, msg, fix, Applicability::MachineApplicable)
-            .emit();
-    }
-
-    /// Parses a pattern, that may be a or-pattern (e.g. `Foo | Bar` in `Some(Foo | Bar)`).
-    /// Corresponds to `pat<allow_top_alt>` in RFC 2535.
-    fn parse_pat_with_or(
-        &mut self,
-        expected: Expected,
-        gate_or: GateOr,
-        rc: RecoverComma,
-    ) -> PResult<'a, P<Pat>> {
         // Parse the first pattern (`p_0`).
-        let first_pat = self.parse_pat(expected)?;
+        let first_pat = self.parse_pat_no_top_alt(expected)?;
         self.maybe_recover_unexpected_comma(first_pat.span, rc, gate_or)?;
 
         // If the next token is not a `|`,
         // this is not an or-pattern and we should exit here.
         if !self.check(&token::BinOp(token::Or)) && self.token != token::OrOr {
+            // If we parsed a leading `|` which should be gated,
+            // then we should really gate the leading `|`.
+            // This complicated procedure is done purely for diagnostics UX.
+            if let Some(leading_vert_span) = leading_vert_span {
+                if gate_or == GateOr::Yes && self.sess.gated_spans.is_ungated(sym::or_patterns) {
+                    self.sess.gated_spans.gate(sym::or_patterns, leading_vert_span);
+                }
+
+                // If there was a leading vert, treat this as an or-pattern. This improves
+                // diagnostics.
+                let span = leading_vert_span.to(self.prev_token.span);
+                return Ok(self.mk_pat(span, PatKind::Or(vec![first_pat])));
+            }
+
             return Ok(first_pat);
         }
 
         // Parse the patterns `p_1 | ... | p_n` where `n > 0`.
-        let lo = first_pat.span;
+        let lo = leading_vert_span.unwrap_or(first_pat.span);
         let mut pats = vec![first_pat];
         while self.eat_or_separator(Some(lo)) {
-            let pat = self.parse_pat(expected).map_err(|mut err| {
+            let pat = self.parse_pat_no_top_alt(expected).map_err(|mut err| {
                 err.span_label(lo, WHILE_PARSING_OR_MSG);
                 err
             })?;
@@ -127,6 +104,62 @@ fn parse_pat_with_or(
         Ok(self.mk_pat(or_pattern_span, PatKind::Or(pats)))
     }
 
+    /// Parse the pattern for a function or function pointer parameter.
+    pub(super) fn parse_fn_param_pat(&mut self) -> PResult<'a, P<Pat>> {
+        // We actually do _not_ allow top-level or-patterns in function params, but we use
+        // `parse_pat_allow_top_alt` anyway so that we can detect when a user tries to use it. This
+        // allows us to print a better error message.
+        //
+        // In order to get good UX, we first recover in the case of a leading vert for an illegal
+        // top-level or-pat. Normally, this means recovering both `|` and `||`, but in this case,
+        // a leading `||` probably doesn't indicate an or-pattern attempt, so we handle that
+        // separately.
+        if let token::OrOr = self.token.kind {
+            let span = self.token.span;
+            let mut err = self.struct_span_err(span, "unexpected `||` before function parameter");
+            err.span_suggestion(
+                span,
+                "remove the `||`",
+                String::new(),
+                Applicability::MachineApplicable,
+            );
+            err.note("alternatives in or-patterns are separated with `|`, not `||`");
+            err.emit();
+            self.bump();
+        }
+
+        let pat = self.parse_pat_allow_top_alt(PARAM_EXPECTED, GateOr::No, RecoverComma::No)?;
+
+        if let PatKind::Or(..) = &pat.kind {
+            self.ban_illegal_fn_param_or_pat(&pat);
+        }
+
+        Ok(pat)
+    }
+
+    /// Ban `A | B` immediately in a parameter pattern and suggest wrapping in parens.
+    fn ban_illegal_fn_param_or_pat(&self, pat: &Pat) {
+        // If all we have a leading vert, then print a special message. This is the case if
+        // `parse_pat_allow_top_alt` returns an or-pattern with one variant.
+        let (msg, fix) = match &pat.kind {
+            PatKind::Or(pats) if pats.len() == 1 => {
+                let msg = "remove the leading `|`";
+                let fix = pprust::pat_to_string(pat);
+                (msg, fix)
+            }
+
+            _ => {
+                let msg = "wrap the pattern in parentheses";
+                let fix = format!("({})", pprust::pat_to_string(pat));
+                (msg, fix)
+            }
+        };
+
+        self.struct_span_err(pat.span, "an or-pattern parameter must be wrapped in parentheses")
+            .span_suggestion(pat.span, msg, fix, Applicability::MachineApplicable)
+            .emit();
+    }
+
     /// Eat the or-pattern `|` separator.
     /// If instead a `||` token is encountered, recover and pretend we parsed `|`.
     fn eat_or_separator(&mut self, lo: Option<Span>) -> bool {
@@ -179,7 +212,7 @@ fn recover_trailing_vert(&mut self, lo: Option<Span>) -> bool {
 
     /// We have parsed `||` instead of `|`. Error and suggest `|` instead.
     fn ban_unexpected_or_or(&mut self, lo: Option<Span>) {
-        let mut err = self.struct_span_err(self.token.span, "unexpected token `||` after pattern");
+        let mut err = self.struct_span_err(self.token.span, "unexpected token `||` in pattern");
         err.span_suggestion(
             self.token.span,
             "use a single `|` to separate multiple alternative patterns",
@@ -244,7 +277,7 @@ fn maybe_recover_unexpected_comma(
     /// sequence of patterns until `)` is reached.
     fn skip_pat_list(&mut self) -> PResult<'a, ()> {
         while !self.check(&token::CloseDelim(token::Paren)) {
-            self.parse_pat(None)?;
+            self.parse_pat_no_top_alt(None)?;
             if !self.eat(&token::Comma) {
                 return Ok(());
             }
@@ -252,22 +285,6 @@ fn skip_pat_list(&mut self) -> PResult<'a, ()> {
         Ok(())
     }
 
-    /// Recursive possibly-or-pattern parser with recovery for an erroneous leading `|`.
-    /// See `parse_pat_with_or` for details on parsing or-patterns.
-    fn parse_pat_with_or_inner(&mut self) -> PResult<'a, P<Pat>> {
-        self.recover_leading_vert(None, "only allowed in a top-level pattern");
-        self.parse_pat_with_or(None, GateOr::Yes, RecoverComma::No)
-    }
-
-    /// Recover if `|` or `||` is here.
-    /// The user is thinking that a leading `|` is allowed in this position.
-    fn recover_leading_vert(&mut self, lo: Option<Span>, ctx: &str) {
-        if let token::BinOp(token::Or) | token::OrOr = self.token.kind {
-            self.ban_illegal_vert(lo, "leading", ctx);
-            self.bump();
-        }
-    }
-
     /// A `|` or possibly `||` token shouldn't be here. Ban it.
     fn ban_illegal_vert(&mut self, lo: Option<Span>, pos: &str, ctx: &str) {
         let span = self.token.span;
@@ -305,8 +322,9 @@ fn parse_pat_with_range_pat(
             self.parse_pat_tuple_or_parens()?
         } else if self.check(&token::OpenDelim(token::Bracket)) {
             // Parse `[pat, pat,...]` as a slice pattern.
-            let (pats, _) =
-                self.parse_delim_comma_seq(token::Bracket, |p| p.parse_pat_with_or_inner())?;
+            let (pats, _) = self.parse_delim_comma_seq(token::Bracket, |p| {
+                p.parse_pat_allow_top_alt(None, GateOr::Yes, RecoverComma::No)
+            })?;
             PatKind::Slice(pats)
         } else if self.check(&token::DotDot) && !self.is_pat_range_end_start(1) {
             // A rest pattern `..`.
@@ -429,7 +447,7 @@ fn recover_intersection_pat(&mut self, lhs: P<Pat>) -> PResult<'a, P<Pat>> {
 
         // At this point we attempt to parse `@ $pat_rhs` and emit an error.
         self.bump(); // `@`
-        let mut rhs = self.parse_pat(None)?;
+        let mut rhs = self.parse_pat_no_top_alt(None)?;
         let sp = lhs.span.to(rhs.span);
 
         if let PatKind::Ident(_, _, ref mut sub @ None) = rhs.kind {
@@ -518,8 +536,9 @@ fn recover_lifetime_in_deref_pat(&mut self) {
 
     /// Parse a tuple or parenthesis pattern.
     fn parse_pat_tuple_or_parens(&mut self) -> PResult<'a, PatKind> {
-        let (fields, trailing_comma) =
-            self.parse_paren_comma_seq(|p| p.parse_pat_with_or_inner())?;
+        let (fields, trailing_comma) = self.parse_paren_comma_seq(|p| {
+            p.parse_pat_allow_top_alt(None, GateOr::Yes, RecoverComma::No)
+        })?;
 
         // Here, `(pat,)` is a tuple pattern.
         // For backward compatibility, `(..)` is a tuple pattern as well.
@@ -548,7 +567,7 @@ fn parse_pat_ident_mut(&mut self) -> PResult<'a, PatKind> {
         }
 
         // Parse the pattern we hope to be an identifier.
-        let mut pat = self.parse_pat(Some("identifier"))?;
+        let mut pat = self.parse_pat_no_top_alt(Some("identifier"))?;
 
         // If we don't have `mut $ident (@ pat)?`, error.
         if let PatKind::Ident(BindingMode::ByValue(m @ Mutability::Not), ..) = &mut pat.kind {
@@ -793,7 +812,7 @@ fn can_be_ident_pat(&mut self) -> bool {
     fn parse_pat_ident(&mut self, binding_mode: BindingMode) -> PResult<'a, PatKind> {
         let ident = self.parse_ident()?;
         let sub = if self.eat(&token::At) {
-            Some(self.parse_pat(Some("binding pattern"))?)
+            Some(self.parse_pat_no_top_alt(Some("binding pattern"))?)
         } else {
             None
         };
@@ -832,7 +851,9 @@ fn parse_pat_tuple_struct(&mut self, qself: Option<QSelf>, path: Path) -> PResul
         if qself.is_some() {
             return self.error_qpath_before_pat(&path, "(");
         }
-        let (fields, _) = self.parse_paren_comma_seq(|p| p.parse_pat_with_or_inner())?;
+        let (fields, _) = self.parse_paren_comma_seq(|p| {
+            p.parse_pat_allow_top_alt(None, GateOr::Yes, RecoverComma::No)
+        })?;
         Ok(PatKind::TupleStruct(path, fields))
     }
 
@@ -998,7 +1019,7 @@ fn parse_pat_field(&mut self, lo: Span, attrs: Vec<Attribute>) -> PResult<'a, Fi
             // Parsing a pattern of the form `fieldname: pat`.
             let fieldname = self.parse_field_name()?;
             self.bump();
-            let pat = self.parse_pat_with_or_inner()?;
+            let pat = self.parse_pat_allow_top_alt(None, GateOr::Yes, RecoverComma::No)?;
             hi = pat.span;
             (pat, fieldname, false)
         } else {
index e36ebd5e481137de6733ebcb22f7e1e65e453994..bb2c7e98861cdaa1cb295929173677449d0eac76 100644 (file)
@@ -97,7 +97,7 @@ fn parse_stmt_without_recovery(
             self.mk_stmt(lo, StmtKind::Empty)
         } else if self.token != token::CloseDelim(token::Brace) {
             // Remainder are line-expr stmts.
-            let e = self.parse_expr_res(Restrictions::STMT_EXPR, Some(attrs.into()))?;
+            let e = self.parse_expr_res(Restrictions::STMT_EXPR, Some(attrs))?;
             self.mk_stmt(lo.to(e.span), StmtKind::Expr(e))
         } else {
             self.error_outer_attrs(&attrs.take_for_recovery());
@@ -131,7 +131,7 @@ fn parse_stmt_path_start(
             };
 
             let expr = this.with_res(Restrictions::STMT_EXPR, |this| {
-                let expr = this.parse_dot_or_call_expr_with(expr, lo, attrs.into())?;
+                let expr = this.parse_dot_or_call_expr_with(expr, lo, attrs)?;
                 this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr))
             })?;
             Ok((
@@ -213,14 +213,14 @@ fn parse_local_mk(
     }
 
     fn recover_local_after_let(&mut self, lo: Span, attrs: AttrVec) -> PResult<'a, Stmt> {
-        let local = self.parse_local(attrs.into())?;
+        let local = self.parse_local(attrs)?;
         Ok(self.mk_stmt(lo.to(self.prev_token.span), StmtKind::Local(local)))
     }
 
     /// Parses a local variable declaration.
     fn parse_local(&mut self, attrs: AttrVec) -> PResult<'a, P<Local>> {
         let lo = self.prev_token.span;
-        let pat = self.parse_top_pat(GateOr::Yes, RecoverComma::Yes)?;
+        let pat = self.parse_pat_allow_top_alt(None, GateOr::Yes, RecoverComma::Yes)?;
 
         let (err, ty) = if self.eat(&token::Colon) {
             // Save the state of the parser before parsing type normally, in case there is a `:`
index 8950f9b33b6dac3ee4d1084d27839a3eca5de028..9328f7cd9ec7b6b72fb6786a328dfc0197eb754c 100644 (file)
@@ -45,7 +45,7 @@ fn required_feature_gates(self) -> Option<&'static [Symbol]> {
                 return None;
             }
 
-            Self::Match(IfLetGuardDesugar) => bug!("if-let guard outside a `match` expression"),
+            Self::Match(IfLetGuardDesugar) => bug!("`if let` guard outside a `match` expression"),
 
             // All other expressions are allowed.
             Self::Loop(Loop | While | WhileLet)
index e35ad10968d33a198fd1e696b3839bdd9a2db06f..fac28281593c81b7609c15f026af3cb58ecf2078 100644 (file)
@@ -66,13 +66,13 @@ fn print(&self, title: &str) {
 
         let mut total_size = 0;
 
-        println!("\n{}\n", title);
+        eprintln!("\n{}\n", title);
 
-        println!("{:<18}{:>18}{:>14}{:>14}", "Name", "Accumulated Size", "Count", "Item Size");
-        println!("----------------------------------------------------------------");
+        eprintln!("{:<18}{:>18}{:>14}{:>14}", "Name", "Accumulated Size", "Count", "Item Size");
+        eprintln!("----------------------------------------------------------------");
 
         for (label, data) in stats {
-            println!(
+            eprintln!(
                 "{:<18}{:>18}{:>14}{:>14}",
                 label,
                 to_readable_str(data.count * data.size),
@@ -82,8 +82,8 @@ fn print(&self, title: &str) {
 
             total_size += data.count * data.size;
         }
-        println!("----------------------------------------------------------------");
-        println!("{:<18}{:>18}\n", "Total", to_readable_str(total_size));
+        eprintln!("----------------------------------------------------------------");
+        eprintln!("{:<18}{:>18}\n", "Total", to_readable_str(total_size));
     }
 }
 
@@ -124,11 +124,6 @@ fn visit_item(&mut self, i: &'v hir::Item<'v>) {
         hir_visit::walk_item(self, i)
     }
 
-    fn visit_mod(&mut self, m: &'v hir::Mod<'v>, _s: Span, n: hir::HirId) {
-        self.record("Mod", Id::None, m);
-        hir_visit::walk_mod(self, m, n)
-    }
-
     fn visit_foreign_item(&mut self, i: &'v hir::ForeignItem<'v>) {
         self.record("ForeignItem", Id::Node(i.hir_id()), i);
         hir_visit::walk_foreign_item(self, i)
@@ -252,11 +247,6 @@ fn visit_macro_def(&mut self, macro_def: &'v hir::MacroDef<'v>) {
 }
 
 impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
-    fn visit_mod(&mut self, m: &'v ast::Mod, _s: Span, _a: &[ast::Attribute], _n: NodeId) {
-        self.record("Mod", Id::None, m);
-        ast_visit::walk_mod(self, m)
-    }
-
     fn visit_foreign_item(&mut self, i: &'v ast::ForeignItem) {
         self.record("ForeignItem", Id::None, i);
         ast_visit::walk_foreign_item(self, i)
index 890493fa85387a2c946798835a4dc053e0d66756..6e0e1c5eeef1524c43c1bcece6f5c0422c2df50d 100644 (file)
@@ -77,6 +77,12 @@ fn visit(&mut self, ty_fragment: impl TypeFoldable<'tcx>) -> ControlFlow<Self::B
     fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> ControlFlow<Self::BreakTy> {
         self.skeleton().visit_trait(trait_ref)
     }
+    fn visit_projection_ty(
+        &mut self,
+        projection: ty::ProjectionTy<'tcx>,
+    ) -> ControlFlow<Self::BreakTy> {
+        self.skeleton().visit_projection_ty(projection)
+    }
     fn visit_predicates(
         &mut self,
         predicates: ty::GenericPredicates<'tcx>,
@@ -101,6 +107,20 @@ fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> ControlFlow<V::BreakTy>
         if self.def_id_visitor.shallow() { ControlFlow::CONTINUE } else { substs.visit_with(self) }
     }
 
+    fn visit_projection_ty(
+        &mut self,
+        projection: ty::ProjectionTy<'tcx>,
+    ) -> ControlFlow<V::BreakTy> {
+        let (trait_ref, assoc_substs) =
+            projection.trait_ref_and_own_substs(self.def_id_visitor.tcx());
+        self.visit_trait(trait_ref)?;
+        if self.def_id_visitor.shallow() {
+            ControlFlow::CONTINUE
+        } else {
+            assoc_substs.iter().try_for_each(|subst| subst.visit_with(self))
+        }
+    }
+
     fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<V::BreakTy> {
         match predicate.kind().skip_binder() {
             ty::PredicateKind::Trait(ty::TraitPredicate { trait_ref }, _) => {
@@ -108,7 +128,7 @@ fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<V::
             }
             ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, ty }) => {
                 ty.visit_with(self)?;
-                self.visit_trait(projection_ty.trait_ref(self.def_id_visitor.tcx()))
+                self.visit_projection_ty(projection_ty)
             }
             ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty, _region)) => {
                 ty.visit_with(self)
@@ -197,7 +217,7 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<V::BreakTy> {
                     return ControlFlow::CONTINUE;
                 }
                 // This will also visit substs if necessary, so we don't need to recurse.
-                return self.visit_trait(proj.trait_ref(tcx));
+                return self.visit_projection_ty(proj);
             }
             ty::Dynamic(predicates, ..) => {
                 // All traits in the list are considered the "primary" part of the type
@@ -1203,10 +1223,9 @@ fn visit_trait_ref(&mut self, trait_ref: &'tcx hir::TraitRef<'tcx>) {
             }
 
             for (poly_predicate, _) in bounds.projection_bounds {
-                let tcx = self.tcx;
                 if self.visit(poly_predicate.skip_binder().ty).is_break()
                     || self
-                        .visit_trait(poly_predicate.skip_binder().projection_ty.trait_ref(tcx))
+                        .visit_projection_ty(poly_predicate.skip_binder().projection_ty)
                         .is_break()
                 {
                     return;
@@ -1849,41 +1868,18 @@ fn visit_def_id(
     }
 }
 
-struct PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> {
+struct PrivateItemsInPublicInterfacesVisitor<'tcx> {
     tcx: TyCtxt<'tcx>,
     has_pub_restricted: bool,
-    old_error_set: &'a HirIdSet,
+    old_error_set_ancestry: HirIdSet,
 }
 
-impl<'a, 'tcx> PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> {
+impl<'tcx> PrivateItemsInPublicInterfacesVisitor<'tcx> {
     fn check(
         &self,
         item_id: hir::HirId,
         required_visibility: ty::Visibility,
     ) -> SearchInterfaceForPrivateItemsVisitor<'tcx> {
-        let mut has_old_errors = false;
-
-        // Slow path taken only if there any errors in the crate.
-        for &id in self.old_error_set {
-            // Walk up the nodes until we find `item_id` (or we hit a root).
-            let mut id = id;
-            loop {
-                if id == item_id {
-                    has_old_errors = true;
-                    break;
-                }
-                let parent = self.tcx.hir().get_parent_node(id);
-                if parent == id {
-                    break;
-                }
-                id = parent;
-            }
-
-            if has_old_errors {
-                break;
-            }
-        }
-
         SearchInterfaceForPrivateItemsVisitor {
             tcx: self.tcx,
             item_id,
@@ -1891,7 +1887,7 @@ fn check(
             span: self.tcx.hir().span(item_id),
             required_visibility,
             has_pub_restricted: self.has_pub_restricted,
-            has_old_errors,
+            has_old_errors: self.old_error_set_ancestry.contains(&item_id),
             in_assoc_ty: false,
         }
     }
@@ -1917,7 +1913,7 @@ fn check_assoc_item(
     }
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> {
+impl<'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'tcx> {
     type Map = Map<'tcx>;
 
     fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
@@ -2137,11 +2133,22 @@ fn check_private_in_public(tcx: TyCtxt<'_>, krate: CrateNum) {
         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 {
+            if !old_error_set_ancestry.insert(id) {
+                break;
+            }
+            let parent = tcx.hir().get_parent_node(id);
+            if parent == id {
+                break;
+            }
+            id = parent;
+        }
+    }
+
     // Check for private types and traits in public interfaces.
-    let mut visitor = PrivateItemsInPublicInterfacesVisitor {
-        tcx,
-        has_pub_restricted,
-        old_error_set: &visitor.old_error_set,
-    };
+    let mut visitor =
+        PrivateItemsInPublicInterfacesVisitor { tcx, has_pub_restricted, old_error_set_ancestry };
     krate.visit_all_item_likes(&mut DeepVisitor::new(&mut visitor));
 }
index 4fb3a683ea2257a8d009f2c7fbc0d8416d2e9959..b13aa2f6ccbac36f84cb59f18882b9ab07be7308 100644 (file)
@@ -964,29 +964,29 @@ struct Stat<Kind: DepKind> {
                                  ----------------------------------------------\
                                  ------------";
 
-        println!("[incremental]");
-        println!("[incremental] DepGraph Statistics");
-        println!("{}", SEPARATOR);
-        println!("[incremental]");
-        println!("[incremental] Total Node Count: {}", total_node_count);
-        println!("[incremental] Total Edge Count: {}", total_edge_count);
+        eprintln!("[incremental]");
+        eprintln!("[incremental] DepGraph Statistics");
+        eprintln!("{}", SEPARATOR);
+        eprintln!("[incremental]");
+        eprintln!("[incremental] Total Node Count: {}", total_node_count);
+        eprintln!("[incremental] Total Edge Count: {}", total_edge_count);
 
         if cfg!(debug_assertions) {
             let total_edge_reads = current.total_read_count.load(Relaxed);
             let total_duplicate_edge_reads = current.total_duplicate_read_count.load(Relaxed);
 
-            println!("[incremental] Total Edge Reads: {}", total_edge_reads);
-            println!("[incremental] Total Duplicate Edge Reads: {}", total_duplicate_edge_reads);
+            eprintln!("[incremental] Total Edge Reads: {}", total_edge_reads);
+            eprintln!("[incremental] Total Duplicate Edge Reads: {}", total_duplicate_edge_reads);
         }
 
-        println!("[incremental]");
+        eprintln!("[incremental]");
 
-        println!(
+        eprintln!(
             "[incremental]  {:<36}| {:<17}| {:<12}| {:<17}|",
             "Node Kind", "Node Frequency", "Node Count", "Avg. Edge Count"
         );
 
-        println!(
+        eprintln!(
             "[incremental] -------------------------------------\
                   |------------------\
                   |-------------\
@@ -997,7 +997,7 @@ struct Stat<Kind: DepKind> {
             let node_kind_ratio = (100.0 * (stat.node_counter as f64)) / (total_node_count as f64);
             let node_kind_avg_edges = (stat.edge_counter as f64) / (stat.node_counter as f64);
 
-            println!(
+            eprintln!(
                 "[incremental]  {:<36}|{:>16.1}% |{:>12} |{:>17.1} |",
                 format!("{:?}", stat.kind),
                 node_kind_ratio,
@@ -1006,8 +1006,8 @@ struct Stat<Kind: DepKind> {
             );
         }
 
-        println!("{}", SEPARATOR);
-        println!("[incremental]");
+        eprintln!("{}", SEPARATOR);
+        eprintln!("[incremental]");
     }
 
     fn next_virtual_depnode_index(&self) -> DepNodeIndex {
index cca40a793dd006cfd2092bb91f97740260f4aa02..701d48a982d36db8c9c1d040d2bfbe31b9e70801 100644 (file)
@@ -1023,7 +1023,7 @@ fn resolve_item(&mut self, item: &'ast Item) {
                 });
             }
 
-            ItemKind::Mod(_) | ItemKind::ForeignMod(_) => {
+            ItemKind::Mod(..) | ItemKind::ForeignMod(_) => {
                 self.with_scope(item.id, |this| {
                     visit::walk_item(this, item);
                 });
@@ -1801,7 +1801,7 @@ fn smart_resolve_path_fragment(
         crate_lint: CrateLint,
     ) -> PartialRes {
         tracing::debug!(
-            "smart_resolve_path_fragment(id={:?},qself={:?},path={:?}",
+            "smart_resolve_path_fragment(id={:?}, qself={:?}, path={:?})",
             id,
             qself,
             path
@@ -1841,11 +1841,10 @@ fn smart_resolve_path_fragment(
 
             // Before we start looking for candidates, we have to get our hands
             // on the type user is trying to perform invocation on; basically:
-            // we're transforming `HashMap::new` into just `HashMap`
-            let path = if let Some((_, path)) = path.split_last() {
-                path
-            } else {
-                return Some(parent_err);
+            // we're transforming `HashMap::new` into just `HashMap`.
+            let path = match path.split_last() {
+                Some((_, path)) if !path.is_empty() => path,
+                _ => return Some(parent_err),
             };
 
             let (mut err, candidates) =
index bca3c7b1b03d3d773b419852acf155891859270f..77fbbaa1532af38a15fa6b4967ff79688fa34ab6 100644 (file)
@@ -11,6 +11,7 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(box_patterns)]
 #![feature(bool_to_option)]
+#![feature(control_flow_enum)]
 #![feature(crate_visibility_modifier)]
 #![feature(format_args_capture)]
 #![feature(nll)]
 
 use rustc_arena::{DroplessArena, TypedArena};
 use rustc_ast::node_id::NodeMap;
+use rustc_ast::ptr::P;
 use rustc_ast::unwrap_or;
 use rustc_ast::visit::{self, Visitor};
 use rustc_ast::{self as ast, NodeId};
 use rustc_ast::{Crate, CRATE_NODE_ID};
-use rustc_ast::{ItemKind, Path};
+use rustc_ast::{ItemKind, ModKind, Path};
 use rustc_ast_lowering::ResolverAstLowering;
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
@@ -59,6 +61,7 @@
 use smallvec::{smallvec, SmallVec};
 use std::cell::{Cell, RefCell};
 use std::collections::BTreeSet;
+use std::ops::ControlFlow;
 use std::{cmp, fmt, iter, ptr};
 use tracing::debug;
 
@@ -283,28 +286,21 @@ struct UsePlacementFinder {
 impl UsePlacementFinder {
     fn check(krate: &Crate, target_module: NodeId) -> (Option<Span>, bool) {
         let mut finder = UsePlacementFinder { target_module, span: None, found_use: false };
-        visit::walk_crate(&mut finder, krate);
+        if let ControlFlow::Continue(..) = finder.check_mod(&krate.items, CRATE_NODE_ID) {
+            visit::walk_crate(&mut finder, krate);
+        }
         (finder.span, finder.found_use)
     }
-}
 
-impl<'tcx> Visitor<'tcx> for UsePlacementFinder {
-    fn visit_mod(
-        &mut self,
-        module: &'tcx ast::Mod,
-        _: Span,
-        _: &[ast::Attribute],
-        node_id: NodeId,
-    ) {
+    fn check_mod(&mut self, items: &[P<ast::Item>], node_id: NodeId) -> ControlFlow<()> {
         if self.span.is_some() {
-            return;
+            return ControlFlow::Break(());
         }
         if node_id != self.target_module {
-            visit::walk_mod(self, module);
-            return;
+            return ControlFlow::Continue(());
         }
         // find a use statement
-        for item in &module.items {
+        for item in items {
             match item.kind {
                 ItemKind::Use(..) => {
                     // don't suggest placing a use before the prelude
@@ -312,7 +308,7 @@ fn visit_mod(
                     if !item.span.from_expansion() {
                         self.span = Some(item.span.shrink_to_lo());
                         self.found_use = true;
-                        return;
+                        return ControlFlow::Break(());
                     }
                 }
                 // don't place use before extern crate
@@ -337,6 +333,18 @@ fn visit_mod(
                 }
             }
         }
+        ControlFlow::Continue(())
+    }
+}
+
+impl<'tcx> Visitor<'tcx> for UsePlacementFinder {
+    fn visit_item(&mut self, item: &'tcx ast::Item) {
+        if let ItemKind::Mod(_, ModKind::Loaded(items, ..)) = &item.kind {
+            if let ControlFlow::Break(..) = self.check_mod(items, item.id) {
+                return;
+            }
+        }
+        visit::walk_item(self, item);
     }
 }
 
index a7ceb9e06a5192ca111f3ac9e463a0fe8eabee48..823aa61c4705daae510050eea3c1b4e6ec2af85f 100644 (file)
@@ -959,19 +959,19 @@ pub fn incr_comp_session_dir_opt(&self) -> Option<cell::Ref<'_, PathBuf>> {
     }
 
     pub fn print_perf_stats(&self) {
-        println!(
+        eprintln!(
             "Total time spent computing symbol hashes:      {}",
             duration_to_secs_str(*self.perf_stats.symbol_hash_time.lock())
         );
-        println!(
+        eprintln!(
             "Total queries canonicalized:                   {}",
             self.perf_stats.queries_canonicalized.load(Ordering::Relaxed)
         );
-        println!(
+        eprintln!(
             "normalize_generic_arg_after_erasing_regions:   {}",
             self.perf_stats.normalize_generic_arg_after_erasing_regions.load(Ordering::Relaxed)
         );
-        println!(
+        eprintln!(
             "normalize_projection_ty:                       {}",
             self.perf_stats.normalize_projection_ty.load(Ordering::Relaxed)
         );
index 298c995b1660b1320ba7b055552855c8294241a8..b7eb6d5b3790b3371f63f549f5ecde10036c9e91 100644 (file)
@@ -778,16 +778,35 @@ pub fn guess_head_span(&self, sp: Span) -> Span {
         self.span_until_char(sp, '{')
     }
 
-    /// Returns a new span representing just the start point of this span.
+    /// Returns a new span representing just the first character of the given span.
     pub fn start_point(&self, sp: Span) -> Span {
-        let pos = sp.lo().0;
-        let width = self.find_width_of_character_at_span(sp, false);
-        let corrected_start_position = pos.checked_add(width).unwrap_or(pos);
-        let end_point = BytePos(cmp::max(corrected_start_position, sp.lo().0));
-        sp.with_hi(end_point)
+        let width = {
+            let sp = sp.data();
+            let local_begin = self.lookup_byte_offset(sp.lo);
+            let start_index = local_begin.pos.to_usize();
+            let src = local_begin.sf.external_src.borrow();
+
+            let snippet = if let Some(ref src) = local_begin.sf.src {
+                Some(&src[start_index..])
+            } else if let Some(src) = src.get_source() {
+                Some(&src[start_index..])
+            } else {
+                None
+            };
+
+            match snippet {
+                None => 1,
+                Some(snippet) => match snippet.chars().next() {
+                    None => 1,
+                    Some(c) => c.len_utf8(),
+                },
+            }
+        };
+
+        sp.with_hi(BytePos(sp.lo().0 + width as u32))
     }
 
-    /// Returns a new span representing just the end point of this span.
+    /// Returns a new span representing just the last character of this span.
     pub fn end_point(&self, sp: Span) -> Span {
         let pos = sp.hi().0;
 
@@ -816,7 +835,8 @@ pub fn next_point(&self, sp: Span) -> Span {
         Span::new(BytePos(start_of_next_point), end_of_next_point, sp.ctxt())
     }
 
-    /// Finds the width of a character, either before or after the provided span.
+    /// Finds the width of the character, either before or after the end of provided span,
+    /// depending on the `forwards` parameter.
     fn find_width_of_character_at_span(&self, sp: Span, forwards: bool) -> u32 {
         let sp = sp.data();
         if sp.lo == sp.hi {
@@ -863,11 +883,9 @@ fn find_width_of_character_at_span(&self, sp: Span, forwards: bool) -> u32 {
         // We need to extend the snippet to the end of the src rather than to end_index so when
         // searching forwards for boundaries we've got somewhere to search.
         let snippet = if let Some(ref src) = local_begin.sf.src {
-            let len = src.len();
-            &src[start_index..len]
+            &src[start_index..]
         } else if let Some(src) = src.get_source() {
-            let len = src.len();
-            &src[start_index..len]
+            &src[start_index..]
         } else {
             return 1;
         };
index 3f22829b049fed28e8bed734e24abc72af3407b8..0aca677248b7291530e6f19f9b1e8e9f6ffb752a 100644 (file)
@@ -243,7 +243,7 @@ fn span_substr(
         substring: &str,
         n: usize,
     ) -> Span {
-        println!(
+        eprintln!(
             "span_substr(file={:?}/{:?}, substring={:?}, n={})",
             file.name, file.start_pos, substring, n
         );
index 8c90eeb7f3f4a9cf476636447959e426d84450cb..653d70b6cf24497ba88e61e2c4f21e238e52e08a 100644 (file)
         dropck_eyepatch,
         dropck_parametricity,
         dylib,
+        dyn_metadata,
         dyn_trait,
         edition_macro_pats,
         eh_catch_typeinfo,
         memory,
         message,
         meta,
+        metadata_type,
         min_align_of,
         min_align_of_val,
         min_const_fn,
         plugin,
         plugin_registrar,
         plugins,
+        pointee_trait,
         pointer,
         pointer_trait,
         pointer_trait_fmt,
index c5dbd3ed089613d53d79660260862cb4f86ff524..5b14795f5457cb63fdf478ea1754a411bfa62c99 100644 (file)
@@ -783,9 +783,11 @@ fn to_json(&self) -> Json {
     ("riscv32imc-unknown-none-elf", riscv32imc_unknown_none_elf),
     ("riscv32imac-unknown-none-elf", riscv32imac_unknown_none_elf),
     ("riscv32gc-unknown-linux-gnu", riscv32gc_unknown_linux_gnu),
+    ("riscv32gc-unknown-linux-musl", riscv32gc_unknown_linux_musl),
     ("riscv64imac-unknown-none-elf", riscv64imac_unknown_none_elf),
     ("riscv64gc-unknown-none-elf", riscv64gc_unknown_none_elf),
     ("riscv64gc-unknown-linux-gnu", riscv64gc_unknown_linux_gnu),
+    ("riscv64gc-unknown-linux-musl", riscv64gc_unknown_linux_musl),
 
     ("aarch64-unknown-none", aarch64_unknown_none),
     ("aarch64-unknown-none-softfloat", aarch64_unknown_none_softfloat),
diff --git a/compiler/rustc_target/src/spec/riscv32gc_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/riscv32gc_unknown_linux_musl.rs
new file mode 100644 (file)
index 0000000..e5fbd09
--- /dev/null
@@ -0,0 +1,19 @@
+use crate::spec::{CodeModel, Target, TargetOptions};
+
+pub fn target() -> Target {
+    Target {
+        llvm_target: "riscv32-unknown-linux-musl".to_string(),
+        pointer_width: 32,
+        data_layout: "e-m:e-p:32:32-i64:64-n32-S128".to_string(),
+        arch: "riscv32".to_string(),
+        options: TargetOptions {
+            unsupported_abis: super::riscv_base::unsupported_abis(),
+            code_model: Some(CodeModel::Medium),
+            cpu: "generic-rv32".to_string(),
+            features: "+m,+a,+f,+d,+c".to_string(),
+            llvm_abiname: "ilp32d".to_string(),
+            max_atomic_width: Some(32),
+            ..super::linux_musl_base::opts()
+        },
+    }
+}
diff --git a/compiler/rustc_target/src/spec/riscv64gc_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/riscv64gc_unknown_linux_musl.rs
new file mode 100644 (file)
index 0000000..0232b15
--- /dev/null
@@ -0,0 +1,19 @@
+use crate::spec::{CodeModel, Target, TargetOptions};
+
+pub fn target() -> Target {
+    Target {
+        llvm_target: "riscv64-unknown-linux-musl".to_string(),
+        pointer_width: 64,
+        data_layout: "e-m:e-p:64:64-i64:64-i128:128-n64-S128".to_string(),
+        arch: "riscv64".to_string(),
+        options: TargetOptions {
+            unsupported_abis: super::riscv_base::unsupported_abis(),
+            code_model: Some(CodeModel::Medium),
+            cpu: "generic-rv64".to_string(),
+            features: "+m,+a,+f,+d,+c".to_string(),
+            llvm_abiname: "lp64d".to_string(),
+            max_atomic_width: Some(64),
+            ..super::linux_musl_base::opts()
+        },
+    }
+}
index 05b6c4a48de1e0816a4c28b24096bb85335071bc..3f24a33f7d57074be463fb87460f02063da359e9 100644 (file)
@@ -6,7 +6,6 @@
 use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt, WithConstness};
 use rustc_middle::ty::{ToPredicate, TypeFoldable};
 use rustc_session::DiagnosticMessageId;
-use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
 
 #[derive(Copy, Clone, Debug)]
@@ -146,11 +145,10 @@ fn overloaded_deref_ty(&mut self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
         let normalized_ty = fulfillcx.normalize_projection_type(
             &self.infcx,
             self.param_env,
-            ty::ProjectionTy::from_ref_and_name(
-                tcx,
-                trait_ref,
-                Ident::with_dummy_span(sym::Target),
-            ),
+            ty::ProjectionTy {
+                item_def_id: tcx.lang_items().deref_target()?,
+                substs: trait_ref.substs,
+            },
             cause,
         );
         if let Err(e) = fulfillcx.select_where_possible(&self.infcx) {
index 6593c1000f28386cf6b36ac782310a52712113c6..97cc258d425111776644dde1ddb7e5d8916530b8 100644 (file)
@@ -77,7 +77,7 @@ pub fn find_auto_trait_generics<A>(
         ty: Ty<'tcx>,
         orig_env: ty::ParamEnv<'tcx>,
         trait_did: DefId,
-        auto_trait_callback: impl Fn(&InferCtxt<'_, 'tcx>, AutoTraitInfo<'tcx>) -> A,
+        mut auto_trait_callback: impl FnMut(&InferCtxt<'_, 'tcx>, AutoTraitInfo<'tcx>) -> A,
     ) -> AutoTraitResult<A> {
         let tcx = self.tcx;
 
index b1ac02d9fed5a0175ee2c03c9d95fefbc10c2891..8a1be7ea1726d1c957bbedf25891b6d7ce282123 100644 (file)
@@ -72,17 +72,16 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
                 // We were unable to unify the abstract constant with
                 // a constant found in the caller bounds, there are
                 // now three possible cases here.
-                //
-                // - The substs are concrete enough that we can simply
-                //   try and evaluate the given constant.
-                // - The abstract const still references an inference
-                //   variable, in this case we return `TooGeneric`.
-                // - The abstract const references a generic parameter,
-                //   this means that we emit an error here.
                 #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
                 enum FailureKind {
+                    /// The abstract const still references an inference
+                    /// variable, in this case we return `TooGeneric`.
                     MentionsInfer,
+                    /// The abstract const references a generic parameter,
+                    /// this means that we emit an error here.
                     MentionsParam,
+                    /// The substs are concrete enough that we can simply
+                    /// try and evaluate the given constant.
                     Concrete,
                 }
                 let mut failure_kind = FailureKind::Concrete;
index 3233d1e048bf735631dce46d97e32926fc619877..bfb5ebcea58b114bf58f11bf5c8d881e129c4422 100644 (file)
@@ -1368,8 +1368,8 @@ fn get_parent_trait_ref(
                     Some(t) => Some(t),
                     None => {
                         let ty = parent_trait_ref.skip_binder().self_ty();
-                        let span =
-                            TyCategory::from_ty(ty).map(|(_, def_id)| self.tcx.def_span(def_id));
+                        let span = TyCategory::from_ty(self.tcx, ty)
+                            .map(|(_, def_id)| self.tcx.def_span(def_id));
                         Some((ty.to_string(), span))
                     }
                 }
@@ -1589,8 +1589,7 @@ fn maybe_report_ambiguity(
                 self.emit_inference_failure_err(body_id, span, a.into(), vec![], ErrorCode::E0282)
             }
             ty::PredicateKind::Projection(data) => {
-                let trait_ref = bound_predicate.rebind(data).to_poly_trait_ref(self.tcx);
-                let self_ty = trait_ref.skip_binder().self_ty();
+                let self_ty = data.projection_ty.self_ty();
                 let ty = data.ty;
                 if predicate.references_error() {
                     return;
index 69f66f6e6b1aa6c0372fa04e931dce10e56e4174..e6a1cf58fe3734c6c8bc98b3ae9dee588a9e0b4b 100644 (file)
@@ -200,22 +200,15 @@ fn on_unimplemented_note(
             if let Some(def) = aty.ty_adt_def() {
                 // We also want to be able to select the array's type's original
                 // signature with no type arguments resolved
-                flags.push((
-                    sym::_Self,
-                    Some(format!("[{}]", self.tcx.type_of(def.did).to_string())),
-                ));
-                let tcx = self.tcx;
-                if let Some(len) = len.try_eval_usize(tcx, ty::ParamEnv::empty()) {
-                    flags.push((
-                        sym::_Self,
-                        Some(format!("[{}; {}]", self.tcx.type_of(def.did).to_string(), len)),
-                    ));
-                } else {
-                    flags.push((
-                        sym::_Self,
-                        Some(format!("[{}; _]", self.tcx.type_of(def.did).to_string())),
-                    ));
-                }
+                let type_string = self.tcx.type_of(def.did).to_string();
+                flags.push((sym::_Self, Some(format!("[{}]", type_string))));
+
+                let len = len.val.try_to_value().and_then(|v| v.try_to_machine_usize(self.tcx));
+                let string = match len {
+                    Some(n) => format!("[{}; {}]", type_string, n),
+                    None => format!("[{}; _]", type_string),
+                };
+                flags.push((sym::_Self, Some(string)));
             }
         }
         if let ty::Dynamic(traits, _) = self_ty.kind() {
index 9fd2f121007406337f6987f488b1e2e555243e74..5c97791530d9989a9a3a030534984cc47444b504 100644 (file)
@@ -17,8 +17,8 @@
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node};
 use rustc_middle::ty::{
-    self, suggest_constraining_type_param, AdtKind, DefIdTree, Infer, InferTy, ToPredicate, Ty,
-    TyCtxt, TypeFoldable, WithConstness,
+    self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree,
+    Infer, InferTy, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
 };
 use rustc_middle::ty::{TypeAndMut, TypeckResults};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -334,7 +334,7 @@ fn suggest_restricting_param_bound(
         let (param_ty, projection) = match self_ty.kind() {
             ty::Param(_) => (true, None),
             ty::Projection(projection) => (false, Some(projection)),
-            _ => return,
+            _ => (false, None),
         };
 
         // FIXME: Add check for trait bound that is already present, particularly `?Sized` so we
@@ -453,6 +453,26 @@ fn suggest_restricting_param_bound(
                     }
                 }
 
+                hir::Node::Item(hir::Item {
+                    kind:
+                        hir::ItemKind::Struct(_, generics)
+                        | hir::ItemKind::Enum(_, generics)
+                        | hir::ItemKind::Union(_, generics)
+                        | hir::ItemKind::Trait(_, _, generics, ..)
+                        | hir::ItemKind::Impl(hir::Impl { generics, .. })
+                        | hir::ItemKind::Fn(_, generics, _)
+                        | hir::ItemKind::TyAlias(_, generics)
+                        | hir::ItemKind::TraitAlias(generics, _)
+                        | hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. }),
+                    ..
+                }) if !param_ty => {
+                    // Missing generic type parameter bound.
+                    let param_name = self_ty.to_string();
+                    let constraint = trait_ref.print_only_trait_path().to_string();
+                    if suggest_arbitrary_trait_bound(generics, &mut err, &param_name, &constraint) {
+                        return;
+                    }
+                }
                 hir::Node::Crate(..) => return,
 
                 _ => {}
index 95f79147efd43e62ea12361b3cc746967c673bd3..3d9f98273db79099eabe4ad60c0a9c1a25b7f8dc 100644 (file)
@@ -6,6 +6,7 @@
 use rustc_infer::traits::{TraitEngine, TraitEngineExt as _, TraitObligation};
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::ty::error::ExpectedFound;
+use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::ToPredicate;
 use rustc_middle::ty::{self, Binder, Const, Ty, TypeFoldable};
 use std::marker::PhantomData;
@@ -633,9 +634,9 @@ fn process_trait_obligation(
                 // only reason we can fail to make progress on
                 // trait selection is because we don't have enough
                 // information about the types in the trait.
-                *stalled_on = trait_ref_infer_vars(
+                *stalled_on = substs_infer_vars(
                     self.selcx,
-                    trait_obligation.predicate.map_bound(|pred| pred.trait_ref),
+                    trait_obligation.predicate.map_bound(|pred| pred.trait_ref.substs),
                 );
 
                 debug!(
@@ -663,9 +664,9 @@ fn process_projection_obligation(
         match project::poly_project_and_unify_type(self.selcx, &project_obligation) {
             Ok(Ok(Some(os))) => ProcessResult::Changed(mk_pending(os)),
             Ok(Ok(None)) => {
-                *stalled_on = trait_ref_infer_vars(
+                *stalled_on = substs_infer_vars(
                     self.selcx,
-                    project_obligation.predicate.to_poly_trait_ref(tcx),
+                    project_obligation.predicate.map_bound(|pred| pred.projection_ty.substs),
                 );
                 ProcessResult::Unchanged
             }
@@ -678,16 +679,15 @@ fn process_projection_obligation(
     }
 }
 
-/// Returns the set of inference variables contained in a trait ref.
-fn trait_ref_infer_vars<'a, 'tcx>(
+/// Returns the set of inference variables contained in `substs`.
+fn substs_infer_vars<'a, 'tcx>(
     selcx: &mut SelectionContext<'a, 'tcx>,
-    trait_ref: ty::PolyTraitRef<'tcx>,
+    substs: ty::Binder<SubstsRef<'tcx>>,
 ) -> Vec<TyOrConstInferVar<'tcx>> {
     selcx
         .infcx()
-        .resolve_vars_if_possible(trait_ref)
-        .skip_binder()
-        .substs
+        .resolve_vars_if_possible(substs)
+        .skip_binder() // ok because this check doesn't care about regions
         .iter()
         // FIXME(eddyb) try using `skip_current_subtree` to skip everything that
         // doesn't contain inference variables, not just the outermost level.
index e155f0366e19f5c006ee8644ed8824949c835f4b..7de20e477fe0479769be5d14a9ecdaf44c00d2f0 100644 (file)
@@ -292,11 +292,7 @@ fn predicate_references_self(
             //
             // This is ALT2 in issue #56288, see that for discussion of the
             // possible alternatives.
-            if data.projection_ty.trait_ref(tcx).substs[1..].iter().any(has_self_ty) {
-                Some(sp)
-            } else {
-                None
-            }
+            if data.projection_ty.substs[1..].iter().any(has_self_ty) { Some(sp) } else { None }
         }
         ty::PredicateKind::WellFormed(..)
         | ty::PredicateKind::ObjectSafe(..)
index 6908480f431e6d13b5f6dbd77419fdfd1f4da030..0af6d6459159e6d10bd73a586d6fddd20d3fda4f 100644 (file)
@@ -12,7 +12,7 @@
 use super::SelectionError;
 use super::{
     ImplSourceClosureData, ImplSourceDiscriminantKindData, ImplSourceFnPointerData,
-    ImplSourceGeneratorData, ImplSourceUserDefinedData,
+    ImplSourceGeneratorData, ImplSourcePointeeData, ImplSourceUserDefinedData,
 };
 use super::{Normalized, NormalizedTy, ProjectionCacheEntry, ProjectionCacheKey};
 
@@ -741,11 +741,7 @@ fn project_type<'cx, 'tcx>(
         return Err(ProjectionTyError::TraitSelectionError(SelectionError::Overflow));
     }
 
-    let obligation_trait_ref = &obligation.predicate.trait_ref(selcx.tcx());
-
-    debug!(?obligation_trait_ref);
-
-    if obligation_trait_ref.references_error() {
+    if obligation.predicate.references_error() {
         return Ok(ProjectedTy::Progress(Progress::error(selcx.tcx())));
     }
 
@@ -754,19 +750,19 @@ fn project_type<'cx, 'tcx>(
     // Make sure that the following procedures are kept in order. ParamEnv
     // needs to be first because it has highest priority, and Select checks
     // the return value of push_candidate which assumes it's ran at last.
-    assemble_candidates_from_param_env(selcx, obligation, &obligation_trait_ref, &mut candidates);
+    assemble_candidates_from_param_env(selcx, obligation, &mut candidates);
 
-    assemble_candidates_from_trait_def(selcx, obligation, &obligation_trait_ref, &mut candidates);
+    assemble_candidates_from_trait_def(selcx, obligation, &mut candidates);
 
-    assemble_candidates_from_object_ty(selcx, obligation, &obligation_trait_ref, &mut candidates);
+    assemble_candidates_from_object_ty(selcx, obligation, &mut candidates);
 
     if let ProjectionTyCandidateSet::Single(ProjectionTyCandidate::Object(_)) = candidates {
         // Avoid normalization cycle from selection (see
         // `assemble_candidates_from_object_ty`).
         // FIXME(lazy_normalization): Lazy normalization should save us from
-        // having to do special case this.
+        // having to special case this.
     } else {
-        assemble_candidates_from_impls(selcx, obligation, &obligation_trait_ref, &mut candidates);
+        assemble_candidates_from_impls(selcx, obligation, &mut candidates);
     };
 
     match candidates {
@@ -792,14 +788,12 @@ fn project_type<'cx, 'tcx>(
 fn assemble_candidates_from_param_env<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
     obligation: &ProjectionTyObligation<'tcx>,
-    obligation_trait_ref: &ty::TraitRef<'tcx>,
     candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
 ) {
     debug!("assemble_candidates_from_param_env(..)");
     assemble_candidates_from_predicates(
         selcx,
         obligation,
-        obligation_trait_ref,
         candidate_set,
         ProjectionTyCandidate::ParamEnv,
         obligation.param_env.caller_bounds().iter(),
@@ -820,7 +814,6 @@ fn assemble_candidates_from_param_env<'cx, 'tcx>(
 fn assemble_candidates_from_trait_def<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
     obligation: &ProjectionTyObligation<'tcx>,
-    obligation_trait_ref: &ty::TraitRef<'tcx>,
     candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
 ) {
     debug!("assemble_candidates_from_trait_def(..)");
@@ -828,7 +821,7 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>(
     let tcx = selcx.tcx();
     // Check whether the self-type is itself a projection.
     // If so, extract what we know from the trait and try to come up with a good answer.
-    let bounds = match *obligation_trait_ref.self_ty().kind() {
+    let bounds = match *obligation.predicate.self_ty().kind() {
         ty::Projection(ref data) => tcx.item_bounds(data.item_def_id).subst(tcx, data.substs),
         ty::Opaque(def_id, substs) => tcx.item_bounds(def_id).subst(tcx, substs),
         ty::Infer(ty::TyVar(_)) => {
@@ -843,7 +836,6 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>(
     assemble_candidates_from_predicates(
         selcx,
         obligation,
-        obligation_trait_ref,
         candidate_set,
         ProjectionTyCandidate::TraitDef,
         bounds.iter(),
@@ -863,14 +855,13 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>(
 fn assemble_candidates_from_object_ty<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
     obligation: &ProjectionTyObligation<'tcx>,
-    obligation_trait_ref: &ty::TraitRef<'tcx>,
     candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
 ) {
     debug!("assemble_candidates_from_object_ty(..)");
 
     let tcx = selcx.tcx();
 
-    let self_ty = obligation_trait_ref.self_ty();
+    let self_ty = obligation.predicate.self_ty();
     let object_ty = selcx.infcx().shallow_resolve(self_ty);
     let data = match object_ty.kind() {
         ty::Dynamic(data, ..) => data,
@@ -890,7 +881,6 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>(
     assemble_candidates_from_predicates(
         selcx,
         obligation,
-        obligation_trait_ref,
         candidate_set,
         ProjectionTyCandidate::Object,
         env_predicates,
@@ -901,7 +891,6 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>(
 fn assemble_candidates_from_predicates<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
     obligation: &ProjectionTyObligation<'tcx>,
-    obligation_trait_ref: &ty::TraitRef<'tcx>,
     candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
     ctor: fn(ty::PolyProjectionPredicate<'tcx>) -> ProjectionTyCandidate<'tcx>,
     env_predicates: impl Iterator<Item = ty::Predicate<'tcx>>,
@@ -921,8 +910,7 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>(
                 && infcx.probe(|_| {
                     selcx.match_projection_projections(
                         obligation,
-                        obligation_trait_ref,
-                        &data,
+                        data,
                         potentially_unnormalized_candidates,
                     )
                 });
@@ -948,14 +936,13 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>(
 fn assemble_candidates_from_impls<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
     obligation: &ProjectionTyObligation<'tcx>,
-    obligation_trait_ref: &ty::TraitRef<'tcx>,
     candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
 ) {
     debug!("assemble_candidates_from_impls");
 
     // If we are resolving `<T as TraitRef<...>>::Item == Type`,
     // start out by selecting the predicate `T as TraitRef<...>`:
-    let poly_trait_ref = ty::Binder::dummy(*obligation_trait_ref);
+    let poly_trait_ref = obligation.predicate.trait_ref(selcx.tcx()).to_poly_trait_ref();
     let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate());
     let _ = selcx.infcx().commit_if_ok(|_| {
         let impl_source = match selcx.select(&trait_obligation) {
@@ -1069,6 +1056,51 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
                     | ty::Error(_) => false,
                 }
             }
+            super::ImplSource::Pointee(..) => {
+                // While `Pointee` is automatically implemented for every type,
+                // the concrete metadata type may not be known yet.
+                //
+                // Any type with multiple potential metadata types is therefore not eligible.
+                let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty());
+
+                // FIXME: should this normalize?
+                let tail = selcx.tcx().struct_tail_without_normalization(self_ty);
+                match tail.kind() {
+                    ty::Bool
+                    | ty::Char
+                    | ty::Int(_)
+                    | ty::Uint(_)
+                    | ty::Float(_)
+                    | ty::Foreign(_)
+                    | ty::Str
+                    | ty::Array(..)
+                    | ty::Slice(_)
+                    | ty::RawPtr(..)
+                    | ty::Ref(..)
+                    | ty::FnDef(..)
+                    | ty::FnPtr(..)
+                    | ty::Dynamic(..)
+                    | ty::Closure(..)
+                    | ty::Generator(..)
+                    | ty::GeneratorWitness(..)
+                    | ty::Never
+                    // If returned by `struct_tail_without_normalization` this is a unit struct
+                    // without any fields, or not a struct, and therefore is Sized.
+                    | ty::Adt(..)
+                    // If returned by `struct_tail_without_normalization` this is the empty tuple.
+                    | ty::Tuple(..)
+                    // Integers and floats are always Sized, and so have unit type metadata.
+                    | ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(..)) => true,
+
+                    ty::Projection(..)
+                    | ty::Opaque(..)
+                    | ty::Param(..)
+                    | ty::Bound(..)
+                    | ty::Placeholder(..)
+                    | ty::Infer(..)
+                    | ty::Error(_) => false,
+                }
+            }
             super::ImplSource::Param(..) => {
                 // This case tell us nothing about the value of an
                 // associated type. Consider:
@@ -1169,6 +1201,7 @@ fn confirm_select_candidate<'cx, 'tcx>(
         super::ImplSource::DiscriminantKind(data) => {
             confirm_discriminant_kind_candidate(selcx, obligation, data)
         }
+        super::ImplSource::Pointee(data) => confirm_pointee_candidate(selcx, obligation, data),
         super::ImplSource::Object(_)
         | super::ImplSource::AutoImpl(..)
         | super::ImplSource::Param(..)
@@ -1256,6 +1289,26 @@ fn confirm_discriminant_kind_candidate<'cx, 'tcx>(
     confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false)
 }
 
+fn confirm_pointee_candidate<'cx, 'tcx>(
+    selcx: &mut SelectionContext<'cx, 'tcx>,
+    obligation: &ProjectionTyObligation<'tcx>,
+    _: ImplSourcePointeeData,
+) -> Progress<'tcx> {
+    let tcx = selcx.tcx();
+
+    let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty());
+    let substs = tcx.mk_substs([self_ty.into()].iter());
+
+    let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None);
+
+    let predicate = ty::ProjectionPredicate {
+        projection_ty: ty::ProjectionTy { substs, item_def_id: metadata_def_id },
+        ty: self_ty.ptr_metadata_ty(tcx),
+    };
+
+    confirm_param_env_candidate(selcx, obligation, ty::Binder::bind(predicate), false)
+}
+
 fn confirm_fn_pointer_candidate<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
     obligation: &ProjectionTyObligation<'tcx>,
@@ -1344,25 +1397,25 @@ fn confirm_param_env_candidate<'cx, 'tcx>(
         poly_cache_entry,
     );
 
-    let cache_trait_ref = cache_entry.projection_ty.trait_ref(infcx.tcx);
-    let obligation_trait_ref = obligation.predicate.trait_ref(infcx.tcx);
+    let cache_projection = cache_entry.projection_ty;
+    let obligation_projection = obligation.predicate;
     let mut nested_obligations = Vec::new();
-    let cache_trait_ref = if potentially_unnormalized_candidate {
+    let cache_projection = if potentially_unnormalized_candidate {
         ensure_sufficient_stack(|| {
             normalize_with_depth_to(
                 selcx,
                 obligation.param_env,
                 obligation.cause.clone(),
                 obligation.recursion_depth + 1,
-                cache_trait_ref,
+                cache_projection,
                 &mut nested_obligations,
             )
         })
     } else {
-        cache_trait_ref
+        cache_projection
     };
 
-    match infcx.at(cause, param_env).eq(cache_trait_ref, obligation_trait_ref) {
+    match infcx.at(cause, param_env).eq(cache_projection, obligation_projection) {
         Ok(InferOk { value: _, obligations }) => {
             nested_obligations.extend(obligations);
             assoc_ty_own_obligations(selcx, obligation, &mut nested_obligations);
index 1688539165ab51edf36c82cefcb1290877230a6c..68356ce73aacd2866c48a704a272e25c4566ae9e 100644 (file)
@@ -43,7 +43,7 @@ fn fully_perform(
             info!("fully_perform({:?})", self);
         }
 
-        scrape_region_constraints(infcx, || Ok((self.closure)(infcx)?))
+        scrape_region_constraints(infcx, || (self.closure)(infcx))
     }
 }
 
index f09ce8d64ed5e1b5bba37d3d21b8df6d8b508dc1..752f6a8debc9ef5c064f0d937cfff2ecbf26811f 100644 (file)
@@ -267,6 +267,9 @@ pub(super) fn assemble_candidates<'o>(
         } else if lang_items.discriminant_kind_trait() == Some(def_id) {
             // `DiscriminantKind` is automatically implemented for every type.
             candidates.vec.push(DiscriminantKindCandidate);
+        } else if lang_items.pointee_trait() == Some(def_id) {
+            // `Pointee` is automatically implemented for every type.
+            candidates.vec.push(PointeeCandidate);
         } else if lang_items.sized_trait() == Some(def_id) {
             // Sized is never implementable by end-users, it is
             // always automatically computed.
index ed3e117fcfabbbb841243ddf86e5eb868862e95e..272930f6bb9cabfddca72019b2da224ee2f44222 100644 (file)
@@ -30,7 +30,8 @@
 use crate::traits::{
     ImplSourceAutoImplData, ImplSourceBuiltinData, ImplSourceClosureData,
     ImplSourceDiscriminantKindData, ImplSourceFnPointerData, ImplSourceGeneratorData,
-    ImplSourceObjectData, ImplSourceTraitAliasData, ImplSourceUserDefinedData,
+    ImplSourceObjectData, ImplSourcePointeeData, ImplSourceTraitAliasData,
+    ImplSourceUserDefinedData,
 };
 use crate::traits::{ObjectCastObligation, PredicateObligation, TraitObligation};
 use crate::traits::{Obligation, ObligationCause};
@@ -99,6 +100,8 @@ pub(super) fn confirm_candidate(
                 Ok(ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData))
             }
 
+            PointeeCandidate => Ok(ImplSource::Pointee(ImplSourcePointeeData)),
+
             TraitAliasCandidate(alias_def_id) => {
                 let data = self.confirm_trait_alias_candidate(obligation, alias_def_id);
                 Ok(ImplSource::TraitAlias(data))
index 87c8099dc3a512ef848b60b2c58937e38a13cdca..45b5aff40a6d277b6c1bbf14497c4850451922cd 100644 (file)
@@ -32,6 +32,7 @@
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::Constness;
+use rustc_infer::infer::LateBoundRegionConversionTime;
 use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::ty::fast_reject;
@@ -1254,32 +1255,33 @@ fn evaluate_where_clause<'o>(
     pub(super) fn match_projection_projections(
         &mut self,
         obligation: &ProjectionTyObligation<'tcx>,
-        obligation_trait_ref: &ty::TraitRef<'tcx>,
-        data: &PolyProjectionPredicate<'tcx>,
+        env_predicate: PolyProjectionPredicate<'tcx>,
         potentially_unnormalized_candidates: bool,
     ) -> bool {
         let mut nested_obligations = Vec::new();
-        let projection_ty = if potentially_unnormalized_candidates {
+        let (infer_predicate, _) = self.infcx.replace_bound_vars_with_fresh_vars(
+            obligation.cause.span,
+            LateBoundRegionConversionTime::HigherRankedType,
+            env_predicate,
+        );
+        let infer_projection = if potentially_unnormalized_candidates {
             ensure_sufficient_stack(|| {
                 project::normalize_with_depth_to(
                     self,
                     obligation.param_env,
                     obligation.cause.clone(),
                     obligation.recursion_depth + 1,
-                    data.map_bound(|data| data.projection_ty),
+                    infer_predicate.projection_ty,
                     &mut nested_obligations,
                 )
             })
         } else {
-            data.map_bound(|data| data.projection_ty)
+            infer_predicate.projection_ty
         };
 
-        // FIXME(generic_associated_types): Compare the whole projections
-        let data_poly_trait_ref = projection_ty.map_bound(|proj| proj.trait_ref(self.tcx()));
-        let obligation_poly_trait_ref = ty::Binder::dummy(*obligation_trait_ref);
         self.infcx
             .at(&obligation.cause, obligation.param_env)
-            .sup(obligation_poly_trait_ref, data_poly_trait_ref)
+            .sup(obligation.predicate, infer_projection)
             .map_or(false, |InferOk { obligations, value: () }| {
                 self.evaluate_predicates_recursively(
                     TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()),
@@ -1318,8 +1320,8 @@ fn candidate_should_be_dropped_in_favor_of(
         let is_global =
             |cand: &ty::PolyTraitRef<'_>| cand.is_global() && !cand.has_late_bound_regions();
 
-        // (*) Prefer `BuiltinCandidate { has_nested: false }` and `DiscriminantKindCandidate`
-        // to anything else.
+        // (*) Prefer `BuiltinCandidate { has_nested: false }`, `PointeeCandidate`,
+        // and `DiscriminantKindCandidate` to anything else.
         //
         // This is a fix for #53123 and prevents winnowing from accidentally extending the
         // lifetime of a variable.
@@ -1332,8 +1334,18 @@ fn candidate_should_be_dropped_in_favor_of(
             }
 
             // (*)
-            (BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate, _) => true,
-            (_, BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate) => false,
+            (
+                BuiltinCandidate { has_nested: false }
+                | DiscriminantKindCandidate
+                | PointeeCandidate,
+                _,
+            ) => true,
+            (
+                _,
+                BuiltinCandidate { has_nested: false }
+                | DiscriminantKindCandidate
+                | PointeeCandidate,
+            ) => false,
 
             (ParamCandidate(other), ParamCandidate(victim)) => {
                 if other.value == victim.value && victim.constness == Constness::NotConst {
index 7d3589c4b6bd870420e484f6329fb3eb31eac97b..fdf5f697e61178910b203811739878a5ad88f265 100644 (file)
@@ -779,14 +779,11 @@ fn lower_into(
         self,
         interner: &RustInterner<'tcx>,
     ) -> chalk_solve::rust_ir::AliasEqBound<RustInterner<'tcx>> {
-        let trait_ref = self.projection_ty.trait_ref(interner.tcx);
+        let (trait_ref, own_substs) = self.projection_ty.trait_ref_and_own_substs(interner.tcx);
         chalk_solve::rust_ir::AliasEqBound {
             trait_bound: trait_ref.lower_into(interner),
             associated_ty_id: chalk_ir::AssocTypeId(self.projection_ty.item_def_id),
-            parameters: self.projection_ty.substs[trait_ref.substs.len()..]
-                .iter()
-                .map(|arg| arg.lower_into(interner))
-                .collect(),
+            parameters: own_substs.iter().map(|arg| arg.lower_into(interner)).collect(),
             value: self.ty.lower_into(interner),
         }
     }
index 1cc580a198386bac4e114439725a3cb89b2d39a4..6b9d46ee0af808af559581e58e761ae3a81118b2 100644 (file)
@@ -275,7 +275,8 @@ fn resolve_associated_item<'tcx>(
         traits::ImplSource::AutoImpl(..)
         | traits::ImplSource::Param(..)
         | traits::ImplSource::TraitAlias(..)
-        | traits::ImplSource::DiscriminantKind(..) => None,
+        | traits::ImplSource::DiscriminantKind(..)
+        | traits::ImplSource::Pointee(..) => None,
     })
 }
 
index 67e37ca8d8e49560aae4aa28d436f655b6532d9d..0ea0ccaceabd46530e2e81a39ed45c8323824462 100644 (file)
@@ -6,8 +6,9 @@
 use crate::errors::AssocTypeBindingNotAllowed;
 use crate::structured_errors::{StructuredDiagnostic, WrongNumberOfGenericArgs};
 use rustc_ast::ast::ParamKindOrd;
-use rustc_errors::{struct_span_err, Applicability, ErrorReported};
+use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported};
 use rustc_hir as hir;
+use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::GenericArg;
 use rustc_middle::ty::{
@@ -43,23 +44,57 @@ fn generic_arg_mismatch_err(
             }
         }
 
+        let add_braces_suggestion = |arg: &GenericArg<'_>, err: &mut DiagnosticBuilder<'_>| {
+            let suggestions = vec![
+                (arg.span().shrink_to_lo(), String::from("{ ")),
+                (arg.span().shrink_to_hi(), String::from(" }")),
+            ];
+            err.multipart_suggestion(
+                "if this generic argument was intended as a const parameter, \
+                 surround it with braces",
+                suggestions,
+                Applicability::MaybeIncorrect,
+            );
+        };
+
         // Specific suggestion set for diagnostics
         match (arg, &param.kind) {
             (
-                GenericArg::Type(hir::Ty { kind: hir::TyKind::Path { .. }, .. }),
-                GenericParamDefKind::Const { .. },
-            ) => {
-                let suggestions = vec![
-                    (arg.span().shrink_to_lo(), String::from("{ ")),
-                    (arg.span().shrink_to_hi(), String::from(" }")),
-                ];
-                err.multipart_suggestion(
-                    "if this generic argument was intended as a const parameter, \
-                try surrounding it with braces:",
-                    suggestions,
-                    Applicability::MaybeIncorrect,
-                );
-            }
+                GenericArg::Type(hir::Ty {
+                    kind: hir::TyKind::Path(rustc_hir::QPath::Resolved(_, path)),
+                    ..
+                }),
+                GenericParamDefKind::Const,
+            ) => match path.res {
+                Res::Err => {
+                    add_braces_suggestion(arg, &mut err);
+                    err.set_primary_message(
+                        "unresolved item provided when a constant was expected",
+                    )
+                    .emit();
+                    return;
+                }
+                Res::Def(DefKind::TyParam, src_def_id) => {
+                    if let Some(param_local_id) = param.def_id.as_local() {
+                        let param_hir_id = tcx.hir().local_def_id_to_hir_id(param_local_id);
+                        let param_name = tcx.hir().ty_param_name(param_hir_id);
+                        let param_type = tcx.type_of(param.def_id);
+                        if param_type.is_suggestable() {
+                            err.span_suggestion(
+                                tcx.def_span(src_def_id),
+                                "consider changing this type paramater to a `const`-generic",
+                                format!("const {}: {}", param_name, param_type),
+                                Applicability::MaybeIncorrect,
+                            );
+                        };
+                    }
+                }
+                _ => add_braces_suggestion(arg, &mut err),
+            },
+            (
+                GenericArg::Type(hir::Ty { kind: hir::TyKind::Path(_), .. }),
+                GenericParamDefKind::Const,
+            ) => add_braces_suggestion(arg, &mut err),
             (
                 GenericArg::Type(hir::Ty { kind: hir::TyKind::Array(_, len), .. }),
                 GenericParamDefKind::Const { .. },
index 2e1fb44d3b5739b57658f19bbf65b5304aac3909..947363fc3ed081307a8787be77b6baf7211074f4 100644 (file)
@@ -985,10 +985,7 @@ fn add_predicates_for_ast_type_binding(
         //
         // We want to produce `<B as SuperTrait<i32>>::T == foo`.
 
-        debug!(
-            "add_predicates_for_ast_type_binding(hir_ref_id {:?}, trait_ref {:?}, binding {:?}, bounds {:?}",
-            hir_ref_id, trait_ref, binding, bounds
-        );
+        debug!(?hir_ref_id, ?trait_ref, ?binding, ?bounds, "add_predicates_for_ast_type_binding",);
         let tcx = self.tcx();
 
         let candidate =
@@ -1326,37 +1323,35 @@ trait here instead: `trait NewTrait: {} {{}}`",
         debug!("regular_traits: {:?}", regular_traits);
         debug!("auto_traits: {:?}", auto_traits);
 
-        // Transform a `PolyTraitRef` into a `PolyExistentialTraitRef` by
-        // removing the dummy `Self` type (`trait_object_dummy_self`).
-        let trait_ref_to_existential = |trait_ref: ty::TraitRef<'tcx>| {
-            if trait_ref.self_ty() != dummy_self {
-                // FIXME: There appears to be a missing filter on top of `expand_trait_aliases`,
-                // which picks up non-supertraits where clauses - but also, the object safety
-                // completely ignores trait aliases, which could be object safety hazards. We
-                // `delay_span_bug` here to avoid an ICE in stable even when the feature is
-                // disabled. (#66420)
-                tcx.sess.delay_span_bug(
-                    DUMMY_SP,
-                    &format!(
-                        "trait_ref_to_existential called on {:?} with non-dummy Self",
-                        trait_ref,
-                    ),
-                );
-            }
-            ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
-        };
-
         // Erase the `dummy_self` (`trait_object_dummy_self`) used above.
-        let existential_trait_refs =
-            regular_traits.iter().map(|i| i.trait_ref().map_bound(trait_ref_to_existential));
+        let existential_trait_refs = regular_traits.iter().map(|i| {
+            i.trait_ref().map_bound(|trait_ref: ty::TraitRef<'tcx>| {
+                if trait_ref.self_ty() != dummy_self {
+                    // FIXME: There appears to be a missing filter on top of `expand_trait_aliases`,
+                    // which picks up non-supertraits where clauses - but also, the object safety
+                    // completely ignores trait aliases, which could be object safety hazards. We
+                    // `delay_span_bug` here to avoid an ICE in stable even when the feature is
+                    // disabled. (#66420)
+                    tcx.sess.delay_span_bug(
+                        DUMMY_SP,
+                        &format!(
+                            "trait_ref_to_existential called on {:?} with non-dummy Self",
+                            trait_ref,
+                        ),
+                    );
+                }
+                ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
+            })
+        });
         let existential_projections = bounds.projection_bounds.iter().map(|(bound, _)| {
             bound.map_bound(|b| {
-                let trait_ref = trait_ref_to_existential(b.projection_ty.trait_ref(tcx));
-                ty::ExistentialProjection {
-                    ty: b.ty,
-                    item_def_id: b.projection_ty.item_def_id,
-                    substs: trait_ref.substs,
+                if b.projection_ty.self_ty() != dummy_self {
+                    tcx.sess.delay_span_bug(
+                        DUMMY_SP,
+                        &format!("trait_ref_to_existential called on {:?} with non-dummy Self", b),
+                    );
                 }
+                ty::ExistentialProjection::erase_self_ty(tcx, b)
             })
         });
 
@@ -1473,7 +1468,6 @@ fn find_bound_for_assoc_item(
                     }),
                     assoc_name,
                 )
-                .into_iter()
             },
             || param_name.to_string(),
             assoc_name,
index 7729df6af349dded4f5b1e2b0388ba709a44c3c8..5d7f5bf1c7b8001b06800c7de473ca09007d476a 100644 (file)
@@ -7,8 +7,9 @@
 use rustc_errors::{Applicability, ErrorReported};
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
+use rustc_hir::intravisit::Visitor;
 use rustc_hir::lang_items::LangItem;
-use rustc_hir::{ItemKind, Node};
+use rustc_hir::{def::Res, ItemKind, Node, PathSegment};
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
 use rustc_middle::ty::fold::TypeFoldable;
@@ -513,10 +514,11 @@ fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy
         }
     }
 
-    #[derive(Debug)]
     struct ProhibitOpaqueVisitor<'tcx> {
         opaque_identity_ty: Ty<'tcx>,
         generics: &'tcx ty::Generics,
+        tcx: TyCtxt<'tcx>,
+        selftys: Vec<(Span, Option<String>)>,
     }
 
     impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> {
@@ -533,6 +535,29 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         }
     }
 
+    impl Visitor<'tcx> for ProhibitOpaqueVisitor<'tcx> {
+        type Map = rustc_middle::hir::map::Map<'tcx>;
+
+        fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> {
+            hir::intravisit::NestedVisitorMap::OnlyBodies(self.tcx.hir())
+        }
+
+        fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) {
+            match arg.kind {
+                hir::TyKind::Path(hir::QPath::Resolved(None, path)) => match &path.segments {
+                    [PathSegment { res: Some(Res::SelfTy(_, impl_ref)), .. }] => {
+                        let impl_ty_name =
+                            impl_ref.map(|(def_id, _)| self.tcx.def_path_str(def_id));
+                        self.selftys.push((path.span, impl_ty_name));
+                    }
+                    _ => {}
+                },
+                _ => {}
+            }
+            hir::intravisit::walk_ty(self, arg);
+        }
+    }
+
     if let ItemKind::OpaqueTy(hir::OpaqueTy {
         origin: hir::OpaqueTyOrigin::AsyncFn | hir::OpaqueTyOrigin::FnReturn,
         ..
@@ -544,17 +569,20 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                 InternalSubsts::identity_for_item(tcx, def_id.to_def_id()),
             ),
             generics: tcx.generics_of(def_id),
+            tcx,
+            selftys: vec![],
         };
         let prohibit_opaque = tcx
             .explicit_item_bounds(def_id)
             .iter()
             .try_for_each(|(predicate, _)| predicate.visit_with(&mut visitor));
         debug!(
-            "check_opaque_for_inheriting_lifetimes: prohibit_opaque={:?}, visitor={:?}",
-            prohibit_opaque, visitor
+            "check_opaque_for_inheriting_lifetimes: prohibit_opaque={:?}, visitor.opaque_identity_ty={:?}, visitor.generics={:?}",
+            prohibit_opaque, visitor.opaque_identity_ty, visitor.generics
         );
 
         if let Some(ty) = prohibit_opaque.break_value() {
+            visitor.visit_item(&item);
             let is_async = match item.kind {
                 ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => {
                     matches!(origin, hir::OpaqueTyOrigin::AsyncFn)
@@ -571,15 +599,13 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                 if is_async { "async fn" } else { "impl Trait" },
             );
 
-            if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(span) {
-                if snippet == "Self" {
-                    err.span_suggestion(
-                        span,
-                        "consider spelling out the type instead",
-                        format!("{:?}", ty),
-                        Applicability::MaybeIncorrect,
-                    );
-                }
+            for (span, name) in visitor.selftys {
+                err.span_suggestion(
+                    span,
+                    "consider spelling out the type instead",
+                    name.unwrap_or_else(|| format!("{:?}", ty)),
+                    Applicability::MaybeIncorrect,
+                );
             }
             err.emit();
         }
index f34aaec10a9b96230cff8cdc2e9feac7ac2eb422..431e6d70ff35c7815db140bc3275daf8b7977626 100644 (file)
@@ -208,7 +208,7 @@ fn deduce_expectations_from_obligations(
             });
 
         // Even if we can't infer the full signature, we may be able to
-        // infer the kind. This can occur if there is a trait-reference
+        // infer the kind. This can occur when we elaborate a predicate
         // like `F : Fn<A>`. Note that due to subtyping we could encounter
         // many viable options, so pick the most restrictive.
         let expected_kind = self
@@ -234,11 +234,11 @@ fn deduce_sig_from_projection(
 
         debug!("deduce_sig_from_projection({:?})", projection);
 
-        let trait_ref = projection.to_poly_trait_ref(tcx);
+        let trait_def_id = projection.trait_def_id(tcx);
 
-        let is_fn = tcx.fn_trait_kind_from_lang_item(trait_ref.def_id()).is_some();
+        let is_fn = tcx.fn_trait_kind_from_lang_item(trait_def_id).is_some();
         let gen_trait = tcx.require_lang_item(LangItem::Generator, cause_span);
-        let is_gen = gen_trait == trait_ref.def_id();
+        let is_gen = gen_trait == trait_def_id;
         if !is_fn && !is_gen {
             debug!("deduce_sig_from_projection: not fn or generator");
             return None;
@@ -256,7 +256,7 @@ fn deduce_sig_from_projection(
         }
 
         let input_tys = if is_fn {
-            let arg_param_ty = trait_ref.skip_binder().substs.type_at(1);
+            let arg_param_ty = projection.skip_binder().projection_ty.substs.type_at(1);
             let arg_param_ty = self.resolve_vars_if_possible(arg_param_ty);
             debug!("deduce_sig_from_projection: arg_param_ty={:?}", arg_param_ty);
 
@@ -662,9 +662,9 @@ fn deduce_future_output_from_projection(
         };
 
         // Check that this is a projection from the `Future` trait.
-        let trait_ref = predicate.projection_ty.trait_ref(self.tcx);
+        let trait_def_id = predicate.projection_ty.trait_def_id(self.tcx);
         let future_trait = self.tcx.require_lang_item(LangItem::Future, Some(cause_span));
-        if trait_ref.def_id != future_trait {
+        if trait_def_id != future_trait {
             debug!("deduce_future_output_from_projection: not a future");
             return None;
         }
index fa09c26c800aea39927eb5e682ee6b833e554ac1..32bf0ab7e85331fe01ff02aaae4ef841cefa5ada 100644 (file)
@@ -2081,6 +2081,8 @@ fn check_expr_yield(
             }
             _ => {
                 self.tcx.sess.emit_err(YieldExprOutsideOfGenerator { span: expr.span });
+                // Avoid expressions without types during writeback (#78653).
+                self.check_expr(value);
                 self.tcx.mk_unit()
             }
         }
index 9e6c11d9dddbb30255eead05deb29b2f2db73d79..f5e9cc1efcc45d9dbc544f0dd1a9e41a41293261 100644 (file)
@@ -769,9 +769,10 @@ pub(in super::super) fn obligations_for_self_ty<'b>(
             .filter_map(move |obligation| {
                 let bound_predicate = obligation.predicate.kind();
                 match bound_predicate.skip_binder() {
-                    ty::PredicateKind::Projection(data) => {
-                        Some((bound_predicate.rebind(data).to_poly_trait_ref(self.tcx), obligation))
-                    }
+                    ty::PredicateKind::Projection(data) => Some((
+                        bound_predicate.rebind(data).required_poly_trait_ref(self.tcx),
+                        obligation,
+                    )),
                     ty::PredicateKind::Trait(data, _) => {
                         Some((bound_predicate.rebind(data).to_poly_trait_ref(), obligation))
                     }
@@ -1073,13 +1074,26 @@ pub(in super::super) fn could_remove_semicolon(
         };
         let last_expr_ty = self.node_ty(last_expr.hir_id);
         let needs_box = match (last_expr_ty.kind(), expected_ty.kind()) {
+            (ty::Opaque(last_def_id, _), ty::Opaque(exp_def_id, _))
+                if last_def_id == exp_def_id =>
+            {
+                StatementAsExpression::CorrectType
+            }
             (ty::Opaque(last_def_id, last_bounds), ty::Opaque(exp_def_id, exp_bounds)) => {
                 debug!(
                     "both opaque, likely future {:?} {:?} {:?} {:?}",
                     last_def_id, last_bounds, exp_def_id, exp_bounds
                 );
-                let last_hir_id = self.tcx.hir().local_def_id_to_hir_id(last_def_id.expect_local());
-                let exp_hir_id = self.tcx.hir().local_def_id_to_hir_id(exp_def_id.expect_local());
+
+                let (last_local_id, exp_local_id) =
+                    match (last_def_id.as_local(), exp_def_id.as_local()) {
+                        (Some(last_hir_id), Some(exp_hir_id)) => (last_hir_id, exp_hir_id),
+                        (_, _) => return None,
+                    };
+
+                let last_hir_id = self.tcx.hir().local_def_id_to_hir_id(last_local_id);
+                let exp_hir_id = self.tcx.hir().local_def_id_to_hir_id(exp_local_id);
+
                 match (
                     &self.tcx.hir().expect_item(last_hir_id).kind,
                     &self.tcx.hir().expect_item(exp_hir_id).kind,
index faa47230d3a068f5dae9404f7a771b297bc20726..721e8ec54f05f273ae53712951d84e97b97950a6 100644 (file)
@@ -23,6 +23,7 @@
 use rustc_trait_selection::traits::Obligation;
 
 use std::cmp::Ordering;
+use std::iter;
 
 use super::probe::Mode;
 use super::{CandidateSource, MethodError, NoMatchData};
@@ -389,7 +390,7 @@ pub fn report_method_error<'b>(
                             "no {} named `{}` found for {} `{}` in the current scope",
                             item_kind,
                             item_name,
-                            actual.prefix_string(),
+                            actual.prefix_string(self.tcx),
                             ty_str,
                         );
                         if let Mode::MethodCall = mode {
@@ -648,21 +649,25 @@ macro_rules! report_function {
                             ty::PredicateKind::Projection(pred) => {
                                 let pred = bound_predicate.rebind(pred);
                                 // `<Foo as Iterator>::Item = String`.
-                                let trait_ref =
-                                    pred.skip_binder().projection_ty.trait_ref(self.tcx);
-                                let assoc = self
-                                    .tcx
-                                    .associated_item(pred.skip_binder().projection_ty.item_def_id);
-                                let ty = pred.skip_binder().ty;
-                                let obligation = format!("{}::{} = {}", trait_ref, assoc.ident, ty);
-                                let quiet = format!(
-                                    "<_ as {}>::{} = {}",
-                                    trait_ref.print_only_trait_path(),
-                                    assoc.ident,
-                                    ty
+                                let projection_ty = pred.skip_binder().projection_ty;
+
+                                let substs_with_infer_self = tcx.mk_substs(
+                                    iter::once(tcx.mk_ty_var(ty::TyVid { index: 0 }).into())
+                                        .chain(projection_ty.substs.iter().skip(1)),
                                 );
-                                bound_span_label(trait_ref.self_ty(), &obligation, &quiet);
-                                Some((obligation, trait_ref.self_ty()))
+
+                                let quiet_projection_ty = ty::ProjectionTy {
+                                    substs: substs_with_infer_self,
+                                    item_def_id: projection_ty.item_def_id,
+                                };
+
+                                let ty = pred.skip_binder().ty;
+
+                                let obligation = format!("{} = {}", projection_ty, ty);
+                                let quiet = format!("{} = {}", quiet_projection_ty, ty);
+
+                                bound_span_label(projection_ty.self_ty(), &obligation, &quiet);
+                                Some((obligation, projection_ty.self_ty()))
                             }
                             ty::PredicateKind::Trait(poly_trait_ref, _) => {
                                 let p = poly_trait_ref.trait_ref;
@@ -727,7 +732,7 @@ trait bound{s}",
                             .map(|(_, path)| path)
                             .collect::<Vec<_>>()
                             .join("\n");
-                        let actual_prefix = actual.prefix_string();
+                        let actual_prefix = actual.prefix_string(self.tcx);
                         err.set_primary_message(&format!(
                             "the {item_kind} `{item_name}` exists for {actual_prefix} `{ty_str}`, but its trait bounds were not satisfied"
                         ));
@@ -1141,7 +1146,7 @@ fn suggest_traits_to_import<'b>(
                             let trait_def_ids: FxHashSet<DefId> = param
                                 .bounds
                                 .iter()
-                                .filter_map(|bound| Some(bound.trait_ref()?.trait_def_id()?))
+                                .filter_map(|bound| bound.trait_ref()?.trait_def_id())
                                 .collect();
                             if !candidates.iter().any(|t| trait_def_ids.contains(&t.def_id)) {
                                 err.span_suggestions(
index d097f863ad2f9dd8b107c1dd7af929389d6ad18a..69c09528662d37d5c2f7535679e6be9935670461 100644 (file)
@@ -180,7 +180,8 @@ fn analyze_closure(
                     debug!("seed place {:?}", place);
 
                     let upvar_id = ty::UpvarId::new(*var_hir_id, local_def_id);
-                    let capture_kind = self.init_capture_kind(capture_clause, upvar_id, span);
+                    let capture_kind =
+                        self.init_capture_kind_for_place(&place, capture_clause, upvar_id, span);
                     let fake_info = ty::CaptureInfo {
                         capture_kind_expr_id: None,
                         path_expr_id: None,
@@ -205,11 +206,8 @@ fn analyze_closure(
             // If we have an origin, store it.
             if let Some(origin) = delegate.current_origin.clone() {
                 let origin = if self.tcx.features().capture_disjoint_fields {
-                    origin
+                    (origin.0, restrict_capture_precision(origin.1))
                 } else {
-                    // FIXME(project-rfc-2229#31): Once the changes to support reborrowing are
-                    //                             made, make sure we are selecting and restricting
-                    //                             the origin correctly.
                     (origin.0, Place { projections: vec![], ..origin.1 })
                 };
 
@@ -449,7 +447,7 @@ fn compute_min_captures(
                 base => bug!("Expected upvar, found={:?}", base),
             };
 
-            let place = restrict_capture_precision(place, capture_info.capture_kind);
+            let place = restrict_capture_precision(place);
 
             let min_cap_list = match root_var_min_capture_list.get_mut(&var_hir_id) {
                 None => {
@@ -897,15 +895,24 @@ fn has_significant_drop_outside_of_captures(
         }
     }
 
-    fn init_capture_kind(
+    fn init_capture_kind_for_place(
         &self,
+        place: &Place<'tcx>,
         capture_clause: hir::CaptureBy,
         upvar_id: ty::UpvarId,
         closure_span: Span,
     ) -> ty::UpvarCapture<'tcx> {
         match capture_clause {
-            hir::CaptureBy::Value => ty::UpvarCapture::ByValue(None),
-            hir::CaptureBy::Ref => {
+            // In case of a move closure if the data is accessed through a reference we
+            // want to capture by ref to allow precise capture using reborrows.
+            //
+            // If the data will be moved out of this place, then the place will be truncated
+            // at the first Deref in `adjust_upvar_borrow_kind_for_consume` and then moved into
+            // the closure.
+            hir::CaptureBy::Value if !place.deref_tys().any(ty::TyS::is_ref) => {
+                ty::UpvarCapture::ByValue(None)
+            }
+            hir::CaptureBy::Value | hir::CaptureBy::Ref => {
                 let origin = UpvarRegion(upvar_id, closure_span);
                 let upvar_region = self.next_region_var(origin);
                 let upvar_borrow = ty::UpvarBorrow { kind: ty::ImmBorrow, region: upvar_region };
@@ -1109,12 +1116,25 @@ fn adjust_upvar_borrow_kind_for_consume(
             place_with_id, diag_expr_id, mode
         );
 
-        // we only care about moves
-        match mode {
-            euv::Copy => {
+        match (self.capture_clause, mode) {
+            // In non-move closures, we only care about moves
+            (hir::CaptureBy::Ref, euv::Copy) => return,
+
+            // We want to capture Copy types that read through a ref via a reborrow
+            (hir::CaptureBy::Value, euv::Copy)
+                if place_with_id.place.deref_tys().any(ty::TyS::is_ref) =>
+            {
                 return;
             }
-            euv::Move => {}
+
+            (hir::CaptureBy::Ref, euv::Move) | (hir::CaptureBy::Value, euv::Move | euv::Copy) => {}
+        };
+
+        let place = truncate_capture_for_move(place_with_id.place.clone());
+        let place_with_id = PlaceWithHirId { place: place.clone(), hir_id: place_with_id.hir_id };
+
+        if !self.capture_information.contains_key(&place) {
+            self.init_capture_info_for_place(&place_with_id, diag_expr_id);
         }
 
         let tcx = self.fcx.tcx;
@@ -1128,13 +1148,15 @@ fn adjust_upvar_borrow_kind_for_consume(
 
         let usage_span = tcx.hir().span(diag_expr_id);
 
-        // To move out of an upvar, this must be a FnOnce closure
-        self.adjust_closure_kind(
-            upvar_id.closure_expr_id,
-            ty::ClosureKind::FnOnce,
-            usage_span,
-            place_with_id.place.clone(),
-        );
+        if matches!(mode, euv::Move) {
+            // To move out of an upvar, this must be a FnOnce closure
+            self.adjust_closure_kind(
+                upvar_id.closure_expr_id,
+                ty::ClosureKind::FnOnce,
+                usage_span,
+                place.clone(),
+            );
+        }
 
         let capture_info = ty::CaptureInfo {
             capture_kind_expr_id: Some(diag_expr_id),
@@ -1317,8 +1339,12 @@ fn init_capture_info_for_place(
         if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base {
             assert_eq!(self.closure_def_id.expect_local(), upvar_id.closure_expr_id);
 
-            let capture_kind =
-                self.fcx.init_capture_kind(self.capture_clause, upvar_id, self.closure_span);
+            let capture_kind = self.fcx.init_capture_kind_for_place(
+                &place_with_id.place,
+                self.capture_clause,
+                upvar_id,
+                self.closure_span,
+            );
 
             let expr_id = Some(diag_expr_id);
             let capture_info = ty::CaptureInfo {
@@ -1392,15 +1418,10 @@ fn mutate(&mut self, assignee_place: &PlaceWithHirId<'tcx>, diag_expr_id: hir::H
 }
 
 /// Truncate projections so that following rules are obeyed by the captured `place`:
-///
-/// - No Derefs in move closure, this will result in value behind a reference getting moved.
 /// - No projections are applied to raw pointers, since these require unsafe blocks. We capture
 ///   them completely.
 /// - No Index projections are captured, since arrays are captured completely.
-fn restrict_capture_precision<'tcx>(
-    mut place: Place<'tcx>,
-    capture_kind: ty::UpvarCapture<'tcx>,
-) -> Place<'tcx> {
+fn restrict_capture_precision<'tcx>(mut place: Place<'tcx>) -> Place<'tcx> {
     if place.projections.is_empty() {
         // Nothing to do here
         return place;
@@ -1412,7 +1433,6 @@ fn restrict_capture_precision<'tcx>(
     }
 
     let mut truncated_length = usize::MAX;
-    let mut first_deref_projection = usize::MAX;
 
     for (i, proj) in place.projections.iter().enumerate() {
         if proj.ty.is_unsafe_ptr() {
@@ -1426,31 +1446,30 @@ fn restrict_capture_precision<'tcx>(
                 truncated_length = truncated_length.min(i);
                 break;
             }
-            ProjectionKind::Deref => {
-                // We only drop Derefs in case of move closures
-                // There might be an index projection or raw ptr ahead, so we don't stop here.
-                first_deref_projection = first_deref_projection.min(i);
-            }
+            ProjectionKind::Deref => {}
             ProjectionKind::Field(..) => {} // ignore
             ProjectionKind::Subslice => {}  // We never capture this
         }
     }
 
-    let length = place
-        .projections
-        .len()
-        .min(truncated_length)
-        // In case of capture `ByValue` we want to not capture derefs
-        .min(match capture_kind {
-            ty::UpvarCapture::ByValue(..) => first_deref_projection,
-            ty::UpvarCapture::ByRef(..) => usize::MAX,
-        });
+    let length = place.projections.len().min(truncated_length);
 
     place.projections.truncate(length);
 
     place
 }
 
+/// Truncates a place so that the resultant capture doesn't move data out of a reference
+fn truncate_capture_for_move(mut place: Place<'tcx>) -> Place<'tcx> {
+    if let Some(i) = place.projections.iter().position(|proj| proj.kind == ProjectionKind::Deref) {
+        // We only drop Derefs in case of move closures
+        // There might be an index projection or raw ptr ahead, so we don't stop here.
+        place.projections.truncate(i);
+    }
+
+    place
+}
+
 fn construct_place_string(tcx: TyCtxt<'_>, place: &Place<'tcx>) -> String {
     let variable_name = match place.base {
         PlaceBase::Upvar(upvar_id) => var_name(tcx, upvar_id.var_path.hir_id).to_string(),
index 05906817914c676ee22b02d30d27035166b9d7d1..f04782a1f442daa5fae94a903a57b473d37506da 100644 (file)
@@ -48,7 +48,20 @@ fn enforce_trait_manually_implementable(
     let did = Some(trait_def_id);
     let li = tcx.lang_items();
 
-    // Disallow *all* explicit impls of `DiscriminantKind`, `Sized` and `Unsize` for now.
+    // Disallow *all* explicit impls of `Pointee`, `DiscriminantKind`, `Sized` and `Unsize` for now.
+    if did == li.pointee_trait() {
+        let span = impl_header_span(tcx, impl_def_id);
+        struct_span_err!(
+            tcx.sess,
+            span,
+            E0322,
+            "explicit impls for the `Pointee` trait are not permitted"
+        )
+        .span_label(span, "impl of 'Pointee' not allowed")
+        .emit();
+        return;
+    }
+
     if did == li.discriminant_kind_trait() {
         let span = impl_header_span(tcx, impl_def_id);
         struct_span_err!(
index 95670b9bdb9838bfa9809c1217135609e83bc333..529de1a2874841b6055b333fb6f2a240cc0a163f 100644 (file)
@@ -198,7 +198,7 @@ pub fn setup_constraining_predicates<'tcx>(
                 //     `<<T as Bar>::Baz as Iterator>::Output = <U as Iterator>::Output`
                 // Then the projection only applies if `T` is known, but it still
                 // does not determine `U`.
-                let inputs = parameters_for(&projection.projection_ty.trait_ref(tcx), true);
+                let inputs = parameters_for(&projection.projection_ty, true);
                 let relies_only_on_inputs = inputs.iter().all(|p| input_parameters.contains(&p));
                 if !relies_only_on_inputs {
                     continue;
index f53ba98143842d5f50ca9f40918a8f9f8e6ecb8a..cd47f97496a4a8735ac3db8cf00b0bafe3afdab9 100644 (file)
@@ -673,19 +673,28 @@ fn hash<H: Hasher>(&self, state: &mut H) {
     #[stable(feature = "rust1", since = "1.0.0")]
     impl<T: ?Sized> Hash for *const T {
         fn hash<H: Hasher>(&self, state: &mut H) {
-            if mem::size_of::<Self>() == mem::size_of::<usize>() {
-                // Thin pointer
-                state.write_usize(*self as *const () as usize);
-            } else {
-                // Fat pointer
-                // SAFETY: we are accessing the memory occupied by `self`
-                // which is guaranteed to be valid.
-                // This assumes a fat pointer can be represented by a `(usize, usize)`,
-                // which is safe to do in `std` because it is shipped and kept in sync
-                // with the implementation of fat pointers in `rustc`.
-                let (a, b) = unsafe { *(self as *const Self as *const (usize, usize)) };
-                state.write_usize(a);
-                state.write_usize(b);
+            #[cfg(not(bootstrap))]
+            {
+                let (address, metadata) = self.to_raw_parts();
+                state.write_usize(address as usize);
+                metadata.hash(state);
+            }
+            #[cfg(bootstrap)]
+            {
+                if mem::size_of::<Self>() == mem::size_of::<usize>() {
+                    // Thin pointer
+                    state.write_usize(*self as *const () as usize);
+                } else {
+                    // Fat pointer
+                    // SAFETY: we are accessing the memory occupied by `self`
+                    // which is guaranteed to be valid.
+                    // This assumes a fat pointer can be represented by a `(usize, usize)`,
+                    // which is safe to do in `std` because it is shipped and kept in sync
+                    // with the implementation of fat pointers in `rustc`.
+                    let (a, b) = unsafe { *(self as *const Self as *const (usize, usize)) };
+                    state.write_usize(a);
+                    state.write_usize(b);
+                }
             }
         }
     }
@@ -693,19 +702,28 @@ fn hash<H: Hasher>(&self, state: &mut H) {
     #[stable(feature = "rust1", since = "1.0.0")]
     impl<T: ?Sized> Hash for *mut T {
         fn hash<H: Hasher>(&self, state: &mut H) {
-            if mem::size_of::<Self>() == mem::size_of::<usize>() {
-                // Thin pointer
-                state.write_usize(*self as *const () as usize);
-            } else {
-                // Fat pointer
-                // SAFETY: we are accessing the memory occupied by `self`
-                // which is guaranteed to be valid.
-                // This assumes a fat pointer can be represented by a `(usize, usize)`,
-                // which is safe to do in `std` because it is shipped and kept in sync
-                // with the implementation of fat pointers in `rustc`.
-                let (a, b) = unsafe { *(self as *const Self as *const (usize, usize)) };
-                state.write_usize(a);
-                state.write_usize(b);
+            #[cfg(not(bootstrap))]
+            {
+                let (address, metadata) = self.to_raw_parts();
+                state.write_usize(address as usize);
+                metadata.hash(state);
+            }
+            #[cfg(bootstrap)]
+            {
+                if mem::size_of::<Self>() == mem::size_of::<usize>() {
+                    // Thin pointer
+                    state.write_usize(*self as *const () as usize);
+                } else {
+                    // Fat pointer
+                    // SAFETY: we are accessing the memory occupied by `self`
+                    // which is guaranteed to be valid.
+                    // This assumes a fat pointer can be represented by a `(usize, usize)`,
+                    // which is safe to do in `std` because it is shipped and kept in sync
+                    // with the implementation of fat pointers in `rustc`.
+                    let (a, b) = unsafe { *(self as *const Self as *const (usize, usize)) };
+                    state.write_usize(a);
+                    state.write_usize(b);
+                }
             }
         }
     }
index fd4a76c1eb548e4365a40fb8bc5c165a100cbdf5..7c0e5ab8926ef731161d5cc5080d9d78ec11dd83 100644 (file)
 #![feature(extended_key_value_attributes)]
 #![feature(extern_types)]
 #![feature(fundamental)]
+#![cfg_attr(not(bootstrap), feature(intra_doc_pointers))]
 #![feature(intrinsics)]
 #![feature(lang_items)]
 #![feature(link_llvm_intrinsics)]
 #![feature(auto_traits)]
 #![feature(or_patterns)]
 #![feature(prelude_import)]
+#![cfg_attr(not(bootstrap), feature(ptr_metadata))]
 #![feature(repr_simd, platform_intrinsics)]
 #![feature(rustc_attrs)]
 #![feature(simd_ffi)]
 #![feature(stmt_expr_attributes)]
 #![feature(str_split_as_str)]
 #![feature(str_split_inclusive_as_str)]
+#![feature(trait_alias)]
 #![feature(transparent_unions)]
 #![feature(try_blocks)]
 #![feature(unboxed_closures)]
index 2766843155a0e7fb2c52622f81017ff29362ad4a..858cc3c9b014693998d9f5fc7dc47bf90cb26328 100644 (file)
@@ -80,11 +80,8 @@ pub fn parse_decimal(s: &str) -> ParseResult<'_> {
 
 /// Carves off decimal digits up to the first non-digit character.
 fn eat_digits(s: &[u8]) -> (&[u8], &[u8]) {
-    let mut i = 0;
-    while i < s.len() && b'0' <= s[i] && s[i] <= b'9' {
-        i += 1;
-    }
-    (&s[..i], &s[i..])
+    let pos = s.iter().position(|c| !c.is_ascii_digit()).unwrap_or(s.len());
+    s.split_at(pos)
 }
 
 /// Exponent extraction and error checking.
index 245152e5490d8c5e87c35f1479463985d428cce4..2419771eae212fa79ef30efdcab1fdf0d951cd6e 100644 (file)
@@ -64,6 +64,7 @@ pub trait Deref {
     /// The resulting type after dereferencing.
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_diagnostic_item = "deref_target"]
+    #[cfg_attr(not(bootstrap), lang = "deref_target")]
     type Target: ?Sized;
 
     /// Dereferences the value.
index 28de28c70e4b44883c2505052b638ba741201d57..ddff0ff67dea2e9aa57bfcda104bebcd70e647b9 100644 (file)
@@ -48,6 +48,17 @@ pub const fn cast<U>(self) -> *const U {
         self as _
     }
 
+    /// Decompose a (possibly wide) pointer into is address and metadata components.
+    ///
+    /// The pointer can be later reconstructed with [`from_raw_parts`].
+    #[cfg(not(bootstrap))]
+    #[unstable(feature = "ptr_metadata", issue = "81513")]
+    #[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")]
+    #[inline]
+    pub const fn to_raw_parts(self) -> (*const (), <T as super::Pointee>::Metadata) {
+        (self.cast(), metadata(self))
+    }
+
     /// Returns `None` if the pointer is null, or else returns a shared reference to
     /// the value wrapped in `Some`. If the value may be uninitialized, [`as_uninit_ref`]
     /// must be used instead.
@@ -905,9 +916,14 @@ impl<T> *const [T] {
     #[unstable(feature = "slice_ptr_len", issue = "71146")]
     #[rustc_const_unstable(feature = "const_slice_ptr_len", issue = "71146")]
     pub const fn len(self) -> usize {
-        // SAFETY: this is safe because `*const [T]` and `FatPtr<T>` have the same layout.
-        // Only `std` can make this guarantee.
-        unsafe { Repr { rust: self }.raw }.len
+        #[cfg(bootstrap)]
+        {
+            // SAFETY: this is safe because `*const [T]` and `FatPtr<T>` have the same layout.
+            // Only `std` can make this guarantee.
+            unsafe { Repr { rust: self }.raw }.len
+        }
+        #[cfg(not(bootstrap))]
+        metadata(self)
     }
 
     /// Returns a raw pointer to the slice's buffer.
diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs
new file mode 100644 (file)
index 0000000..7c7dce0
--- /dev/null
@@ -0,0 +1,265 @@
+#![unstable(feature = "ptr_metadata", issue = "81513")]
+
+use crate::fmt;
+use crate::hash::{Hash, Hasher};
+
+/// Provides the pointer metadata type of any pointed-to type.
+///
+/// # Pointer metadata
+///
+/// Raw pointer types and reference types in Rust can be thought of as made of two parts:
+/// a data pointer that contains the memory address of the value, and some metadata.
+///
+/// For statically-sized types (that implement the `Sized` traits)
+/// as well as for `extern` types,
+/// pointers are said to be “thin”: metadata is zero-sized and its type is `()`.
+///
+/// Pointers to [dynamically-sized types][dst] are said to be “wide” or “fat”,
+/// they have non-zero-sized metadata:
+///
+/// * For structs whose last field is a DST, metadata is the metadata for the last field
+/// * For the `str` type, metadata is the length in bytes as `usize`
+/// * For slice types like `[T]`, metadata is the length in items as `usize`
+/// * For trait objects like `dyn SomeTrait`, metadata is [`DynMetadata<Self>`][DynMetadata]
+///   (e.g. `DynMetadata<dyn SomeTrait>`)
+///
+/// In the future, the Rust language may gain new kinds of types
+/// that have different pointer metadata.
+///
+/// [dst]: https://doc.rust-lang.org/nomicon/exotic-sizes.html#dynamically-sized-types-dsts
+///
+///
+/// # The `Pointee` trait
+///
+/// The point of this trait is its `Metadata` associated type,
+/// which is `()` or `usize` or `DynMetadata<_>` as described above.
+/// It is automatically implemented for every type.
+/// It can be assumed to be implemented in a generic context, even without a corresponding bound.
+///
+///
+/// # Usage
+///
+/// Raw pointers can be decomposed into the data address and metadata components
+/// with their [`to_raw_parts`] method.
+///
+/// Alternatively, metadata alone can be extracted with the [`metadata`] function.
+/// A reference can be passed to [`metadata`] and implicitly coerced.
+///
+/// A (possibly-wide) pointer can be put back together from its address and metadata
+/// with [`from_raw_parts`] or [`from_raw_parts_mut`].
+///
+/// [`to_raw_parts`]: *const::to_raw_parts
+#[lang = "pointee_trait"]
+pub trait Pointee {
+    /// The type for metadata in pointers and references to `Self`.
+    #[lang = "metadata_type"]
+    // NOTE: Keep trait bounds in `static_assert_expected_bounds_for_metadata`
+    // in `library/core/src/ptr/metadata.rs`
+    // in sync with those here:
+    type Metadata: Copy + Send + Sync + Ord + Hash + Unpin;
+}
+
+/// Pointers to types implementing this trait alias are “thin”.
+///
+/// This includes statically-`Sized` types and `extern` types.
+///
+/// # Example
+///
+/// ```rust
+/// #![feature(ptr_metadata)]
+///
+/// fn this_never_panics<T: std::ptr::Thin>() {
+///     assert_eq!(std::mem::size_of::<&T>(), std::mem::size_of::<usize>())
+/// }
+/// ```
+#[unstable(feature = "ptr_metadata", issue = "81513")]
+// NOTE: don’t stabilize this before trait aliases are stable in the language?
+pub trait Thin = Pointee<Metadata = ()>;
+
+/// Extract the metadata component of a pointer.
+///
+/// Values of type `*mut T`, `&T`, or `&mut T` can be passed directly to this function
+/// as they implicitly coerce to `*const T`.
+///
+/// # Example
+///
+/// ```
+/// #![feature(ptr_metadata)]
+///
+/// assert_eq!(std::ptr::metadata("foo"), 3_usize);
+/// ```
+#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")]
+#[inline]
+pub const fn metadata<T: ?Sized>(ptr: *const T) -> <T as Pointee>::Metadata {
+    // SAFETY: Accessing the value from the `PtrRepr` union is safe since *const T
+    // and PtrComponents<T> have the same memory layouts. Only std can make this
+    // guarantee.
+    unsafe { PtrRepr { const_ptr: ptr }.components.metadata }
+}
+
+/// Forms a (possibly-wide) raw pointer from a data address and metadata.
+///
+/// This function is safe but the returned pointer is not necessarily safe to dereference.
+/// For slices, see the documentation of [`slice::from_raw_parts`] for safety requirements.
+/// For trait objects, the metadata must come from a pointer to the same underlying ereased type.
+///
+/// [`slice::from_raw_parts`]: crate::slice::from_raw_parts
+#[unstable(feature = "ptr_metadata", issue = "81513")]
+#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")]
+#[inline]
+pub const fn from_raw_parts<T: ?Sized>(
+    data_address: *const (),
+    metadata: <T as Pointee>::Metadata,
+) -> *const T {
+    // SAFETY: Accessing the value from the `PtrRepr` union is safe since *const T
+    // and PtrComponents<T> have the same memory layouts. Only std can make this
+    // guarantee.
+    unsafe { PtrRepr { components: PtrComponents { data_address, metadata } }.const_ptr }
+}
+
+/// Performs the same functionality as [`from_raw_parts`], except that a
+/// raw `*mut` pointer is returned, as opposed to a raw `*const` pointer.
+///
+/// See the documentation of [`from_raw_parts`] for more details.
+#[unstable(feature = "ptr_metadata", issue = "81513")]
+#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")]
+#[inline]
+pub const fn from_raw_parts_mut<T: ?Sized>(
+    data_address: *mut (),
+    metadata: <T as Pointee>::Metadata,
+) -> *mut T {
+    // SAFETY: Accessing the value from the `PtrRepr` union is safe since *const T
+    // and PtrComponents<T> have the same memory layouts. Only std can make this
+    // guarantee.
+    unsafe { PtrRepr { components: PtrComponents { data_address, metadata } }.mut_ptr }
+}
+
+#[repr(C)]
+pub(crate) union PtrRepr<T: ?Sized> {
+    pub(crate) const_ptr: *const T,
+    pub(crate) mut_ptr: *mut T,
+    pub(crate) components: PtrComponents<T>,
+}
+
+#[repr(C)]
+pub(crate) struct PtrComponents<T: ?Sized> {
+    pub(crate) data_address: *const (),
+    pub(crate) metadata: <T as Pointee>::Metadata,
+}
+
+// Manual impl needed to avoid `T: Copy` bound.
+impl<T: ?Sized> Copy for PtrComponents<T> {}
+
+// Manual impl needed to avoid `T: Clone` bound.
+impl<T: ?Sized> Clone for PtrComponents<T> {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+
+/// The metadata for a `Dyn = dyn SomeTrait` trait object type.
+///
+/// It is a pointer to a vtable (virtual call table)
+/// that represents all the necessary information
+/// to manipulate the concrete type stored inside a trait object.
+/// The vtable notably it contains:
+///
+/// * type size
+/// * type alignment
+/// * a pointer to the type’s `drop_in_place` impl (may be a no-op for plain-old-data)
+/// * pointers to all the methods for the type’s implementation of the trait
+///
+/// Note that the first three are special because they’re necessary to allocate, drop,
+/// and deallocate any trait object.
+///
+/// It is possible to name this struct with a type parameter that is not a `dyn` trait object
+/// (for example `DynMetadata<u64>`) but not to obtain a meaningful value of that struct.
+#[lang = "dyn_metadata"]
+pub struct DynMetadata<Dyn: ?Sized> {
+    vtable_ptr: &'static VTable,
+    phantom: crate::marker::PhantomData<Dyn>,
+}
+
+/// The common prefix of all vtables. It is followed by function pointers for trait methods.
+///
+/// Private implementation detail of `DynMetadata::size_of` etc.
+#[repr(C)]
+struct VTable {
+    drop_in_place: fn(*mut ()),
+    size_of: usize,
+    align_of: usize,
+}
+
+impl<Dyn: ?Sized> DynMetadata<Dyn> {
+    /// Returns the size of the type associated with this vtable.
+    #[inline]
+    pub fn size_of(self) -> usize {
+        self.vtable_ptr.size_of
+    }
+
+    /// Returns the alignment of the type associated with this vtable.
+    #[inline]
+    pub fn align_of(self) -> usize {
+        self.vtable_ptr.align_of
+    }
+
+    /// Returns the size and alignment together as a `Layout`
+    #[inline]
+    pub fn layout(self) -> crate::alloc::Layout {
+        // SAFETY: the compiler emitted this vtable for a concrete Rust type which
+        // is known to have a valid layout. Same rationale as in `Layout::for_value`.
+        unsafe { crate::alloc::Layout::from_size_align_unchecked(self.size_of(), self.align_of()) }
+    }
+}
+
+unsafe impl<Dyn: ?Sized> Send for DynMetadata<Dyn> {}
+unsafe impl<Dyn: ?Sized> Sync for DynMetadata<Dyn> {}
+
+impl<Dyn: ?Sized> fmt::Debug for DynMetadata<Dyn> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_tuple("DynMetadata").field(&(self.vtable_ptr as *const VTable)).finish()
+    }
+}
+
+// Manual impls needed to avoid `Dyn: $Trait` bounds.
+
+impl<Dyn: ?Sized> Unpin for DynMetadata<Dyn> {}
+
+impl<Dyn: ?Sized> Copy for DynMetadata<Dyn> {}
+
+impl<Dyn: ?Sized> Clone for DynMetadata<Dyn> {
+    #[inline]
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+
+impl<Dyn: ?Sized> Eq for DynMetadata<Dyn> {}
+
+impl<Dyn: ?Sized> PartialEq for DynMetadata<Dyn> {
+    #[inline]
+    fn eq(&self, other: &Self) -> bool {
+        crate::ptr::eq::<VTable>(self.vtable_ptr, other.vtable_ptr)
+    }
+}
+
+impl<Dyn: ?Sized> Ord for DynMetadata<Dyn> {
+    #[inline]
+    fn cmp(&self, other: &Self) -> crate::cmp::Ordering {
+        (self.vtable_ptr as *const VTable).cmp(&(other.vtable_ptr as *const VTable))
+    }
+}
+
+impl<Dyn: ?Sized> PartialOrd for DynMetadata<Dyn> {
+    #[inline]
+    fn partial_cmp(&self, other: &Self) -> Option<crate::cmp::Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+impl<Dyn: ?Sized> Hash for DynMetadata<Dyn> {
+    #[inline]
+    fn hash<H: Hasher>(&self, hasher: &mut H) {
+        crate::ptr::hash::<VTable, _>(self.vtable_ptr, hasher)
+    }
+}
index f71233e7c32b9e8e3ba35e329cacd9ef4b5f3369..9c53430ce3556319da81f9619f757ca3f9e63956 100644 (file)
 #[doc(inline)]
 pub use crate::intrinsics::write_bytes;
 
+#[cfg(not(bootstrap))]
+mod metadata;
+#[cfg(not(bootstrap))]
+pub(crate) use metadata::PtrRepr;
+#[cfg(not(bootstrap))]
+#[unstable(feature = "ptr_metadata", issue = "81513")]
+pub use metadata::{from_raw_parts, from_raw_parts_mut, metadata, DynMetadata, Pointee, Thin};
+
 mod non_null;
 #[stable(feature = "nonnull", since = "1.25.0")]
 pub use non_null::NonNull;
@@ -220,6 +228,7 @@ pub const fn null_mut<T>() -> *mut T {
     0 as *mut T
 }
 
+#[cfg(bootstrap)]
 #[repr(C)]
 pub(crate) union Repr<T> {
     pub(crate) rust: *const [T],
@@ -227,12 +236,14 @@ pub(crate) union Repr<T> {
     pub(crate) raw: FatPtr<T>,
 }
 
+#[cfg(bootstrap)]
 #[repr(C)]
 pub(crate) struct FatPtr<T> {
     data: *const T,
     pub(crate) len: usize,
 }
 
+#[cfg(bootstrap)]
 // Manual impl needed to avoid `T: Clone` bound.
 impl<T> Clone for FatPtr<T> {
     fn clone(&self) -> Self {
@@ -240,6 +251,7 @@ fn clone(&self) -> Self {
     }
 }
 
+#[cfg(bootstrap)]
 // Manual impl needed to avoid `T: Copy` bound.
 impl<T> Copy for FatPtr<T> {}
 
@@ -267,10 +279,15 @@ impl<T> Copy for FatPtr<T> {}
 #[stable(feature = "slice_from_raw_parts", since = "1.42.0")]
 #[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "67456")]
 pub const fn slice_from_raw_parts<T>(data: *const T, len: usize) -> *const [T] {
-    // SAFETY: Accessing the value from the `Repr` union is safe since *const [T]
-    // and FatPtr have the same memory layouts. Only std can make this
-    // guarantee.
-    unsafe { Repr { raw: FatPtr { data, len } }.rust }
+    #[cfg(bootstrap)]
+    {
+        // SAFETY: Accessing the value from the `Repr` union is safe since *const [T]
+        // and FatPtr have the same memory layouts. Only std can make this
+        // guarantee.
+        unsafe { Repr { raw: FatPtr { data, len } }.rust }
+    }
+    #[cfg(not(bootstrap))]
+    from_raw_parts(data.cast(), len)
 }
 
 /// Performs the same functionality as [`slice_from_raw_parts`], except that a
@@ -302,9 +319,14 @@ pub const fn slice_from_raw_parts<T>(data: *const T, len: usize) -> *const [T] {
 #[stable(feature = "slice_from_raw_parts", since = "1.42.0")]
 #[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "67456")]
 pub const fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T] {
-    // SAFETY: Accessing the value from the `Repr` union is safe since *mut [T]
-    // and FatPtr have the same memory layouts
-    unsafe { Repr { raw: FatPtr { data, len } }.rust_mut }
+    #[cfg(bootstrap)]
+    {
+        // SAFETY: Accessing the value from the `Repr` union is safe since *mut [T]
+        // and FatPtr have the same memory layouts
+        unsafe { Repr { raw: FatPtr { data, len } }.rust_mut }
+    }
+    #[cfg(not(bootstrap))]
+    from_raw_parts_mut(data.cast(), len)
 }
 
 /// Swaps the values at two mutable locations of the same type, without
index 99744fc7112165711a418af92a38521a9d0c7345..6651c3dd4e86bd90dd2657870f548f4c918411fb 100644 (file)
@@ -47,6 +47,17 @@ pub const fn cast<U>(self) -> *mut U {
         self as _
     }
 
+    /// Decompose a (possibly wide) pointer into is address and metadata components.
+    ///
+    /// The pointer can be later reconstructed with [`from_raw_parts_mut`].
+    #[cfg(not(bootstrap))]
+    #[unstable(feature = "ptr_metadata", issue = "81513")]
+    #[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")]
+    #[inline]
+    pub const fn to_raw_parts(self) -> (*mut (), <T as super::Pointee>::Metadata) {
+        (self.cast(), super::metadata(self))
+    }
+
     /// Returns `None` if the pointer is null, or else returns a shared reference to
     /// the value wrapped in `Some`. If the value may be uninitialized, [`as_uninit_ref`]
     /// must be used instead.
@@ -1162,9 +1173,14 @@ impl<T> *mut [T] {
     #[unstable(feature = "slice_ptr_len", issue = "71146")]
     #[rustc_const_unstable(feature = "const_slice_ptr_len", issue = "71146")]
     pub const fn len(self) -> usize {
-        // SAFETY: this is safe because `*const [T]` and `FatPtr<T>` have the same layout.
-        // Only `std` can make this guarantee.
-        unsafe { Repr { rust_mut: self }.raw }.len
+        #[cfg(bootstrap)]
+        {
+            // SAFETY: this is safe because `*const [T]` and `FatPtr<T>` have the same layout.
+            // Only `std` can make this guarantee.
+            unsafe { Repr { rust_mut: self }.raw }.len
+        }
+        #[cfg(not(bootstrap))]
+        metadata(self)
     }
 
     /// Returns a raw pointer to the slice's buffer.
index e45fefc7ed7657f1c3e0f949d97ed58a46f626ce..709c247f2961466138e8e7bf2ef8dc9d595b38dc 100644 (file)
@@ -175,6 +175,37 @@ pub fn new(ptr: *mut T) -> Option<Self> {
         }
     }
 
+    /// Performs the same functionality as [`std::ptr::from_raw_parts`], except that a
+    /// `NonNull` pointer is returned, as opposed to a raw `*const` pointer.
+    ///
+    /// See the documentation of [`std::ptr::from_raw_parts`] for more details.
+    ///
+    /// [`std::ptr::from_raw_parts`]: crate::ptr::from_raw_parts
+    #[cfg(not(bootstrap))]
+    #[unstable(feature = "ptr_metadata", issue = "81513")]
+    #[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")]
+    #[inline]
+    pub const fn from_raw_parts(
+        data_address: NonNull<()>,
+        metadata: <T as super::Pointee>::Metadata,
+    ) -> NonNull<T> {
+        // SAFETY: The result of `ptr::from::raw_parts_mut` is non-null because `data_address` is.
+        unsafe {
+            NonNull::new_unchecked(super::from_raw_parts_mut(data_address.as_ptr(), metadata))
+        }
+    }
+
+    /// Decompose a (possibly wide) pointer into is address and metadata components.
+    ///
+    /// The pointer can be later reconstructed with [`NonNull::from_raw_parts`].
+    #[cfg(not(bootstrap))]
+    #[unstable(feature = "ptr_metadata", issue = "81513")]
+    #[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")]
+    #[inline]
+    pub const fn to_raw_parts(self) -> (NonNull<()>, <T as super::Pointee>::Metadata) {
+        (self.cast(), super::metadata(self.as_ptr()))
+    }
+
     /// Acquires the underlying `*mut` pointer.
     #[stable(feature = "nonnull", since = "1.25.0")]
     #[rustc_const_stable(feature = "const_nonnull_as_ptr", since = "1.32.0")]
index a43ba5882edcd704bbeabf6ca730eb3e2221631e..d8747f8b8d6dcb4900af1f98325333cc47cf8586 100644 (file)
@@ -1276,6 +1276,41 @@ pub fn flatten(self) -> Result<T, E> {
     }
 }
 
+impl<T> Result<T, T> {
+    /// Returns the [`Ok`] value if `self` is `Ok`, and the [`Err`] value if
+    /// `self` is `Err`.
+    ///
+    /// In other words, this function returns the value (the `T`) of a
+    /// `Result<T, T>`, regardless of whether or not that result is `Ok` or
+    /// `Err`.
+    ///
+    /// This can be useful in conjunction with APIs such as
+    /// [`Atomic*::compare_exchange`], or [`slice::binary_search`][binary_search], but only in
+    /// cases where you don't care if the result was `Ok` or not.
+    ///
+    /// [`Atomic*::compare_exchange`]: crate::sync::atomic::AtomicBool::compare_exchange
+    /// [binary_search]: ../../std/primitive.slice.html#method.binary_search
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(result_into_ok_or_err)]
+    /// let ok: Result<u32, u32> = Ok(3);
+    /// let err: Result<u32, u32> = Err(4);
+    ///
+    /// assert_eq!(ok.into_ok_or_err(), 3);
+    /// assert_eq!(err.into_ok_or_err(), 4);
+    /// ```
+    #[inline]
+    #[unstable(feature = "result_into_ok_or_err", reason = "newly added", issue = "82223")]
+    pub const fn into_ok_or_err(self) -> T {
+        match self {
+            Ok(v) => v,
+            Err(v) => v,
+        }
+    }
+}
+
 // This is a separate function to reduce the code size of the methods
 #[inline(never)]
 #[cold]
index a6929e462e7f069ca35730712b3d0cada9934096..1c1b9e0b27e2558a8bc53e2b13a0da1f119572c4 100644 (file)
@@ -94,9 +94,23 @@ impl<T> [T] {
     // SAFETY: const sound because we transmute out the length field as a usize (which it must be)
     #[rustc_allow_const_fn_unstable(const_fn_union)]
     pub const fn len(&self) -> usize {
-        // SAFETY: this is safe because `&[T]` and `FatPtr<T>` have the same layout.
-        // Only `std` can make this guarantee.
-        unsafe { crate::ptr::Repr { rust: self }.raw.len }
+        #[cfg(bootstrap)]
+        {
+            // SAFETY: this is safe because `&[T]` and `FatPtr<T>` have the same layout.
+            // Only `std` can make this guarantee.
+            unsafe { crate::ptr::Repr { rust: self }.raw.len }
+        }
+        #[cfg(not(bootstrap))]
+        {
+            // FIXME: Replace with `crate::ptr::metadata(self)` when that is const-stable.
+            // As of this writing this causes a "Const-stable functions can only call other
+            // const-stable functions" error.
+
+            // SAFETY: Accessing the value from the `PtrRepr` union is safe since *const T
+            // and PtrComponents<T> have the same memory layouts. Only std can make this
+            // guarantee.
+            unsafe { crate::ptr::PtrRepr { const_ptr: self }.components.metadata }
+        }
     }
 
     /// Returns `true` if the slice has a length of 0.
index 2d1e4496aeef7496cad65c4b2c429ef348fa3306..b735957666fc52b8d4a35235fc8cc22d2b532a02 100644 (file)
@@ -59,6 +59,26 @@ fn uint_xor() {
     assert_eq!(x.load(SeqCst), 0xf731 ^ 0x137f);
 }
 
+#[test]
+#[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins
+fn uint_min() {
+    let x = AtomicUsize::new(0xf731);
+    assert_eq!(x.fetch_min(0x137f, SeqCst), 0xf731);
+    assert_eq!(x.load(SeqCst), 0x137f);
+    assert_eq!(x.fetch_min(0xf731, SeqCst), 0x137f);
+    assert_eq!(x.load(SeqCst), 0x137f);
+}
+
+#[test]
+#[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins
+fn uint_max() {
+    let x = AtomicUsize::new(0x137f);
+    assert_eq!(x.fetch_max(0xf731, SeqCst), 0x137f);
+    assert_eq!(x.load(SeqCst), 0xf731);
+    assert_eq!(x.fetch_max(0x137f, SeqCst), 0xf731);
+    assert_eq!(x.load(SeqCst), 0xf731);
+}
+
 #[test]
 fn int_and() {
     let x = AtomicIsize::new(0xf731);
@@ -87,6 +107,26 @@ fn int_xor() {
     assert_eq!(x.load(SeqCst), 0xf731 ^ 0x137f);
 }
 
+#[test]
+#[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins
+fn int_min() {
+    let x = AtomicIsize::new(0xf731);
+    assert_eq!(x.fetch_min(0x137f, SeqCst), 0xf731);
+    assert_eq!(x.load(SeqCst), 0x137f);
+    assert_eq!(x.fetch_min(0xf731, SeqCst), 0x137f);
+    assert_eq!(x.load(SeqCst), 0x137f);
+}
+
+#[test]
+#[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins
+fn int_max() {
+    let x = AtomicIsize::new(0x137f);
+    assert_eq!(x.fetch_max(0xf731, SeqCst), 0x137f);
+    assert_eq!(x.load(SeqCst), 0xf731);
+    assert_eq!(x.fetch_max(0x137f, SeqCst), 0xf731);
+    assert_eq!(x.load(SeqCst), 0xf731);
+}
+
 static S_FALSE: AtomicBool = AtomicBool::new(false);
 static S_TRUE: AtomicBool = AtomicBool::new(true);
 static S_INT: AtomicIsize = AtomicIsize::new(0);
index 40dc6473b7d4088358dae9738faa12a71eabb95e..12182accc471a0eb191f2687efbfba91745c0130 100644 (file)
@@ -27,6 +27,7 @@
 #![feature(duration_saturating_ops)]
 #![feature(duration_zero)]
 #![feature(exact_size_is_empty)]
+#![feature(extern_types)]
 #![feature(fixed_size_array)]
 #![feature(flt2dec)]
 #![feature(fmt_internals)]
 #![feature(never_type)]
 #![feature(unwrap_infallible)]
 #![feature(option_result_unwrap_unchecked)]
+#![feature(result_into_ok_or_err)]
 #![feature(option_unwrap_none)]
 #![feature(peekable_peek_mut)]
+#![cfg_attr(not(bootstrap), feature(ptr_metadata))]
 #![feature(once_cell)]
 #![feature(unsafe_block_in_unsafe_fn)]
+#![feature(unsized_tuple_coercion)]
 #![feature(int_bits_const)]
 #![feature(nonzero_leading_trailing_zeros)]
 #![feature(const_option)]
@@ -76,6 +80,7 @@
 #![feature(slice_group_by)]
 #![feature(trusted_random_access)]
 #![deny(unsafe_op_in_unsafe_fn)]
+#![cfg_attr(not(bootstrap), feature(unsize))]
 
 extern crate test;
 
index 57c2fb06c16dd2d3e298cb3b4a1475cc78bc4354..224a58e3ccdb7bcc81f2c80a29155c6ca571a4b9 100644 (file)
@@ -1,5 +1,9 @@
 use core::cell::RefCell;
+#[cfg(not(bootstrap))]
+use core::ptr;
 use core::ptr::*;
+#[cfg(not(bootstrap))]
+use std::fmt::{Debug, Display};
 
 #[test]
 fn test_const_from_raw_parts() {
@@ -413,3 +417,253 @@ fn offset_from() {
         assert_eq!(ptr2.offset(-2), ptr1);
     }
 }
+
+#[test]
+#[cfg(not(bootstrap))]
+fn ptr_metadata() {
+    struct Unit;
+    struct Pair<A, B: ?Sized>(A, B);
+    extern "C" {
+        type Extern;
+    }
+    let () = metadata(&());
+    let () = metadata(&Unit);
+    let () = metadata(&4_u32);
+    let () = metadata(&String::new());
+    let () = metadata(&Some(4_u32));
+    let () = metadata(&ptr_metadata);
+    let () = metadata(&|| {});
+    let () = metadata(&[4, 7]);
+    let () = metadata(&(4, String::new()));
+    let () = metadata(&Pair(4, String::new()));
+    let () = metadata(0 as *const Extern);
+    let () = metadata(0 as *const <&u32 as std::ops::Deref>::Target);
+
+    assert_eq!(metadata("foo"), 3_usize);
+    assert_eq!(metadata(&[4, 7][..]), 2_usize);
+
+    let dst_tuple: &(bool, [u8]) = &(true, [0x66, 0x6F, 0x6F]);
+    let dst_struct: &Pair<bool, [u8]> = &Pair(true, [0x66, 0x6F, 0x6F]);
+    assert_eq!(metadata(dst_tuple), 3_usize);
+    assert_eq!(metadata(dst_struct), 3_usize);
+    unsafe {
+        let dst_tuple: &(bool, str) = std::mem::transmute(dst_tuple);
+        let dst_struct: &Pair<bool, str> = std::mem::transmute(dst_struct);
+        assert_eq!(&dst_tuple.1, "foo");
+        assert_eq!(&dst_struct.1, "foo");
+        assert_eq!(metadata(dst_tuple), 3_usize);
+        assert_eq!(metadata(dst_struct), 3_usize);
+    }
+
+    let vtable_1: DynMetadata<dyn Debug> = metadata(&4_u16 as &dyn Debug);
+    let vtable_2: DynMetadata<dyn Display> = metadata(&4_u16 as &dyn Display);
+    let vtable_3: DynMetadata<dyn Display> = metadata(&4_u32 as &dyn Display);
+    let vtable_4: DynMetadata<dyn Display> = metadata(&(true, 7_u32) as &(bool, dyn Display));
+    let vtable_5: DynMetadata<dyn Display> =
+        metadata(&Pair(true, 7_u32) as &Pair<bool, dyn Display>);
+    unsafe {
+        let address_1: usize = std::mem::transmute(vtable_1);
+        let address_2: usize = std::mem::transmute(vtable_2);
+        let address_3: usize = std::mem::transmute(vtable_3);
+        let address_4: usize = std::mem::transmute(vtable_4);
+        let address_5: usize = std::mem::transmute(vtable_5);
+        // Different trait => different vtable pointer
+        assert_ne!(address_1, address_2);
+        // Different erased type => different vtable pointer
+        assert_ne!(address_2, address_3);
+        // Same erased type and same trait => same vtable pointer
+        assert_eq!(address_3, address_4);
+        assert_eq!(address_3, address_5);
+    }
+}
+
+#[test]
+#[cfg(not(bootstrap))]
+fn ptr_metadata_bounds() {
+    fn metadata_eq_method_address<T: ?Sized>() -> usize {
+        // The `Metadata` associated type has an `Ord` bound, so this is valid:
+        <<T as Pointee>::Metadata as PartialEq>::eq as usize
+    }
+    // "Synthetic" trait impls generated by the compiler like those of `Pointee`
+    // are not checked for bounds of associated type.
+    // So with a buggy libcore we could have both:
+    // * `<dyn Display as Pointee>::Metadata == DynMetadata`
+    // * `DynMetadata: !PartialEq`
+    // … and cause an ICE here:
+    metadata_eq_method_address::<dyn Display>();
+
+    // For this reason, let’s check here that bounds are satisfied:
+
+    let _ = static_assert_expected_bounds_for_metadata::<()>;
+    let _ = static_assert_expected_bounds_for_metadata::<usize>;
+    let _ = static_assert_expected_bounds_for_metadata::<DynMetadata<dyn Display>>;
+    fn _static_assert_associated_type<T: ?Sized>() {
+        let _ = static_assert_expected_bounds_for_metadata::<<T as Pointee>::Metadata>;
+    }
+
+    fn static_assert_expected_bounds_for_metadata<Meta>()
+    where
+        // Keep this in sync with the associated type in `library/core/src/ptr/metadata.rs`
+        Meta: Copy + Send + Sync + Ord + std::hash::Hash + Unpin,
+    {
+    }
+}
+
+#[test]
+#[cfg(not(bootstrap))]
+fn dyn_metadata() {
+    #[derive(Debug)]
+    #[repr(align(32))]
+    struct Something([u8; 47]);
+
+    let value = Something([0; 47]);
+    let trait_object: &dyn Debug = &value;
+    let meta = metadata(trait_object);
+
+    assert_eq!(meta.size_of(), 64);
+    assert_eq!(meta.size_of(), std::mem::size_of::<Something>());
+    assert_eq!(meta.align_of(), 32);
+    assert_eq!(meta.align_of(), std::mem::align_of::<Something>());
+    assert_eq!(meta.layout(), std::alloc::Layout::new::<Something>());
+
+    assert!(format!("{:?}", meta).starts_with("DynMetadata(0x"));
+}
+
+#[test]
+#[cfg(not(bootstrap))]
+fn from_raw_parts() {
+    let mut value = 5_u32;
+    let address = &mut value as *mut _ as *mut ();
+    let trait_object: &dyn Display = &mut value;
+    let vtable = metadata(trait_object);
+    let trait_object = NonNull::from(trait_object);
+
+    assert_eq!(ptr::from_raw_parts(address, vtable), trait_object.as_ptr());
+    assert_eq!(ptr::from_raw_parts_mut(address, vtable), trait_object.as_ptr());
+    assert_eq!(NonNull::from_raw_parts(NonNull::new(address).unwrap(), vtable), trait_object);
+
+    let mut array = [5_u32, 5, 5, 5, 5];
+    let address = &mut array as *mut _ as *mut ();
+    let array_ptr = NonNull::from(&mut array);
+    let slice_ptr = NonNull::from(&mut array[..]);
+
+    assert_eq!(ptr::from_raw_parts(address, ()), array_ptr.as_ptr());
+    assert_eq!(ptr::from_raw_parts_mut(address, ()), array_ptr.as_ptr());
+    assert_eq!(NonNull::from_raw_parts(NonNull::new(address).unwrap(), ()), array_ptr);
+
+    assert_eq!(ptr::from_raw_parts(address, 5), slice_ptr.as_ptr());
+    assert_eq!(ptr::from_raw_parts_mut(address, 5), slice_ptr.as_ptr());
+    assert_eq!(NonNull::from_raw_parts(NonNull::new(address).unwrap(), 5), slice_ptr);
+}
+
+#[test]
+#[cfg(not(bootstrap))]
+fn thin_box() {
+    let foo = ThinBox::<dyn Display>::new(4);
+    assert_eq!(foo.to_string(), "4");
+    drop(foo);
+    let bar = ThinBox::<dyn Display>::new(7);
+    assert_eq!(bar.to_string(), "7");
+
+    // A slightly more interesting library that could be built on top of metadata APIs.
+    //
+    // * It could be generalized to any `T: ?Sized` (not just trait object)
+    //   if `{size,align}_of_for_meta<T: ?Sized>(T::Metadata)` are added.
+    // * Constructing a `ThinBox` without consuming and deallocating a `Box`
+    //   requires either the unstable `Unsize` marker trait,
+    //   or the unstable `unsized_locals` language feature,
+    //   or taking `&dyn T` and restricting to `T: Copy`.
+
+    use std::alloc::*;
+    use std::marker::PhantomData;
+
+    struct ThinBox<T>
+    where
+        T: ?Sized + Pointee<Metadata = DynMetadata<T>>,
+    {
+        ptr: NonNull<DynMetadata<T>>,
+        phantom: PhantomData<T>,
+    }
+
+    impl<T> ThinBox<T>
+    where
+        T: ?Sized + Pointee<Metadata = DynMetadata<T>>,
+    {
+        pub fn new<Value: std::marker::Unsize<T>>(value: Value) -> Self {
+            let unsized_: &T = &value;
+            let meta = metadata(unsized_);
+            let meta_layout = Layout::for_value(&meta);
+            let value_layout = Layout::for_value(&value);
+            let (layout, offset) = meta_layout.extend(value_layout).unwrap();
+            // `DynMetadata` is pointer-sized:
+            assert!(layout.size() > 0);
+            // If `ThinBox<T>` is generalized to any `T: ?Sized`,
+            // handle ZSTs with a dangling pointer without going through `alloc()`,
+            // like `Box<T>` does.
+            unsafe {
+                let ptr = NonNull::new(alloc(layout))
+                    .unwrap_or_else(|| handle_alloc_error(layout))
+                    .cast::<DynMetadata<T>>();
+                ptr.as_ptr().write(meta);
+                ptr.cast::<u8>().as_ptr().add(offset).cast::<Value>().write(value);
+                Self { ptr, phantom: PhantomData }
+            }
+        }
+
+        fn meta(&self) -> DynMetadata<T> {
+            unsafe { *self.ptr.as_ref() }
+        }
+
+        fn layout(&self) -> (Layout, usize) {
+            let meta = self.meta();
+            Layout::for_value(&meta).extend(meta.layout()).unwrap()
+        }
+
+        fn value_ptr(&self) -> *const T {
+            let (_, offset) = self.layout();
+            let data_ptr = unsafe { self.ptr.cast::<u8>().as_ptr().add(offset) };
+            ptr::from_raw_parts(data_ptr.cast(), self.meta())
+        }
+
+        fn value_mut_ptr(&mut self) -> *mut T {
+            let (_, offset) = self.layout();
+            // FIXME: can this line be shared with the same in `value_ptr()`
+            // without upsetting Stacked Borrows?
+            let data_ptr = unsafe { self.ptr.cast::<u8>().as_ptr().add(offset) };
+            from_raw_parts_mut(data_ptr.cast(), self.meta())
+        }
+    }
+
+    impl<T> std::ops::Deref for ThinBox<T>
+    where
+        T: ?Sized + Pointee<Metadata = DynMetadata<T>>,
+    {
+        type Target = T;
+
+        fn deref(&self) -> &T {
+            unsafe { &*self.value_ptr() }
+        }
+    }
+
+    impl<T> std::ops::DerefMut for ThinBox<T>
+    where
+        T: ?Sized + Pointee<Metadata = DynMetadata<T>>,
+    {
+        fn deref_mut(&mut self) -> &mut T {
+            unsafe { &mut *self.value_mut_ptr() }
+        }
+    }
+
+    impl<T> std::ops::Drop for ThinBox<T>
+    where
+        T: ?Sized + Pointee<Metadata = DynMetadata<T>>,
+    {
+        fn drop(&mut self) {
+            let (layout, _) = self.layout();
+            unsafe {
+                drop_in_place::<T>(&mut **self);
+                dealloc(self.ptr.cast().as_ptr(), layout);
+            }
+        }
+    }
+}
index 7aa44c6e593b3f6fa8a9807df30d420cdde98412..5fcd7b4d3a3273d6427104d10edf8b7a8c659f08 100644 (file)
@@ -95,6 +95,15 @@ fn test_unwrap_or() {
     assert_eq!(ok_err.unwrap_or(50), 50);
 }
 
+#[test]
+fn test_ok_or_err() {
+    let ok: Result<isize, isize> = Ok(100);
+    let err: Result<isize, isize> = Err(200);
+
+    assert_eq!(ok.into_ok_or_err(), 100);
+    assert_eq!(err.into_ok_or_err(), 200);
+}
+
 #[test]
 fn test_unwrap_or_else() {
     fn handler(msg: &'static str) -> isize {
index a89e7b53e43c4fbc1c0b06cad12a16fd58b458eb..5f1f7d8cac418f89481ca5049fb320068c141ded 100644 (file)
@@ -842,13 +842,20 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     }
 }
 
-#[stable(feature = "proc_macro_punct_eq", since = "1.49.0")]
+#[stable(feature = "proc_macro_punct_eq", since = "1.50.0")]
 impl PartialEq<char> for Punct {
     fn eq(&self, rhs: &char) -> bool {
         self.as_char() == *rhs
     }
 }
 
+#[stable(feature = "proc_macro_punct_eq_flipped", since = "1.52.0")]
+impl PartialEq<Punct> for char {
+    fn eq(&self, rhs: &Punct) -> bool {
+        *self == rhs.as_char()
+    }
+}
+
 /// An identifier (`ident`).
 #[derive(Clone)]
 #[stable(feature = "proc_macro_lib2", since = "1.29.0")]
index 80933f6de3d729c72a32a7882f688a3349b64b5c..d1f9049c8fabbb9dcee67a72748c74a9718ae290 100644 (file)
@@ -231,7 +231,7 @@ pub struct Stdin {
     inner: &'static Mutex<BufReader<StdinRaw>>,
 }
 
-/// A locked reference to the `Stdin` handle.
+/// A locked reference to the [`Stdin`] handle.
 ///
 /// This handle implements both the [`Read`] and [`BufRead`] traits, and
 /// is constructed via the [`Stdin::lock`] method.
@@ -494,7 +494,7 @@ pub struct Stdout {
     inner: Pin<&'static ReentrantMutex<RefCell<LineWriter<StdoutRaw>>>>,
 }
 
-/// A locked reference to the `Stdout` handle.
+/// A locked reference to the [`Stdout`] handle.
 ///
 /// This handle implements the [`Write`] trait, and is constructed via
 /// the [`Stdout::lock`] method.
@@ -708,9 +708,9 @@ pub struct Stderr {
     inner: Pin<&'static ReentrantMutex<RefCell<StderrRaw>>>,
 }
 
-/// A locked reference to the `Stderr` handle.
+/// A locked reference to the [`Stderr`] handle.
 ///
-/// This handle implements the `Write` trait and is constructed via
+/// This handle implements the [`Write`] trait and is constructed via
 /// the [`Stderr::lock`] method.
 ///
 /// ### Note: Windows Portability Consideration
index bc9b47029417d312ee6da89eac9b19bf17187b28..16733b7ccd3537262156b610df39330f462ad6e2 100644 (file)
 #![feature(int_error_matching)]
 #![feature(integer_atomics)]
 #![feature(into_future)]
+#![cfg_attr(not(bootstrap), feature(intra_doc_pointers))]
 #![feature(lang_items)]
 #![feature(link_args)]
 #![feature(linkage)]
index a01ebb316e886a4989258c605456a61130d86118..ab61618dc7d7bb92fb5ad805b9f81d068a1c852c 100644 (file)
@@ -219,6 +219,26 @@ pub fn new(t: T) -> Mutex<T> {
             data: UnsafeCell::new(t),
         }
     }
+
+    /// Immediately drops the guard, and consequently unlocks the mutex.
+    ///
+    /// This function is equivalent to calling [`drop`] on the guard but is more self-documenting.
+    /// Alternately, the guard will be automatically dropped when it goes out of scope.
+    ///
+    /// ```
+    /// #![feature(mutex_unlock)]
+    ///
+    /// use std::sync::Mutex;
+    /// let mutex = Mutex::new(0);
+    ///
+    /// let mut guard = mutex.lock().unwrap();
+    /// *guard += 20;
+    /// Mutex::unlock(guard);
+    /// ```
+    #[unstable(feature = "mutex_unlock", issue = "81872")]
+    pub fn unlock(guard: MutexGuard<'_, T>) {
+        drop(guard);
+    }
 }
 
 impl<T: ?Sized> Mutex<T> {
index 3d680a7f2d94fed6f01c9375bbcfea71034bd1f4..67412e1677937b7afea82a624d6f13581bade34b 100644 (file)
@@ -105,6 +105,22 @@ pub trait CommandExt: Sealed {
     /// [1]: https://docs.microsoft.com/en-us/windows/win32/procthread/process-creation-flags
     #[stable(feature = "windows_process_extensions", since = "1.16.0")]
     fn creation_flags(&mut self, flags: u32) -> &mut process::Command;
+
+    /// Forces all arguments to be wrapped in quote (`"`) characters.
+    ///
+    /// This is useful for passing arguments to [MSYS2/Cygwin][1] based
+    /// executables: these programs will expand unquoted arguments containing
+    /// wildcard characters (`?` and `*`) by searching for any file paths
+    /// matching the wildcard pattern.
+    ///
+    /// Adding quotes has no effect when passing arguments to programs
+    /// that use [msvcrt][2]. This includes programs built with both
+    /// MinGW and MSVC.
+    ///
+    /// [1]: <https://github.com/msys2/MSYS2-packages/issues/2176>
+    /// [2]: <https://msdn.microsoft.com/en-us/library/17w5ykft.aspx>
+    #[unstable(feature = "windows_process_extensions_force_quotes", issue = "82227")]
+    fn force_quotes(&mut self, enabled: bool) -> &mut process::Command;
 }
 
 #[stable(feature = "windows_process_extensions", since = "1.16.0")]
@@ -113,4 +129,9 @@ fn creation_flags(&mut self, flags: u32) -> &mut process::Command {
         self.as_inner_mut().creation_flags(flags);
         self
     }
+
+    fn force_quotes(&mut self, enabled: bool) -> &mut process::Command {
+        self.as_inner_mut().force_quotes(enabled);
+        self
+    }
 }
index 243065b94b125419d17dcc7b4aa5d47bf03728db..83d37795ee5c10bf4099a561cfe3ce6427ced88a 100644 (file)
@@ -78,6 +78,7 @@ pub struct Command {
     stdin: Option<Stdio>,
     stdout: Option<Stdio>,
     stderr: Option<Stdio>,
+    force_quotes_enabled: bool,
 }
 
 pub enum Stdio {
@@ -109,6 +110,7 @@ pub fn new(program: &OsStr) -> Command {
             stdin: None,
             stdout: None,
             stderr: None,
+            force_quotes_enabled: false,
         }
     }
 
@@ -134,6 +136,10 @@ pub fn creation_flags(&mut self, flags: u32) {
         self.flags = flags;
     }
 
+    pub fn force_quotes(&mut self, enabled: bool) {
+        self.force_quotes_enabled = enabled;
+    }
+
     pub fn get_program(&self) -> &OsStr {
         &self.program
     }
@@ -181,7 +187,7 @@ pub fn spawn(
         si.dwFlags = c::STARTF_USESTDHANDLES;
 
         let program = program.as_ref().unwrap_or(&self.program);
-        let mut cmd_str = make_command_line(program, &self.args)?;
+        let mut cmd_str = make_command_line(program, &self.args, self.force_quotes_enabled)?;
         cmd_str.push(0); // add null terminator
 
         // stolen from the libuv code.
@@ -467,7 +473,7 @@ fn zeroed_process_information() -> c::PROCESS_INFORMATION {
 
 // 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: &OsStr, args: &[OsString]) -> io::Result<Vec<u16>> {
+fn make_command_line(prog: &OsStr, args: &[OsString], 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();
@@ -476,7 +482,7 @@ fn make_command_line(prog: &OsStr, args: &[OsString]) -> io::Result<Vec<u16>> {
     append_arg(&mut cmd, prog, true)?;
     for arg in args {
         cmd.push(' ' as u16);
-        append_arg(&mut cmd, arg, false)?;
+        append_arg(&mut cmd, arg, force_quotes)?;
     }
     return Ok(cmd);
 
index 81627ad139bb9035541c5a226c8ea7e49ed77b3a..8830ae049c65d8b10e690ab770b1ba78debb827d 100644 (file)
@@ -3,29 +3,41 @@
 
 #[test]
 fn test_make_command_line() {
-    fn test_wrapper(prog: &str, args: &[&str]) -> String {
+    fn test_wrapper(prog: &str, args: &[&str], force_quotes: bool) -> String {
         let command_line = &make_command_line(
             OsStr::new(prog),
             &args.iter().map(|a| OsString::from(a)).collect::<Vec<OsString>>(),
+            force_quotes,
         )
         .unwrap();
         String::from_utf16(command_line).unwrap()
     }
 
-    assert_eq!(test_wrapper("prog", &["aaa", "bbb", "ccc"]), "\"prog\" aaa bbb ccc");
+    assert_eq!(test_wrapper("prog", &["aaa", "bbb", "ccc"], false), "\"prog\" aaa bbb ccc");
 
     assert_eq!(
-        test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa"]),
+        test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa"], false),
         "\"C:\\Program Files\\blah\\blah.exe\" aaa"
     );
     assert_eq!(
-        test_wrapper("C:\\Program Files\\test", &["aa\"bb"]),
+        test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa", "v*"], false),
+        "\"C:\\Program Files\\blah\\blah.exe\" aaa v*"
+    );
+    assert_eq!(
+        test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa", "v*"], true),
+        "\"C:\\Program Files\\blah\\blah.exe\" \"aaa\" \"v*\""
+    );
+    assert_eq!(
+        test_wrapper("C:\\Program Files\\test", &["aa\"bb"], false),
         "\"C:\\Program Files\\test\" aa\\\"bb"
     );
-    assert_eq!(test_wrapper("echo", &["a b c"]), "\"echo\" \"a b c\"");
-    assert_eq!(test_wrapper("echo", &["\" \\\" \\", "\\"]), "\"echo\" \"\\\" \\\\\\\" \\\\\" \\");
+    assert_eq!(test_wrapper("echo", &["a b c"], false), "\"echo\" \"a b c\"");
+    assert_eq!(
+        test_wrapper("echo", &["\" \\\" \\", "\\"], false),
+        "\"echo\" \"\\\" \\\\\\\" \\\\\" \\"
+    );
     assert_eq!(
-        test_wrapper("\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}", &[]),
+        test_wrapper("\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}", &[], false),
         "\"\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}\""
     );
 }
index c38a8c965be6137829a31bc4df8e7c133e5448cd..f9e65be9b0d40028ebfaff37963020756274b9f0 100644 (file)
@@ -353,12 +353,13 @@ fn calc_timeout(timeout_queue: &VecDeque<TimeoutEntry>) -> Option<Duration> {
             }
 
             let mut completed_test = res.unwrap();
-            let running_test = running_tests.remove(&completed_test.desc).unwrap();
-            if let Some(join_handle) = running_test.join_handle {
-                if let Err(_) = join_handle.join() {
-                    if let TrOk = completed_test.result {
-                        completed_test.result =
-                            TrFailedMsg("panicked after reporting success".to_string());
+            if let Some(running_test) = running_tests.remove(&completed_test.desc) {
+                if let Some(join_handle) = running_test.join_handle {
+                    if let Err(_) = join_handle.join() {
+                        if let TrOk = completed_test.result {
+                            completed_test.result =
+                                TrFailedMsg("panicked after reporting success".to_string());
+                        }
                     }
                 }
             }
@@ -506,7 +507,18 @@ fn run_test_inner(
         let supports_threads = !cfg!(target_os = "emscripten") && !cfg!(target_arch = "wasm32");
         if concurrency == Concurrent::Yes && supports_threads {
             let cfg = thread::Builder::new().name(name.as_slice().to_owned());
-            Some(cfg.spawn(runtest).unwrap())
+            let mut runtest = Arc::new(Mutex::new(Some(runtest)));
+            let runtest2 = runtest.clone();
+            match cfg.spawn(move || runtest2.lock().unwrap().take().unwrap()()) {
+                Ok(handle) => Some(handle),
+                Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
+                    // `ErrorKind::WouldBlock` means hitting the thread limit on some
+                    // platforms, so run the test synchronously here instead.
+                    Arc::get_mut(&mut runtest).unwrap().get_mut().unwrap().take().unwrap()();
+                    None
+                }
+                Err(e) => panic!("failed to spawn thread to run test: {}", e),
+            }
         } else {
             runtest();
             None
index a32a4a7fe56c2814bbd781340287fa0f5c23a1c9..e730a2557e0bf38fd1f7a961b059c25c34c85a9b 100644 (file)
@@ -22,7 +22,10 @@ fn main() {
     let suggest_setup = !config.config.exists() && !matches!(config.cmd, Subcommand::Setup { .. });
     if suggest_setup {
         println!("warning: you have not made a `config.toml`");
-        println!("help: consider running `x.py setup` or copying `config.toml.example`");
+        println!(
+            "help: consider running `./x.py setup` or copying `config.toml.example` by running \
+            `cp config.toml.example config.toml`"
+        );
     } else if let Some(suggestion) = &changelog_suggestion {
         println!("{}", suggestion);
     }
@@ -31,7 +34,10 @@ fn main() {
 
     if suggest_setup {
         println!("warning: you have not made a `config.toml`");
-        println!("help: consider running `x.py setup` or copying `config.toml.example`");
+        println!(
+            "help: consider running `./x.py setup` or copying `config.toml.example` by running \
+            `cp config.toml.example config.toml`"
+        );
     } else if let Some(suggestion) = &changelog_suggestion {
         println!("{}", suggestion);
     }
index dee0c154201362f89c5f052033115188e24cd822..7d5e3d05b11facb56677a513a0eb94c55117bb86 100644 (file)
@@ -27,7 +27,7 @@
 use crate::dist;
 use crate::native;
 use crate::tool::SourceType;
-use crate::util::{exe, is_dylib, symlink_dir};
+use crate::util::{exe, is_debug_info, is_dylib, symlink_dir};
 use crate::{Compiler, DependencyType, GitRepo, Mode};
 
 #[derive(Debug, PartialOrd, Ord, Copy, Clone, PartialEq, Eq, Hash)]
@@ -1049,7 +1049,8 @@ fn run(self, builder: &Builder<'_>) -> Compiler {
         let src_libdir = builder.sysroot_libdir(build_compiler, host);
         for f in builder.read_dir(&src_libdir) {
             let filename = f.file_name().into_string().unwrap();
-            if is_dylib(&filename) && !proc_macros.contains(&filename) {
+            if (is_dylib(&filename) || is_debug_info(&filename)) && !proc_macros.contains(&filename)
+            {
                 builder.copy(&f.path(), &rustc_libdir.join(&filename));
             }
         }
@@ -1166,6 +1167,7 @@ pub fn run_cargo(
             if !(filename.ends_with(".rlib")
                 || filename.ends_with(".lib")
                 || filename.ends_with(".a")
+                || is_debug_info(&filename)
                 || is_dylib(&filename)
                 || (is_check && filename.ends_with(".rmeta")))
             {
index 22124ec67f5f3373d74c270da4edaf7ff1431f0f..b427420d577959f9e80cec4e5dc3d119c8df24c3 100644 (file)
@@ -53,7 +53,7 @@ fn install_sh(
 }
 
 fn default_path(config: &Option<PathBuf>, default: &str) -> PathBuf {
-    PathBuf::from(config.as_ref().cloned().unwrap_or_else(|| PathBuf::from(default)))
+    config.as_ref().cloned().unwrap_or_else(|| PathBuf::from(default))
 }
 
 fn prepare_dir(mut path: PathBuf) -> String {
index b35d1b99fa5c70f1642c01f75d37cb042e2c97c0..b4421a82714fcebd01bd65a7ed8ac9c70aa2215b 100644 (file)
@@ -32,6 +32,12 @@ pub fn is_dylib(name: &str) -> bool {
     name.ends_with(".dylib") || name.ends_with(".so") || name.ends_with(".dll")
 }
 
+/// Returns `true` if the file name given looks like a debug info file
+pub fn is_debug_info(name: &str) -> bool {
+    // FIXME: consider split debug info on other platforms (e.g., Linux, macOS)
+    name.ends_with(".pdb")
+}
+
 /// Returns the corresponding relative library directory that the compiler's
 /// dylibs will be found in.
 pub fn libdir(target: TargetSelection) -> &'static str {
index eb740419647013fd47c343eb44a39ef020827a13..8198dbaa5278caa63c87b3cfef2ea70669a0682a 100644 (file)
@@ -204,7 +204,9 @@ target | std | host | notes
 `powerpc64-unknown-linux-musl` | ? |  |
 `powerpc64-wrs-vxworks` | ? |  |
 `powerpc64le-unknown-linux-musl` | ? |  |
+`riscv64gc-unknown-linux-musl` |   |   | RISC-V Linux (kernel 4.20, musl 1.2.0)
 `riscv32gc-unknown-linux-gnu` |   |   | RISC-V Linux (kernel 5.4, glibc 2.33)
+`riscv32gc-unknown-linux-musl` |   |   | RISC-V Linux (kernel 5.4, musl + RISCV32 support patches)
 `sparc-unknown-linux-gnu` | ✓ |  | 32-bit SPARC Linux
 `sparc64-unknown-netbsd` | ✓ | ✓ | NetBSD/sparc64
 `sparc64-unknown-openbsd` | ? |  |
index 80f7851debfbd7a163d1e2e8f6bb667e1b499514..0302fbecb6ed09ca0ba63a2771cad70715c16a6d 100644 (file)
@@ -422,3 +422,10 @@ $ rustdoc src/lib.rs --crate-version 1.3.37
 When `rustdoc` receives this flag, it will print an extra "Version (version)" into the sidebar of
 the crate root's docs. You can use this flag to differentiate between different versions of your
 library's documentation.
+
+## `@path`: load command-line flags from a path
+
+If you specify `@path` on the command-line, then it will open `path` and read
+command line options from it. These options are one per line; a blank line indicates
+an empty option. The file can use Unix or Windows style line endings, and must be
+encoded as UTF-8.
index 83114a72b8d5aea6add71f235f0740f9a836d1e9..711b0298565d7f7d3f34f8065c363e31ab0ba1cc 100644 (file)
@@ -21,130 +21,144 @@ struct RegionDeps<'tcx> {
 }
 
 crate struct AutoTraitFinder<'a, 'tcx> {
-    crate cx: &'a core::DocContext<'tcx>,
-    crate f: auto_trait::AutoTraitFinder<'tcx>,
+    crate cx: &'a mut core::DocContext<'tcx>,
 }
 
 impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
-    crate fn new(cx: &'a core::DocContext<'tcx>) -> Self {
-        let f = auto_trait::AutoTraitFinder::new(cx.tcx);
+    crate fn new(cx: &'a mut core::DocContext<'tcx>) -> Self {
+        AutoTraitFinder { cx }
+    }
+
+    fn generate_for_trait(
+        &mut self,
+        ty: Ty<'tcx>,
+        trait_def_id: DefId,
+        param_env: ty::ParamEnv<'tcx>,
+        param_env_def_id: DefId,
+        f: &auto_trait::AutoTraitFinder<'tcx>,
+        // If this is set, show only negative trait implementations, not positive ones.
+        discard_positive_impl: bool,
+    ) -> Option<Item> {
+        let tcx = self.cx.tcx;
+        let trait_ref = ty::TraitRef { def_id: trait_def_id, substs: tcx.mk_substs_trait(ty, &[]) };
+        if !self.cx.generated_synthetics.borrow_mut().insert((ty, trait_def_id)) {
+            debug!("get_auto_trait_impl_for({:?}): already generated, aborting", trait_ref);
+            return None;
+        }
+
+        let result = f.find_auto_trait_generics(ty, param_env, trait_def_id, |infcx, info| {
+            let region_data = info.region_data;
+
+            let names_map = tcx
+                .generics_of(param_env_def_id)
+                .params
+                .iter()
+                .filter_map(|param| match param.kind {
+                    ty::GenericParamDefKind::Lifetime => Some(param.name),
+                    _ => None,
+                })
+                .map(|name| (name, Lifetime(name)))
+                .collect();
+            let lifetime_predicates = Self::handle_lifetimes(&region_data, &names_map);
+            let new_generics = self.param_env_to_generics(
+                infcx.tcx,
+                param_env_def_id,
+                info.full_user_env,
+                lifetime_predicates,
+                info.vid_to_region,
+            );
+
+            debug!(
+                "find_auto_trait_generics(param_env_def_id={:?}, trait_def_id={:?}): \
+                    finished with {:?}",
+                param_env_def_id, trait_def_id, new_generics
+            );
+
+            new_generics
+        });
+
+        let negative_polarity;
+        let new_generics = match result {
+            AutoTraitResult::PositiveImpl(new_generics) => {
+                negative_polarity = false;
+                if discard_positive_impl {
+                    return None;
+                }
+                new_generics
+            }
+            AutoTraitResult::NegativeImpl => {
+                negative_polarity = true;
+
+                // For negative impls, we use the generic params, but *not* the predicates,
+                // from the original type. Otherwise, the displayed impl appears to be a
+                // conditional negative impl, when it's really unconditional.
+                //
+                // For example, consider the struct Foo<T: Copy>(*mut T). Using
+                // the original predicates in our impl would cause us to generate
+                // `impl !Send for Foo<T: Copy>`, which makes it appear that Foo
+                // implements Send where T is not copy.
+                //
+                // Instead, we generate `impl !Send for Foo<T>`, which better
+                // expresses the fact that `Foo<T>` never implements `Send`,
+                // regardless of the choice of `T`.
+                let params = (tcx.generics_of(param_env_def_id), ty::GenericPredicates::default())
+                    .clean(self.cx)
+                    .params;
+
+                Generics { params, where_predicates: Vec::new() }
+            }
+            AutoTraitResult::ExplicitImpl => return None,
+        };
 
-        AutoTraitFinder { cx, f }
+        Some(Item {
+            source: Span::dummy(),
+            name: None,
+            attrs: Default::default(),
+            visibility: Inherited,
+            def_id: self.cx.next_def_id(param_env_def_id.krate),
+            kind: box ImplItem(Impl {
+                unsafety: hir::Unsafety::Normal,
+                generics: new_generics,
+                provided_trait_methods: Default::default(),
+                trait_: Some(trait_ref.clean(self.cx).get_trait_type().unwrap()),
+                for_: ty.clean(self.cx),
+                items: Vec::new(),
+                negative_polarity,
+                synthetic: true,
+                blanket_impl: None,
+            }),
+        })
     }
 
     // FIXME(eddyb) figure out a better way to pass information about
     // parametrization of `ty` than `param_env_def_id`.
-    crate fn get_auto_trait_impls(&self, ty: Ty<'tcx>, param_env_def_id: DefId) -> Vec<Item> {
-        let param_env = self.cx.tcx.param_env(param_env_def_id);
+    crate fn get_auto_trait_impls(&mut self, ty: Ty<'tcx>, param_env_def_id: DefId) -> Vec<Item> {
+        let tcx = self.cx.tcx;
+        let param_env = tcx.param_env(param_env_def_id);
+        let f = auto_trait::AutoTraitFinder::new(self.cx.tcx);
 
         debug!("get_auto_trait_impls({:?})", ty);
-        let auto_traits = self.cx.auto_traits.iter().cloned();
-        auto_traits
+        let auto_traits: Vec<_> = self.cx.auto_traits.iter().cloned().collect();
+        let mut auto_traits: Vec<Item> = auto_traits
+            .into_iter()
             .filter_map(|trait_def_id| {
-                let trait_ref = ty::TraitRef {
-                    def_id: trait_def_id,
-                    substs: self.cx.tcx.mk_substs_trait(ty, &[]),
-                };
-                if !self.cx.generated_synthetics.borrow_mut().insert((ty, trait_def_id)) {
-                    debug!("get_auto_trait_impl_for({:?}): already generated, aborting", trait_ref);
-                    return None;
-                }
-
-                let result =
-                    self.f.find_auto_trait_generics(ty, param_env, trait_def_id, |infcx, info| {
-                        let region_data = info.region_data;
-
-                        let names_map = self
-                            .cx
-                            .tcx
-                            .generics_of(param_env_def_id)
-                            .params
-                            .iter()
-                            .filter_map(|param| match param.kind {
-                                ty::GenericParamDefKind::Lifetime => Some(param.name),
-                                _ => None,
-                            })
-                            .map(|name| (name, Lifetime(name)))
-                            .collect();
-                        let lifetime_predicates = self.handle_lifetimes(&region_data, &names_map);
-                        let new_generics = self.param_env_to_generics(
-                            infcx.tcx,
-                            param_env_def_id,
-                            info.full_user_env,
-                            lifetime_predicates,
-                            info.vid_to_region,
-                        );
-
-                        debug!(
-                            "find_auto_trait_generics(param_env_def_id={:?}, trait_def_id={:?}): \
-                            finished with {:?}",
-                            param_env_def_id, trait_def_id, new_generics
-                        );
-
-                        new_generics
-                    });
-
-                let negative_polarity;
-                let new_generics = match result {
-                    AutoTraitResult::PositiveImpl(new_generics) => {
-                        negative_polarity = false;
-                        new_generics
-                    }
-                    AutoTraitResult::NegativeImpl => {
-                        negative_polarity = true;
-
-                        // For negative impls, we use the generic params, but *not* the predicates,
-                        // from the original type. Otherwise, the displayed impl appears to be a
-                        // conditional negative impl, when it's really unconditional.
-                        //
-                        // For example, consider the struct Foo<T: Copy>(*mut T). Using
-                        // the original predicates in our impl would cause us to generate
-                        // `impl !Send for Foo<T: Copy>`, which makes it appear that Foo
-                        // implements Send where T is not copy.
-                        //
-                        // Instead, we generate `impl !Send for Foo<T>`, which better
-                        // expresses the fact that `Foo<T>` never implements `Send`,
-                        // regardless of the choice of `T`.
-                        let params = (
-                            self.cx.tcx.generics_of(param_env_def_id),
-                            ty::GenericPredicates::default(),
-                        )
-                            .clean(self.cx)
-                            .params;
-
-                        Generics { params, where_predicates: Vec::new() }
-                    }
-                    AutoTraitResult::ExplicitImpl => return None,
-                };
-
-                Some(Item {
-                    source: Span::dummy(),
-                    name: None,
-                    attrs: Default::default(),
-                    visibility: Inherited,
-                    def_id: self.cx.next_def_id(param_env_def_id.krate),
-                    kind: box ImplItem(Impl {
-                        unsafety: hir::Unsafety::Normal,
-                        generics: new_generics,
-                        provided_trait_methods: Default::default(),
-                        trait_: Some(trait_ref.clean(self.cx).get_trait_type().unwrap()),
-                        for_: ty.clean(self.cx),
-                        items: Vec::new(),
-                        negative_polarity,
-                        synthetic: true,
-                        blanket_impl: None,
-                    }),
-                })
+                self.generate_for_trait(ty, trait_def_id, param_env, param_env_def_id, &f, false)
             })
-            .collect()
+            .collect();
+        // We are only interested in case the type *doesn't* implement the Sized trait.
+        if !ty.is_sized(self.cx.tcx.at(rustc_span::DUMMY_SP), param_env) {
+            // In case `#![no_core]` is used, `sized_trait` returns nothing.
+            if let Some(item) = self.cx.tcx.lang_items().sized_trait().and_then(|sized_trait_did| {
+                self.generate_for_trait(ty, sized_trait_did, param_env, param_env_def_id, &f, true)
+            }) {
+                auto_traits.push(item);
+            }
+        }
+        auto_traits
     }
 
-    fn get_lifetime(
-        &self,
-        region: Region<'_>,
-        names_map: &FxHashMap<Symbol, Lifetime>,
-    ) -> Lifetime {
-        self.region_name(region)
+    fn get_lifetime(region: Region<'_>, names_map: &FxHashMap<Symbol, Lifetime>) -> Lifetime {
+        region_name(region)
             .map(|name| {
                 names_map.get(&name).unwrap_or_else(|| {
                     panic!("Missing lifetime with name {:?} for {:?}", name.as_str(), region)
@@ -154,13 +168,6 @@ fn get_lifetime(
             .clone()
     }
 
-    fn region_name(&self, region: Region<'_>) -> Option<Symbol> {
-        match region {
-            &ty::ReEarlyBound(r) => Some(r.name),
-            _ => None,
-        }
-    }
-
     // This method calculates two things: Lifetime constraints of the form 'a: 'b,
     // and region constraints of the form ReVar: 'a
     //
@@ -172,7 +179,6 @@ fn region_name(&self, region: Region<'_>) -> Option<Symbol> {
     // to perform the calculations we need on our own, rather than trying to make
     // existing inference/solver code do what we want.
     fn handle_lifetimes<'cx>(
-        &self,
         regions: &RegionConstraintData<'cx>,
         names_map: &FxHashMap<Symbol, Lifetime>,
     ) -> Vec<WherePredicate> {
@@ -210,9 +216,9 @@ fn handle_lifetimes<'cx>(
                 &Constraint::RegSubReg(r1, r2) => {
                     // The constraint is already in the form that we want, so we're done with it
                     // Desired order is 'larger, smaller', so flip then
-                    if self.region_name(r1) != self.region_name(r2) {
+                    if region_name(r1) != region_name(r2) {
                         finished
-                            .entry(self.region_name(r2).expect("no region_name found"))
+                            .entry(region_name(r2).expect("no region_name found"))
                             .or_default()
                             .push(r1);
                     }
@@ -245,9 +251,9 @@ fn handle_lifetimes<'cx>(
                 for larger in deps.larger.iter() {
                     match (smaller, larger) {
                         (&RegionTarget::Region(r1), &RegionTarget::Region(r2)) => {
-                            if self.region_name(r1) != self.region_name(r2) {
+                            if region_name(r1) != region_name(r2) {
                                 finished
-                                    .entry(self.region_name(r2).expect("no region name found"))
+                                    .entry(region_name(r2).expect("no region name found"))
                                     .or_default()
                                     .push(r1) // Larger, smaller
                             }
@@ -292,7 +298,7 @@ fn handle_lifetimes<'cx>(
                     .get(name)
                     .unwrap_or(&empty)
                     .iter()
-                    .map(|region| GenericBound::Outlives(self.get_lifetime(region, names_map)))
+                    .map(|region| GenericBound::Outlives(Self::get_lifetime(region, names_map)))
                     .collect();
 
                 if bounds.is_empty() {
@@ -437,7 +443,7 @@ fn make_final_bounds(
     // K', we use the dedicated syntax 'T: Fn() -> K'
     // * We explicitly add a '?Sized' bound if we didn't find any 'Sized' predicates for a type
     fn param_env_to_generics(
-        &self,
+        &mut self,
         tcx: TyCtxt<'tcx>,
         param_env_def_id: DefId,
         param_env: ty::ParamEnv<'tcx>,
@@ -468,10 +474,7 @@ fn param_env_to_generics(
                         _ => false,
                     }
             })
-            .map(|p| {
-                let replaced = p.fold_with(&mut replacer);
-                (replaced, replaced.clean(self.cx))
-            });
+            .map(|p| p.fold_with(&mut replacer));
 
         let mut generic_params =
             (tcx.generics_of(param_env_def_id), tcx.explicit_predicates_of(param_env_def_id))
@@ -490,7 +493,8 @@ fn param_env_to_generics(
 
         let mut ty_to_fn: FxHashMap<Type, (Option<PolyTrait>, Option<Type>)> = Default::default();
 
-        for (orig_p, p) in clean_where_predicates {
+        for p in clean_where_predicates {
+            let (orig_p, p) = (p, p.clean(self.cx));
             if p.is_none() {
                 continue;
             }
@@ -749,6 +753,13 @@ fn is_fn_ty(&self, tcx: TyCtxt<'_>, ty: &Type) -> bool {
     }
 }
 
+fn region_name(region: Region<'_>) -> Option<Symbol> {
+    match region {
+        &ty::ReEarlyBound(r) => Some(r.name),
+        _ => None,
+    }
+}
+
 // Replaces all ReVars in a type with ty::Region's, using the provided map
 struct RegionReplacer<'a, 'tcx> {
     vid_to_region: &'a FxHashMap<ty::RegionVid, ty::Region<'tcx>>,
index f1c26feea46ec4376675ea9036e9dc4733fcdafe..a9d19a725c44f594f991011152f92321909e6091 100644 (file)
 use super::*;
 
 crate struct BlanketImplFinder<'a, 'tcx> {
-    crate cx: &'a core::DocContext<'tcx>,
+    crate cx: &'a mut core::DocContext<'tcx>,
 }
 
 impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
-    crate fn new(cx: &'a core::DocContext<'tcx>) -> Self {
-        BlanketImplFinder { cx }
-    }
-
     // FIXME(eddyb) figure out a better way to pass information about
     // parametrization of `ty` than `param_env_def_id`.
-    crate fn get_blanket_impls(&self, ty: Ty<'tcx>, param_env_def_id: DefId) -> Vec<Item> {
+    crate fn get_blanket_impls(&mut self, ty: Ty<'tcx>, param_env_def_id: DefId) -> Vec<Item> {
         let param_env = self.cx.tcx.param_env(param_env_def_id);
 
         debug!("get_blanket_impls({:?})", ty);
index cacca542284d96285b28e93ba34f79af1ad2d0dc..fded0499ba6a8f0f60a584e5fb15e36af698138d 100644 (file)
@@ -37,7 +37,7 @@
 ///
 /// `parent_module` refers to the parent of the *re-export*, not the original item.
 crate fn try_inline(
-    cx: &DocContext<'_>,
+    cx: &mut DocContext<'_>,
     parent_module: DefId,
     res: Res,
     name: Symbol,
 }
 
 crate fn try_inline_glob(
-    cx: &DocContext<'_>,
+    cx: &mut DocContext<'_>,
     res: Res,
     visited: &mut FxHashSet<DefId>,
 ) -> Option<Vec<clean::Item>> {
     }
 }
 
-crate fn build_external_trait(cx: &DocContext<'_>, did: DefId) -> clean::Trait {
+crate fn build_external_trait(cx: &mut DocContext<'_>, did: DefId) -> clean::Trait {
     let trait_items =
         cx.tcx.associated_items(did).in_definition_order().map(|item| item.clean(cx)).collect();
 
     }
 }
 
-fn build_external_function(cx: &DocContext<'_>, did: DefId) -> clean::Function {
+fn build_external_function(cx: &mut DocContext<'_>, did: DefId) -> clean::Function {
     let sig = cx.tcx.fn_sig(did);
 
     let constness =
         if is_min_const_fn(cx.tcx, did) { hir::Constness::Const } else { hir::Constness::NotConst };
     let asyncness = cx.tcx.asyncness(did);
     let predicates = cx.tcx.predicates_of(did);
-    let (generics, decl) = clean::enter_impl_trait(cx, || {
+    let (generics, decl) = clean::enter_impl_trait(cx, |cx| {
         ((cx.tcx.generics_of(did), predicates).clean(cx), (did, sig).clean(cx))
     });
     clean::Function {
@@ -224,7 +224,7 @@ fn build_external_function(cx: &DocContext<'_>, did: DefId) -> clean::Function {
     }
 }
 
-fn build_enum(cx: &DocContext<'_>, did: DefId) -> clean::Enum {
+fn build_enum(cx: &mut DocContext<'_>, did: DefId) -> clean::Enum {
     let predicates = cx.tcx.explicit_predicates_of(did);
 
     clean::Enum {
@@ -234,7 +234,7 @@ fn build_enum(cx: &DocContext<'_>, did: DefId) -> clean::Enum {
     }
 }
 
-fn build_struct(cx: &DocContext<'_>, did: DefId) -> clean::Struct {
+fn build_struct(cx: &mut DocContext<'_>, did: DefId) -> clean::Struct {
     let predicates = cx.tcx.explicit_predicates_of(did);
     let variant = cx.tcx.adt_def(did).non_enum_variant();
 
@@ -246,7 +246,7 @@ fn build_struct(cx: &DocContext<'_>, did: DefId) -> clean::Struct {
     }
 }
 
-fn build_union(cx: &DocContext<'_>, did: DefId) -> clean::Union {
+fn build_union(cx: &mut DocContext<'_>, did: DefId) -> clean::Union {
     let predicates = cx.tcx.explicit_predicates_of(did);
     let variant = cx.tcx.adt_def(did).non_enum_variant();
 
@@ -257,7 +257,7 @@ fn build_union(cx: &DocContext<'_>, did: DefId) -> clean::Union {
     }
 }
 
-fn build_type_alias(cx: &DocContext<'_>, did: DefId) -> clean::Typedef {
+fn build_type_alias(cx: &mut DocContext<'_>, did: DefId) -> clean::Typedef {
     let predicates = cx.tcx.explicit_predicates_of(did);
     let type_ = cx.tcx.type_of(did).clean(cx);
 
@@ -270,7 +270,7 @@ fn build_type_alias(cx: &DocContext<'_>, did: DefId) -> clean::Typedef {
 
 /// Builds all inherent implementations of an ADT (struct/union/enum) or Trait item/path/reexport.
 crate fn build_impls(
-    cx: &DocContext<'_>,
+    cx: &mut DocContext<'_>,
     parent_module: Option<DefId>,
     did: DefId,
     attrs: Option<Attrs<'_>>,
@@ -286,7 +286,7 @@ fn build_type_alias(cx: &DocContext<'_>, did: DefId) -> clean::Typedef {
 
 /// `parent_module` refers to the parent of the re-export, not the original item
 fn merge_attrs(
-    cx: &DocContext<'_>,
+    cx: &mut DocContext<'_>,
     parent_module: Option<DefId>,
     old_attrs: Attrs<'_>,
     new_attrs: Option<Attrs<'_>>,
@@ -311,7 +311,7 @@ fn merge_attrs(
 
 /// Builds a specific implementation of a type. The `did` could be a type method or trait method.
 crate fn build_impl(
-    cx: &DocContext<'_>,
+    cx: &mut DocContext<'_>,
     parent_module: impl Into<Option<DefId>>,
     did: DefId,
     attrs: Option<Attrs<'_>>,
@@ -394,7 +394,7 @@ fn merge_attrs(
                     }
                 })
                 .collect::<Vec<_>>(),
-            clean::enter_impl_trait(cx, || (tcx.generics_of(did), predicates).clean(cx)),
+            clean::enter_impl_trait(cx, |cx| (tcx.generics_of(did), predicates).clean(cx)),
         ),
     };
     let polarity = tcx.impl_polarity(did);
@@ -437,7 +437,11 @@ fn merge_attrs(
     ret.push(item);
 }
 
-fn build_module(cx: &DocContext<'_>, did: DefId, visited: &mut FxHashSet<DefId>) -> clean::Module {
+fn build_module(
+    cx: &mut DocContext<'_>,
+    did: DefId,
+    visited: &mut FxHashSet<DefId>,
+) -> clean::Module {
     let mut items = Vec::new();
 
     // If we're re-exporting a re-export it may actually re-export something in
@@ -495,7 +499,7 @@ fn build_module(cx: &DocContext<'_>, did: DefId, visited: &mut FxHashSet<DefId>)
     }
 }
 
-fn build_const(cx: &DocContext<'_>, did: DefId) -> clean::Constant {
+fn build_const(cx: &mut DocContext<'_>, did: DefId) -> clean::Constant {
     clean::Constant {
         type_: cx.tcx.type_of(did).clean(cx),
         expr: print_inlined_const(cx, did),
@@ -506,7 +510,7 @@ fn build_const(cx: &DocContext<'_>, did: DefId) -> clean::Constant {
     }
 }
 
-fn build_static(cx: &DocContext<'_>, did: DefId, mutable: bool) -> clean::Static {
+fn build_static(cx: &mut DocContext<'_>, did: DefId, mutable: bool) -> clean::Static {
     clean::Static {
         type_: cx.tcx.type_of(did).clean(cx),
         mutability: if mutable { Mutability::Mut } else { Mutability::Not },
@@ -514,7 +518,7 @@ fn build_static(cx: &DocContext<'_>, did: DefId, mutable: bool) -> clean::Static
     }
 }
 
-fn build_macro(cx: &DocContext<'_>, did: DefId, name: Symbol) -> clean::ItemKind {
+fn build_macro(cx: &mut DocContext<'_>, did: DefId, name: Symbol) -> clean::ItemKind {
     let imported_from = cx.tcx.original_crate_name(did.krate);
     match cx.enter_resolver(|r| r.cstore().load_macro_untracked(did, cx.sess())) {
         LoadedMacro::MacroDef(def, _) => {
@@ -603,7 +607,7 @@ fn separate_supertrait_bounds(
     (g, ty_bounds)
 }
 
-crate fn record_extern_trait(cx: &DocContext<'_>, did: DefId) {
+crate fn record_extern_trait(cx: &mut DocContext<'_>, did: DefId) {
     if did.is_local() {
         return;
     }
index 1b3d3b52cdbdf9cad2a8558ba5b6c89cc9b01b39..1cfa6090ef48d6dc095c0e138cbf01e96424fce1 100644 (file)
 crate use self::types::*;
 
 crate trait Clean<T> {
-    fn clean(&self, cx: &DocContext<'_>) -> T;
+    fn clean(&self, cx: &mut DocContext<'_>) -> T;
 }
 
 impl<T: Clean<U>, U> Clean<Vec<U>> for [T] {
-    fn clean(&self, cx: &DocContext<'_>) -> Vec<U> {
+    fn clean(&self, cx: &mut DocContext<'_>) -> Vec<U> {
         self.iter().map(|x| x.clean(cx)).collect()
     }
 }
 
 impl<T: Clean<U>, U, V: Idx> Clean<IndexVec<V, U>> for IndexVec<V, T> {
-    fn clean(&self, cx: &DocContext<'_>) -> IndexVec<V, U> {
+    fn clean(&self, cx: &mut DocContext<'_>) -> IndexVec<V, U> {
         self.iter().map(|x| x.clean(cx)).collect()
     }
 }
 
 impl<T: Clean<U>, U> Clean<U> for &T {
-    fn clean(&self, cx: &DocContext<'_>) -> U {
+    fn clean(&self, cx: &mut DocContext<'_>) -> U {
         (**self).clean(cx)
     }
 }
 
 impl<T: Clean<U>, U> Clean<U> for Rc<T> {
-    fn clean(&self, cx: &DocContext<'_>) -> U {
+    fn clean(&self, cx: &mut DocContext<'_>) -> U {
         (**self).clean(cx)
     }
 }
 
 impl<T: Clean<U>, U> Clean<Option<U>> for Option<T> {
-    fn clean(&self, cx: &DocContext<'_>) -> Option<U> {
+    fn clean(&self, cx: &mut DocContext<'_>) -> Option<U> {
         self.as_ref().map(|v| v.clean(cx))
     }
 }
 
 impl Clean<ExternalCrate> for CrateNum {
-    fn clean(&self, cx: &DocContext<'_>) -> ExternalCrate {
+    fn clean(&self, cx: &mut DocContext<'_>) -> ExternalCrate {
+        let tcx = cx.tcx;
         let root = DefId { krate: *self, index: CRATE_DEF_INDEX };
-        let krate_span = cx.tcx.def_span(root);
+        let krate_span = tcx.def_span(root);
         let krate_src = cx.sess().source_map().span_to_filename(krate_span);
 
         // Collect all inner modules which are tagged as implementations of
@@ -105,7 +106,7 @@ fn clean(&self, cx: &DocContext<'_>) -> ExternalCrate {
         // Also note that this does not attempt to deal with modules tagged
         // duplicately for the same primitive. This is handled later on when
         // rendering by delegating everything to a hash map.
-        let as_primitive = |res: Res| {
+        let mut as_primitive = |res: Res| {
             if let Res::Def(DefKind::Mod, def_id) = res {
                 let attrs = cx.tcx.get_attrs(def_id).clean(cx);
                 let mut prim = None;
@@ -125,15 +126,14 @@ fn clean(&self, cx: &DocContext<'_>) -> ExternalCrate {
             None
         };
         let primitives = if root.is_local() {
-            cx.tcx
-                .hir()
+            tcx.hir()
                 .krate()
                 .item
                 .module
                 .item_ids
                 .iter()
                 .filter_map(|&id| {
-                    let item = cx.tcx.hir().item(id);
+                    let item = tcx.hir().item(id);
                     match item.kind {
                         hir::ItemKind::Mod(_) => {
                             as_primitive(Res::Def(DefKind::Mod, id.def_id.to_def_id()))
@@ -151,17 +151,12 @@ fn clean(&self, cx: &DocContext<'_>) -> ExternalCrate {
                 })
                 .collect()
         } else {
-            cx.tcx
-                .item_children(root)
-                .iter()
-                .map(|item| item.res)
-                .filter_map(as_primitive)
-                .collect()
+            tcx.item_children(root).iter().map(|item| item.res).filter_map(as_primitive).collect()
         };
 
-        let as_keyword = |res: Res| {
+        let mut as_keyword = |res: Res| {
             if let Res::Def(DefKind::Mod, def_id) = res {
-                let attrs = cx.tcx.get_attrs(def_id).clean(cx);
+                let attrs = tcx.get_attrs(def_id).clean(cx);
                 let mut keyword = None;
                 for attr in attrs.lists(sym::doc) {
                     if attr.has_name(sym::keyword) {
@@ -176,15 +171,14 @@ fn clean(&self, cx: &DocContext<'_>) -> ExternalCrate {
             None
         };
         let keywords = if root.is_local() {
-            cx.tcx
-                .hir()
+            tcx.hir()
                 .krate()
                 .item
                 .module
                 .item_ids
                 .iter()
                 .filter_map(|&id| {
-                    let item = cx.tcx.hir().item(id);
+                    let item = tcx.hir().item(id);
                     match item.kind {
                         hir::ItemKind::Mod(_) => {
                             as_keyword(Res::Def(DefKind::Mod, id.def_id.to_def_id()))
@@ -199,13 +193,13 @@ fn clean(&self, cx: &DocContext<'_>) -> ExternalCrate {
                 })
                 .collect()
         } else {
-            cx.tcx.item_children(root).iter().map(|item| item.res).filter_map(as_keyword).collect()
+            tcx.item_children(root).iter().map(|item| item.res).filter_map(as_keyword).collect()
         };
 
         ExternalCrate {
-            name: cx.tcx.crate_name(*self),
+            name: tcx.crate_name(*self),
             src: krate_src,
-            attrs: cx.tcx.get_attrs(root).clean(cx),
+            attrs: tcx.get_attrs(root).clean(cx),
             primitives,
             keywords,
         }
@@ -213,7 +207,7 @@ fn clean(&self, cx: &DocContext<'_>) -> ExternalCrate {
 }
 
 impl Clean<Item> for doctree::Module<'_> {
-    fn clean(&self, cx: &DocContext<'_>) -> Item {
+    fn clean(&self, cx: &mut DocContext<'_>) -> Item {
         let mut items: Vec<Item> = vec![];
         items.extend(self.foreigns.iter().map(|x| x.clean(cx)));
         items.extend(self.mods.iter().map(|x| x.clean(cx)));
@@ -246,13 +240,13 @@ fn clean(&self, cx: &DocContext<'_>) -> Item {
 }
 
 impl Clean<Attributes> for [ast::Attribute] {
-    fn clean(&self, cx: &DocContext<'_>) -> Attributes {
+    fn clean(&self, cx: &mut DocContext<'_>) -> Attributes {
         Attributes::from_ast(cx.sess().diagnostic(), self, None)
     }
 }
 
 impl Clean<GenericBound> for hir::GenericBound<'_> {
-    fn clean(&self, cx: &DocContext<'_>) -> GenericBound {
+    fn clean(&self, cx: &mut DocContext<'_>) -> GenericBound {
         match *self {
             hir::GenericBound::Outlives(lt) => GenericBound::Outlives(lt.clean(cx)),
             hir::GenericBound::LangItemTrait(lang_item, span, _, generic_args) => {
@@ -279,7 +273,7 @@ fn clean(&self, cx: &DocContext<'_>) -> GenericBound {
 }
 
 impl Clean<Type> for (ty::TraitRef<'_>, &[TypeBinding]) {
-    fn clean(&self, cx: &DocContext<'_>) -> Type {
+    fn clean(&self, cx: &mut DocContext<'_>) -> Type {
         let (trait_ref, bounds) = *self;
         inline::record_extern_fqn(cx, trait_ref.def_id, TypeKind::Trait);
         let path = external_path(
@@ -298,7 +292,7 @@ fn clean(&self, cx: &DocContext<'_>) -> Type {
 }
 
 impl<'tcx> Clean<GenericBound> for ty::TraitRef<'tcx> {
-    fn clean(&self, cx: &DocContext<'_>) -> GenericBound {
+    fn clean(&self, cx: &mut DocContext<'_>) -> GenericBound {
         GenericBound::TraitBound(
             PolyTrait { trait_: (*self, &[][..]).clean(cx), generic_params: vec![] },
             hir::TraitBoundModifier::None,
@@ -307,7 +301,7 @@ fn clean(&self, cx: &DocContext<'_>) -> GenericBound {
 }
 
 impl Clean<GenericBound> for (ty::PolyTraitRef<'_>, &[TypeBinding]) {
-    fn clean(&self, cx: &DocContext<'_>) -> GenericBound {
+    fn clean(&self, cx: &mut DocContext<'_>) -> GenericBound {
         let (poly_trait_ref, bounds) = *self;
         let poly_trait_ref = poly_trait_ref.lift_to_tcx(cx.tcx).unwrap();
 
@@ -335,13 +329,13 @@ fn clean(&self, cx: &DocContext<'_>) -> GenericBound {
 }
 
 impl<'tcx> Clean<GenericBound> for ty::PolyTraitRef<'tcx> {
-    fn clean(&self, cx: &DocContext<'_>) -> GenericBound {
+    fn clean(&self, cx: &mut DocContext<'_>) -> GenericBound {
         (*self, &[][..]).clean(cx)
     }
 }
 
 impl<'tcx> Clean<Option<Vec<GenericBound>>> for InternalSubsts<'tcx> {
-    fn clean(&self, cx: &DocContext<'_>) -> Option<Vec<GenericBound>> {
+    fn clean(&self, cx: &mut DocContext<'_>) -> Option<Vec<GenericBound>> {
         let mut v = Vec::new();
         v.extend(self.regions().filter_map(|r| r.clean(cx)).map(GenericBound::Outlives));
         v.extend(self.types().map(|t| {
@@ -355,7 +349,7 @@ fn clean(&self, cx: &DocContext<'_>) -> Option<Vec<GenericBound>> {
 }
 
 impl Clean<Lifetime> for hir::Lifetime {
-    fn clean(&self, cx: &DocContext<'_>) -> Lifetime {
+    fn clean(&self, cx: &mut DocContext<'_>) -> Lifetime {
         let def = cx.tcx.named_region(self.hir_id);
         match def {
             Some(
@@ -374,7 +368,7 @@ fn clean(&self, cx: &DocContext<'_>) -> Lifetime {
 }
 
 impl Clean<Lifetime> for hir::GenericParam<'_> {
-    fn clean(&self, _: &DocContext<'_>) -> Lifetime {
+    fn clean(&self, _: &mut DocContext<'_>) -> Lifetime {
         match self.kind {
             hir::GenericParamKind::Lifetime { .. } => {
                 if !self.bounds.is_empty() {
@@ -398,7 +392,7 @@ fn clean(&self, _: &DocContext<'_>) -> Lifetime {
 }
 
 impl Clean<Constant> for hir::ConstArg {
-    fn clean(&self, cx: &DocContext<'_>) -> Constant {
+    fn clean(&self, cx: &mut DocContext<'_>) -> Constant {
         Constant {
             type_: cx
                 .tcx
@@ -412,13 +406,13 @@ fn clean(&self, cx: &DocContext<'_>) -> Constant {
 }
 
 impl Clean<Lifetime> for ty::GenericParamDef {
-    fn clean(&self, _cx: &DocContext<'_>) -> Lifetime {
+    fn clean(&self, _cx: &mut DocContext<'_>) -> Lifetime {
         Lifetime(self.name)
     }
 }
 
 impl Clean<Option<Lifetime>> for ty::RegionKind {
-    fn clean(&self, _cx: &DocContext<'_>) -> Option<Lifetime> {
+    fn clean(&self, _cx: &mut DocContext<'_>) -> Option<Lifetime> {
         match *self {
             ty::ReStatic => Some(Lifetime::statik()),
             ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name) }) => {
@@ -440,7 +434,7 @@ fn clean(&self, _cx: &DocContext<'_>) -> Option<Lifetime> {
 }
 
 impl Clean<WherePredicate> for hir::WherePredicate<'_> {
-    fn clean(&self, cx: &DocContext<'_>) -> WherePredicate {
+    fn clean(&self, cx: &mut DocContext<'_>) -> WherePredicate {
         match *self {
             hir::WherePredicate::BoundPredicate(ref wbp) => WherePredicate::BoundPredicate {
                 ty: wbp.bounded_ty.clean(cx),
@@ -460,7 +454,7 @@ fn clean(&self, cx: &DocContext<'_>) -> WherePredicate {
 }
 
 impl<'a> Clean<Option<WherePredicate>> for ty::Predicate<'a> {
-    fn clean(&self, cx: &DocContext<'_>) -> Option<WherePredicate> {
+    fn clean(&self, cx: &mut DocContext<'_>) -> Option<WherePredicate> {
         let bound_predicate = self.kind();
         match bound_predicate.skip_binder() {
             ty::PredicateKind::Trait(pred, _) => Some(bound_predicate.rebind(pred).clean(cx)),
@@ -480,7 +474,7 @@ fn clean(&self, cx: &DocContext<'_>) -> Option<WherePredicate> {
 }
 
 impl<'a> Clean<WherePredicate> for ty::PolyTraitPredicate<'a> {
-    fn clean(&self, cx: &DocContext<'_>) -> WherePredicate {
+    fn clean(&self, cx: &mut DocContext<'_>) -> WherePredicate {
         let poly_trait_ref = self.map_bound(|pred| pred.trait_ref);
         WherePredicate::BoundPredicate {
             ty: poly_trait_ref.skip_binder().self_ty().clean(cx),
@@ -492,7 +486,7 @@ fn clean(&self, cx: &DocContext<'_>) -> WherePredicate {
 impl<'tcx> Clean<Option<WherePredicate>>
     for ty::OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>
 {
-    fn clean(&self, cx: &DocContext<'_>) -> Option<WherePredicate> {
+    fn clean(&self, cx: &mut DocContext<'_>) -> Option<WherePredicate> {
         let ty::OutlivesPredicate(a, b) = self;
 
         if let (ty::ReEmpty(_), ty::ReEmpty(_)) = (a, b) {
@@ -507,7 +501,7 @@ fn clean(&self, cx: &DocContext<'_>) -> Option<WherePredicate> {
 }
 
 impl<'tcx> Clean<Option<WherePredicate>> for ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>> {
-    fn clean(&self, cx: &DocContext<'_>) -> Option<WherePredicate> {
+    fn clean(&self, cx: &mut DocContext<'_>) -> Option<WherePredicate> {
         let ty::OutlivesPredicate(ty, lt) = self;
 
         if let ty::ReEmpty(_) = lt {
@@ -522,14 +516,14 @@ fn clean(&self, cx: &DocContext<'_>) -> Option<WherePredicate> {
 }
 
 impl<'tcx> Clean<WherePredicate> for ty::ProjectionPredicate<'tcx> {
-    fn clean(&self, cx: &DocContext<'_>) -> WherePredicate {
+    fn clean(&self, cx: &mut DocContext<'_>) -> WherePredicate {
         let ty::ProjectionPredicate { projection_ty, ty } = self;
         WherePredicate::EqPredicate { lhs: projection_ty.clean(cx), rhs: ty.clean(cx) }
     }
 }
 
 impl<'tcx> Clean<Type> for ty::ProjectionTy<'tcx> {
-    fn clean(&self, cx: &DocContext<'_>) -> Type {
+    fn clean(&self, cx: &mut DocContext<'_>) -> Type {
         let lifted = self.lift_to_tcx(cx.tcx).unwrap();
         let trait_ = match lifted.trait_ref(cx.tcx).clean(cx) {
             GenericBound::TraitBound(t, _) => t.trait_,
@@ -544,7 +538,7 @@ fn clean(&self, cx: &DocContext<'_>) -> Type {
 }
 
 impl Clean<GenericParamDef> for ty::GenericParamDef {
-    fn clean(&self, cx: &DocContext<'_>) -> GenericParamDef {
+    fn clean(&self, cx: &mut DocContext<'_>) -> GenericParamDef {
         let (name, kind) = match self.kind {
             ty::GenericParamDefKind::Lifetime => (self.name, GenericParamDefKind::Lifetime),
             ty::GenericParamDefKind::Type { has_default, synthetic, .. } => {
@@ -574,7 +568,7 @@ fn clean(&self, cx: &DocContext<'_>) -> GenericParamDef {
 }
 
 impl Clean<GenericParamDef> for hir::GenericParam<'_> {
-    fn clean(&self, cx: &DocContext<'_>) -> GenericParamDef {
+    fn clean(&self, cx: &mut DocContext<'_>) -> GenericParamDef {
         let (name, kind) = match self.kind {
             hir::GenericParamKind::Lifetime { .. } => {
                 let name = if !self.bounds.is_empty() {
@@ -617,7 +611,7 @@ fn clean(&self, cx: &DocContext<'_>) -> GenericParamDef {
 }
 
 impl Clean<Generics> for hir::Generics<'_> {
-    fn clean(&self, cx: &DocContext<'_>) -> Generics {
+    fn clean(&self, cx: &mut DocContext<'_>) -> Generics {
         // Synthetic type-parameters are inserted after normal ones.
         // In order for normal parameters to be able to refer to synthetic ones,
         // scans them first.
@@ -697,7 +691,7 @@ fn is_elided_lifetime(param: &hir::GenericParam<'_>) -> bool {
 }
 
 impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics, ty::GenericPredicates<'tcx>) {
-    fn clean(&self, cx: &DocContext<'_>) -> Generics {
+    fn clean(&self, cx: &mut DocContext<'_>) -> Generics {
         use self::WherePredicate as WP;
         use std::collections::BTreeMap;
 
@@ -801,7 +795,8 @@ fn clean(&self, cx: &DocContext<'_>) -> Generics {
             if let crate::core::ImplTraitParam::ParamIndex(idx) = param {
                 if let Some(proj) = impl_trait_proj.remove(&idx) {
                     for (trait_did, name, rhs) in proj {
-                        simplify::merge_bounds(cx, &mut bounds, trait_did, name, &rhs.clean(cx));
+                        let rhs = rhs.clean(cx);
+                        simplify::merge_bounds(cx, &mut bounds, trait_did, name, &rhs);
                     }
                 }
             } else {
@@ -866,7 +861,7 @@ fn clean_fn_or_proc_macro(
     generics: &'a hir::Generics<'a>,
     body_id: hir::BodyId,
     name: &mut Symbol,
-    cx: &DocContext<'_>,
+    cx: &mut DocContext<'_>,
 ) -> ItemKind {
     let macro_kind = item.attrs.iter().find_map(|a| {
         if a.has_name(sym::proc_macro) {
@@ -921,15 +916,15 @@ fn clean_fn_or_proc_macro(
 }
 
 impl<'a> Clean<Function> for (&'a hir::FnSig<'a>, &'a hir::Generics<'a>, hir::BodyId) {
-    fn clean(&self, cx: &DocContext<'_>) -> Function {
+    fn clean(&self, cx: &mut DocContext<'_>) -> Function {
         let (generics, decl) =
-            enter_impl_trait(cx, || (self.1.clean(cx), (&*self.0.decl, self.2).clean(cx)));
+            enter_impl_trait(cx, |cx| (self.1.clean(cx), (&*self.0.decl, self.2).clean(cx)));
         Function { decl, generics, header: self.0.header }
     }
 }
 
 impl<'a> Clean<Arguments> for (&'a [hir::Ty<'a>], &'a [Ident]) {
-    fn clean(&self, cx: &DocContext<'_>) -> Arguments {
+    fn clean(&self, cx: &mut DocContext<'_>) -> Arguments {
         Arguments {
             values: self
                 .0
@@ -948,7 +943,7 @@ fn clean(&self, cx: &DocContext<'_>) -> Arguments {
 }
 
 impl<'a> Clean<Arguments> for (&'a [hir::Ty<'a>], hir::BodyId) {
-    fn clean(&self, cx: &DocContext<'_>) -> Arguments {
+    fn clean(&self, cx: &mut DocContext<'_>) -> Arguments {
         let body = cx.tcx.hir().body(self.1);
 
         Arguments {
@@ -969,7 +964,7 @@ impl<'a, A: Copy> Clean<FnDecl> for (&'a hir::FnDecl<'a>, A)
 where
     (&'a [hir::Ty<'a>], A): Clean<Arguments>,
 {
-    fn clean(&self, cx: &DocContext<'_>) -> FnDecl {
+    fn clean(&self, cx: &mut DocContext<'_>) -> FnDecl {
         FnDecl {
             inputs: (self.0.inputs, self.1).clean(cx),
             output: self.0.output.clean(cx),
@@ -980,7 +975,7 @@ fn clean(&self, cx: &DocContext<'_>) -> FnDecl {
 }
 
 impl<'tcx> Clean<FnDecl> for (DefId, ty::PolyFnSig<'tcx>) {
-    fn clean(&self, cx: &DocContext<'_>) -> FnDecl {
+    fn clean(&self, cx: &mut DocContext<'_>) -> FnDecl {
         let (did, sig) = *self;
         let mut names = if did.is_local() { &[] } else { cx.tcx.fn_arg_names(did) }.iter();
 
@@ -1004,7 +999,7 @@ fn clean(&self, cx: &DocContext<'_>) -> FnDecl {
 }
 
 impl Clean<FnRetTy> for hir::FnRetTy<'_> {
-    fn clean(&self, cx: &DocContext<'_>) -> FnRetTy {
+    fn clean(&self, cx: &mut DocContext<'_>) -> FnRetTy {
         match *self {
             Self::Return(ref typ) => Return(typ.clean(cx)),
             Self::DefaultReturn(..) => DefaultReturn,
@@ -1013,7 +1008,7 @@ fn clean(&self, cx: &DocContext<'_>) -> FnRetTy {
 }
 
 impl Clean<bool> for hir::IsAuto {
-    fn clean(&self, _: &DocContext<'_>) -> bool {
+    fn clean(&self, _: &mut DocContext<'_>) -> bool {
         match *self {
             hir::IsAuto::Yes => true,
             hir::IsAuto::No => false,
@@ -1022,13 +1017,14 @@ fn clean(&self, _: &DocContext<'_>) -> bool {
 }
 
 impl Clean<Type> for hir::TraitRef<'_> {
-    fn clean(&self, cx: &DocContext<'_>) -> Type {
-        resolve_type(cx, self.path.clean(cx), self.hir_ref_id)
+    fn clean(&self, cx: &mut DocContext<'_>) -> Type {
+        let path = self.path.clean(cx);
+        resolve_type(cx, path, self.hir_ref_id)
     }
 }
 
 impl Clean<PolyTrait> for hir::PolyTraitRef<'_> {
-    fn clean(&self, cx: &DocContext<'_>) -> PolyTrait {
+    fn clean(&self, cx: &mut DocContext<'_>) -> PolyTrait {
         PolyTrait {
             trait_: self.trait_ref.clean(cx),
             generic_params: self.bound_generic_params.clean(cx),
@@ -1037,15 +1033,15 @@ fn clean(&self, cx: &DocContext<'_>) -> PolyTrait {
 }
 
 impl Clean<TypeKind> for hir::def::DefKind {
-    fn clean(&self, _: &DocContext<'_>) -> TypeKind {
+    fn clean(&self, _: &mut DocContext<'_>) -> TypeKind {
         (*self).into()
     }
 }
 
 impl Clean<Item> for hir::TraitItem<'_> {
-    fn clean(&self, cx: &DocContext<'_>) -> Item {
+    fn clean(&self, cx: &mut DocContext<'_>) -> Item {
         let local_did = self.def_id.to_def_id();
-        cx.with_param_env(local_did, || {
+        cx.with_param_env(local_did, |cx| {
             let inner = match self.kind {
                 hir::TraitItemKind::Const(ref ty, default) => {
                     AssocConstItem(ty.clean(cx), default.map(|e| print_const_expr(cx.tcx, e)))
@@ -1060,7 +1056,7 @@ fn clean(&self, cx: &DocContext<'_>) -> Item {
                     MethodItem(m, None)
                 }
                 hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(ref names)) => {
-                    let (generics, decl) = enter_impl_trait(cx, || {
+                    let (generics, decl) = enter_impl_trait(cx, |cx| {
                         (self.generics.clean(cx), (&*sig.decl, &names[..]).clean(cx))
                     });
                     let mut t = Function { header: sig.header, decl, generics };
@@ -1084,9 +1080,9 @@ fn clean(&self, cx: &DocContext<'_>) -> Item {
 }
 
 impl Clean<Item> for hir::ImplItem<'_> {
-    fn clean(&self, cx: &DocContext<'_>) -> Item {
+    fn clean(&self, cx: &mut DocContext<'_>) -> Item {
         let local_did = self.def_id.to_def_id();
-        cx.with_param_env(local_did, || {
+        cx.with_param_env(local_did, |cx| {
             let inner = match self.kind {
                 hir::ImplItemKind::Const(ref ty, expr) => {
                     AssocConstItem(ty.clean(cx), Some(print_const_expr(cx.tcx, expr)))
@@ -1133,10 +1129,11 @@ fn clean(&self, cx: &DocContext<'_>) -> Item {
 }
 
 impl Clean<Item> for ty::AssocItem {
-    fn clean(&self, cx: &DocContext<'_>) -> Item {
+    fn clean(&self, cx: &mut DocContext<'_>) -> Item {
+        let tcx = cx.tcx;
         let kind = match self.kind {
             ty::AssocKind::Const => {
-                let ty = cx.tcx.type_of(self.def_id);
+                let ty = tcx.type_of(self.def_id);
                 let default = if self.defaultness.has_value() {
                     Some(inline::print_inlined_const(cx, self.def_id))
                 } else {
@@ -1146,15 +1143,15 @@ fn clean(&self, cx: &DocContext<'_>) -> Item {
             }
             ty::AssocKind::Fn => {
                 let generics =
-                    (cx.tcx.generics_of(self.def_id), cx.tcx.explicit_predicates_of(self.def_id))
+                    (tcx.generics_of(self.def_id), tcx.explicit_predicates_of(self.def_id))
                         .clean(cx);
-                let sig = cx.tcx.fn_sig(self.def_id);
+                let sig = tcx.fn_sig(self.def_id);
                 let mut decl = (self.def_id, sig).clean(cx);
 
                 if self.fn_has_self_parameter {
                     let self_ty = match self.container {
-                        ty::ImplContainer(def_id) => cx.tcx.type_of(def_id),
-                        ty::TraitContainer(_) => cx.tcx.types.self_param,
+                        ty::ImplContainer(def_id) => tcx.type_of(def_id),
+                        ty::TraitContainer(_) => tcx.types.self_param,
                     };
                     let self_arg_ty = sig.input(0).skip_binder();
                     if self_arg_ty == self_ty {
@@ -1176,12 +1173,12 @@ fn clean(&self, cx: &DocContext<'_>) -> Item {
                     ty::TraitContainer(_) => self.defaultness.has_value(),
                 };
                 if provided {
-                    let constness = if is_min_const_fn(cx.tcx, self.def_id) {
+                    let constness = if is_min_const_fn(tcx, self.def_id) {
                         hir::Constness::Const
                     } else {
                         hir::Constness::NotConst
                     };
-                    let asyncness = cx.tcx.asyncness(self.def_id);
+                    let asyncness = tcx.asyncness(self.def_id);
                     let defaultness = match self.container {
                         ty::ImplContainer(_) => Some(self.defaultness),
                         ty::TraitContainer(_) => None,
@@ -1216,9 +1213,9 @@ fn clean(&self, cx: &DocContext<'_>) -> Item {
                 let my_name = self.ident.name;
 
                 if let ty::TraitContainer(_) = self.container {
-                    let bounds = cx.tcx.explicit_item_bounds(self.def_id);
+                    let bounds = tcx.explicit_item_bounds(self.def_id);
                     let predicates = ty::GenericPredicates { parent: None, predicates: bounds };
-                    let generics = (cx.tcx.generics_of(self.def_id), predicates).clean(cx);
+                    let generics = (tcx.generics_of(self.def_id), predicates).clean(cx);
                     let mut bounds = generics
                         .where_predicates
                         .iter()
@@ -1258,7 +1255,7 @@ fn clean(&self, cx: &DocContext<'_>) -> Item {
                     }
 
                     let ty = if self.defaultness.has_value() {
-                        Some(cx.tcx.type_of(self.def_id))
+                        Some(tcx.type_of(self.def_id))
                     } else {
                         None
                     };
@@ -1266,7 +1263,7 @@ fn clean(&self, cx: &DocContext<'_>) -> Item {
                     AssocTypeItem(bounds, ty.clean(cx))
                 } else {
                     // FIXME: when could this happen? Associated items in inherent impls?
-                    let type_ = cx.tcx.type_of(self.def_id).clean(cx);
+                    let type_ = tcx.type_of(self.def_id).clean(cx);
                     TypedefItem(
                         Typedef {
                             type_,
@@ -1283,7 +1280,7 @@ fn clean(&self, cx: &DocContext<'_>) -> Item {
     }
 }
 
-fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &DocContext<'_>) -> Type {
+fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type {
     use rustc_hir::GenericParamCount;
     let hir::Ty { hir_id, span, ref kind } = *hir_ty;
     let qpath = match kind {
@@ -1389,9 +1386,10 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &DocContext<'_>) -> Type {
                         }
                     }
                 }
-                return cx.enter_alias(ty_substs, lt_substs, ct_substs, || ty.clean(cx));
+                return cx.enter_alias(ty_substs, lt_substs, ct_substs, |cx| ty.clean(cx));
             }
-            resolve_type(cx, path.clean(cx), hir_id)
+            let path = path.clean(cx);
+            resolve_type(cx, path, hir_id)
         }
         hir::QPath::Resolved(Some(ref qself), ref p) => {
             // Try to normalize `<X as Y>::T` to a type
@@ -1423,11 +1421,11 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &DocContext<'_>) -> Type {
             } else {
                 Res::Err
             };
-            let trait_path = hir::Path { span, res, segments: &[] };
+            let trait_path = hir::Path { span, res, segments: &[] }.clean(cx);
             Type::QPath {
                 name: segment.ident.name,
                 self_type: box qself.clean(cx),
-                trait_: box resolve_type(cx, trait_path.clean(cx), hir_id),
+                trait_: box resolve_type(cx, trait_path, hir_id),
             }
         }
         hir::QPath::LangItem(..) => bug!("clean: requiring documentation of lang item"),
@@ -1435,7 +1433,7 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &DocContext<'_>) -> Type {
 }
 
 impl Clean<Type> for hir::Ty<'_> {
-    fn clean(&self, cx: &DocContext<'_>) -> Type {
+    fn clean(&self, cx: &mut DocContext<'_>) -> Type {
         use rustc_hir::*;
 
         match self.kind {
@@ -1507,7 +1505,7 @@ fn clean(&self, cx: &DocContext<'_>) -> Type {
 }
 
 /// Returns `None` if the type could not be normalized
-fn normalize(cx: &DocContext<'tcx>, ty: Ty<'_>) -> Option<Ty<'tcx>> {
+fn normalize(cx: &mut DocContext<'tcx>, ty: Ty<'_>) -> Option<Ty<'tcx>> {
     // HACK: low-churn fix for #79459 while we wait for a trait normalization fix
     if !cx.tcx.sess.opts.debugging_opts.normalize_docs {
         return None;
@@ -1538,7 +1536,7 @@ fn normalize(cx: &DocContext<'tcx>, ty: Ty<'_>) -> Option<Ty<'tcx>> {
 }
 
 impl<'tcx> Clean<Type> for Ty<'tcx> {
-    fn clean(&self, cx: &DocContext<'_>) -> Type {
+    fn clean(&self, cx: &mut DocContext<'_>) -> Type {
         debug!("cleaning type: {:?}", self);
         let ty = normalize(cx, self).unwrap_or(self);
         match *ty.kind() {
@@ -1746,7 +1744,7 @@ fn clean(&self, cx: &DocContext<'_>) -> Type {
 }
 
 impl<'tcx> Clean<Constant> for ty::Const<'tcx> {
-    fn clean(&self, cx: &DocContext<'_>) -> Constant {
+    fn clean(&self, cx: &mut DocContext<'_>) -> Constant {
         Constant {
             type_: self.ty.clean(cx),
             expr: format!("{}", self),
@@ -1757,7 +1755,7 @@ fn clean(&self, cx: &DocContext<'_>) -> Constant {
 }
 
 impl Clean<Item> for hir::StructField<'_> {
-    fn clean(&self, cx: &DocContext<'_>) -> Item {
+    fn clean(&self, cx: &mut DocContext<'_>) -> Item {
         let what_rustc_thinks = Item::from_hir_id_and_parts(
             self.hir_id,
             Some(self.ident.name),
@@ -1770,7 +1768,7 @@ fn clean(&self, cx: &DocContext<'_>) -> Item {
 }
 
 impl Clean<Item> for ty::FieldDef {
-    fn clean(&self, cx: &DocContext<'_>) -> Item {
+    fn clean(&self, cx: &mut DocContext<'_>) -> Item {
         let what_rustc_thinks = Item::from_def_id_and_parts(
             self.did,
             Some(self.ident.name),
@@ -1783,7 +1781,7 @@ fn clean(&self, cx: &DocContext<'_>) -> Item {
 }
 
 impl Clean<Visibility> for hir::Visibility<'_> {
-    fn clean(&self, cx: &DocContext<'_>) -> Visibility {
+    fn clean(&self, cx: &mut DocContext<'_>) -> Visibility {
         match self.node {
             hir::VisibilityKind::Public => Visibility::Public,
             hir::VisibilityKind::Inherited => Visibility::Inherited,
@@ -1801,7 +1799,7 @@ fn clean(&self, cx: &DocContext<'_>) -> Visibility {
 }
 
 impl Clean<Visibility> for ty::Visibility {
-    fn clean(&self, _cx: &DocContext<'_>) -> Visibility {
+    fn clean(&self, _cx: &mut DocContext<'_>) -> Visibility {
         match *self {
             ty::Visibility::Public => Visibility::Public,
             // NOTE: this is not quite right: `ty` uses `Invisible` to mean 'private',
@@ -1816,7 +1814,7 @@ fn clean(&self, _cx: &DocContext<'_>) -> Visibility {
 }
 
 impl Clean<VariantStruct> for rustc_hir::VariantData<'_> {
-    fn clean(&self, cx: &DocContext<'_>) -> VariantStruct {
+    fn clean(&self, cx: &mut DocContext<'_>) -> VariantStruct {
         VariantStruct {
             struct_type: CtorKind::from_hir(self),
             fields: self.fields().iter().map(|x| x.clean(cx)).collect(),
@@ -1826,7 +1824,7 @@ fn clean(&self, cx: &DocContext<'_>) -> VariantStruct {
 }
 
 impl Clean<Item> for ty::VariantDef {
-    fn clean(&self, cx: &DocContext<'_>) -> Item {
+    fn clean(&self, cx: &mut DocContext<'_>) -> Item {
         let kind = match self.ctor_kind {
             CtorKind::Const => Variant::CLike,
             CtorKind::Fn => Variant::Tuple(
@@ -1857,7 +1855,7 @@ fn clean(&self, cx: &DocContext<'_>) -> Item {
 }
 
 impl Clean<Variant> for hir::VariantData<'_> {
-    fn clean(&self, cx: &DocContext<'_>) -> Variant {
+    fn clean(&self, cx: &mut DocContext<'_>) -> Variant {
         match self {
             hir::VariantData::Struct(..) => Variant::Struct(self.clean(cx)),
             hir::VariantData::Tuple(..) => {
@@ -1869,13 +1867,13 @@ fn clean(&self, cx: &DocContext<'_>) -> Variant {
 }
 
 impl Clean<Span> for rustc_span::Span {
-    fn clean(&self, _cx: &DocContext<'_>) -> Span {
+    fn clean(&self, _cx: &mut DocContext<'_>) -> Span {
         Span::from_rustc_span(*self)
     }
 }
 
 impl Clean<Path> for hir::Path<'_> {
-    fn clean(&self, cx: &DocContext<'_>) -> Path {
+    fn clean(&self, cx: &mut DocContext<'_>) -> Path {
         Path {
             global: self.is_global(),
             res: self.res,
@@ -1885,7 +1883,7 @@ fn clean(&self, cx: &DocContext<'_>) -> Path {
 }
 
 impl Clean<GenericArgs> for hir::GenericArgs<'_> {
-    fn clean(&self, cx: &DocContext<'_>) -> GenericArgs {
+    fn clean(&self, cx: &mut DocContext<'_>) -> GenericArgs {
         if self.parenthesized {
             let output = self.bindings[0].ty().clean(cx);
             GenericArgs::Parenthesized {
@@ -1913,28 +1911,28 @@ fn clean(&self, cx: &DocContext<'_>) -> GenericArgs {
 }
 
 impl Clean<PathSegment> for hir::PathSegment<'_> {
-    fn clean(&self, cx: &DocContext<'_>) -> PathSegment {
+    fn clean(&self, cx: &mut DocContext<'_>) -> PathSegment {
         PathSegment { name: self.ident.name, args: self.args().clean(cx) }
     }
 }
 
 impl Clean<String> for Ident {
     #[inline]
-    fn clean(&self, cx: &DocContext<'_>) -> String {
+    fn clean(&self, cx: &mut DocContext<'_>) -> String {
         self.name.clean(cx)
     }
 }
 
 impl Clean<String> for Symbol {
     #[inline]
-    fn clean(&self, _: &DocContext<'_>) -> String {
+    fn clean(&self, _: &mut DocContext<'_>) -> String {
         self.to_string()
     }
 }
 
 impl Clean<BareFunctionDecl> for hir::BareFnTy<'_> {
-    fn clean(&self, cx: &DocContext<'_>) -> BareFunctionDecl {
-        let (generic_params, decl) = enter_impl_trait(cx, || {
+    fn clean(&self, cx: &mut DocContext<'_>) -> BareFunctionDecl {
+        let (generic_params, decl) = enter_impl_trait(cx, |cx| {
             (self.generic_params.clean(cx), (&*self.decl, self.param_names).clean(cx))
         });
         BareFunctionDecl { unsafety: self.unsafety, abi: self.abi, decl, generic_params }
@@ -1942,13 +1940,13 @@ fn clean(&self, cx: &DocContext<'_>) -> BareFunctionDecl {
 }
 
 impl Clean<Vec<Item>> for (&hir::Item<'_>, Option<Symbol>) {
-    fn clean(&self, cx: &DocContext<'_>) -> Vec<Item> {
+    fn clean(&self, cx: &mut DocContext<'_>) -> Vec<Item> {
         use hir::ItemKind;
 
         let (item, renamed) = self;
         let def_id = item.def_id.to_def_id();
         let mut name = renamed.unwrap_or_else(|| cx.tcx.hir().name(item.hir_id()));
-        cx.with_param_env(def_id, || {
+        cx.with_param_env(def_id, |cx| {
             let kind = match item.kind {
                 ItemKind::Static(ty, mutability, body_id) => {
                     StaticItem(Static { type_: ty.clean(cx), mutability, expr: Some(body_id) })
@@ -2031,7 +2029,7 @@ fn clean(&self, cx: &DocContext<'_>) -> Vec<Item> {
 }
 
 impl Clean<Item> for hir::Variant<'_> {
-    fn clean(&self, cx: &DocContext<'_>) -> Item {
+    fn clean(&self, cx: &mut DocContext<'_>) -> Item {
         let kind = VariantItem(self.data.clean(cx));
         let what_rustc_thinks =
             Item::from_hir_id_and_parts(self.id, Some(self.ident.name), kind, cx);
@@ -2042,7 +2040,7 @@ fn clean(&self, cx: &DocContext<'_>) -> Item {
 
 impl Clean<bool> for ty::ImplPolarity {
     /// Returns whether the impl has negative polarity.
-    fn clean(&self, _: &DocContext<'_>) -> bool {
+    fn clean(&self, _: &mut DocContext<'_>) -> bool {
         match self {
             &ty::ImplPolarity::Positive |
             // FIXME: do we want to do something else here?
@@ -2052,30 +2050,31 @@ fn clean(&self, _: &DocContext<'_>) -> bool {
     }
 }
 
-fn clean_impl(impl_: &hir::Impl<'_>, hir_id: hir::HirId, cx: &DocContext<'_>) -> Vec<Item> {
+fn clean_impl(impl_: &hir::Impl<'_>, hir_id: hir::HirId, cx: &mut DocContext<'_>) -> Vec<Item> {
+    let tcx = cx.tcx;
     let mut ret = Vec::new();
     let trait_ = impl_.of_trait.clean(cx);
     let items =
-        impl_.items.iter().map(|ii| cx.tcx.hir().impl_item(ii.id).clean(cx)).collect::<Vec<_>>();
-    let def_id = cx.tcx.hir().local_def_id(hir_id);
+        impl_.items.iter().map(|ii| tcx.hir().impl_item(ii.id).clean(cx)).collect::<Vec<_>>();
+    let def_id = tcx.hir().local_def_id(hir_id);
 
     // If this impl block is an implementation of the Deref trait, then we
     // need to try inlining the target's inherent impl blocks as well.
-    if trait_.def_id() == cx.tcx.lang_items().deref_trait() {
+    if trait_.def_id() == tcx.lang_items().deref_trait() {
         build_deref_target_impls(cx, &items, &mut ret);
     }
 
     let provided: FxHashSet<Symbol> = trait_
         .def_id()
-        .map(|did| cx.tcx.provided_trait_methods(did).map(|meth| meth.ident.name).collect())
+        .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.ident.name).collect())
         .unwrap_or_default();
 
     let for_ = impl_.self_ty.clean(cx);
-    let type_alias = for_.def_id().and_then(|did| match cx.tcx.def_kind(did) {
-        DefKind::TyAlias => Some(cx.tcx.type_of(did).clean(cx)),
+    let type_alias = for_.def_id().and_then(|did| match tcx.def_kind(did) {
+        DefKind::TyAlias => Some(tcx.type_of(did).clean(cx)),
         _ => None,
     });
-    let make_item = |trait_: Option<Type>, for_: Type, items: Vec<Item>| {
+    let mut make_item = |trait_: Option<Type>, for_: Type, items: Vec<Item>| {
         let kind = ImplItem(Impl {
             unsafety: impl_.unsafety,
             generics: impl_.generics.clean(cx),
@@ -2083,7 +2082,7 @@ fn clean_impl(impl_: &hir::Impl<'_>, hir_id: hir::HirId, cx: &DocContext<'_>) ->
             trait_,
             for_,
             items,
-            negative_polarity: cx.tcx.impl_polarity(def_id).clean(cx),
+            negative_polarity: tcx.impl_polarity(def_id).clean(cx),
             synthetic: false,
             blanket_impl: None,
         });
@@ -2100,7 +2099,7 @@ fn clean_extern_crate(
     krate: &hir::Item<'_>,
     name: Symbol,
     orig_name: Option<Symbol>,
-    cx: &DocContext<'_>,
+    cx: &mut DocContext<'_>,
 ) -> Vec<Item> {
     // this is the ID of the `extern crate` statement
     let cnum = cx.tcx.extern_mod_stmt_cnum(krate.def_id).unwrap_or(LOCAL_CRATE);
@@ -2147,7 +2146,7 @@ fn clean_use_statement(
     name: Symbol,
     path: &hir::Path<'_>,
     kind: hir::UseKind,
-    cx: &DocContext<'_>,
+    cx: &mut DocContext<'_>,
 ) -> Vec<Item> {
     // We need this comparison because some imports (for std types for example)
     // are "inserted" as well but directly by the compiler and they should not be
@@ -2237,13 +2236,13 @@ fn clean_use_statement(
 }
 
 impl Clean<Item> for (&hir::ForeignItem<'_>, Option<Symbol>) {
-    fn clean(&self, cx: &DocContext<'_>) -> Item {
+    fn clean(&self, cx: &mut DocContext<'_>) -> Item {
         let (item, renamed) = self;
-        cx.with_param_env(item.def_id.to_def_id(), || {
+        cx.with_param_env(item.def_id.to_def_id(), |cx| {
             let kind = match item.kind {
                 hir::ForeignItemKind::Fn(ref decl, ref names, ref generics) => {
                     let abi = cx.tcx.hir().get_foreign_abi(item.hir_id());
-                    let (generics, decl) = enter_impl_trait(cx, || {
+                    let (generics, decl) = enter_impl_trait(cx, |cx| {
                         (generics.clean(cx), (&**decl, &names[..]).clean(cx))
                     });
                     ForeignFunctionItem(Function {
@@ -2274,7 +2273,7 @@ fn clean(&self, cx: &DocContext<'_>) -> Item {
 }
 
 impl Clean<Item> for (&hir::MacroDef<'_>, Option<Symbol>) {
-    fn clean(&self, cx: &DocContext<'_>) -> Item {
+    fn clean(&self, cx: &mut DocContext<'_>) -> Item {
         let (item, renamed) = self;
         let name = renamed.unwrap_or(item.ident.name);
         let tts = item.ast.body.inner_tokens().trees().collect::<Vec<_>>();
@@ -2323,13 +2322,13 @@ fn clean(&self, cx: &DocContext<'_>) -> Item {
 }
 
 impl Clean<TypeBinding> for hir::TypeBinding<'_> {
-    fn clean(&self, cx: &DocContext<'_>) -> TypeBinding {
+    fn clean(&self, cx: &mut DocContext<'_>) -> TypeBinding {
         TypeBinding { name: self.ident.name, kind: self.kind.clean(cx) }
     }
 }
 
 impl Clean<TypeBindingKind> for hir::TypeBindingKind<'_> {
-    fn clean(&self, cx: &DocContext<'_>) -> TypeBindingKind {
+    fn clean(&self, cx: &mut DocContext<'_>) -> TypeBindingKind {
         match *self {
             hir::TypeBindingKind::Equality { ref ty } => {
                 TypeBindingKind::Equality { ty: ty.clean(cx) }
index e1ccbfd9da9deb7c4941cabbf4c587660fbc9dd9..3e7196fa7fa03d0f0950d570520ac8ec8c311bee 100644 (file)
@@ -130,7 +130,7 @@ pub fn from_hir_id_and_parts(
         hir_id: hir::HirId,
         name: Option<Symbol>,
         kind: ItemKind,
-        cx: &DocContext<'_>,
+        cx: &mut DocContext<'_>,
     ) -> Item {
         Item::from_def_id_and_parts(cx.tcx.hir().local_def_id(hir_id).to_def_id(), name, kind, cx)
     }
@@ -139,7 +139,7 @@ pub fn from_def_id_and_parts(
         def_id: DefId,
         name: Option<Symbol>,
         kind: ItemKind,
-        cx: &DocContext<'_>,
+        cx: &mut DocContext<'_>,
     ) -> Item {
         debug!("name={:?}, def_id={:?}", name, def_id);
 
@@ -936,7 +936,7 @@ fn lists(&self, name: Symbol) -> ListAttributesIter<'_> {
 }
 
 impl GenericBound {
-    crate fn maybe_sized(cx: &DocContext<'_>) -> GenericBound {
+    crate fn maybe_sized(cx: &mut DocContext<'_>) -> GenericBound {
         let did = cx.tcx.require_lang_item(LangItem::Sized, None);
         let empty = cx.tcx.intern_substs(&[]);
         let path = external_path(cx, cx.tcx.item_name(did), Some(did), false, vec![], empty);
index 59af49b0d8a283426d1f9bdf9d032d1e36e48d91..c7bfd363a129b5a40b89c0a2432763ef9f806c30 100644 (file)
@@ -90,7 +90,7 @@
 }
 
 fn external_generic_args(
-    cx: &DocContext<'_>,
+    cx: &mut DocContext<'_>,
     trait_did: Option<DefId>,
     has_self: bool,
     bindings: Vec<TypeBinding>,
@@ -142,7 +142,7 @@ fn external_generic_args(
 // trait_did should be set to a trait's DefId if called on a TraitRef, in order to sugar
 // from Fn<(A, B,), C> to Fn(A, B) -> C
 pub(super) fn external_path(
-    cx: &DocContext<'_>,
+    cx: &mut DocContext<'_>,
     name: Symbol,
     trait_did: Option<DefId>,
     has_self: bool,
@@ -214,7 +214,7 @@ pub(super) fn external_path(
     s
 }
 
-crate fn build_deref_target_impls(cx: &DocContext<'_>, items: &[Item], ret: &mut Vec<Item>) {
+crate fn build_deref_target_impls(cx: &mut DocContext<'_>, items: &[Item], ret: &mut Vec<Item>) {
     let tcx = cx.tcx;
 
     for item in items {
@@ -241,7 +241,7 @@ pub(super) fn external_path(
 
 impl ToSource for rustc_span::Span {
     fn to_src(&self, cx: &DocContext<'_>) -> String {
-        debug!("converting span {:?} to snippet", self.clean(cx));
+        debug!("converting span {:?} to snippet", self);
         let sn = match cx.sess().source_map().span_to_snippet(*self) {
             Ok(x) => x,
             Err(_) => String::new(),
@@ -407,7 +407,7 @@ fn print_const_with_custom_print_scalar(cx: &DocContext<'_>, ct: &'tcx ty::Const
 }
 
 /// Given a type Path, resolve it to a Type using the TyCtxt
-crate fn resolve_type(cx: &DocContext<'_>, path: Path, id: hir::HirId) -> Type {
+crate fn resolve_type(cx: &mut DocContext<'_>, path: Path, id: hir::HirId) -> Type {
     debug!("resolve_type({:?},{:?})", path, id);
 
     let is_generic = match path.res {
@@ -421,12 +421,12 @@ fn print_const_with_custom_print_scalar(cx: &DocContext<'_>, ct: &'tcx ty::Const
         Res::SelfTy(..) | Res::Def(DefKind::TyParam | DefKind::AssocTy, _) => true,
         _ => false,
     };
-    let did = register_res(&*cx, path.res);
+    let did = register_res(cx, path.res);
     ResolvedPath { path, param_names: None, did, is_generic }
 }
 
 crate fn get_auto_trait_and_blanket_impls(
-    cx: &DocContext<'tcx>,
+    cx: &mut DocContext<'tcx>,
     ty: Ty<'tcx>,
     param_env_def_id: DefId,
 ) -> impl Iterator<Item = Item> {
@@ -439,11 +439,11 @@ fn print_const_with_custom_print_scalar(cx: &DocContext<'_>, ct: &'tcx ty::Const
         .sess()
         .prof
         .generic_activity("get_blanket_impls")
-        .run(|| BlanketImplFinder::new(cx).get_blanket_impls(ty, param_env_def_id));
+        .run(|| BlanketImplFinder { cx }.get_blanket_impls(ty, param_env_def_id));
     auto_impls.into_iter().chain(blanket_impls)
 }
 
-crate fn register_res(cx: &DocContext<'_>, res: Res) -> DefId {
+crate fn register_res(cx: &mut DocContext<'_>, res: Res) -> DefId {
     debug!("register_res({:?})", res);
 
     let (did, kind) = match res {
@@ -483,21 +483,21 @@ fn print_const_with_custom_print_scalar(cx: &DocContext<'_>, ct: &'tcx ty::Const
     did
 }
 
-crate fn resolve_use_source(cx: &DocContext<'_>, path: Path) -> ImportSource {
+crate fn resolve_use_source(cx: &mut DocContext<'_>, path: Path) -> ImportSource {
     ImportSource {
         did: if path.res.opt_def_id().is_none() { None } else { Some(register_res(cx, path.res)) },
         path,
     }
 }
 
-crate fn enter_impl_trait<F, R>(cx: &DocContext<'_>, f: F) -> R
+crate fn enter_impl_trait<F, R>(cx: &mut DocContext<'_>, f: F) -> R
 where
-    F: FnOnce() -> R,
+    F: FnOnce(&mut DocContext<'_>) -> R,
 {
-    let old_bounds = mem::take(&mut *cx.impl_trait_bounds.borrow_mut());
-    let r = f();
+    let old_bounds = mem::take(&mut *cx.impl_trait_bounds.get_mut());
+    let r = f(cx);
     assert!(cx.impl_trait_bounds.borrow().is_empty());
-    *cx.impl_trait_bounds.borrow_mut() = old_bounds;
+    *cx.impl_trait_bounds.get_mut() = old_bounds;
     r
 }
 
index d79c47bbe3de652fe804204259b91df3d63ff977..1c2d2ad626c5a6999ff3cda3d25a4bdbbb812450 100644 (file)
@@ -32,6 +32,7 @@
 };
 
 use crate::clean;
+use crate::clean::inline::build_external_trait;
 use crate::clean::{AttributesExt, MAX_DEF_IDX};
 use crate::config::{Options as RustdocOptions, RenderOptions};
 use crate::config::{OutputFormat, RenderInfo};
 }
 
 impl<'tcx> DocContext<'tcx> {
-    crate fn sess(&self) -> &Session {
+    crate fn sess(&self) -> &'tcx Session {
         &self.tcx.sess
     }
 
-    crate fn with_param_env<T, F: FnOnce() -> T>(&self, def_id: DefId, f: F) -> T {
+    crate fn with_param_env<T, F: FnOnce(&mut Self) -> T>(&mut self, def_id: DefId, f: F) -> T {
         let old_param_env = self.param_env.replace(self.tcx.param_env(def_id));
-        let ret = f();
+        let ret = f(self);
         self.param_env.set(old_param_env);
         ret
     }
@@ -104,24 +105,24 @@ impl<'tcx> DocContext<'tcx> {
     /// Call the closure with the given parameters set as
     /// the substitutions for a type alias' RHS.
     crate fn enter_alias<F, R>(
-        &self,
+        &mut self,
         ty_substs: FxHashMap<DefId, clean::Type>,
         lt_substs: FxHashMap<DefId, clean::Lifetime>,
         ct_substs: FxHashMap<DefId, clean::Constant>,
         f: F,
     ) -> R
     where
-        F: FnOnce() -> R,
+        F: FnOnce(&mut Self) -> R,
     {
         let (old_tys, old_lts, old_cts) = (
-            mem::replace(&mut *self.ty_substs.borrow_mut(), ty_substs),
-            mem::replace(&mut *self.lt_substs.borrow_mut(), lt_substs),
-            mem::replace(&mut *self.ct_substs.borrow_mut(), ct_substs),
+            mem::replace(&mut *self.ty_substs.get_mut(), ty_substs),
+            mem::replace(&mut *self.lt_substs.get_mut(), lt_substs),
+            mem::replace(&mut *self.ct_substs.get_mut(), ct_substs),
         );
-        let r = f();
-        *self.ty_substs.borrow_mut() = old_tys;
-        *self.lt_substs.borrow_mut() = old_lts;
-        *self.ct_substs.borrow_mut() = old_cts;
+        let r = f(self);
+        *self.ty_substs.get_mut() = old_tys;
+        *self.lt_substs.get_mut() = old_lts;
+        *self.ct_substs.get_mut() = old_cts;
         r
     }
 
@@ -161,7 +162,7 @@ impl<'tcx> DocContext<'tcx> {
             }
             Entry::Occupied(e) => e.into_mut(),
         };
-        *def_index = DefIndex::from(*def_index + 1);
+        *def_index = *def_index + 1;
 
         DefId { krate: crate_num, index: *def_index }
     }
@@ -530,6 +531,16 @@ pub(crate) fn init_lints<F>(
         module_trait_cache: RefCell::new(FxHashMap::default()),
         cache: Cache::default(),
     };
+
+    // Small hack to force the Sized trait to be present.
+    //
+    // Note that in case of `#![no_core]`, the trait is not available.
+    if let Some(sized_trait_did) = ctxt.tcx.lang_items().sized_trait() {
+        let mut sized_trait = build_external_trait(&mut ctxt, sized_trait_did);
+        sized_trait.is_auto = true;
+        ctxt.external_traits.borrow_mut().insert(sized_trait_did, sized_trait);
+    }
+
     debug!("crate: {:?}", tcx.hir().krate());
 
     let mut krate = tcx.sess.time("clean_crate", || clean::krate(&mut ctxt));
@@ -627,7 +638,7 @@ fn report_deprecated_attr(name: &str, diag: &rustc_errors::Handler) {
         };
         if run {
             debug!("running pass {}", p.pass.name);
-            krate = ctxt.tcx.sess.time(p.pass.name, || (p.pass.run)(krate, &ctxt));
+            krate = ctxt.tcx.sess.time(p.pass.name, || (p.pass.run)(krate, &mut ctxt));
         }
     }
 
index 914ad35e7a4881eb93b85606e2f2a746b38cd6fd..f5eb92c1bb5aa0522b736321736d31c22551ec06 100644 (file)
@@ -181,7 +181,7 @@ fn tcx(&self) -> TyCtxt<'tcx> {
         self.shared.tcx
     }
 
-    fn sess(&self) -> &Session {
+    fn sess(&self) -> &'tcx Session {
         &self.shared.tcx.sess
     }
 }
index bbb833e54aeb959e641b622d1eb2cd6635f2afa4..689cda76cc0947a175f2f01efeb62674e4e872b1 100644 (file)
@@ -70,8 +70,8 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
     }
 }
 
-impl SourceCollector<'_, '_> {
-    fn sess(&self) -> &Session {
+impl SourceCollector<'_, 'tcx> {
+    fn sess(&self) -> &'tcx Session {
         &self.scx.tcx.sess
     }
 
index e2652ca378a81d78bade61d2edf208d1a8409291..b248fcdefbe7f337c9ee8bf78f84e54e31a55565 100644 (file)
@@ -182,7 +182,7 @@ fn from_clean_item_kind(item: clean::ItemKind, tcx: TyCtxt<'_>) -> ItemEnum {
             bounds: g.into_iter().map(Into::into).collect(),
             default: t.map(Into::into),
         },
-        StrippedItem(inner) => from_clean_item_kind(*inner, tcx).into(),
+        StrippedItem(inner) => from_clean_item_kind(*inner, tcx),
         PrimitiveItem(_) | KeywordItem(_) => {
             panic!("{:?} is not supported for JSON output", item)
         }
index b31276c9dcb7fb49e5f35197f34573eb8e16054c..ce88e09b174e5ba8a7c812945ffb6d6ea0b88c66 100644 (file)
@@ -37,8 +37,8 @@
     cache: Rc<Cache>,
 }
 
-impl JsonRenderer<'_> {
-    fn sess(&self) -> &Session {
+impl JsonRenderer<'tcx> {
+    fn sess(&self) -> &'tcx Session {
         self.tcx.sess
     }
 
index 18bc275572ff0752ca9f5ca92cd6f513bdfd98b6..d7978c4a0228db64f252037a25106accf8d50a1f 100644 (file)
@@ -432,13 +432,16 @@ fn usage(argv0: &str) {
         (option.apply)(&mut options);
     }
     println!("{}", options.usage(&format!("{} [options] <input>", argv0)));
+    println!("    @path               Read newline separated options from `path`\n");
     println!("More information available at https://doc.rust-lang.org/rustdoc/what-is-rustdoc.html")
 }
 
 /// A result type used by several functions under `main()`.
 type MainResult = Result<(), ErrorReported>;
 
-fn main_args(args: &[String]) -> MainResult {
+fn main_args(at_args: &[String]) -> MainResult {
+    let args = rustc_driver::args::arg_expand_all(at_args);
+
     let mut options = getopts::Options::new();
     for option in opts() {
         (option.apply)(&mut options);
index cdbff62d0645ccf9946c08b64f6a8402f94c2a29..542cf6d2c275ad5838fe367c7c1bcad4f66cb9f4 100644 (file)
@@ -20,8 +20,8 @@
     description: "counts the number of items with and without documentation",
 };
 
-fn calculate_doc_coverage(krate: clean::Crate, ctx: &DocContext<'_>) -> clean::Crate {
-    let mut calc = CoverageCalculator::new(ctx);
+fn calculate_doc_coverage(krate: clean::Crate, ctx: &mut DocContext<'_>) -> clean::Crate {
+    let mut calc = CoverageCalculator { items: Default::default(), ctx };
     let krate = calc.fold_crate(krate);
 
     calc.print_results();
@@ -101,7 +101,7 @@ fn add_assign(&mut self, rhs: Self) {
 
 struct CoverageCalculator<'a, 'b> {
     items: BTreeMap<FileName, ItemCount>,
-    ctx: &'a DocContext<'b>,
+    ctx: &'a mut DocContext<'b>,
 }
 
 fn limit_filename_len(filename: String) -> String {
@@ -115,10 +115,6 @@ fn limit_filename_len(filename: String) -> String {
 }
 
 impl<'a, 'b> CoverageCalculator<'a, 'b> {
-    fn new(ctx: &'a DocContext<'b>) -> CoverageCalculator<'a, 'b> {
-        CoverageCalculator { items: Default::default(), ctx }
-    }
-
     fn to_json(&self) -> String {
         serde_json::to_string(
             &self
index 9516130034b59216a76fd9446c941162859ece0e..c85490864ec70e68a1037d780ac961bc001896c1 100644 (file)
@@ -17,7 +17,7 @@
     description: "validates syntax inside Rust code blocks",
 };
 
-crate fn check_code_block_syntax(krate: clean::Crate, cx: &DocContext<'_>) -> clean::Crate {
+crate fn check_code_block_syntax(krate: clean::Crate, cx: &mut DocContext<'_>) -> clean::Crate {
     SyntaxChecker { cx }.fold_crate(krate)
 }
 
index a54b4adc13295c605f7139803cd3ea7ae3229e40..2c2ae9d03bf82ea272225c673f1a2581e7553c32 100644 (file)
     description: "resolves intra-doc links",
 };
 
-crate fn collect_intra_doc_links(krate: Crate, cx: &DocContext<'_>) -> Crate {
-    LinkCollector::new(cx).fold_crate(krate)
+crate fn collect_intra_doc_links(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
+    LinkCollector {
+        cx,
+        mod_ids: Vec::new(),
+        kind_side_channel: Cell::new(None),
+        visited_links: FxHashMap::default(),
+    }
+    .fold_crate(krate)
 }
 
 /// Top-level errors emitted by this pass.
@@ -257,7 +263,7 @@ struct CachedLink {
 }
 
 struct LinkCollector<'a, 'tcx> {
-    cx: &'a DocContext<'tcx>,
+    cx: &'a mut DocContext<'tcx>,
     /// A stack of modules used to decide what scope to resolve in.
     ///
     /// The last module will be used if the parent scope of the current item is
@@ -273,15 +279,6 @@ struct LinkCollector<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
-    fn new(cx: &'a DocContext<'tcx>) -> Self {
-        LinkCollector {
-            cx,
-            mod_ids: Vec::new(),
-            kind_side_channel: Cell::new(None),
-            visited_links: FxHashMap::default(),
-        }
-    }
-
     /// Given a full link, parse it as an [enum struct variant].
     ///
     /// In particular, this will return an error whenever there aren't three
@@ -293,7 +290,7 @@ fn variant_field(
         path_str: &'path str,
         module_id: DefId,
     ) -> Result<(Res, Option<String>), ErrorKind<'path>> {
-        let cx = self.cx;
+        let tcx = self.cx.tcx;
         let no_res = || ResolutionFailure::NotResolved {
             module_id,
             partial_res: None,
@@ -317,7 +314,8 @@ fn variant_field(
             // If there's no third component, we saw `[a::b]` before and it failed to resolve.
             // So there's no partial res.
             .ok_or_else(no_res)?;
-        let ty_res = cx
+        let ty_res = self
+            .cx
             .enter_resolver(|resolver| {
                 resolver.resolve_str_path_error(DUMMY_SP, &path, TypeNS, module_id)
             })
@@ -326,18 +324,17 @@ fn variant_field(
 
         match ty_res {
             Res::Def(DefKind::Enum, did) => {
-                if cx
-                    .tcx
+                if tcx
                     .inherent_impls(did)
                     .iter()
-                    .flat_map(|imp| cx.tcx.associated_items(*imp).in_definition_order())
+                    .flat_map(|imp| tcx.associated_items(*imp).in_definition_order())
                     .any(|item| item.ident.name == variant_name)
                 {
                     // This is just to let `fold_item` know that this shouldn't be considered;
                     // it's a bug for the error to make it to the user
                     return Err(ResolutionFailure::Dummy.into());
                 }
-                match cx.tcx.type_of(did).kind() {
+                match tcx.type_of(did).kind() {
                     ty::Adt(def, _) if def.is_enum() => {
                         if def.all_fields().any(|item| item.ident.name == variant_field_name) {
                             Ok((
@@ -380,20 +377,14 @@ fn resolve_primitive_associated_item(
         item_name: Symbol,
         item_str: &'path str,
     ) -> Result<(Res, Option<String>), ErrorKind<'path>> {
-        let cx = self.cx;
+        let tcx = self.cx.tcx;
 
         prim_ty
-            .impls(cx.tcx)
+            .impls(tcx)
             .into_iter()
             .find_map(|&impl_| {
-                cx.tcx
-                    .associated_items(impl_)
-                    .find_by_name_and_namespace(
-                        cx.tcx,
-                        Ident::with_dummy_span(item_name),
-                        ns,
-                        impl_,
-                    )
+                tcx.associated_items(impl_)
+                    .find_by_name_and_namespace(tcx, Ident::with_dummy_span(item_name), ns, impl_)
                     .map(|item| {
                         let kind = item.kind;
                         self.kind_side_channel.set(Some((kind.as_def_kind(), item.def_id)));
@@ -434,9 +425,8 @@ fn resolve_macro(
         path_str: &'a str,
         module_id: DefId,
     ) -> Result<Res, ResolutionFailure<'a>> {
-        let cx = self.cx;
         let path = ast::Path::from_ident(Ident::from_str(path_str));
-        cx.enter_resolver(|resolver| {
+        self.cx.enter_resolver(|resolver| {
             // FIXME(jynelson): does this really need 3 separate lookups?
             if let Ok((Some(ext), res)) = resolver.resolve_macro_path(
                 &path,
@@ -498,7 +488,7 @@ fn resolve<'path>(
         module_id: DefId,
         extra_fragment: &Option<String>,
     ) -> Result<(Res, Option<String>), ErrorKind<'path>> {
-        let cx = self.cx;
+        let cx = &self.cx;
 
         if let Some(res) = self.resolve_path(path_str, ns, module_id) {
             match res {
@@ -948,12 +938,18 @@ fn resolve_link(
             return None;
         }
 
-        let cx = self.cx;
         let link = ori_link.link.replace("`", "");
         let parts = link.split('#').collect::<Vec<_>>();
         let (link, extra_fragment) = if parts.len() > 2 {
             // A valid link can't have multiple #'s
-            anchor_failure(cx, &item, &link, dox, ori_link.range, AnchorFailure::MultipleAnchors);
+            anchor_failure(
+                self.cx,
+                &item,
+                &link,
+                dox,
+                ori_link.range,
+                AnchorFailure::MultipleAnchors,
+            );
             return None;
         } else if parts.len() == 2 {
             if parts[0].trim().is_empty() {
@@ -1105,7 +1101,7 @@ fn resolve_link(
                 if matches!(disambiguator, Some(Disambiguator::Primitive)) {
                     if fragment.is_some() {
                         anchor_failure(
-                            cx,
+                            self.cx,
                             &item,
                             path_str,
                             dox,
@@ -1119,7 +1115,7 @@ fn resolve_link(
                 } else {
                     // `[char]` when a `char` module is in scope
                     let candidates = vec![res, prim];
-                    ambiguity_error(cx, &item, path_str, dox, ori_link.range, candidates);
+                    ambiguity_error(self.cx, &item, path_str, dox, ori_link.range, candidates);
                     return None;
                 }
             }
@@ -1140,7 +1136,7 @@ fn resolve_link(
                 suggest_disambiguator(resolved, diag, path_str, dox, sp, &ori_link.range);
             };
             report_diagnostic(
-                cx,
+                self.cx,
                 BROKEN_INTRA_DOC_LINKS,
                 &msg,
                 &item,
@@ -1187,7 +1183,7 @@ fn resolve_link(
                 if self.cx.tcx.privacy_access_levels(LOCAL_CRATE).is_exported(hir_src)
                     && !self.cx.tcx.privacy_access_levels(LOCAL_CRATE).is_exported(hir_dst)
                 {
-                    privacy_error(cx, &item, &path_str, dox, &ori_link);
+                    privacy_error(self.cx, &item, &path_str, dox, &ori_link);
                 }
             }
 
@@ -1211,7 +1207,7 @@ fn resolve_link(
                         && !self.cx.tcx.features().intra_doc_pointers
                     {
                         let span = super::source_span_for_markdown_range(
-                            cx,
+                            self.cx,
                             dox,
                             &ori_link.range,
                             &item.attrs,
@@ -1243,7 +1239,7 @@ fn resolve_link(
             }
             Res::Def(kind, id) => {
                 verify(kind, id)?;
-                let id = clean::register_res(cx, rustc_hir::def::Res::Def(kind, id));
+                let id = clean::register_res(self.cx, rustc_hir::def::Res::Def(kind, id));
                 Some(ItemLink { link: ori_link.link, link_text, did: Some(id), fragment })
             }
         }
index 0951a9c2c9794169314d256befd671a670e1e05c..0b6d81d1b447effc3aa557e1831f7f6e35ccfb0c 100644 (file)
     description: "retrieves trait impls for items in the crate",
 };
 
-crate fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate {
-    let mut synth = SyntheticImplCollector::new(cx);
-    let mut krate = cx.sess().time("collect_synthetic_impls", || synth.fold_crate(krate));
+crate fn collect_trait_impls(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
+    let (mut krate, synth_impls) = cx.sess().time("collect_synthetic_impls", || {
+        let mut synth = SyntheticImplCollector { cx, impls: Vec::new() };
+        (synth.fold_crate(krate), synth.impls)
+    });
 
     let prims: FxHashSet<PrimitiveType> = krate.primitives.iter().map(|p| p.1).collect();
 
@@ -142,7 +144,7 @@ fn add_deref_target(
         panic!("collect-trait-impls can't run");
     };
 
-    items.extend(synth.impls);
+    items.extend(synth_impls);
     for it in new_items.drain(..) {
         if let ImplItem(Impl { ref for_, ref trait_, ref blanket_impl, .. }) = *it.kind {
             if !(cleaner.keep_impl(for_)
@@ -160,16 +162,10 @@ fn add_deref_target(
 }
 
 struct SyntheticImplCollector<'a, 'tcx> {
-    cx: &'a DocContext<'tcx>,
+    cx: &'a mut DocContext<'tcx>,
     impls: Vec<Item>,
 }
 
-impl<'a, 'tcx> SyntheticImplCollector<'a, 'tcx> {
-    fn new(cx: &'a DocContext<'tcx>) -> Self {
-        SyntheticImplCollector { cx, impls: Vec::new() }
-    }
-}
-
 impl<'a, 'tcx> DocFolder for SyntheticImplCollector<'a, 'tcx> {
     fn fold_item(&mut self, i: Item) -> Option<Item> {
         if i.is_struct() || i.is_enum() || i.is_union() {
index 11f572560d60695d45bfab700256019fafe7d81f..042a895d2fa2f4e8daf314db6a3660e2b89451a4 100644 (file)
 };
 
 struct PrivateItemDocTestLinter<'a, 'tcx> {
-    cx: &'a DocContext<'tcx>,
+    cx: &'a mut DocContext<'tcx>,
 }
 
-impl<'a, 'tcx> PrivateItemDocTestLinter<'a, 'tcx> {
-    fn new(cx: &'a DocContext<'tcx>) -> Self {
-        PrivateItemDocTestLinter { cx }
-    }
-}
-
-crate fn check_private_items_doc_tests(krate: Crate, cx: &DocContext<'_>) -> Crate {
-    let mut coll = PrivateItemDocTestLinter::new(cx);
+crate fn check_private_items_doc_tests(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
+    let mut coll = PrivateItemDocTestLinter { cx };
 
     coll.fold_crate(krate)
 }
 
 impl<'a, 'tcx> DocFolder for PrivateItemDocTestLinter<'a, 'tcx> {
     fn fold_item(&mut self, item: Item) -> Option<Item> {
-        let cx = self.cx;
         let dox = item.attrs.collapsed_doc_value().unwrap_or_else(String::new);
 
-        look_for_tests(&cx, &dox, &item);
+        look_for_tests(self.cx, &dox, &item);
 
         Some(self.fold_item_recur(item))
     }
index 38ec2bef0adeb574881b22e17c966eef42312b19..a6fe7e228d7e8105ed7c95c0eee666ed6747e4c7 100644 (file)
 };
 
 struct InvalidHtmlTagsLinter<'a, 'tcx> {
-    cx: &'a DocContext<'tcx>,
+    cx: &'a mut DocContext<'tcx>,
 }
 
-impl<'a, 'tcx> InvalidHtmlTagsLinter<'a, 'tcx> {
-    fn new(cx: &'a DocContext<'tcx>) -> Self {
-        InvalidHtmlTagsLinter { cx }
-    }
-}
-
-crate fn check_invalid_html_tags(krate: Crate, cx: &DocContext<'_>) -> Crate {
+crate fn check_invalid_html_tags(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
     if !cx.tcx.sess.is_nightly_build() {
         krate
     } else {
-        let mut coll = InvalidHtmlTagsLinter::new(cx);
+        let mut coll = InvalidHtmlTagsLinter { cx };
 
         coll.fold_crate(krate)
     }
index 7ac42c759924890a0e5a3d7e8c42f908fe654e31..5813732facb6e92f6ad38e4195ca391d74a5b24d 100644 (file)
@@ -53,7 +53,7 @@
 #[derive(Copy, Clone)]
 crate struct Pass {
     crate name: &'static str,
-    crate run: fn(clean::Crate, &DocContext<'_>) -> clean::Crate,
+    crate run: fn(clean::Crate, &mut DocContext<'_>) -> clean::Crate,
     crate description: &'static str,
 }
 
index efb5df08cafdb33a8d14a3cd1d8c32506ad5af0c..9d4539a9769ca05891848a0ea954deab15ceeda2 100644 (file)
 );
 
 struct NonAutolinksLinter<'a, 'tcx> {
-    cx: &'a DocContext<'tcx>,
+    cx: &'a mut DocContext<'tcx>,
     regex: Regex,
 }
 
 impl<'a, 'tcx> NonAutolinksLinter<'a, 'tcx> {
-    fn new(cx: &'a DocContext<'tcx>) -> Self {
-        Self { cx, regex: Regex::new(URL_REGEX).expect("failed to build regex") }
-    }
-
     fn find_raw_urls(
         &self,
         text: &str,
@@ -52,11 +48,12 @@ fn find_raw_urls(
     }
 }
 
-crate fn check_non_autolinks(krate: Crate, cx: &DocContext<'_>) -> Crate {
+crate fn check_non_autolinks(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
     if !cx.tcx.sess.is_nightly_build() {
         krate
     } else {
-        let mut coll = NonAutolinksLinter::new(cx);
+        let mut coll =
+            NonAutolinksLinter { cx, regex: Regex::new(URL_REGEX).expect("failed to build regex") };
 
         coll.fold_crate(krate)
     }
index 6722d7c2fc9feaa998c9e3857b9e17ba6a5b3725..2369ff78b1ce05eee76299ab1e9383da4b919fbc 100644 (file)
@@ -12,7 +12,7 @@
     description: "propagates `#[doc(cfg(...))]` to child items",
 };
 
-crate fn propagate_doc_cfg(cr: Crate, _: &DocContext<'_>) -> Crate {
+crate fn propagate_doc_cfg(cr: Crate, _: &mut DocContext<'_>) -> Crate {
     CfgPropagator { parent_cfg: None }.fold_crate(cr)
 }
 
index 79f8562c4726df74769fb6bdf6bf63863512f2b0..c742d32cb62eab09756d992a712d76ebeedcbf53 100644 (file)
@@ -15,7 +15,7 @@
 };
 
 /// Strip items marked `#[doc(hidden)]`
-crate fn strip_hidden(krate: clean::Crate, _: &DocContext<'_>) -> clean::Crate {
+crate fn strip_hidden(krate: clean::Crate, _: &mut DocContext<'_>) -> clean::Crate {
     let mut retained = DefIdSet::default();
 
     // strip all #[doc(hidden)] items
index 6eeaabacbc138fe9212d04e4d628fed4fd74635b..63869324cb8d234c94314a14a09f33b74b92ad9c 100644 (file)
@@ -9,6 +9,6 @@
     description: "strips all private import statements (`use`, `extern crate`) from a crate",
 };
 
-crate fn strip_priv_imports(krate: clean::Crate, _: &DocContext<'_>) -> clean::Crate {
+crate fn strip_priv_imports(krate: clean::Crate, _: &mut DocContext<'_>) -> clean::Crate {
     ImportStripper.fold_crate(krate)
 }
index e812bcd87fe3c8c838a764c4e7b1a346ba9e58b9..c0bb05af3edb51dda040b94ef9a758beb5374cdb 100644 (file)
@@ -14,7 +14,7 @@
 
 /// Strip private items from the point of view of a crate or externally from a
 /// crate, specified by the `xcrate` flag.
-crate fn strip_private(mut krate: clean::Crate, cx: &DocContext<'_>) -> clean::Crate {
+crate fn strip_private(mut krate: clean::Crate, cx: &mut DocContext<'_>) -> clean::Crate {
     // This stripper collects all *retained* nodes.
     let mut retained = DefIdSet::default();
     let access_levels = cx.renderinfo.borrow().access_levels.clone();
index 1cad480d4e84705dcb4172b3ba57ec03861a3d95..da2eda73641228e737f6f70cab177bbc48511940 100644 (file)
@@ -14,7 +14,7 @@
     description: "removes excess indentation on comments in order for markdown to like it",
 };
 
-crate fn unindent_comments(krate: clean::Crate, _: &DocContext<'_>) -> clean::Crate {
+crate fn unindent_comments(krate: clean::Crate, _: &mut DocContext<'_>) -> clean::Crate {
     CommentCleaner.fold_crate(krate)
 }
 
index 789e4bc80ace90d079cc1c59e5a4a37e420eb017..8877c6cc9927b9111e1afaf0994a20f110c61343 100644 (file)
@@ -13,4 +13,6 @@ impl X for () {
     type Y<T> where Self: Sized = u32;
 }
 
+fn f<T: X<Y<()> = i32>>() {}
+
 fn main() { }
diff --git a/src/test/run-make/libtest-thread-limit/Makefile b/src/test/run-make/libtest-thread-limit/Makefile
new file mode 100644 (file)
index 0000000..29c1bc7
--- /dev/null
@@ -0,0 +1,7 @@
+-include ../../run-make-fulldeps/tools.mk
+
+# only-linux
+
+all:
+       $(RUSTC) test.rs --test --target $(TARGET)
+       $(shell ulimit -p 0 && $(call RUN,test))
diff --git a/src/test/run-make/libtest-thread-limit/test.rs b/src/test/run-make/libtest-thread-limit/test.rs
new file mode 100644 (file)
index 0000000..d899411
--- /dev/null
@@ -0,0 +1,16 @@
+#![feature(once_cell)]
+
+use std::{io::ErrorKind, lazy::SyncOnceCell, thread::{self, Builder, ThreadId}};
+
+static THREAD_ID: SyncOnceCell<ThreadId> = SyncOnceCell::new();
+
+#[test]
+fn spawn_thread_would_block() {
+    assert_eq!(Builder::new().spawn(|| unreachable!()).unwrap_err().kind(), ErrorKind::WouldBlock);
+    THREAD_ID.set(thread::current().id()).unwrap();
+}
+
+#[test]
+fn run_in_same_thread() {
+    assert_eq!(*THREAD_ID.get().unwrap(), thread::current().id());
+}
diff --git a/src/test/rustdoc-ui/commandline-argfile-badutf8.args b/src/test/rustdoc-ui/commandline-argfile-badutf8.args
new file mode 100644 (file)
index 0000000..c070b0c
--- /dev/null
@@ -0,0 +1,2 @@
+--cfg
+unbroken\80
\ No newline at end of file
diff --git a/src/test/rustdoc-ui/commandline-argfile-badutf8.rs b/src/test/rustdoc-ui/commandline-argfile-badutf8.rs
new file mode 100644 (file)
index 0000000..e2984e3
--- /dev/null
@@ -0,0 +1,12 @@
+// Check to see if we can get parameters from an @argsfile file
+//
+// compile-flags: --cfg cmdline_set @{{src-base}}/commandline-argfile-badutf8.args
+
+#[cfg(not(cmdline_set))]
+compile_error!("cmdline_set not set");
+
+#[cfg(not(unbroken))]
+compile_error!("unbroken not set");
+
+fn main() {
+}
diff --git a/src/test/rustdoc-ui/commandline-argfile-badutf8.stderr b/src/test/rustdoc-ui/commandline-argfile-badutf8.stderr
new file mode 100644 (file)
index 0000000..9af6fc0
--- /dev/null
@@ -0,0 +1,2 @@
+error: Failed to load argument file: Utf8 error in $DIR/commandline-argfile-badutf8.args
+
diff --git a/src/test/rustdoc-ui/commandline-argfile-missing.rs b/src/test/rustdoc-ui/commandline-argfile-missing.rs
new file mode 100644 (file)
index 0000000..020c3ff
--- /dev/null
@@ -0,0 +1,15 @@
+// Check to see if we can get parameters from an @argsfile file
+//
+// ignore-tidy-linelength
+// normalize-stderr-test: "os error \d+" -> "os error $$ERR"
+// normalize-stderr-test: "commandline-argfile-missing.args:[^(]*" -> "commandline-argfile-missing.args: $$FILE_MISSING "
+// compile-flags: --cfg cmdline_set @{{src-base}}/commandline-argfile-missing.args
+
+#[cfg(not(cmdline_set))]
+compile_error!("cmdline_set not set");
+
+#[cfg(not(unbroken))]
+compile_error!("unbroken not set");
+
+fn main() {
+}
diff --git a/src/test/rustdoc-ui/commandline-argfile-missing.stderr b/src/test/rustdoc-ui/commandline-argfile-missing.stderr
new file mode 100644 (file)
index 0000000..179ad83
--- /dev/null
@@ -0,0 +1,2 @@
+error: Failed to load argument file: IO Error: $DIR/commandline-argfile-missing.args: $FILE_MISSING (os error $ERR)
+
diff --git a/src/test/rustdoc-ui/commandline-argfile.args b/src/test/rustdoc-ui/commandline-argfile.args
new file mode 100644 (file)
index 0000000..972938b
--- /dev/null
@@ -0,0 +1,2 @@
+--cfg
+unbroken
\ No newline at end of file
diff --git a/src/test/rustdoc-ui/commandline-argfile.rs b/src/test/rustdoc-ui/commandline-argfile.rs
new file mode 100644 (file)
index 0000000..cc8c872
--- /dev/null
@@ -0,0 +1,13 @@
+// Check to see if we can get parameters from an @argsfile file
+//
+// check-pass
+// compile-flags: --cfg cmdline_set @{{src-base}}/commandline-argfile.args
+
+#[cfg(not(cmdline_set))]
+compile_error!("cmdline_set not set");
+
+#[cfg(not(unbroken))]
+compile_error!("unbroken not set");
+
+fn main() {
+}
index d0af3aec6609782384c90afa9f80d5c263f68575..fc0ff904389320f01f8be3c86d034311d1dccf41 100644 (file)
@@ -1,3 +1,4 @@
 #![deny(broken_intra_doc_links)]
+#![feature(intra_doc_pointers)]
 
 pub use std::*;
diff --git a/src/test/rustdoc/sized_trait.rs b/src/test/rustdoc/sized_trait.rs
new file mode 100644 (file)
index 0000000..26d1281
--- /dev/null
@@ -0,0 +1,17 @@
+#![crate_name = "foo"]
+
+// @has foo/struct.Bar.html
+// @!has - '//h3[@id="impl-Sized"]'
+pub struct Bar {
+    a: u16,
+}
+
+// @has foo/struct.Foo.html
+// @!has - '//h3[@id="impl-Sized"]'
+pub struct Foo<T: ?Sized>(T);
+
+// @has foo/struct.Unsized.html
+// @has - '//h3[@id="impl-Sized"]/code' 'impl !Sized for Unsized'
+pub struct Unsized {
+    data: [u8],
+}
index 127ab8673556d5bf1554ae11d92027176b84fff6..6897b31fe46857dd89de03866b7719553126c631 100644 (file)
@@ -31,82 +31,47 @@ LL |     bar::<IntStruct>();
 error: implementation of `TheTrait` is not general enough
   --> $DIR/associated-types-eq-hr.rs:96:5
    |
-LL | / pub trait TheTrait<T> {
-LL | |     type A;
-LL | |
-LL | |     fn get(&self, t: T) -> Self::A;
-LL | | }
-   | |_- trait `TheTrait` defined here
-...
-LL |       tuple_one::<Tuple>();
-   |       ^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough
+LL |     tuple_one::<Tuple>();
+   |     ^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough
    |
    = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`...
-   = note: ...but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
+   = note: ...but it actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
 
 error: implementation of `TheTrait` is not general enough
   --> $DIR/associated-types-eq-hr.rs:96:5
    |
-LL | / pub trait TheTrait<T> {
-LL | |     type A;
-LL | |
-LL | |     fn get(&self, t: T) -> Self::A;
-LL | | }
-   | |_- trait `TheTrait` defined here
-...
-LL |       tuple_one::<Tuple>();
-   |       ^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough
+LL |     tuple_one::<Tuple>();
+   |     ^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough
    |
    = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`...
-   = note: ...but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
+   = note: ...but it actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
 
 error: implementation of `TheTrait` is not general enough
   --> $DIR/associated-types-eq-hr.rs:102:5
    |
-LL | / pub trait TheTrait<T> {
-LL | |     type A;
-LL | |
-LL | |     fn get(&self, t: T) -> Self::A;
-LL | | }
-   | |_- trait `TheTrait` defined here
-...
-LL |       tuple_two::<Tuple>();
-   |       ^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough
+LL |     tuple_two::<Tuple>();
+   |     ^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough
    |
    = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`...
-   = note: ...but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
+   = note: ...but it actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
 
 error: implementation of `TheTrait` is not general enough
   --> $DIR/associated-types-eq-hr.rs:102:5
    |
-LL | / pub trait TheTrait<T> {
-LL | |     type A;
-LL | |
-LL | |     fn get(&self, t: T) -> Self::A;
-LL | | }
-   | |_- trait `TheTrait` defined here
-...
-LL |       tuple_two::<Tuple>();
-   |       ^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough
+LL |     tuple_two::<Tuple>();
+   |     ^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough
    |
    = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`...
-   = note: ...but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
+   = note: ...but it actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
 
 error: implementation of `TheTrait` is not general enough
   --> $DIR/associated-types-eq-hr.rs:112:5
    |
-LL | / pub trait TheTrait<T> {
-LL | |     type A;
-LL | |
-LL | |     fn get(&self, t: T) -> Self::A;
-LL | | }
-   | |_- trait `TheTrait` defined here
-...
-LL |       tuple_four::<Tuple>();
-   |       ^^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough
+LL |     tuple_four::<Tuple>();
+   |     ^^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough
    |
    = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`...
-   = note: ...but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
+   = note: ...but it actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
 
 error: aborting due to 7 previous errors
 
diff --git a/src/test/ui/associated-types/issue-21726.rs b/src/test/ui/associated-types/issue-21726.rs
new file mode 100644 (file)
index 0000000..b98cf21
--- /dev/null
@@ -0,0 +1,38 @@
+// check-pass
+#![allow(dead_code)]
+// Regression test for #21726: an issue arose around the rules for
+// subtyping of projection types that resulted in an unconstrained
+// region, yielding region inference failures.
+
+// pretty-expanded FIXME #23616
+
+fn main() { }
+
+fn foo<'a>(s: &'a str) {
+    let b: B<()> = B::new(s, ());
+    b.get_short();
+}
+
+trait IntoRef<'a> {
+    type T: Clone;
+    fn into_ref(self, _: &'a str) -> Self::T;
+}
+
+impl<'a> IntoRef<'a> for () {
+    type T = &'a str;
+    fn into_ref(self, s: &'a str) -> &'a str {
+        s
+    }
+}
+
+struct B<'a, P: IntoRef<'a>>(P::T);
+
+impl<'a, P: IntoRef<'a>> B<'a, P> {
+    fn new(s: &'a str, i: P) -> B<'a, P> {
+        B(i.into_ref(s))
+    }
+
+    fn get_short(&self) -> P::T {
+        self.0.clone()
+    }
+}
diff --git a/src/test/ui/associated-types/issue-22560.rs b/src/test/ui/associated-types/issue-22560.rs
new file mode 100644 (file)
index 0000000..44be881
--- /dev/null
@@ -0,0 +1,15 @@
+trait Add<Rhs=Self> {
+    type Output;
+}
+
+trait Sub<Rhs=Self> {
+    type Output;
+}
+
+type Test = dyn Add + Sub;
+//~^ ERROR E0393
+//~| ERROR E0191
+//~| ERROR E0393
+//~| ERROR E0225
+
+fn main() { }
diff --git a/src/test/ui/associated-types/issue-22560.stderr b/src/test/ui/associated-types/issue-22560.stderr
new file mode 100644 (file)
index 0000000..9dda991
--- /dev/null
@@ -0,0 +1,60 @@
+error[E0393]: the type parameter `Rhs` must be explicitly specified
+  --> $DIR/issue-22560.rs:9:23
+   |
+LL | / trait Sub<Rhs=Self> {
+LL | |     type Output;
+LL | | }
+   | |_- type parameter `Rhs` must be specified for this
+LL | 
+LL |   type Test = dyn Add + Sub;
+   |                         ^^^ help: set the type parameter to the desired type: `Sub<Rhs>`
+   |
+   = note: because of the default `Self` reference, type parameters must be specified on object types
+
+error[E0393]: the type parameter `Rhs` must be explicitly specified
+  --> $DIR/issue-22560.rs:9:17
+   |
+LL | / trait Add<Rhs=Self> {
+LL | |     type Output;
+LL | | }
+   | |_- type parameter `Rhs` must be specified for this
+...
+LL |   type Test = dyn Add + Sub;
+   |                   ^^^ help: set the type parameter to the desired type: `Add<Rhs>`
+   |
+   = note: because of the default `Self` reference, type parameters must be specified on object types
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/issue-22560.rs:9:23
+   |
+LL | type Test = dyn Add + Sub;
+   |                 ---   ^^^ additional non-auto trait
+   |                 |
+   |                 first non-auto trait
+   |
+   = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Add<[type error]> + Sub<[type error]> {}`
+   = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
+
+error[E0191]: the value of the associated types `Output` (from trait `Add`), `Output` (from trait `Sub`) must be specified
+  --> $DIR/issue-22560.rs:9:17
+   |
+LL |     type Output;
+   |     ------------ `Output` defined here
+...
+LL |     type Output;
+   |     ------------ `Output` defined here
+...
+LL | type Test = dyn Add + Sub;
+   |                 ^^^   ^^^ associated type `Output` must be specified
+   |                 |
+   |                 associated type `Output` must be specified
+   |
+help: specify the associated types
+   |
+LL | type Test = dyn Add<Output = Type> + Sub<Output = Type>;
+   |                 ^^^^^^^^^^^^^^^^^^   ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0191, E0225, E0393.
+For more information about an error, try `rustc --explain E0191`.
diff --git a/src/test/ui/associated-types/issue-23595-2.rs b/src/test/ui/associated-types/issue-23595-2.rs
new file mode 100644 (file)
index 0000000..2bfee7a
--- /dev/null
@@ -0,0 +1,10 @@
+#![feature(associated_type_defaults)]
+
+pub struct C<AType: A> {a:AType}
+
+pub trait A {
+    type B = C<Self::anything_here_kills_it>;
+    //~^ ERROR: associated type `anything_here_kills_it` not found for `Self`
+}
+
+fn main() {}
diff --git a/src/test/ui/associated-types/issue-23595-2.stderr b/src/test/ui/associated-types/issue-23595-2.stderr
new file mode 100644 (file)
index 0000000..dded673
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0220]: associated type `anything_here_kills_it` not found for `Self`
+  --> $DIR/issue-23595-2.rs:6:22
+   |
+LL |     type B = C<Self::anything_here_kills_it>;
+   |                      ^^^^^^^^^^^^^^^^^^^^^^ associated type `anything_here_kills_it` not found
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0220`.
diff --git a/src/test/ui/associated-types/issue-24204.rs b/src/test/ui/associated-types/issue-24204.rs
new file mode 100644 (file)
index 0000000..5a7b345
--- /dev/null
@@ -0,0 +1,25 @@
+// check-pass
+
+#![allow(dead_code)]
+
+trait MultiDispatch<T> {
+    type O;
+}
+
+trait Trait: Sized {
+    type A: MultiDispatch<Self::B, O = Self>;
+    type B;
+
+    fn new<U>(u: U) -> <Self::A as MultiDispatch<U>>::O
+    where
+        Self::A: MultiDispatch<U>;
+}
+
+fn test<T: Trait<B = i32>>(b: i32) -> T
+where
+    T::A: MultiDispatch<i32>,
+{
+    T::new(b)
+}
+
+fn main() {}
diff --git a/src/test/ui/associated-types/issue-43784-associated-type.rs b/src/test/ui/associated-types/issue-43784-associated-type.rs
new file mode 100644 (file)
index 0000000..78815d8
--- /dev/null
@@ -0,0 +1,17 @@
+pub trait Partial<X: ?Sized>: Copy {
+}
+
+pub trait Complete {
+    type Assoc: Partial<Self>;
+}
+
+impl<T> Partial<T> for T::Assoc where
+    T: Complete
+{
+}
+
+impl<T> Complete for T {
+    type Assoc = T; //~ ERROR the trait bound `T: Copy` is not satisfied
+}
+
+fn main() {}
diff --git a/src/test/ui/associated-types/issue-43784-associated-type.stderr b/src/test/ui/associated-types/issue-43784-associated-type.stderr
new file mode 100644 (file)
index 0000000..d5105ae
--- /dev/null
@@ -0,0 +1,17 @@
+error[E0277]: the trait bound `T: Copy` is not satisfied
+  --> $DIR/issue-43784-associated-type.rs:14:5
+   |
+LL |     type Assoc: Partial<Self>;
+   |                 ------------- required by this bound in `Complete::Assoc`
+...
+LL |     type Assoc = T;
+   |     ^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T`
+   |
+help: consider restricting type parameter `T`
+   |
+LL | impl<T: Copy> Complete for T {
+   |       ^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/associated-types/project-defer-unification.rs b/src/test/ui/associated-types/project-defer-unification.rs
new file mode 100644 (file)
index 0000000..547ff45
--- /dev/null
@@ -0,0 +1,104 @@
+// run-pass
+
+#![allow(dead_code)]
+#![allow(unused_variables)]
+#![allow(unreachable_code)]
+// A regression test extracted from image-0.3.11. The point of
+// failure was in `index_colors` below.
+
+use std::ops::{Deref, DerefMut};
+
+#[derive(Copy, Clone)]
+pub struct Luma<T: Primitive> { pub data: [T; 1] }
+
+impl<T: Primitive + 'static> Pixel for Luma<T> {
+    type Subpixel = T;
+}
+
+pub struct ImageBuffer<P: Pixel, Container> {
+    pixels: P,
+    c: Container,
+}
+
+pub trait GenericImage: Sized {
+    type Pixel: Pixel;
+}
+
+pub trait Pixel: Copy + Clone {
+    type Subpixel: Primitive;
+}
+
+pub trait Primitive: Copy + PartialOrd<Self> + Clone  {
+}
+
+impl<P, Container> GenericImage for ImageBuffer<P, Container>
+where P: Pixel + 'static,
+      Container: Deref<Target=[P::Subpixel]> + DerefMut,
+      P::Subpixel: 'static {
+
+    type Pixel = P;
+}
+
+impl Primitive for u8 { }
+
+impl<P, Container> ImageBuffer<P, Container>
+where P: Pixel + 'static,
+      P::Subpixel: 'static,
+      Container: Deref<Target=[P::Subpixel]>
+{
+    pub fn pixels<'a>(&'a self) -> Pixels<'a, Self> {
+        loop { }
+    }
+
+    pub fn pixels_mut(&mut self) -> PixelsMut<P> {
+        loop { }
+    }
+}
+
+pub struct Pixels<'a, I: 'a> {
+    image:  &'a I,
+    x:      u32,
+    y:      u32,
+    width:  u32,
+    height: u32
+}
+
+impl<'a, I: GenericImage> Iterator for Pixels<'a, I> {
+    type Item = (u32, u32, I::Pixel);
+
+    fn next(&mut self) -> Option<(u32, u32, I::Pixel)> {
+        loop { }
+    }
+}
+
+pub struct PixelsMut<'a, P: Pixel + 'a> where P::Subpixel: 'a {
+    chunks: &'a mut P::Subpixel
+}
+
+impl<'a, P: Pixel + 'a> Iterator for PixelsMut<'a, P> where P::Subpixel: 'a {
+    type Item = &'a mut P;
+
+    fn next(&mut self) -> Option<&'a mut P> {
+        loop { }
+    }
+}
+
+pub fn index_colors<Pix>(image: &ImageBuffer<Pix, Vec<u8>>)
+                         -> ImageBuffer<Luma<u8>, Vec<u8>>
+where Pix: Pixel<Subpixel=u8> + 'static,
+{
+    // When NLL-enabled, `let mut` below is deemed unnecessary (due to
+    // the remaining code being unreachable); so ignore that lint.
+    #![allow(unused_mut)]
+
+    let mut indices: ImageBuffer<_,Vec<_>> = loop { };
+    for (pixel, idx) in image.pixels().zip(indices.pixels_mut()) {
+        // failured occurred here ^^ because we were requiring that we
+        // could project Pixel or Subpixel from `T_indices` (type of
+        // `indices`), but the type is insufficiently constrained
+        // until we reach the return below.
+    }
+    indices
+}
+
+fn main() { }
index 02342af8dc53e15fe12755ceeba6d87e0a53ffc7..0307875c154b8bc291f608841b70dd4eba35bb85 100644 (file)
@@ -1 +1 @@
-{"module":{"inner":{"lo":0,"hi":0},"unsafety":"No","items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]}
+{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"span":{"lo":0,"hi":0},"proc_macros":[]}
index 235f39c567b8eee3184a50227c8d3da169facb3f..d26530efe3ecd7fb337cb57afb0e5b0700685013 100644 (file)
@@ -1 +1 @@
-{"module":{"inner":{"lo":0,"hi":0},"unsafety":"No","items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"v1","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]}
+{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"v1","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"span":{"lo":0,"hi":0},"proc_macros":[]}
diff --git a/src/test/ui/async-await/generator-desc.rs b/src/test/ui/async-await/generator-desc.rs
new file mode 100644 (file)
index 0000000..5008120
--- /dev/null
@@ -0,0 +1,16 @@
+// edition:2018
+#![feature(async_closure)]
+use std::future::Future;
+
+async fn one() {}
+async fn two() {}
+
+fn fun<F: Future<Output = ()>>(f1: F, f2: F) {}
+fn main() {
+    fun(async {}, async {});
+    //~^ ERROR mismatched types
+    fun(one(), two());
+    //~^ ERROR mismatched types
+    fun((async || {})(), (async || {})());
+    //~^ ERROR mismatched types
+}
diff --git a/src/test/ui/async-await/generator-desc.stderr b/src/test/ui/async-await/generator-desc.stderr
new file mode 100644 (file)
index 0000000..b85926c
--- /dev/null
@@ -0,0 +1,49 @@
+error[E0308]: mismatched types
+  --> $DIR/generator-desc.rs:10:25
+   |
+LL |     fun(async {}, async {});
+   |               --        ^^ expected `async` block, found a different `async` block
+   |               |
+   |               the expected `async` block
+   |
+   = note: expected `async` block `[static generator@$DIR/generator-desc.rs:10:15: 10:17]`
+              found `async` block `[static generator@$DIR/generator-desc.rs:10:25: 10:27]`
+
+error[E0308]: mismatched types
+  --> $DIR/generator-desc.rs:12:16
+   |
+LL | async fn one() {}
+   |                - the `Output` of this `async fn`'s expected opaque type
+LL | async fn two() {}
+   |                - the `Output` of this `async fn`'s found opaque type
+...
+LL |     fun(one(), two());
+   |                ^^^^^ expected opaque type, found a different opaque type
+   |
+   = note: expected opaque type `impl Future` (opaque type at <$DIR/generator-desc.rs:5:16>)
+              found opaque type `impl Future` (opaque type at <$DIR/generator-desc.rs:6:16>)
+   = help: consider `await`ing on both `Future`s
+   = note: distinct uses of `impl Trait` result in different opaque types
+
+error[E0308]: mismatched types
+  --> $DIR/generator-desc.rs:14:26
+   |
+LL |     fun((async || {})(), (async || {})());
+   |                   --     ^^^^^^^^^^^^^^^ expected `async` closure body, found a different `async` closure body
+   |                   |
+   |                   the expected `async` closure body
+   | 
+  ::: $SRC_DIR/core/src/future/mod.rs:LL:COL
+   |
+LL | pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
+   |                                           -------------------------------
+   |                                           |
+   |                                           the expected opaque type
+   |                                           the found opaque type
+   |
+   = note: expected opaque type `impl Future` (`async` closure body)
+              found opaque type `impl Future` (`async` closure body)
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/async-await/issue-77993-2.rs b/src/test/ui/async-await/issue-77993-2.rs
new file mode 100644 (file)
index 0000000..4d554a0
--- /dev/null
@@ -0,0 +1,9 @@
+// edition:2018
+
+async fn test() -> Result<(), Box<dyn std::error::Error>> {
+    macro!();
+    //~^ ERROR expected identifier, found `!`
+    Ok(())
+}
+
+fn main() {}
diff --git a/src/test/ui/async-await/issue-77993-2.stderr b/src/test/ui/async-await/issue-77993-2.stderr
new file mode 100644 (file)
index 0000000..64b378f
--- /dev/null
@@ -0,0 +1,8 @@
+error: expected identifier, found `!`
+  --> $DIR/issue-77993-2.rs:4:10
+   |
+LL |     macro!();
+   |          ^ expected identifier
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/async-await/issues/issue-78600.rs b/src/test/ui/async-await/issues/issue-78600.rs
new file mode 100644 (file)
index 0000000..8aaeaec
--- /dev/null
@@ -0,0 +1,12 @@
+// edition:2018
+
+struct S<'a>(&'a i32);
+
+impl<'a> S<'a> {
+    async fn new(i: &'a i32) -> Result<Self, ()> {
+        //~^ ERROR: `async fn`
+        Ok(S(&22))
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/async-await/issues/issue-78600.stderr b/src/test/ui/async-await/issues/issue-78600.stderr
new file mode 100644 (file)
index 0000000..92b6614
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0760]: `async fn` return type cannot contain a projection or `Self` that references lifetimes from a parent scope
+  --> $DIR/issue-78600.rs:6:33
+   |
+LL |     async fn new(i: &'a i32) -> Result<Self, ()> {
+   |                                 ^^^^^^^----^^^^^
+   |                                        |
+   |                                        help: consider spelling out the type instead: `S<'a>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0760`.
diff --git a/src/test/ui/async-await/repeat_count_const_in_async_fn.rs b/src/test/ui/async-await/repeat_count_const_in_async_fn.rs
new file mode 100644 (file)
index 0000000..ebabc3f
--- /dev/null
@@ -0,0 +1,10 @@
+// check-pass
+// edition:2018
+// compile-flags: --crate-type=lib
+
+pub async fn test() {
+    const C: usize = 4;
+    foo(&mut [0u8; C]).await;
+}
+
+async fn foo(_: &mut [u8]) {}
index 3ea8d402a3ef4161039ee41b05a4138a12d650e8..28d57e92c37313b17bb483a17a1d533f1b470484 100644 (file)
@@ -6,7 +6,7 @@ pub fn main() {
     if let Some(y) = x {
         assert_eq!(y, 3);
     } else {
-        panic!("if-let panicked");
+        panic!("`if let` panicked");
     }
     let mut worked = false;
     if let Some(_) = x {
@@ -54,7 +54,7 @@ enum Foo {
         if let Foo::Two(b) = a {
             assert_eq!(b, 42_usize);
         } else {
-            panic!("panic in nested if-let");
+            panic!("panic in nested `if let`");
         }
     }
 }
diff --git a/src/test/ui/cleanup-rvalue-during-if-and-while.rs b/src/test/ui/cleanup-rvalue-during-if-and-while.rs
deleted file mode 100644 (file)
index 6fecb4e..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-// run-pass
-// This test verifies that temporaries created for `while`'s and `if`
-// conditions are dropped after the condition is evaluated.
-
-#![feature(box_syntax)]
-
-struct Temporary;
-
-static mut DROPPED: isize = 0;
-
-impl Drop for Temporary {
-    fn drop(&mut self) {
-        unsafe { DROPPED += 1; }
-    }
-}
-
-impl Temporary {
-    fn do_stuff(&self) -> bool {true}
-}
-
-fn borrow() -> Box<Temporary> { box Temporary }
-
-
-pub fn main() {
-    let mut i = 0;
-
-    // This loop's condition
-    // should call `Temporary`'s
-    // `drop` 6 times.
-    while borrow().do_stuff() {
-        i += 1;
-        unsafe { assert_eq!(DROPPED, i) }
-        if i > 5 {
-            break;
-        }
-    }
-
-    // This if condition should
-    // call it 1 time
-    if borrow().do_stuff() {
-        unsafe { assert_eq!(DROPPED, i + 1) }
-    }
-}
index 1007fb582e5eda6e68f00f04f22fadd569b233fb..27c8fb1363f17a03144b1707cece124c012c1769 100644 (file)
@@ -26,7 +26,8 @@ fn big_box() {
     //~^ First Pass analysis includes:
     //~| Min Capture analysis includes:
         let p = t.0.0;
-        //~^ NOTE: Capturing t[(0, 0),Deref,(0, 0)] -> ByValue
+        //~^ NOTE: Capturing t[(0, 0),Deref,(0, 0)] -> ImmBorrow
+        //~| NOTE: Capturing t[(0, 0)] -> ByValue
         //~| NOTE: Min Capture t[(0, 0)] -> ByValue
         println!("{} {:?}", t.1, p);
         //~^ NOTE: Capturing t[(1, 0)] -> ImmBorrow
index fe04dbef6d8b55a56637bef5c78057e2981ebab1..944e4c40a78ef6707a21e7b35bf1f11544235829 100644 (file)
@@ -28,13 +28,18 @@ LL | |
 LL | |     };
    | |_____^
    |
-note: Capturing t[(0, 0),Deref,(0, 0)] -> ByValue
+note: Capturing t[(0, 0),Deref,(0, 0)] -> ImmBorrow
+  --> $DIR/by_value.rs:28:17
+   |
+LL |         let p = t.0.0;
+   |                 ^^^^^
+note: Capturing t[(0, 0)] -> ByValue
   --> $DIR/by_value.rs:28:17
    |
 LL |         let p = t.0.0;
    |                 ^^^^^
 note: Capturing t[(1, 0)] -> ImmBorrow
-  --> $DIR/by_value.rs:31:29
+  --> $DIR/by_value.rs:32:29
    |
 LL |         println!("{} {:?}", t.1, p);
    |                             ^^^
@@ -57,7 +62,7 @@ note: Min Capture t[(0, 0)] -> ByValue
 LL |         let p = t.0.0;
    |                 ^^^^^
 note: Min Capture t[(1, 0)] -> ImmBorrow
-  --> $DIR/by_value.rs:31:29
+  --> $DIR/by_value.rs:32:29
    |
 LL |         println!("{} {:?}", t.1, p);
    |                             ^^^
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-array-diagnostics.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-array-diagnostics.rs
new file mode 100644 (file)
index 0000000..cd7c256
--- /dev/null
@@ -0,0 +1,16 @@
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+//~| `#[warn(incomplete_features)]` on by default
+//~| see issue #53488 <https://github.com/rust-lang/rust/issues/53488>
+
+// Test that array access is not stored as part of closure kind origin
+
+fn expect_fn<F: Fn()>(_f: F) {}
+
+fn main() {
+    let s = [format!("s"), format!("s")];
+    let c = || { //~ ERROR expected a closure that implements the `Fn`
+        let [_, _s] = s;
+    };
+    expect_fn(c);
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-array-diagnostics.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-array-diagnostics.stderr
new file mode 100644 (file)
index 0000000..bd94287
--- /dev/null
@@ -0,0 +1,23 @@
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/closure-origin-array-diagnostics.rs:1:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
+  --> $DIR/closure-origin-array-diagnostics.rs:12:13
+   |
+LL |     let c = || {
+   |             ^^ this closure implements `FnOnce`, not `Fn`
+LL |         let [_, _s] = s;
+   |                       - closure is `FnOnce` because it moves the variable `s` out of its environment
+LL |     };
+LL |     expect_fn(c);
+   |     --------- the requirement to implement `Fn` derives from here
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0525`.
index 8486f03f2eb8e8502082b2384232430e1a757d61..6107a082237c6617708b5041820c955da4e4797b 100644 (file)
@@ -16,7 +16,7 @@ fn main() {
         // FIXME(project-rfc-2229#24): Change this to be a destructure pattern
         // once this is fixed, to remove the warning.
         if let SingleVariant::Point(ref mut x, _) = point {
-            //~^ WARNING: irrefutable if-let pattern
+            //~^ WARNING: irrefutable `if let` pattern
             *x += 1;
         }
     };
index ad66f6d7ffcaa6c37baeb6bd1a17b187f2723dba..8586dfd91863cb13a605cad3d3946e814559a043 100644 (file)
@@ -7,7 +7,7 @@ LL | #![feature(capture_disjoint_fields)]
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
 
-warning: irrefutable if-let pattern
+warning: irrefutable `if let` pattern
   --> $DIR/closure-origin-single-variant-diagnostics.rs:18:9
    |
 LL | /         if let SingleVariant::Point(ref mut x, _) = point {
@@ -17,6 +17,8 @@ LL | |         }
    | |_________^
    |
    = note: `#[warn(irrefutable_let_patterns)]` on by default
+   = note: this pattern will always match, so the `if let` is useless
+   = help: consider replacing the `if let` with a `let`
 
 error[E0382]: use of moved value: `c`
   --> $DIR/closure-origin-single-variant-diagnostics.rs:25:13
index 8bdc999ca3c3feade9f49922806945d452e0e01a..1c574da5f48bc24bc182d975425e72eaf1226466 100644 (file)
@@ -6,7 +6,25 @@
 //~| NOTE: see issue #53488 <https://github.com/rust-lang/rust/issues/53488>
 #![feature(rustc_attrs)]
 
-// Test we truncate derefs properly
+fn simple_move_closure() {
+    struct S(String);
+    struct T(S);
+
+    let t = T(S("s".into()));
+    let mut c = #[rustc_capture_analysis]
+    //~^ ERROR: attributes on expressions are experimental
+    //~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
+    move || {
+    //~^ ERROR: First Pass analysis includes:
+    //~| ERROR: Min Capture analysis includes:
+        t.0.0 = "new S".into();
+        //~^ NOTE: Capturing t[(0, 0),(0, 0)] -> ByValue
+        //~| NOTE: Min Capture t[(0, 0),(0, 0)] -> ByValue
+    };
+    c();
+}
+
+// Test move closure use reborrows when using references
 fn simple_ref() {
     let mut s = 10;
     let ref_s = &mut s;
@@ -18,14 +36,14 @@ fn simple_ref() {
     //~^ ERROR: First Pass analysis includes:
     //~| ERROR: Min Capture analysis includes:
         *ref_s += 10;
-        //~^ NOTE: Capturing ref_s[Deref] -> ByValue
-        //~| NOTE: Min Capture ref_s[] -> ByValue
+        //~^ NOTE: Capturing ref_s[Deref] -> UniqueImmBorrow
+        //~| NOTE: Min Capture ref_s[Deref] -> UniqueImmBorrow
     };
     c();
 }
 
-// Test we truncate derefs properly
-fn struct_contains_ref_to_another_struct() {
+// Test move closure use reborrows when using references
+fn struct_contains_ref_to_another_struct_1() {
     struct S(String);
     struct T<'a>(&'a mut S);
 
@@ -39,34 +57,85 @@ fn struct_contains_ref_to_another_struct() {
     //~^ ERROR: First Pass analysis includes:
     //~| ERROR: Min Capture analysis includes:
         t.0.0 = "new s".into();
-        //~^ NOTE: Capturing t[(0, 0),Deref,(0, 0)] -> ByValue
-        //~| NOTE: Min Capture t[(0, 0)] -> ByValue
+        //~^ NOTE: Capturing t[(0, 0),Deref,(0, 0)] -> UniqueImmBorrow
+        //~| NOTE: Min Capture t[(0, 0),Deref,(0, 0)] -> UniqueImmBorrow
     };
 
     c();
 }
 
-// Test that we don't reduce precision when there is nothing deref.
-fn no_ref() {
+// Test that we can use reborrows to read data of Copy types
+// i.e. without truncating derefs
+fn struct_contains_ref_to_another_struct_2() {
+    struct S(i32);
+    struct T<'a>(&'a S);
+
+    let s = S(0);
+    let t = T(&s);
+
+    let mut c = #[rustc_capture_analysis]
+    //~^ ERROR: attributes on expressions are experimental
+    //~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
+    move || {
+    //~^ ERROR: First Pass analysis includes:
+    //~| ERROR: Min Capture analysis includes:
+        let _t = t.0.0;
+        //~^ NOTE: Capturing t[(0, 0),Deref,(0, 0)] -> ImmBorrow
+        //~| NOTE: Min Capture t[(0, 0),Deref,(0, 0)] -> ImmBorrow
+    };
+
+    c();
+}
+
+// Test that we can use truncate to move out of !Copy types
+fn struct_contains_ref_to_another_struct_3() {
     struct S(String);
-    struct T(S);
+    struct T<'a>(&'a S);
+
+    let s = S("s".into());
+    let t = T(&s);
 
-    let t = T(S("s".into()));
     let mut c = #[rustc_capture_analysis]
     //~^ ERROR: attributes on expressions are experimental
     //~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
     move || {
     //~^ ERROR: First Pass analysis includes:
     //~| ERROR: Min Capture analysis includes:
-        t.0.0 = "new S".into();
-        //~^ NOTE: Capturing t[(0, 0),(0, 0)] -> ByValue
-        //~| NOTE: Min Capture t[(0, 0),(0, 0)] -> ByValue
+        let _t = t.0.0;
+        //~^ NOTE: Capturing t[(0, 0),Deref,(0, 0)] -> ImmBorrow
+        //~| NOTE: Capturing t[(0, 0)] -> ByValue
+        //~| NOTE: Min Capture t[(0, 0)] -> ByValue
     };
+
+    c();
+}
+
+// Test that derefs of box are truncated in move closures
+fn truncate_box_derefs() {
+    struct S(i32);
+
+    let b = Box::new(S(10));
+
+    let c = #[rustc_capture_analysis]
+    //~^ ERROR: attributes on expressions are experimental
+    //~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
+    move || {
+    //~^ ERROR: First Pass analysis includes:
+    //~| ERROR: Min Capture analysis includes:
+        let _t = b.0;
+        //~^ NOTE: Capturing b[Deref,(0, 0)] -> ByValue
+        //~| NOTE: Capturing b[] -> ByValue
+        //~| NOTE: Min Capture b[] -> ByValue
+    };
+
     c();
 }
 
 fn main() {
+    simple_move_closure();
     simple_ref();
-    struct_contains_ref_to_another_struct();
-    no_ref();
+    struct_contains_ref_to_another_struct_1();
+    struct_contains_ref_to_another_struct_2();
+    struct_contains_ref_to_another_struct_3();
+    truncate_box_derefs();
 }
index a745f14598ee2b022f10352b34f729970e223745..b91ef4dd85c487118d3ac1509fb9c2fc0c11054d 100644 (file)
@@ -8,7 +8,7 @@ LL |     let mut c = #[rustc_capture_analysis]
    = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
 
 error[E0658]: attributes on expressions are experimental
-  --> $DIR/move_closure.rs:35:17
+  --> $DIR/move_closure.rs:32:17
    |
 LL |     let mut c = #[rustc_capture_analysis]
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -17,7 +17,7 @@ LL |     let mut c = #[rustc_capture_analysis]
    = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
 
 error[E0658]: attributes on expressions are experimental
-  --> $DIR/move_closure.rs:55:17
+  --> $DIR/move_closure.rs:53:17
    |
 LL |     let mut c = #[rustc_capture_analysis]
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -25,6 +25,33 @@ LL |     let mut c = #[rustc_capture_analysis]
    = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
    = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
 
+error[E0658]: attributes on expressions are experimental
+  --> $DIR/move_closure.rs:76:17
+   |
+LL |     let mut c = #[rustc_capture_analysis]
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
+   = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
+
+error[E0658]: attributes on expressions are experimental
+  --> $DIR/move_closure.rs:98:17
+   |
+LL |     let mut c = #[rustc_capture_analysis]
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
+   = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
+
+error[E0658]: attributes on expressions are experimental
+  --> $DIR/move_closure.rs:119:13
+   |
+LL |     let c = #[rustc_capture_analysis]
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
+   = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
+
 warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/move_closure.rs:3:12
    |
@@ -40,20 +67,56 @@ error: First Pass analysis includes:
 LL | /     move || {
 LL | |
 LL | |
-LL | |         *ref_s += 10;
+LL | |         t.0.0 = "new S".into();
+LL | |
+LL | |
+LL | |     };
+   | |_____^
+   |
+note: Capturing t[(0, 0),(0, 0)] -> ByValue
+  --> $DIR/move_closure.rs:20:9
+   |
+LL |         t.0.0 = "new S".into();
+   |         ^^^^^
+
+error: Min Capture analysis includes:
+  --> $DIR/move_closure.rs:17:5
+   |
+LL | /     move || {
+LL | |
+LL | |
+LL | |         t.0.0 = "new S".into();
 LL | |
 LL | |
 LL | |     };
    | |_____^
    |
-note: Capturing ref_s[Deref] -> ByValue
+note: Min Capture t[(0, 0),(0, 0)] -> ByValue
   --> $DIR/move_closure.rs:20:9
    |
+LL |         t.0.0 = "new S".into();
+   |         ^^^^^
+
+error: First Pass analysis includes:
+  --> $DIR/move_closure.rs:35:5
+   |
+LL | /     move || {
+LL | |
+LL | |
+LL | |         *ref_s += 10;
+LL | |
+LL | |
+LL | |     };
+   | |_____^
+   |
+note: Capturing ref_s[Deref] -> UniqueImmBorrow
+  --> $DIR/move_closure.rs:38:9
+   |
 LL |         *ref_s += 10;
    |         ^^^^^^
 
 error: Min Capture analysis includes:
-  --> $DIR/move_closure.rs:17:5
+  --> $DIR/move_closure.rs:35:5
    |
 LL | /     move || {
 LL | |
@@ -64,14 +127,14 @@ LL | |
 LL | |     };
    | |_____^
    |
-note: Min Capture ref_s[] -> ByValue
-  --> $DIR/move_closure.rs:20:9
+note: Min Capture ref_s[Deref] -> UniqueImmBorrow
+  --> $DIR/move_closure.rs:38:9
    |
 LL |         *ref_s += 10;
    |         ^^^^^^
 
 error: First Pass analysis includes:
-  --> $DIR/move_closure.rs:38:5
+  --> $DIR/move_closure.rs:56:5
    |
 LL | /     move || {
 LL | |
@@ -82,14 +145,14 @@ LL | |
 LL | |     };
    | |_____^
    |
-note: Capturing t[(0, 0),Deref,(0, 0)] -> ByValue
-  --> $DIR/move_closure.rs:41:9
+note: Capturing t[(0, 0),Deref,(0, 0)] -> UniqueImmBorrow
+  --> $DIR/move_closure.rs:59:9
    |
 LL |         t.0.0 = "new s".into();
    |         ^^^^^
 
 error: Min Capture analysis includes:
-  --> $DIR/move_closure.rs:38:5
+  --> $DIR/move_closure.rs:56:5
    |
 LL | /     move || {
 LL | |
@@ -100,48 +163,130 @@ LL | |
 LL | |     };
    | |_____^
    |
-note: Min Capture t[(0, 0)] -> ByValue
-  --> $DIR/move_closure.rs:41:9
+note: Min Capture t[(0, 0),Deref,(0, 0)] -> UniqueImmBorrow
+  --> $DIR/move_closure.rs:59:9
    |
 LL |         t.0.0 = "new s".into();
    |         ^^^^^
 
 error: First Pass analysis includes:
-  --> $DIR/move_closure.rs:58:5
+  --> $DIR/move_closure.rs:79:5
    |
 LL | /     move || {
 LL | |
 LL | |
-LL | |         t.0.0 = "new S".into();
+LL | |         let _t = t.0.0;
 LL | |
 LL | |
 LL | |     };
    | |_____^
    |
-note: Capturing t[(0, 0),(0, 0)] -> ByValue
-  --> $DIR/move_closure.rs:61:9
+note: Capturing t[(0, 0),Deref,(0, 0)] -> ImmBorrow
+  --> $DIR/move_closure.rs:82:18
    |
-LL |         t.0.0 = "new S".into();
-   |         ^^^^^
+LL |         let _t = t.0.0;
+   |                  ^^^^^
 
 error: Min Capture analysis includes:
-  --> $DIR/move_closure.rs:58:5
+  --> $DIR/move_closure.rs:79:5
    |
 LL | /     move || {
 LL | |
 LL | |
-LL | |         t.0.0 = "new S".into();
+LL | |         let _t = t.0.0;
 LL | |
 LL | |
 LL | |     };
    | |_____^
    |
-note: Min Capture t[(0, 0),(0, 0)] -> ByValue
-  --> $DIR/move_closure.rs:61:9
+note: Min Capture t[(0, 0),Deref,(0, 0)] -> ImmBorrow
+  --> $DIR/move_closure.rs:82:18
    |
-LL |         t.0.0 = "new S".into();
-   |         ^^^^^
+LL |         let _t = t.0.0;
+   |                  ^^^^^
+
+error: First Pass analysis includes:
+  --> $DIR/move_closure.rs:101:5
+   |
+LL | /     move || {
+LL | |
+LL | |
+LL | |         let _t = t.0.0;
+...  |
+LL | |
+LL | |     };
+   | |_____^
+   |
+note: Capturing t[(0, 0),Deref,(0, 0)] -> ImmBorrow
+  --> $DIR/move_closure.rs:104:18
+   |
+LL |         let _t = t.0.0;
+   |                  ^^^^^
+note: Capturing t[(0, 0)] -> ByValue
+  --> $DIR/move_closure.rs:104:18
+   |
+LL |         let _t = t.0.0;
+   |                  ^^^^^
+
+error: Min Capture analysis includes:
+  --> $DIR/move_closure.rs:101:5
+   |
+LL | /     move || {
+LL | |
+LL | |
+LL | |         let _t = t.0.0;
+...  |
+LL | |
+LL | |     };
+   | |_____^
+   |
+note: Min Capture t[(0, 0)] -> ByValue
+  --> $DIR/move_closure.rs:104:18
+   |
+LL |         let _t = t.0.0;
+   |                  ^^^^^
+
+error: First Pass analysis includes:
+  --> $DIR/move_closure.rs:122:5
+   |
+LL | /     move || {
+LL | |
+LL | |
+LL | |         let _t = b.0;
+...  |
+LL | |
+LL | |     };
+   | |_____^
+   |
+note: Capturing b[Deref,(0, 0)] -> ByValue
+  --> $DIR/move_closure.rs:125:18
+   |
+LL |         let _t = b.0;
+   |                  ^^^
+note: Capturing b[] -> ByValue
+  --> $DIR/move_closure.rs:125:18
+   |
+LL |         let _t = b.0;
+   |                  ^^^
+
+error: Min Capture analysis includes:
+  --> $DIR/move_closure.rs:122:5
+   |
+LL | /     move || {
+LL | |
+LL | |
+LL | |         let _t = b.0;
+...  |
+LL | |
+LL | |     };
+   | |_____^
+   |
+note: Min Capture b[] -> ByValue
+  --> $DIR/move_closure.rs:125:18
+   |
+LL |         let _t = b.0;
+   |                  ^^^
 
-error: aborting due to 9 previous errors; 1 warning emitted
+error: aborting due to 18 previous errors; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0658`.
index 4007a5a48aaecb4d94efedec5dc465996653a36c..afaafbda018774feb36039447a98ec1feae56170 100644 (file)
@@ -56,9 +56,50 @@ fn no_ref_nested() {
     c();
 }
 
+struct A<'a>(&'a mut String,  &'a mut String);
+// Test that reborrowing works as expected for move closures
+// by attempting a disjoint capture through a reference.
+fn disjoint_via_ref() {
+    let mut x = String::new();
+    let mut y = String::new();
+
+    let mut a = A(&mut x, &mut y);
+    let a = &mut a;
+
+    let mut c1 = move || {
+        a.0.truncate(0);
+    };
+
+    let mut c2 = move || {
+        a.1.truncate(0);
+    };
+
+    c1();
+    c2();
+}
+
+// Test that even if a path is moved into the closure, the closure is not FnOnce
+// if the path is not moved by the closure call.
+fn data_moved_but_not_fn_once() {
+    let x = Box::new(10i32);
+
+    let c = move || {
+        // *x has type i32 which is Copy. So even though the box `x` will be moved
+        // into the closure, `x` is never moved when the closure is called, i.e. the
+        // ownership stays with the closure and therefore we can call the function multiple times.
+        let _x = *x;
+    };
+
+    c();
+    c();
+}
+
 fn main() {
     simple_ref();
     struct_contains_ref_to_another_struct();
     no_ref();
     no_ref_nested();
+
+    disjoint_via_ref();
+    data_moved_but_not_fn_once();
 }
index 7447ca3ff36315992568a524d80ed0344f585196..17ccd2f3527b0c64b0c13dea8d5e5d54377018a5 100644 (file)
@@ -4,7 +4,7 @@ error[E0747]: type provided when a constant was expected
 LL | fn test<const N: usize>() -> Foo<N> {
    |                                  ^
    |
-help: if this generic argument was intended as a const parameter, try surrounding it with braces:
+help: if this generic argument was intended as a const parameter, surround it with braces
    |
 LL | fn test<const N: usize>() -> Foo<{ N }> {
    |                                  ^   ^
diff --git a/src/test/ui/const-generics/diagnostics.rs b/src/test/ui/const-generics/diagnostics.rs
new file mode 100644 (file)
index 0000000..1581af5
--- /dev/null
@@ -0,0 +1,18 @@
+#![crate_type="lib"]
+#![feature(min_const_generics)]
+#![allow(incomplete_features)]
+
+struct A<const N: u8>;
+trait Foo {}
+impl Foo for A<N> {}
+//~^ ERROR cannot find type
+//~| unresolved item provided when a constant
+
+struct B<const N: u8>;
+impl<N> Foo for B<N> {}
+//~^ ERROR type provided when a constant
+
+struct C<const C: u8, const N: u8>;
+impl<const N: u8> Foo for C<N, T> {}
+//~^ ERROR cannot find type
+//~| unresolved item provided when a constant
diff --git a/src/test/ui/const-generics/diagnostics.stderr b/src/test/ui/const-generics/diagnostics.stderr
new file mode 100644 (file)
index 0000000..7d038ff
--- /dev/null
@@ -0,0 +1,52 @@
+error[E0412]: cannot find type `N` in this scope
+  --> $DIR/diagnostics.rs:7:16
+   |
+LL | struct A<const N: u8>;
+   | ---------------------- similarly named struct `A` defined here
+LL | trait Foo {}
+LL | impl Foo for A<N> {}
+   |                ^ help: a struct with a similar name exists: `A`
+
+error[E0412]: cannot find type `T` in this scope
+  --> $DIR/diagnostics.rs:16:32
+   |
+LL | struct A<const N: u8>;
+   | ---------------------- similarly named struct `A` defined here
+...
+LL | impl<const N: u8> Foo for C<N, T> {}
+   |                                ^ help: a struct with a similar name exists: `A`
+
+error[E0747]: unresolved item provided when a constant was expected
+  --> $DIR/diagnostics.rs:7:16
+   |
+LL | impl Foo for A<N> {}
+   |                ^
+   |
+help: if this generic argument was intended as a const parameter, surround it with braces
+   |
+LL | impl Foo for A<{ N }> {}
+   |                ^   ^
+
+error[E0747]: type provided when a constant was expected
+  --> $DIR/diagnostics.rs:12:19
+   |
+LL | impl<N> Foo for B<N> {}
+   |      -            ^
+   |      |
+   |      help: consider changing this type paramater to a `const`-generic: `const N: u8`
+
+error[E0747]: unresolved item provided when a constant was expected
+  --> $DIR/diagnostics.rs:16:32
+   |
+LL | impl<const N: u8> Foo for C<N, T> {}
+   |                                ^
+   |
+help: if this generic argument was intended as a const parameter, surround it with braces
+   |
+LL | impl<const N: u8> Foo for C<N, { T }> {}
+   |                                ^   ^
+
+error: aborting due to 5 previous errors
+
+Some errors have detailed explanations: E0412, E0747.
+For more information about an error, try `rustc --explain E0412`.
diff --git a/src/test/ui/const-generics/dont-evaluate-array-len-on-err-1.rs b/src/test/ui/const-generics/dont-evaluate-array-len-on-err-1.rs
new file mode 100644 (file)
index 0000000..afef748
--- /dev/null
@@ -0,0 +1,22 @@
+#![feature(const_generics, const_evaluatable_checked)]
+#![allow(incomplete_features)]
+
+// This tests that during error handling for the "trait not implemented" error
+// we dont try to evaluate std::mem::size_of::<Self::Assoc> causing an ICE
+
+struct Adt;
+
+trait Foo {
+    type Assoc;
+    fn foo()
+    where
+        [Adt; std::mem::size_of::<Self::Assoc>()]: ,
+    {
+        <[Adt; std::mem::size_of::<Self::Assoc>()] as Foo>::bar()
+        //~^ Error: the trait bound
+    }
+
+    fn bar() {}
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/dont-evaluate-array-len-on-err-1.stderr b/src/test/ui/const-generics/dont-evaluate-array-len-on-err-1.stderr
new file mode 100644 (file)
index 0000000..d894fa9
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0277]: the trait bound `[Adt; _]: Foo` is not satisfied
+  --> $DIR/dont-evaluate-array-len-on-err-1.rs:15:9
+   |
+LL |         <[Adt; std::mem::size_of::<Self::Assoc>()] as Foo>::bar()
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `[Adt; _]`
+...
+LL |     fn bar() {}
+   |     -------- required by `Foo::bar`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
index 4ca10ed8b71a25d9c941b0c449fe76db9389bbcd..32939dcd2861bd1c7432c31238ab3e974f4184e2 100644 (file)
@@ -3,14 +3,14 @@
 
 #[derive(PartialEq, Eq)]
 enum CompileFlag {
-  A,
-  B,
+    A,
+    B,
 }
 
 pub fn test_1<const CF: CompileFlag>() {}
 pub fn test_2<T, const CF: CompileFlag>(x: T) {}
 pub struct Example<const CF: CompileFlag, T=u32>{
-  x: T,
+    x: T,
 }
 
 impl<const CF: CompileFlag, T> Example<CF, T> {
@@ -20,15 +20,15 @@ impl<const CF: CompileFlag, T> Example<CF, T> {
 pub fn main() {
   test_1::<CompileFlag::A>();
   //~^ ERROR: expected type, found variant
-  //~| ERROR: type provided when a constant was expected
+  //~| ERROR: unresolved item provided when a constant was expected
 
   test_2::<_, CompileFlag::A>(0);
   //~^ ERROR: expected type, found variant
-  //~| ERROR: type provided when a constant was expected
+  //~| ERROR: unresolved item provided when a constant was expected
 
   let _: Example<CompileFlag::A, _> = Example { x: 0 };
   //~^ ERROR: expected type, found variant
-  //~| ERROR: type provided when a constant was expected
+  //~| ERROR: unresolved item provided when a constant was expected
 
   let _: Example<Example::ASSOC_FLAG, _> = Example { x: 0 };
   //~^ ERROR: type provided when a constant was expected
index 7822fc072e35ce81f716bc428181162d35f9e610..cfbc61f02543bc6ae4c7eaa4a5b33db37658f873 100644 (file)
@@ -25,13 +25,13 @@ LL |   let _: Example<CompileFlag::A, _> = Example { x: 0 };
    |                  not a type
    |                  help: try using the variant's enum: `CompileFlag`
 
-error[E0747]: type provided when a constant was expected
+error[E0747]: unresolved item provided when a constant was expected
   --> $DIR/invalid-enum.rs:29:18
    |
 LL |   let _: Example<CompileFlag::A, _> = Example { x: 0 };
    |                  ^^^^^^^^^^^^^^
    |
-help: if this generic argument was intended as a const parameter, try surrounding it with braces:
+help: if this generic argument was intended as a const parameter, surround it with braces
    |
 LL |   let _: Example<{ CompileFlag::A }, _> = Example { x: 0 };
    |                  ^                ^
@@ -42,29 +42,29 @@ error[E0747]: type provided when a constant was expected
 LL |   let _: Example<Example::ASSOC_FLAG, _> = Example { x: 0 };
    |                  ^^^^^^^^^^^^^^^^^^^
    |
-help: if this generic argument was intended as a const parameter, try surrounding it with braces:
+help: if this generic argument was intended as a const parameter, surround it with braces
    |
 LL |   let _: Example<{ Example::ASSOC_FLAG }, _> = Example { x: 0 };
    |                  ^                     ^
 
-error[E0747]: type provided when a constant was expected
+error[E0747]: unresolved item provided when a constant was expected
   --> $DIR/invalid-enum.rs:21:12
    |
 LL |   test_1::<CompileFlag::A>();
    |            ^^^^^^^^^^^^^^
    |
-help: if this generic argument was intended as a const parameter, try surrounding it with braces:
+help: if this generic argument was intended as a const parameter, surround it with braces
    |
 LL |   test_1::<{ CompileFlag::A }>();
    |            ^                ^
 
-error[E0747]: type provided when a constant was expected
+error[E0747]: unresolved item provided when a constant was expected
   --> $DIR/invalid-enum.rs:25:15
    |
 LL |   test_2::<_, CompileFlag::A>(0);
    |               ^^^^^^^^^^^^^^
    |
-help: if this generic argument was intended as a const parameter, try surrounding it with braces:
+help: if this generic argument was intended as a const parameter, surround it with braces
    |
 LL |   test_2::<_, { CompileFlag::A }>(0);
    |               ^                ^
diff --git a/src/test/ui/consts/issue-13837.rs b/src/test/ui/consts/issue-13837.rs
new file mode 100644 (file)
index 0000000..645b1c0
--- /dev/null
@@ -0,0 +1,13 @@
+// check-pass
+#![allow(dead_code)]
+// pretty-expanded FIXME #23616
+
+struct TestStruct {
+    x: *const [isize; 2]
+}
+
+unsafe impl Sync for TestStruct {}
+
+static TEST_VALUE : TestStruct = TestStruct{x: 0x1234 as *const [isize; 2]};
+
+fn main() {}
diff --git a/src/test/ui/consts/issue-17718-references.rs b/src/test/ui/consts/issue-17718-references.rs
new file mode 100644 (file)
index 0000000..03d5f8b
--- /dev/null
@@ -0,0 +1,24 @@
+#![allow(warnings)]
+
+struct Struct { a: usize }
+
+const C: usize = 1;
+static S: usize = 1;
+
+const T1: &'static usize = &C;
+const T2: &'static usize = &S; //~ ERROR: constants cannot refer to statics
+static T3: &'static usize = &C;
+static T4: &'static usize = &S;
+
+const T5: usize = C;
+const T6: usize = S; //~ ERROR: constants cannot refer to statics
+static T7: usize = C;
+static T8: usize = S;
+
+const T9: Struct = Struct { a: C };
+const T10: Struct = Struct { a: S };
+//~^ ERROR: constants cannot refer to statics
+static T11: Struct = Struct { a: C };
+static T12: Struct = Struct { a: S };
+
+fn main() {}
diff --git a/src/test/ui/consts/issue-17718-references.stderr b/src/test/ui/consts/issue-17718-references.stderr
new file mode 100644 (file)
index 0000000..e3c3b36
--- /dev/null
@@ -0,0 +1,27 @@
+error[E0013]: constants cannot refer to statics
+  --> $DIR/issue-17718-references.rs:9:29
+   |
+LL | const T2: &'static usize = &S;
+   |                             ^
+   |
+   = help: consider extracting the value of the `static` to a `const`, and referring to that
+
+error[E0013]: constants cannot refer to statics
+  --> $DIR/issue-17718-references.rs:14:19
+   |
+LL | const T6: usize = S;
+   |                   ^
+   |
+   = help: consider extracting the value of the `static` to a `const`, and referring to that
+
+error[E0013]: constants cannot refer to statics
+  --> $DIR/issue-17718-references.rs:19:33
+   |
+LL | const T10: Struct = Struct { a: S };
+   |                                 ^
+   |
+   = help: consider extracting the value of the `static` to a `const`, and referring to that
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0013`.
diff --git a/src/test/ui/consts/issue-32829.rs b/src/test/ui/consts/issue-32829.rs
new file mode 100644 (file)
index 0000000..adfee7b
--- /dev/null
@@ -0,0 +1,6 @@
+static S : u64 = { { panic!("foo"); 0 } };
+//~^ ERROR panicking in statics is unstable
+
+fn main() {
+    println!("{:?}", S);
+}
diff --git a/src/test/ui/consts/issue-32829.stderr b/src/test/ui/consts/issue-32829.stderr
new file mode 100644 (file)
index 0000000..48e0880
--- /dev/null
@@ -0,0 +1,13 @@
+error[E0658]: panicking in statics is unstable
+  --> $DIR/issue-32829.rs:1:22
+   |
+LL | static S : u64 = { { panic!("foo"); 0 } };
+   |                      ^^^^^^^^^^^^^^
+   |
+   = note: see issue #51999 <https://github.com/rust-lang/rust/issues/51999> for more information
+   = help: add `#![feature(const_panic)]` to the crate attributes to enable
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/issue-33537.rs b/src/test/ui/consts/issue-33537.rs
new file mode 100644 (file)
index 0000000..3539aa6
--- /dev/null
@@ -0,0 +1,14 @@
+// run-pass
+
+const fn foo() -> *const i8 {
+    b"foo" as *const _ as *const i8
+}
+
+const fn bar() -> i32 {
+    *&{(1, 2, 3).1}
+}
+
+fn main() {
+    assert_eq!(foo(), b"foo" as *const _ as *const i8);
+    assert_eq!(bar(), 2);
+}
diff --git a/src/test/ui/consts/rvalue-static-promotion.rs b/src/test/ui/consts/rvalue-static-promotion.rs
new file mode 100644 (file)
index 0000000..2d7e4ab
--- /dev/null
@@ -0,0 +1,19 @@
+// run-pass
+
+use std::cell::Cell;
+
+const NONE_CELL_STRING: Option<Cell<String>> = None;
+
+struct Foo<T>(T);
+impl<T> Foo<T> {
+    const FOO: Option<Box<T>> = None;
+}
+
+fn main() {
+    let _: &'static u32 = &42;
+    let _: &'static Option<u32> = &None;
+
+    // We should be able to peek at consts and see they're None.
+    let _: &'static Option<Cell<String>> = &NONE_CELL_STRING;
+    let _: &'static Option<Box<()>> = &Foo::FOO;
+}
diff --git a/src/test/ui/consts/write-to-static-mut-in-static.rs b/src/test/ui/consts/write-to-static-mut-in-static.rs
new file mode 100644 (file)
index 0000000..43c63fe
--- /dev/null
@@ -0,0 +1,10 @@
+pub static mut A: u32 = 0;
+pub static mut B: () = unsafe { A = 1; };
+//~^ ERROR could not evaluate static initializer
+
+pub static mut C: u32 = unsafe { C = 1; 0 };
+//~^ ERROR cycle detected
+
+pub static D: u32 = D;
+
+fn main() {}
diff --git a/src/test/ui/consts/write-to-static-mut-in-static.stderr b/src/test/ui/consts/write-to-static-mut-in-static.stderr
new file mode 100644 (file)
index 0000000..789919b
--- /dev/null
@@ -0,0 +1,24 @@
+error[E0080]: could not evaluate static initializer
+  --> $DIR/write-to-static-mut-in-static.rs:2:33
+   |
+LL | pub static mut B: () = unsafe { A = 1; };
+   |                                 ^^^^^ modifying a static's initial value from another static's initializer
+
+error[E0391]: cycle detected when const-evaluating + checking `C`
+  --> $DIR/write-to-static-mut-in-static.rs:5:1
+   |
+LL | pub static mut C: u32 = unsafe { C = 1; 0 };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: ...which requires const-evaluating + checking `C`...
+  --> $DIR/write-to-static-mut-in-static.rs:5:1
+   |
+LL | pub static mut C: u32 = unsafe { C = 1; 0 };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: ...which again requires const-evaluating + checking `C`, completing the cycle
+   = note: cycle used when running analysis passes on this crate
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0080, E0391.
+For more information about an error, try `rustc --explain E0080`.
diff --git a/src/test/ui/dotdotdot-expr.rs b/src/test/ui/dotdotdot-expr.rs
deleted file mode 100644 (file)
index d842fb6..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-fn main() {
-    let _redemptive = 1...21;
-    //~^ ERROR unexpected token
-}
diff --git a/src/test/ui/dotdotdot-expr.stderr b/src/test/ui/dotdotdot-expr.stderr
deleted file mode 100644 (file)
index ec1335c..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-error: unexpected token: `...`
-  --> $DIR/dotdotdot-expr.rs:2:24
-   |
-LL |     let _redemptive = 1...21;
-   |                        ^^^
-   |
-help: use `..` for an exclusive range
-   |
-LL |     let _redemptive = 1..21;
-   |                        ^^
-help: or `..=` for an inclusive range
-   |
-LL |     let _redemptive = 1..=21;
-   |                        ^^^
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/emit-artifact-notifications.nll.stderr b/src/test/ui/emit-artifact-notifications.nll.stderr
deleted file mode 100644 (file)
index 5547631..0000000
+++ /dev/null
@@ -1 +0,0 @@
-{"artifact":"$TEST_BUILD_DIR/emit-artifact-notifications.nll/libemit_artifact_notifications.rmeta","emit":"metadata"}
diff --git a/src/test/ui/emit-artifact-notifications.polonius.stderr b/src/test/ui/emit-artifact-notifications.polonius.stderr
deleted file mode 100644 (file)
index 47b48b3..0000000
+++ /dev/null
@@ -1 +0,0 @@
-{"artifact":"$TEST_BUILD_DIR/emit-artifact-notifications.polonius/libemit_artifact_notifications.rmeta","emit":"metadata"}
diff --git a/src/test/ui/emit-artifact-notifications.rs b/src/test/ui/emit-artifact-notifications.rs
deleted file mode 100644 (file)
index 984a7fa..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-// compile-flags:--emit=metadata --error-format=json --json artifacts
-// build-pass
-// ignore-pass
-// ^-- needed because `--pass check` does not emit the output needed.
-
-// A very basic test for the emission of artifact notifications in JSON output.
-
-fn main() {}
diff --git a/src/test/ui/emit-artifact-notifications.stderr b/src/test/ui/emit-artifact-notifications.stderr
deleted file mode 100644 (file)
index 260d41b..0000000
+++ /dev/null
@@ -1 +0,0 @@
-{"artifact":"$TEST_BUILD_DIR/emit-artifact-notifications/libemit_artifact_notifications.rmeta","emit":"metadata"}
diff --git a/src/test/ui/emit-metadata-obj.rs b/src/test/ui/emit-metadata-obj.rs
deleted file mode 100644 (file)
index 334c7cc..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-// compile-flags:--emit=metadata,obj
-// build-pass
-
-// A test for the emission of metadata + obj and other metadata + non-link
-// combinations. See issue #81117.
-
-fn main() {}
diff --git a/src/test/ui/expr-if-panic.rs b/src/test/ui/expr-if-panic.rs
deleted file mode 100644 (file)
index 6069cd8..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-// run-pass
-
-fn test_if_panic() {
-    let x = if false { panic!() } else { 10 };
-    assert_eq!(x, 10);
-}
-
-fn test_else_panic() {
-    let x = if true { 10 } else { panic!() };
-    assert_eq!(x, 10);
-}
-
-fn test_elseif_panic() {
-    let x = if false { 0 } else if false { panic!() } else { 10 };
-    assert_eq!(x, 10);
-}
-
-pub fn main() { test_if_panic(); test_else_panic(); test_elseif_panic(); }
diff --git a/src/test/ui/expr/if/expr-if-panic-pass.rs b/src/test/ui/expr/if/expr-if-panic-pass.rs
new file mode 100644 (file)
index 0000000..6069cd8
--- /dev/null
@@ -0,0 +1,18 @@
+// run-pass
+
+fn test_if_panic() {
+    let x = if false { panic!() } else { 10 };
+    assert_eq!(x, 10);
+}
+
+fn test_else_panic() {
+    let x = if true { 10 } else { panic!() };
+    assert_eq!(x, 10);
+}
+
+fn test_elseif_panic() {
+    let x = if false { 0 } else if false { panic!() } else { 10 };
+    assert_eq!(x, 10);
+}
+
+pub fn main() { test_if_panic(); test_else_panic(); test_elseif_panic(); }
index 2ab0f9fed3fc67fc9b0b4dcd99addc3f62327848..7208e388a16212a4fa334224f71d693958363e7f 100644 (file)
@@ -4,8 +4,8 @@ fn macros() {
     macro_rules! foo{
         ($p:pat, $e:expr, $b:block) => {{
             if let $p = $e $b
-            //~^ WARN irrefutable if-let
-            //~| WARN irrefutable if-let
+            //~^ WARN irrefutable `if let`
+            //~| WARN irrefutable `if let`
         }}
     }
     macro_rules! bar{
@@ -23,27 +23,27 @@ macro_rules! bar{
 }
 
 pub fn main() {
-    if let a = 1 { //~ WARN irrefutable if-let
+    if let a = 1 { //~ WARN irrefutable `if let`
         println!("irrefutable pattern");
     }
 
-    if let a = 1 { //~ WARN irrefutable if-let
+    if let a = 1 { //~ WARN irrefutable `if let`
         println!("irrefutable pattern");
     } else if true {
-        println!("else-if in irrefutable if-let");
+        println!("else-if in irrefutable `if let`");
     } else {
-        println!("else in irrefutable if-let");
+        println!("else in irrefutable `if let`");
     }
 
     if let 1 = 2 {
         println!("refutable pattern");
-    } else if let a = 1 { //~ WARN irrefutable if-let
+    } else if let a = 1 { //~ WARN irrefutable `if let`
         println!("irrefutable pattern");
     }
 
     if true {
         println!("if");
-    } else if let a = 1 { //~ WARN irrefutable if-let
+    } else if let a = 1 { //~ WARN irrefutable `if let`
         println!("irrefutable pattern");
     }
 }
index ee2b78af3b84d03ede4cef6743415a72780fc18e..c64c9093ee54a9771cfe7c94efafac2e0aef766d 100644 (file)
@@ -1,4 +1,4 @@
-warning: irrefutable if-let pattern
+warning: irrefutable `if let` pattern
   --> $DIR/if-let.rs:6:13
    |
 LL |               if let $p = $e $b
@@ -10,9 +10,11 @@ LL | |     });
    | |_______- in this macro invocation
    |
    = note: `#[warn(irrefutable_let_patterns)]` on by default
+   = note: this pattern will always match, so the `if let` is useless
+   = help: consider replacing the `if let` with a `let`
    = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
-warning: irrefutable if-let pattern
+warning: irrefutable `if let` pattern
   --> $DIR/if-let.rs:6:13
    |
 LL |               if let $p = $e $b
@@ -23,29 +25,37 @@ LL | |         println!("irrefutable pattern");
 LL | |     });
    | |_______- in this macro invocation
    |
+   = note: this pattern will always match, so the `if let` is useless
+   = help: consider replacing the `if let` with a `let`
    = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
-warning: irrefutable if-let pattern
+warning: irrefutable `if let` pattern
   --> $DIR/if-let.rs:26:5
    |
 LL | /     if let a = 1 {
 LL | |         println!("irrefutable pattern");
 LL | |     }
    | |_____^
+   |
+   = note: this pattern will always match, so the `if let` is useless
+   = help: consider replacing the `if let` with a `let`
 
-warning: irrefutable if-let pattern
+warning: irrefutable `if let` pattern
   --> $DIR/if-let.rs:30:5
    |
 LL | /     if let a = 1 {
 LL | |         println!("irrefutable pattern");
 LL | |     } else if true {
-LL | |         println!("else-if in irrefutable if-let");
+LL | |         println!("else-if in irrefutable `if let`");
 LL | |     } else {
-LL | |         println!("else in irrefutable if-let");
+LL | |         println!("else in irrefutable `if let`");
 LL | |     }
    | |_____^
+   |
+   = note: this pattern will always match, so the `if let` is useless
+   = help: consider replacing the `if let` with a `let`
 
-warning: irrefutable if-let pattern
+warning: irrefutable `if let` pattern
   --> $DIR/if-let.rs:40:12
    |
 LL |       } else if let a = 1 {
@@ -53,8 +63,11 @@ LL |       } else if let a = 1 {
 LL | |         println!("irrefutable pattern");
 LL | |     }
    | |_____^
+   |
+   = note: this pattern will always match, so the `if let` is useless
+   = help: consider replacing the `if let` with a `let`
 
-warning: irrefutable if-let pattern
+warning: irrefutable `if let` pattern
   --> $DIR/if-let.rs:46:12
    |
 LL |       } else if let a = 1 {
@@ -62,6 +75,9 @@ LL |       } else if let a = 1 {
 LL | |         println!("irrefutable pattern");
 LL | |     }
    | |_____^
+   |
+   = note: this pattern will always match, so the `if let` is useless
+   = help: consider replacing the `if let` with a `let`
 
 warning: 6 warnings emitted
 
diff --git a/src/test/ui/expr/if/issue-4201.rs b/src/test/ui/expr/if/issue-4201.rs
new file mode 100644 (file)
index 0000000..1f29222
--- /dev/null
@@ -0,0 +1,9 @@
+fn main() {
+    let a = if true {
+        0
+    } else if false {
+//~^ ERROR `if` may be missing an `else` clause
+//~| expected `()`, found integer
+        1
+    };
+}
diff --git a/src/test/ui/expr/if/issue-4201.stderr b/src/test/ui/expr/if/issue-4201.stderr
new file mode 100644 (file)
index 0000000..bc638dd
--- /dev/null
@@ -0,0 +1,18 @@
+error[E0317]: `if` may be missing an `else` clause
+  --> $DIR/issue-4201.rs:4:12
+   |
+LL |       } else if false {
+   |  ____________^
+LL | |
+LL | |
+LL | |         1
+   | |         - found here
+LL | |     };
+   | |_____^ expected `()`, found integer
+   |
+   = note: `if` expressions without `else` evaluate to `()`
+   = help: consider adding an `else` block that evaluates to the expected type
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0317`.
diff --git a/src/test/ui/for-loop-while/cleanup-rvalue-during-if-and-while.rs b/src/test/ui/for-loop-while/cleanup-rvalue-during-if-and-while.rs
new file mode 100644 (file)
index 0000000..6fecb4e
--- /dev/null
@@ -0,0 +1,43 @@
+// run-pass
+// This test verifies that temporaries created for `while`'s and `if`
+// conditions are dropped after the condition is evaluated.
+
+#![feature(box_syntax)]
+
+struct Temporary;
+
+static mut DROPPED: isize = 0;
+
+impl Drop for Temporary {
+    fn drop(&mut self) {
+        unsafe { DROPPED += 1; }
+    }
+}
+
+impl Temporary {
+    fn do_stuff(&self) -> bool {true}
+}
+
+fn borrow() -> Box<Temporary> { box Temporary }
+
+
+pub fn main() {
+    let mut i = 0;
+
+    // This loop's condition
+    // should call `Temporary`'s
+    // `drop` 6 times.
+    while borrow().do_stuff() {
+        i += 1;
+        unsafe { assert_eq!(DROPPED, i) }
+        if i > 5 {
+            break;
+        }
+    }
+
+    // This if condition should
+    // call it 1 time
+    if borrow().do_stuff() {
+        unsafe { assert_eq!(DROPPED, i + 1) }
+    }
+}
index 5ec462e10465f8c3f2205bb0f75caa9e1dd10378..da3d3249f0e7ee157cef94630c21f310d70dfb1a 100644 (file)
@@ -1,33 +1,24 @@
 error: implementation of `Foo` is not general enough
   --> $DIR/auto-trait-regions.rs:31:5
    |
-LL | auto trait Foo {}
-   | ----------------- trait `Foo` defined here
-...
 LL |     assert_foo(gen);
    |     ^^^^^^^^^^ implementation of `Foo` is not general enough
    |
-   = note: `Foo` would have to be implemented for the type `&'0 OnlyFooIfStaticRef`, for any lifetime `'0`...
-   = note: ...but `Foo` is actually implemented for the type `&'1 OnlyFooIfStaticRef`, for some specific lifetime `'1`
+   = note: `&'0 OnlyFooIfStaticRef` must implement `Foo`, for any lifetime `'0`...
+   = note: ...but `Foo` is actually implemented for the type `&'static OnlyFooIfStaticRef`
 
 error: implementation of `Foo` is not general enough
   --> $DIR/auto-trait-regions.rs:31:5
    |
-LL | auto trait Foo {}
-   | ----------------- trait `Foo` defined here
-...
 LL |     assert_foo(gen);
    |     ^^^^^^^^^^ implementation of `Foo` is not general enough
    |
-   = note: `Foo` would have to be implemented for the type `&'0 OnlyFooIfStaticRef`, for any lifetime `'0`...
-   = note: ...but `Foo` is actually implemented for the type `&'1 OnlyFooIfStaticRef`, for some specific lifetime `'1`
+   = note: `&'0 OnlyFooIfStaticRef` must implement `Foo`, for any lifetime `'0`...
+   = note: ...but `Foo` is actually implemented for the type `&'static OnlyFooIfStaticRef`
 
 error: implementation of `Foo` is not general enough
   --> $DIR/auto-trait-regions.rs:50:5
    |
-LL | auto trait Foo {}
-   | ----------------- trait `Foo` defined here
-...
 LL |     assert_foo(gen);
    |     ^^^^^^^^^^ implementation of `Foo` is not general enough
    |
@@ -37,9 +28,6 @@ LL |     assert_foo(gen);
 error: implementation of `Foo` is not general enough
   --> $DIR/auto-trait-regions.rs:50:5
    |
-LL | auto trait Foo {}
-   | ----------------- trait `Foo` defined here
-...
 LL |     assert_foo(gen);
    |     ^^^^^^^^^^ implementation of `Foo` is not general enough
    |
diff --git a/src/test/ui/generator/yield-outside-generator-issue-78653.rs b/src/test/ui/generator/yield-outside-generator-issue-78653.rs
new file mode 100644 (file)
index 0000000..4e8050c
--- /dev/null
@@ -0,0 +1,7 @@
+#![feature(generators)]
+
+fn main() {
+    yield || for i in 0 { }
+    //~^ ERROR yield expression outside of generator literal
+    //~| ERROR `{integer}` is not an iterator
+}
diff --git a/src/test/ui/generator/yield-outside-generator-issue-78653.stderr b/src/test/ui/generator/yield-outside-generator-issue-78653.stderr
new file mode 100644 (file)
index 0000000..f0c7cb0
--- /dev/null
@@ -0,0 +1,21 @@
+error[E0627]: yield expression outside of generator literal
+  --> $DIR/yield-outside-generator-issue-78653.rs:4:5
+   |
+LL |     yield || for i in 0 { }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0277]: `{integer}` is not an iterator
+  --> $DIR/yield-outside-generator-issue-78653.rs:4:23
+   |
+LL |     yield || for i in 0 { }
+   |                       ^ `{integer}` is not an iterator
+   |
+   = help: the trait `Iterator` is not implemented for `{integer}`
+   = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
+   = note: required because of the requirements on the impl of `IntoIterator` for `{integer}`
+   = note: required by `into_iter`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0277, E0627.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/generic-associated-types/constraint-assoc-type-suggestion.rs b/src/test/ui/generic-associated-types/constraint-assoc-type-suggestion.rs
new file mode 100644 (file)
index 0000000..36db3d1
--- /dev/null
@@ -0,0 +1,17 @@
+// Test that correct syntax is used in suggestion to constrain associated type
+
+#![feature(generic_associated_types)]
+//~^ WARNING the feature `generic_associated_types` is incomplete
+
+trait X {
+    type Y<T>;
+}
+
+fn f<T: X>(a: T::Y<i32>) {
+    //~^ HELP consider constraining the associated type `<T as X>::Y<i32>` to `Vec<i32>`
+    //~| SUGGESTION Y<i32> = Vec<i32>>
+    let b: Vec<i32> = a;
+    //~^ ERROR mismatched types
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/constraint-assoc-type-suggestion.stderr b/src/test/ui/generic-associated-types/constraint-assoc-type-suggestion.stderr
new file mode 100644 (file)
index 0000000..ecf559d
--- /dev/null
@@ -0,0 +1,27 @@
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/constraint-assoc-type-suggestion.rs:3:12
+   |
+LL | #![feature(generic_associated_types)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+
+error[E0308]: mismatched types
+  --> $DIR/constraint-assoc-type-suggestion.rs:13:23
+   |
+LL |     let b: Vec<i32> = a;
+   |            --------   ^ expected struct `Vec`, found associated type
+   |            |
+   |            expected due to this
+   |
+   = note:       expected struct `Vec<i32>`
+           found associated type `<T as X>::Y<i32>`
+help: consider constraining the associated type `<T as X>::Y<i32>` to `Vec<i32>`
+   |
+LL | fn f<T: X<Y<i32> = Vec<i32>>>(a: T::Y<i32>) {
+   |          ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/generic-associated-types/generic-associated-type-bounds.rs b/src/test/ui/generic-associated-types/generic-associated-type-bounds.rs
new file mode 100644 (file)
index 0000000..8094450
--- /dev/null
@@ -0,0 +1,35 @@
+// run-pass
+
+#![allow(incomplete_features)]
+#![feature(generic_associated_types)]
+
+pub trait X {
+    type Y<'a>;
+    fn m(&self) -> Self::Y<'_>;
+}
+
+impl X for () {
+    type Y<'a> = &'a ();
+
+    fn m(&self) -> Self::Y<'_> {
+        self
+    }
+}
+
+fn f(x: &impl for<'a> X<Y<'a> = &'a ()>) -> &() {
+    x.m()
+}
+
+fn g<T: for<'a> X<Y<'a> = &'a ()>>(x: &T) -> &() {
+    x.m()
+}
+
+fn h(x: &()) -> &() {
+    x.m()
+}
+
+fn main() {
+    f(&());
+    g(&());
+    h(&());
+}
index 2b4757d8d15edcf8a245263c2b695a6222da93c6..5e73a8829862233ca6242d7087979ae55e8a79ec 100644 (file)
@@ -1,11 +1,11 @@
 #![feature(generic_associated_types)]
- //~^ WARNING the feature
+//~^ WARNING the feature
 
 pub trait SubTrait {}
 
 pub trait SuperTrait {
     type SubType<'a>: SubTrait;
-      //~^ ERROR missing generics for associated
+    //~^ ERROR missing generics for associated
 
     fn get_sub<'a>(&'a mut self) -> Self::SubType<'a>;
 }
@@ -36,6 +36,4 @@ fn get_sub<'a>(&'a mut self) -> Self::SubType<'a> {
 
 fn main() {
     let sub: Box<dyn SuperTrait<SubType = SubStruct>> = Box::new(SuperStruct::new(0));
-      //~^ ERROR the trait
-      //~| ERROR the trait
 }
index ce4875af9c012a04fb3c8900cae4a57d00c253ed..17661e0d90a4aecf2b550d95f27498ba38f4ea3e 100644 (file)
@@ -23,41 +23,6 @@ help: use angle brackets to add missing lifetime argument
 LL |     type SubType<'a><'a>: SubTrait;
    |                 ^^^^
 
-error[E0038]: the trait `SuperTrait` cannot be made into an object
-  --> $DIR/issue-76535.rs:38:14
-   |
-LL |     let sub: Box<dyn SuperTrait<SubType = SubStruct>> = Box::new(SuperStruct::new(0));
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SuperTrait` cannot be made into an object
-   |
-   = help: consider moving `get_sub` to another trait
-note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
-  --> $DIR/issue-76535.rs:10:37
-   |
-LL | pub trait SuperTrait {
-   |           ---------- this trait cannot be made into an object...
-...
-LL |     fn get_sub<'a>(&'a mut self) -> Self::SubType<'a>;
-   |                                     ^^^^^^^^^^^^^^^^^ ...because method `get_sub` references the `Self` type in its return type
-
-error[E0038]: the trait `SuperTrait` cannot be made into an object
-  --> $DIR/issue-76535.rs:38:57
-   |
-LL |     let sub: Box<dyn SuperTrait<SubType = SubStruct>> = Box::new(SuperStruct::new(0));
-   |                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SuperTrait` cannot be made into an object
-   |
-   = help: consider moving `get_sub` to another trait
-note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
-  --> $DIR/issue-76535.rs:10:37
-   |
-LL | pub trait SuperTrait {
-   |           ---------- this trait cannot be made into an object...
-...
-LL |     fn get_sub<'a>(&'a mut self) -> Self::SubType<'a>;
-   |                                     ^^^^^^^^^^^^^^^^^ ...because method `get_sub` references the `Self` type in its return type
-   = note: required because of the requirements on the impl of `CoerceUnsized<Box<dyn SuperTrait<SubType = SubStruct<'_>>>>` for `Box<SuperStruct>`
-   = note: required by cast to type `Box<dyn SuperTrait<SubType = SubStruct<'_>>>`
-
-error: aborting due to 3 previous errors; 1 warning emitted
+error: aborting due to previous error; 1 warning emitted
 
-Some errors have detailed explanations: E0038, E0107.
-For more information about an error, try `rustc --explain E0038`.
+For more information about this error, try `rustc --explain E0107`.
index 26b38430dd9a5e24de357e1417fd132c3d728588..aeb33ca54641cc399daa00c0ef7209194e4aba85 100644 (file)
@@ -19,7 +19,7 @@ fn t(&'a self) -> &'a T {
 
 trait MapLike<K, V> {
     type VRefCont<'a>: RefCont<'a, V>;
-      //~^ ERROR missing generics
+    //~^ ERROR missing generics
     fn get<'a>(&'a self, key: &K) -> Option<Self::VRefCont<'a>>;
 }
 
@@ -42,6 +42,5 @@ fn get<'a>(&self, _: &K) -> Option<Box<V>> {
 fn main() {
     let m = Box::new(std::collections::BTreeMap::<u8, u8>::new())
         as Box<dyn MapLike<u8, u8, VRefCont = dyn RefCont<'_, u8>>>;
-      //~^ ERROR the trait
-      //~^^^ ERROR the trait
+    //~^^ ERROR type mismatch resolving
 }
index d2e12962715f0e0eb886521428fba5b13d8eb2a1..a119bff03e2906e68bf67f30895e0ea4e9b110a1 100644 (file)
@@ -14,41 +14,17 @@ help: use angle brackets to add missing lifetime argument
 LL |     type VRefCont<'a><'a>: RefCont<'a, V>;
    |                  ^^^^
 
-error[E0038]: the trait `MapLike` cannot be made into an object
-  --> $DIR/issue-79422.rs:44:12
-   |
-LL |         as Box<dyn MapLike<u8, u8, VRefCont = dyn RefCont<'_, u8>>>;
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `MapLike` cannot be made into an object
-   |
-   = help: consider moving `get` to another trait
-note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
-  --> $DIR/issue-79422.rs:23:38
-   |
-LL | trait MapLike<K, V> {
-   |       ------- this trait cannot be made into an object...
-...
-LL |     fn get<'a>(&'a self, key: &K) -> Option<Self::VRefCont<'a>>;
-   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^ ...because method `get` references the `Self` type in its return type
-
-error[E0038]: the trait `MapLike` cannot be made into an object
+error[E0271]: type mismatch resolving `<BTreeMap<u8, u8> as MapLike<u8, u8>>::VRefCont<'static> == (dyn RefCont<'_, u8> + 'static)`
   --> $DIR/issue-79422.rs:43:13
    |
 LL |     let m = Box::new(std::collections::BTreeMap::<u8, u8>::new())
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `MapLike` cannot be made into an object
-   |
-   = help: consider moving `get` to another trait
-note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
-  --> $DIR/issue-79422.rs:23:38
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn RefCont`, found reference
    |
-LL | trait MapLike<K, V> {
-   |       ------- this trait cannot be made into an object...
-...
-LL |     fn get<'a>(&'a self, key: &K) -> Option<Self::VRefCont<'a>>;
-   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^ ...because method `get` references the `Self` type in its return type
-   = note: required because of the requirements on the impl of `CoerceUnsized<Box<dyn MapLike<u8, u8, VRefCont = (dyn RefCont<'_, u8> + 'static)>>>` for `Box<BTreeMap<u8, u8>>`
-   = note: required by cast to type `Box<dyn MapLike<u8, u8, VRefCont = (dyn RefCont<'_, u8> + 'static)>>`
+   = note: expected trait object `(dyn RefCont<'_, u8> + 'static)`
+                 found reference `&'static u8`
+   = note: required for the cast to the object type `dyn MapLike<u8, u8, VRefCont = (dyn RefCont<'_, u8> + 'static)>`
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0038, E0107.
-For more information about an error, try `rustc --explain E0038`.
+Some errors have detailed explanations: E0107, E0271.
+For more information about an error, try `rustc --explain E0107`.
diff --git a/src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.rs b/src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.rs
new file mode 100644 (file)
index 0000000..2de4c7b
--- /dev/null
@@ -0,0 +1,35 @@
+// Test that the predicate printed in an unresolved method error prints the
+// generics for a generic associated type.
+
+#![feature(generic_associated_types)]
+//~^ WARNING the feature `generic_associated_types` is incomplete
+//~| NOTE `#[warn(incomplete_features)]` on by default
+//~| NOTE see issue #44265
+
+trait X {
+    type Y<T>;
+}
+
+trait M {
+    fn f(&self) {}
+}
+
+impl<T: X<Y<i32> = i32>> M for T {}
+
+struct S;
+//~^ NOTE method `f` not found for this
+//~| NOTE doesn't satisfy `<S as X>::Y<i32> = i32`
+//~| NOTE doesn't satisfy `S: M`
+
+impl X for S {
+    type Y<T> = bool;
+}
+
+fn f(a: S) {
+    a.f();
+    //~^ ERROR the method `f` exists for struct `S`, but its trait bounds were not satisfied
+    //~| NOTE method cannot be called on `S` due to unsatisfied trait bounds
+    //~| NOTE the following trait bounds were not satisfied:
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.stderr b/src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.stderr
new file mode 100644 (file)
index 0000000..c94155d
--- /dev/null
@@ -0,0 +1,29 @@
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/method-unsatified-assoc-type-predicate.rs:4:12
+   |
+LL | #![feature(generic_associated_types)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+
+error[E0599]: the method `f` exists for struct `S`, but its trait bounds were not satisfied
+  --> $DIR/method-unsatified-assoc-type-predicate.rs:29:7
+   |
+LL | struct S;
+   | ---------
+   | |
+   | method `f` not found for this
+   | doesn't satisfy `<S as X>::Y<i32> = i32`
+   | doesn't satisfy `S: M`
+...
+LL |     a.f();
+   |       ^ method cannot be called on `S` due to unsatisfied trait bounds
+   |
+   = note: the following trait bounds were not satisfied:
+           `<S as X>::Y<i32> = i32`
+           which is required by `S: M`
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.rs b/src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.rs
new file mode 100644 (file)
index 0000000..0024e12
--- /dev/null
@@ -0,0 +1,36 @@
+#![allow(incomplete_features)]
+#![feature(generic_associated_types)]
+
+pub trait X {
+    type Y<'a>;
+    fn m(&self) -> Self::Y<'_>;
+}
+
+impl X for () {
+    type Y<'a> = &'a ();
+
+    fn m(&self) -> Self::Y<'_> {
+        self
+    }
+}
+
+fn f(x: &impl for<'a> X<Y<'a> = &'a ()>) -> &'static () {
+    x.m()
+    //~^ ERROR explicit lifetime required
+}
+
+fn g<T: for<'a> X<Y<'a> = &'a ()>>(x: &T) -> &'static () {
+    x.m()
+    //~^ ERROR explicit lifetime required
+}
+
+fn h(x: &()) -> &'static () {
+    x.m()
+    //~^ ERROR explicit lifetime required
+}
+
+fn main() {
+    f(&());
+    g(&());
+    h(&());
+}
diff --git a/src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.stderr b/src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.stderr
new file mode 100644 (file)
index 0000000..13b765d
--- /dev/null
@@ -0,0 +1,27 @@
+error[E0621]: explicit lifetime required in the type of `x`
+  --> $DIR/projection-type-lifetime-mismatch.rs:18:5
+   |
+LL | fn f(x: &impl for<'a> X<Y<'a> = &'a ()>) -> &'static () {
+   |         ------------------------------- help: add explicit lifetime `'static` to the type of `x`: `&'static impl for<'a> X<Y<'a> = &'a ()>`
+LL |     x.m()
+   |     ^^^^^ lifetime `'static` required
+
+error[E0621]: explicit lifetime required in the type of `x`
+  --> $DIR/projection-type-lifetime-mismatch.rs:23:5
+   |
+LL | fn g<T: for<'a> X<Y<'a> = &'a ()>>(x: &T) -> &'static () {
+   |                                       -- help: add explicit lifetime `'static` to the type of `x`: `&'static T`
+LL |     x.m()
+   |     ^^^^^ lifetime `'static` required
+
+error[E0621]: explicit lifetime required in the type of `x`
+  --> $DIR/projection-type-lifetime-mismatch.rs:28:5
+   |
+LL | fn h(x: &()) -> &'static () {
+   |         --- help: add explicit lifetime `'static` to the type of `x`: `&'static ()`
+LL |     x.m()
+   |     ^^^^^ lifetime `'static` required
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0621`.
diff --git a/src/test/ui/generic-associated-types/unsatified-item-lifetime-bound.rs b/src/test/ui/generic-associated-types/unsatified-item-lifetime-bound.rs
new file mode 100644 (file)
index 0000000..7bcc7ba
--- /dev/null
@@ -0,0 +1,28 @@
+#![allow(incomplete_features)]
+#![feature(generic_associated_types)]
+
+pub trait X {
+    type Y<'a: 'static>;
+    //~^ WARNING unnecessary lifetime parameter
+}
+
+impl X for () {
+    type Y<'a> = &'a ();
+}
+
+struct B<'a, T: for<'r> X<Y<'r> = &'r ()>> {
+    f: <T as X>::Y<'a>,
+    //~^ ERROR lifetime bound not satisfied
+}
+
+struct C<'a, T: X> {
+    f: <T as X>::Y<'a>,
+    //~^ ERROR lifetime bound not satisfied
+}
+
+struct D<'a> {
+    f: <() as X>::Y<'a>,
+    //~^ ERROR lifetime bound not satisfied
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/unsatified-item-lifetime-bound.stderr b/src/test/ui/generic-associated-types/unsatified-item-lifetime-bound.stderr
new file mode 100644 (file)
index 0000000..1c81d33
--- /dev/null
@@ -0,0 +1,50 @@
+warning: unnecessary lifetime parameter `'a`
+  --> $DIR/unsatified-item-lifetime-bound.rs:5:12
+   |
+LL |     type Y<'a: 'static>;
+   |            ^^^^^^^^^^^
+   |
+   = help: you can use the `'static` lifetime directly, in place of `'a`
+
+error[E0478]: lifetime bound not satisfied
+  --> $DIR/unsatified-item-lifetime-bound.rs:14:8
+   |
+LL |     f: <T as X>::Y<'a>,
+   |        ^^^^^^^^^^^^^^^
+   |
+note: lifetime parameter instantiated with the lifetime `'a` as defined on the struct at 13:10
+  --> $DIR/unsatified-item-lifetime-bound.rs:13:10
+   |
+LL | struct B<'a, T: for<'r> X<Y<'r> = &'r ()>> {
+   |          ^^
+   = note: but lifetime parameter must outlive the static lifetime
+
+error[E0478]: lifetime bound not satisfied
+  --> $DIR/unsatified-item-lifetime-bound.rs:19:8
+   |
+LL |     f: <T as X>::Y<'a>,
+   |        ^^^^^^^^^^^^^^^
+   |
+note: lifetime parameter instantiated with the lifetime `'a` as defined on the struct at 18:10
+  --> $DIR/unsatified-item-lifetime-bound.rs:18:10
+   |
+LL | struct C<'a, T: X> {
+   |          ^^
+   = note: but lifetime parameter must outlive the static lifetime
+
+error[E0478]: lifetime bound not satisfied
+  --> $DIR/unsatified-item-lifetime-bound.rs:24:8
+   |
+LL |     f: <() as X>::Y<'a>,
+   |        ^^^^^^^^^^^^^^^^
+   |
+note: lifetime parameter instantiated with the lifetime `'a` as defined on the struct at 23:10
+  --> $DIR/unsatified-item-lifetime-bound.rs:23:10
+   |
+LL | struct D<'a> {
+   |          ^^
+   = note: but lifetime parameter must outlive the static lifetime
+
+error: aborting due to 3 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0478`.
index e4096ec059a6e9c52a488da06575525b2096344a..520938a633514b6c41bdf929605ab24a2f061843 100644 (file)
@@ -3,9 +3,6 @@ error: implementation of `Foo` is not general enough
    |
 LL |     test::<FooS>(&mut 42);
    |     ^^^^^^^^^^^^ implementation of `Foo` is not general enough
-...
-LL | trait Foo<'a> {}
-   | ---------------- trait `Foo` defined here
    |
    = note: `FooS<'_>` must implement `Foo<'0>`, for any lifetime `'0`...
    = note: ...but `FooS<'_>` actually implements `Foo<'1>`, for some specific lifetime `'1`
index 003f32659351f18744c964da3de373b30dbdcaf0..f014eab8601fa4a728a6411304841a81553f5eeb 100644 (file)
@@ -1,9 +1,6 @@
 error: implementation of `Deserialize` is not general enough
   --> $DIR/hrtb-cache-issue-54302.rs:19:5
    |
-LL | trait Deserialize<'de> {}
-   | ------------------------- trait `Deserialize` defined here
-...
 LL |     assert_deserialize_owned::<&'static str>();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Deserialize` is not general enough
    |
index 45573814d13c0945f2577dd3843a8e13da15fb06..b1d4c0bf375059018da73037ace6791a091c262a 100644 (file)
@@ -1,16 +1,11 @@
 error: implementation of `Foo` is not general enough
   --> $DIR/hrtb-conflate-regions.rs:27:10
    |
-LL | / trait Foo<X> {
-LL | |     fn foo(&self, x: X) { }
-LL | | }
-   | |_- trait `Foo` defined here
-...
-LL |   fn b() { want_foo2::<SomeStruct>(); }
-   |            ^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
+LL | fn b() { want_foo2::<SomeStruct>(); }
+   |          ^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
    |
    = note: `SomeStruct` must implement `Foo<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`...
-   = note: ...but `SomeStruct` actually implements `Foo<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
+   = note: ...but it actually implements `Foo<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
 
 error: aborting due to previous error
 
index fe8209d054c8ad641044ddda3eda030241b2ec80..613f4dc4951ec3f16ced03fdcb9f1b0ed25e7e8e 100644 (file)
@@ -1,14 +1,11 @@
 error: implementation of `Trait` is not general enough
   --> $DIR/hrtb-exists-forall-trait-contravariant.rs:34:5
    |
-LL | trait Trait<T> {}
-   | ----------------- trait `Trait` defined here
-...
 LL |     foo::<()>();
    |     ^^^^^^^^^ implementation of `Trait` is not general enough
    |
    = note: `()` must implement `Trait<for<'b> fn(&'b u32)>`
-   = note: ...but `()` actually implements `Trait<fn(&'0 u32)>`, for some specific lifetime `'0`
+   = note: ...but it actually implements `Trait<fn(&'0 u32)>`, for some specific lifetime `'0`
 
 error: aborting due to previous error
 
index 8bd23aa9018df0f6fa92e71e0e3df620b3fea54a..b487ce3e0ffa1ce09b5f4dc8771a12e03c162217 100644 (file)
@@ -1,14 +1,11 @@
 error: implementation of `Trait` is not general enough
   --> $DIR/hrtb-exists-forall-trait-invariant.rs:28:5
    |
-LL | trait Trait<T> {}
-   | ----------------- trait `Trait` defined here
-...
 LL |     foo::<()>();
    |     ^^^^^^^^^ implementation of `Trait` is not general enough
    |
    = note: `()` must implement `Trait<for<'b> fn(Cell<&'b u32>)>`
-   = note: ...but `()` actually implements `Trait<fn(Cell<&'0 u32>)>`, for some specific lifetime `'0`
+   = note: ...but it actually implements `Trait<fn(Cell<&'0 u32>)>`, for some specific lifetime `'0`
 
 error: aborting due to previous error
 
index 5e3014317f5bc7025c8eddaeee4a217aee17639f..ffc83aab4af4d03dd35344ded3eba490c6b73323 100644 (file)
@@ -1,27 +1,17 @@
 error: implementation of `Foo` is not general enough
   --> $DIR/hrtb-just-for-static.rs:24:5
    |
-LL | / trait Foo<X> {
-LL | |     fn foo(&self, x: X) { }
-LL | | }
-   | |_- trait `Foo` defined here
-...
-LL |       want_hrtb::<StaticInt>()
-   |       ^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
+LL |     want_hrtb::<StaticInt>()
+   |     ^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
    |
    = note: `StaticInt` must implement `Foo<&'0 isize>`, for any lifetime `'0`...
-   = note: ...but `StaticInt` actually implements `Foo<&'1 isize>`, for some specific lifetime `'1`
+   = note: ...but it actually implements `Foo<&'static isize>`
 
 error: implementation of `Foo` is not general enough
   --> $DIR/hrtb-just-for-static.rs:30:5
    |
-LL | / trait Foo<X> {
-LL | |     fn foo(&self, x: X) { }
-LL | | }
-   | |_- trait `Foo` defined here
-...
-LL |       want_hrtb::<&'a u32>()
-   |       ^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
+LL |     want_hrtb::<&'a u32>()
+   |     ^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
    |
    = note: `Foo<&'0 isize>` would have to be implemented for the type `&'a u32`, for any lifetime `'0`...
    = note: ...but `Foo<&'1 isize>` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1`
index edce0e6702ee14e55cc7a97b8871648588c0eb13..c3dd794957540ccfd50f1d5228f23b63d1e12014 100644 (file)
@@ -1,11 +1,11 @@
 warning: function cannot return without recursing
-  --> $DIR/hrtb-perfect-forwarding.rs:22:1
+  --> $DIR/hrtb-perfect-forwarding.rs:16:1
    |
-LL | / fn no_hrtb<'b,T>(mut t: T)
-LL | |     where T : Bar<&'b isize>
+LL | / fn no_hrtb<'b, T>(mut t: T)
+LL | | where
+LL | |     T: Bar<&'b isize>,
 LL | | {
-LL | |     // OK -- `T : Bar<&'b isize>`, and thus the impl above ensures that
-LL | |     // `&mut T : Bar<&'b isize>`.
+...  |
 LL | |     no_hrtb(&mut t);
    | |     --------------- recursive call site
 LL | | }
@@ -15,12 +15,12 @@ LL | | }
    = help: a `loop` may express intention better if this is on purpose
 
 warning: function cannot return without recursing
-  --> $DIR/hrtb-perfect-forwarding.rs:30:1
+  --> $DIR/hrtb-perfect-forwarding.rs:25:1
    |
 LL | / fn bar_hrtb<T>(mut t: T)
-LL | |     where T : for<'b> Bar<&'b isize>
+LL | | where
+LL | |     T: for<'b> Bar<&'b isize>,
 LL | | {
-LL | |     // OK -- `T : for<'b> Bar<&'b isize>`, and thus the impl above
 ...  |
 LL | |     bar_hrtb(&mut t);
    | |     ---------------- recursive call site
@@ -30,25 +30,26 @@ LL | | }
    = help: a `loop` may express intention better if this is on purpose
 
 warning: function cannot return without recursing
-  --> $DIR/hrtb-perfect-forwarding.rs:39:1
+  --> $DIR/hrtb-perfect-forwarding.rs:35:1
    |
-LL | / fn foo_hrtb_bar_not<'b,T>(mut t: T)
-LL | |     where T : for<'a> Foo<&'a isize> + Bar<&'b isize>
+LL | / fn foo_hrtb_bar_not<'b, T>(mut t: T)
+LL | | where
+LL | |     T: for<'a> Foo<&'a isize> + Bar<&'b isize>,
 LL | | {
-LL | |     // Not OK -- The forwarding impl for `Foo` requires that `Bar` also
 ...  |
 LL | |     foo_hrtb_bar_not(&mut t);
    | |     ------------------------ recursive call site
 LL | |
+LL | |
 LL | | }
    | |_^ cannot return without recursing
    |
    = help: a `loop` may express intention better if this is on purpose
 
 error: lifetime may not live long enough
-  --> $DIR/hrtb-perfect-forwarding.rs:46:5
+  --> $DIR/hrtb-perfect-forwarding.rs:43:5
    |
-LL | fn foo_hrtb_bar_not<'b,T>(mut t: T)
+LL | fn foo_hrtb_bar_not<'b, T>(mut t: T)
    |                     -- lifetime `'b` defined here
 ...
 LL |     foo_hrtb_bar_not(&mut t);
@@ -57,18 +58,19 @@ LL |     foo_hrtb_bar_not(&mut t);
    = help: consider replacing `'b` with `'static`
 
 error: higher-ranked subtype error
-  --> $DIR/hrtb-perfect-forwarding.rs:46:5
+  --> $DIR/hrtb-perfect-forwarding.rs:43:5
    |
 LL |     foo_hrtb_bar_not(&mut t);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: function cannot return without recursing
-  --> $DIR/hrtb-perfect-forwarding.rs:50:1
+  --> $DIR/hrtb-perfect-forwarding.rs:48:1
    |
 LL | / fn foo_hrtb_bar_hrtb<T>(mut t: T)
-LL | |     where T : for<'a> Foo<&'a isize> + for<'b> Bar<&'b isize>
+LL | | where
+LL | |     T: for<'a> Foo<&'a isize> + for<'b> Bar<&'b isize>,
 LL | | {
-LL | |     // OK -- now we have `T : for<'b> Bar&'b isize>`.
+LL | |     // OK -- now we have `T : for<'b> Bar<&'b isize>`.
 LL | |     foo_hrtb_bar_hrtb(&mut t);
    | |     ------------------------- recursive call site
 LL | | }
index 0303a764c12def1154c80a48ffa058418ffe630c..441a788359e0345a0ce8f41d667fe24f5ff38b07 100644 (file)
@@ -2,25 +2,20 @@
 // is being applied to `for<'a> Foo<&'a mut X>`. Issue #19730.
 
 trait Foo<X> {
-    fn foo(&mut self, x: X) { }
+    fn foo(&mut self, x: X) {}
 }
 
 trait Bar<X> {
-    fn bar(&mut self, x: X) { }
+    fn bar(&mut self, x: X) {}
 }
 
-impl<'a,X,F> Foo<X> for &'a mut F
-    where F : Foo<X> + Bar<X>
-{
-}
+impl<'a, X, F> Foo<X> for &'a mut F where F: Foo<X> + Bar<X> {}
 
-impl<'a,X,F> Bar<X> for &'a mut F
-    where F : Bar<X>
-{
-}
+impl<'a, X, F> Bar<X> for &'a mut F where F: Bar<X> {}
 
-fn no_hrtb<'b,T>(mut t: T)
-    where T : Bar<&'b isize>
+fn no_hrtb<'b, T>(mut t: T)
+where
+    T: Bar<&'b isize>,
 {
     // OK -- `T : Bar<&'b isize>`, and thus the impl above ensures that
     // `&mut T : Bar<&'b isize>`.
@@ -28,7 +23,8 @@ fn no_hrtb<'b,T>(mut t: T)
 }
 
 fn bar_hrtb<T>(mut t: T)
-    where T : for<'b> Bar<&'b isize>
+where
+    T: for<'b> Bar<&'b isize>,
 {
     // OK -- `T : for<'b> Bar<&'b isize>`, and thus the impl above
     // ensures that `&mut T : for<'b> Bar<&'b isize>`.  This is an
@@ -36,22 +32,25 @@ fn bar_hrtb<T>(mut t: T)
     bar_hrtb(&mut t);
 }
 
-fn foo_hrtb_bar_not<'b,T>(mut t: T)
-    where T : for<'a> Foo<&'a isize> + Bar<&'b isize>
+fn foo_hrtb_bar_not<'b, T>(mut t: T)
+where
+    T: for<'a> Foo<&'a isize> + Bar<&'b isize>,
 {
     // Not OK -- The forwarding impl for `Foo` requires that `Bar` also
     // be implemented. Thus to satisfy `&mut T : for<'a> Foo<&'a
     // isize>`, we require `T : for<'a> Bar<&'a isize>`, but the where
     // clause only specifies `T : Bar<&'b isize>`.
-    foo_hrtb_bar_not(&mut t); //~ ERROR mismatched types
-                              //~| ERROR mismatched types
+    foo_hrtb_bar_not(&mut t);
+    //~^ ERROR implementation of `Bar` is not general enough
+    //~| ERROR implementation of `Bar` is not general enough
 }
 
 fn foo_hrtb_bar_hrtb<T>(mut t: T)
-    where T : for<'a> Foo<&'a isize> + for<'b> Bar<&'b isize>
+where
+    T: for<'a> Foo<&'a isize> + for<'b> Bar<&'b isize>,
 {
-    // OK -- now we have `T : for<'b> Bar&'b isize>`.
+    // OK -- now we have `T : for<'b> Bar<&'b isize>`.
     foo_hrtb_bar_hrtb(&mut t);
 }
 
-fn main() { }
+fn main() {}
index ed810d443bef7f098f209e71dceb32decdb9b5a8..07ff9b96e44ff807d28eaa9571396338558acdda 100644 (file)
@@ -1,41 +1,20 @@
-error[E0308]: mismatched types
-  --> $DIR/hrtb-perfect-forwarding.rs:46:5
+error: implementation of `Bar` is not general enough
+  --> $DIR/hrtb-perfect-forwarding.rs:43:5
    |
 LL |     foo_hrtb_bar_not(&mut t);
-   |     ^^^^^^^^^^^^^^^^ lifetime mismatch
+   |     ^^^^^^^^^^^^^^^^ implementation of `Bar` is not general enough
    |
-   = note: expected type `Bar<&'a isize>`
-              found type `Bar<&'b isize>`
-note: the required lifetime does not necessarily outlive the lifetime `'b` as defined on the function body at 39:21
-  --> $DIR/hrtb-perfect-forwarding.rs:39:21
-   |
-LL | fn foo_hrtb_bar_not<'b,T>(mut t: T)
-   |                     ^^
-note: the lifetime requirement is introduced here
-  --> $DIR/hrtb-perfect-forwarding.rs:40:15
-   |
-LL |     where T : for<'a> Foo<&'a isize> + Bar<&'b isize>
-   |               ^^^^^^^^^^^^^^^^^^^^^^
+   = note: `T` must implement `Bar<&'0 isize>`, for any lifetime `'0`...
+   = note: ...but it actually implements `Bar<&'b isize>`
 
-error[E0308]: mismatched types
-  --> $DIR/hrtb-perfect-forwarding.rs:46:5
+error: implementation of `Bar` is not general enough
+  --> $DIR/hrtb-perfect-forwarding.rs:43:5
    |
 LL |     foo_hrtb_bar_not(&mut t);
-   |     ^^^^^^^^^^^^^^^^ lifetime mismatch
-   |
-   = note: expected type `Bar<&'a isize>`
-              found type `Bar<&'b isize>`
-note: the lifetime `'b` as defined on the function body at 39:21 doesn't meet the lifetime requirements
-  --> $DIR/hrtb-perfect-forwarding.rs:39:21
-   |
-LL | fn foo_hrtb_bar_not<'b,T>(mut t: T)
-   |                     ^^
-note: the lifetime requirement is introduced here
-  --> $DIR/hrtb-perfect-forwarding.rs:40:15
+   |     ^^^^^^^^^^^^^^^^ implementation of `Bar` is not general enough
    |
-LL |     where T : for<'a> Foo<&'a isize> + Bar<&'b isize>
-   |               ^^^^^^^^^^^^^^^^^^^^^^
+   = note: `T` must implement `Bar<&'0 isize>`, for any lifetime `'0`...
+   = note: ...but it actually implements `Bar<&'b isize>`
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0308`.
index c85c37ff9239e3a3a6d78870395c7c0789843cd9..f3d906cae4cc3c43c939b51befe8c4d9568045e0 100644 (file)
@@ -1,9 +1,6 @@
 error: implementation of `Foo` is not general enough
   --> $DIR/issue-46989.rs:38:5
    |
-LL | trait Foo {}
-   | ------------ trait `Foo` defined here
-...
 LL |     assert_foo::<fn(&i32)>();
    |     ^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
    |
diff --git a/src/test/ui/html-literals.rs b/src/test/ui/html-literals.rs
deleted file mode 100644 (file)
index ae45e97..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-// run-pass
-
-#![allow(non_camel_case_types)]
-// A test of the macro system. Can we do HTML literals?
-
-/*
-
-This is an HTML parser written as a macro. It's all CPS, and we have
-to carry around a bunch of state. The arguments to macros all look like this:
-
-{ tag_stack* # expr* # tokens }
-
-The stack keeps track of where we are in the tree. The expr is a list
-of children of the current node. The tokens are everything that's
-left.
-
-*/
-use HTMLFragment::{tag, text};
-
-macro_rules! html {
-    ( $($body:tt)* ) => (
-        parse_node!( []; []; $($body)* )
-    )
-}
-
-macro_rules! parse_node {
-    (
-        [:$head:ident ($(:$head_nodes:expr),*)
-         $(:$tags:ident ($(:$tag_nodes:expr),*))*];
-        [$(:$nodes:expr),*];
-        </$tag:ident> $($rest:tt)*
-    ) => (
-        parse_node!(
-            [$(: $tags ($(:$tag_nodes),*))*];
-            [$(:$head_nodes,)* :tag(stringify!($head).to_string(),
-                                    vec![$($nodes),*])];
-            $($rest)*
-        )
-    );
-
-    (
-        [$(:$tags:ident ($(:$tag_nodes:expr),*) )*];
-        [$(:$nodes:expr),*];
-        <$tag:ident> $($rest:tt)*
-    ) => (
-        parse_node!(
-            [:$tag ($(:$nodes)*) $(: $tags ($(:$tag_nodes),*) )*];
-            [];
-            $($rest)*
-        )
-    );
-
-    (
-        [$(:$tags:ident ($(:$tag_nodes:expr),*) )*];
-        [$(:$nodes:expr),*];
-        . $($rest:tt)*
-    ) => (
-        parse_node!(
-            [$(: $tags ($(:$tag_nodes),*))*];
-            [$(:$nodes,)* :text(".".to_string())];
-            $($rest)*
-        )
-    );
-
-    (
-        [$(:$tags:ident ($(:$tag_nodes:expr),*) )*];
-        [$(:$nodes:expr),*];
-        $word:ident $($rest:tt)*
-    ) => (
-        parse_node!(
-            [$(: $tags ($(:$tag_nodes),*))*];
-            [$(:$nodes,)* :text(stringify!($word).to_string())];
-            $($rest)*
-        )
-    );
-
-    ( []; [:$e:expr]; ) => ( $e );
-}
-
-pub fn main() {
-    let _page = html! (
-        <html>
-            <head><title>This is the title.</title></head>
-            <body>
-            <p>This is some text</p>
-            </body>
-        </html>
-    );
-}
-
-enum HTMLFragment {
-    tag(String, Vec<HTMLFragment> ),
-    text(String),
-}
diff --git a/src/test/ui/hygiene/issue-40847.rs b/src/test/ui/hygiene/issue-40847.rs
new file mode 100644 (file)
index 0000000..087b40a
--- /dev/null
@@ -0,0 +1,17 @@
+// run-pass
+macro_rules! gen {
+    ($name:ident ( $($dol:tt $var:ident)* ) $($body:tt)*) => {
+        macro_rules! $name {
+            ($($dol $var:ident)*) => {
+                $($body)*
+            }
+        }
+    }
+}
+
+gen!(m($var) $var);
+
+fn main() {
+    let x = 1;
+    assert_eq!(m!(x), 1);
+}
diff --git a/src/test/ui/issue-6157.rs b/src/test/ui/issue-6157.rs
new file mode 100644 (file)
index 0000000..b7a44ed
--- /dev/null
@@ -0,0 +1,23 @@
+// run-pass
+// pretty-expanded FIXME #23616
+
+pub trait OpInt { fn call(&mut self, _: isize, _: isize) -> isize; }
+
+impl<F> OpInt for F where F: FnMut(isize, isize) -> isize {
+    fn call(&mut self, a:isize, b:isize) -> isize {
+        (*self)(a, b)
+    }
+}
+
+fn squarei<'a>(x: isize, op: &'a mut dyn OpInt) -> isize { op.call(x, x) }
+
+fn muli(x:isize, y:isize) -> isize { x * y }
+
+pub fn main() {
+    let mut f = |x, y| muli(x, y);
+    {
+        let g = &mut f;
+        let h = g as &mut dyn OpInt;
+        squarei(3, h);
+    }
+}
diff --git a/src/test/ui/issues/issue-13837.rs b/src/test/ui/issues/issue-13837.rs
deleted file mode 100644 (file)
index 645b1c0..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-// check-pass
-#![allow(dead_code)]
-// pretty-expanded FIXME #23616
-
-struct TestStruct {
-    x: *const [isize; 2]
-}
-
-unsafe impl Sync for TestStruct {}
-
-static TEST_VALUE : TestStruct = TestStruct{x: 0x1234 as *const [isize; 2]};
-
-fn main() {}
diff --git a/src/test/ui/issues/issue-17718-references.rs b/src/test/ui/issues/issue-17718-references.rs
deleted file mode 100644 (file)
index 03d5f8b..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-#![allow(warnings)]
-
-struct Struct { a: usize }
-
-const C: usize = 1;
-static S: usize = 1;
-
-const T1: &'static usize = &C;
-const T2: &'static usize = &S; //~ ERROR: constants cannot refer to statics
-static T3: &'static usize = &C;
-static T4: &'static usize = &S;
-
-const T5: usize = C;
-const T6: usize = S; //~ ERROR: constants cannot refer to statics
-static T7: usize = C;
-static T8: usize = S;
-
-const T9: Struct = Struct { a: C };
-const T10: Struct = Struct { a: S };
-//~^ ERROR: constants cannot refer to statics
-static T11: Struct = Struct { a: C };
-static T12: Struct = Struct { a: S };
-
-fn main() {}
diff --git a/src/test/ui/issues/issue-17718-references.stderr b/src/test/ui/issues/issue-17718-references.stderr
deleted file mode 100644 (file)
index e3c3b36..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-error[E0013]: constants cannot refer to statics
-  --> $DIR/issue-17718-references.rs:9:29
-   |
-LL | const T2: &'static usize = &S;
-   |                             ^
-   |
-   = help: consider extracting the value of the `static` to a `const`, and referring to that
-
-error[E0013]: constants cannot refer to statics
-  --> $DIR/issue-17718-references.rs:14:19
-   |
-LL | const T6: usize = S;
-   |                   ^
-   |
-   = help: consider extracting the value of the `static` to a `const`, and referring to that
-
-error[E0013]: constants cannot refer to statics
-  --> $DIR/issue-17718-references.rs:19:33
-   |
-LL | const T10: Struct = Struct { a: S };
-   |                                 ^
-   |
-   = help: consider extracting the value of the `static` to a `const`, and referring to that
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0013`.
index 0f3f83001d3c689c99b3c03233243df4cb6eecd6..1f3b73f96d8b9c2c965e32f41ddacf00cb9e0c0c 100644 (file)
@@ -1,4 +1,4 @@
-// Test if the sugared if-let construct correctly prints "missing an else clause" when an else
+// Test if the sugared `if let` construct correctly prints "missing an else clause" when an else
 // clause does not exist, instead of the unsympathetic "`match` arms have incompatible types"
 
 fn main() {
diff --git a/src/test/ui/issues/issue-20616-3.rs b/src/test/ui/issues/issue-20616-3.rs
deleted file mode 100644 (file)
index b237105..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-// We need all these 9 issue-20616-N.rs files
-// because we can only catch one parsing error at a time
-
-type Type_1_<'a, T> = &'a T;
-
-
-//type Type_1<'a T> = &'a T; // error: expected `,` or `>` after lifetime name, found `T`
-
-
-//type Type_2 = Type_1_<'static ()>; // error: expected `,` or `>` after lifetime name, found `(`
-
-
-type Type_3<T> = Box<T,,>;
-//~^ error: expected one of `>`, a const expression, lifetime, or type, found `,`
-
-
-//type Type_4<T> = Type_1_<'static,, T>; // error: expected type, found `,`
-
-
-type Type_5_<'a> = Type_1_<'a, ()>;
-
-
-//type Type_5<'a> = Type_1_<'a, (),,>; // error: expected type, found `,`
-
-
-//type Type_6 = Type_5_<'a,,>; // error: expected type, found `,`
-
-
-//type Type_7 = Box<(),,>; // error: expected type, found `,`
-
-
-//type Type_8<'a,,> = &'a (); // error: expected ident, found `,`
-
-
-//type Type_9<T,,> = Box<T>; // error: expected ident, found `,`
diff --git a/src/test/ui/issues/issue-20616-3.stderr b/src/test/ui/issues/issue-20616-3.stderr
deleted file mode 100644 (file)
index b535c7a..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-error: expected one of `>`, a const expression, lifetime, or type, found `,`
-  --> $DIR/issue-20616-3.rs:13:24
-   |
-LL | type Type_3<T> = Box<T,,>;
-   |                        ^ expected one of `>`, a const expression, lifetime, or type
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/issues/issue-21726.rs b/src/test/ui/issues/issue-21726.rs
deleted file mode 100644 (file)
index b98cf21..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-// check-pass
-#![allow(dead_code)]
-// Regression test for #21726: an issue arose around the rules for
-// subtyping of projection types that resulted in an unconstrained
-// region, yielding region inference failures.
-
-// pretty-expanded FIXME #23616
-
-fn main() { }
-
-fn foo<'a>(s: &'a str) {
-    let b: B<()> = B::new(s, ());
-    b.get_short();
-}
-
-trait IntoRef<'a> {
-    type T: Clone;
-    fn into_ref(self, _: &'a str) -> Self::T;
-}
-
-impl<'a> IntoRef<'a> for () {
-    type T = &'a str;
-    fn into_ref(self, s: &'a str) -> &'a str {
-        s
-    }
-}
-
-struct B<'a, P: IntoRef<'a>>(P::T);
-
-impl<'a, P: IntoRef<'a>> B<'a, P> {
-    fn new(s: &'a str, i: P) -> B<'a, P> {
-        B(i.into_ref(s))
-    }
-
-    fn get_short(&self) -> P::T {
-        self.0.clone()
-    }
-}
diff --git a/src/test/ui/issues/issue-22560.rs b/src/test/ui/issues/issue-22560.rs
deleted file mode 100644 (file)
index 44be881..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-trait Add<Rhs=Self> {
-    type Output;
-}
-
-trait Sub<Rhs=Self> {
-    type Output;
-}
-
-type Test = dyn Add + Sub;
-//~^ ERROR E0393
-//~| ERROR E0191
-//~| ERROR E0393
-//~| ERROR E0225
-
-fn main() { }
diff --git a/src/test/ui/issues/issue-22560.stderr b/src/test/ui/issues/issue-22560.stderr
deleted file mode 100644 (file)
index 9dda991..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-error[E0393]: the type parameter `Rhs` must be explicitly specified
-  --> $DIR/issue-22560.rs:9:23
-   |
-LL | / trait Sub<Rhs=Self> {
-LL | |     type Output;
-LL | | }
-   | |_- type parameter `Rhs` must be specified for this
-LL | 
-LL |   type Test = dyn Add + Sub;
-   |                         ^^^ help: set the type parameter to the desired type: `Sub<Rhs>`
-   |
-   = note: because of the default `Self` reference, type parameters must be specified on object types
-
-error[E0393]: the type parameter `Rhs` must be explicitly specified
-  --> $DIR/issue-22560.rs:9:17
-   |
-LL | / trait Add<Rhs=Self> {
-LL | |     type Output;
-LL | | }
-   | |_- type parameter `Rhs` must be specified for this
-...
-LL |   type Test = dyn Add + Sub;
-   |                   ^^^ help: set the type parameter to the desired type: `Add<Rhs>`
-   |
-   = note: because of the default `Self` reference, type parameters must be specified on object types
-
-error[E0225]: only auto traits can be used as additional traits in a trait object
-  --> $DIR/issue-22560.rs:9:23
-   |
-LL | type Test = dyn Add + Sub;
-   |                 ---   ^^^ additional non-auto trait
-   |                 |
-   |                 first non-auto trait
-   |
-   = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Add<[type error]> + Sub<[type error]> {}`
-   = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
-
-error[E0191]: the value of the associated types `Output` (from trait `Add`), `Output` (from trait `Sub`) must be specified
-  --> $DIR/issue-22560.rs:9:17
-   |
-LL |     type Output;
-   |     ------------ `Output` defined here
-...
-LL |     type Output;
-   |     ------------ `Output` defined here
-...
-LL | type Test = dyn Add + Sub;
-   |                 ^^^   ^^^ associated type `Output` must be specified
-   |                 |
-   |                 associated type `Output` must be specified
-   |
-help: specify the associated types
-   |
-LL | type Test = dyn Add<Output = Type> + Sub<Output = Type>;
-   |                 ^^^^^^^^^^^^^^^^^^   ^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 4 previous errors
-
-Some errors have detailed explanations: E0191, E0225, E0393.
-For more information about an error, try `rustc --explain E0191`.
diff --git a/src/test/ui/issues/issue-23595-2.rs b/src/test/ui/issues/issue-23595-2.rs
deleted file mode 100644 (file)
index 2bfee7a..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#![feature(associated_type_defaults)]
-
-pub struct C<AType: A> {a:AType}
-
-pub trait A {
-    type B = C<Self::anything_here_kills_it>;
-    //~^ ERROR: associated type `anything_here_kills_it` not found for `Self`
-}
-
-fn main() {}
diff --git a/src/test/ui/issues/issue-23595-2.stderr b/src/test/ui/issues/issue-23595-2.stderr
deleted file mode 100644 (file)
index dded673..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0220]: associated type `anything_here_kills_it` not found for `Self`
-  --> $DIR/issue-23595-2.rs:6:22
-   |
-LL |     type B = C<Self::anything_here_kills_it>;
-   |                      ^^^^^^^^^^^^^^^^^^^^^^ associated type `anything_here_kills_it` not found
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0220`.
diff --git a/src/test/ui/issues/issue-24204.rs b/src/test/ui/issues/issue-24204.rs
deleted file mode 100644 (file)
index 5a7b345..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-// check-pass
-
-#![allow(dead_code)]
-
-trait MultiDispatch<T> {
-    type O;
-}
-
-trait Trait: Sized {
-    type A: MultiDispatch<Self::B, O = Self>;
-    type B;
-
-    fn new<U>(u: U) -> <Self::A as MultiDispatch<U>>::O
-    where
-        Self::A: MultiDispatch<U>;
-}
-
-fn test<T: Trait<B = i32>>(b: i32) -> T
-where
-    T::A: MultiDispatch<i32>,
-{
-    T::new(b)
-}
-
-fn main() {}
diff --git a/src/test/ui/issues/issue-31924-non-snake-ffi.rs b/src/test/ui/issues/issue-31924-non-snake-ffi.rs
deleted file mode 100644 (file)
index 63e42b4..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-// check-pass
-
-#![deny(non_snake_case)]
-
-#[no_mangle]
-pub extern "C" fn SparklingGenerationForeignFunctionInterface() {} // OK
-
-fn main() {}
diff --git a/src/test/ui/issues/issue-32829.rs b/src/test/ui/issues/issue-32829.rs
deleted file mode 100644 (file)
index adfee7b..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-static S : u64 = { { panic!("foo"); 0 } };
-//~^ ERROR panicking in statics is unstable
-
-fn main() {
-    println!("{:?}", S);
-}
diff --git a/src/test/ui/issues/issue-32829.stderr b/src/test/ui/issues/issue-32829.stderr
deleted file mode 100644 (file)
index 48e0880..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-error[E0658]: panicking in statics is unstable
-  --> $DIR/issue-32829.rs:1:22
-   |
-LL | static S : u64 = { { panic!("foo"); 0 } };
-   |                      ^^^^^^^^^^^^^^
-   |
-   = note: see issue #51999 <https://github.com/rust-lang/rust/issues/51999> for more information
-   = help: add `#![feature(const_panic)]` to the crate attributes to enable
-   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/issues/issue-33537.rs b/src/test/ui/issues/issue-33537.rs
deleted file mode 100644 (file)
index 3539aa6..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-// run-pass
-
-const fn foo() -> *const i8 {
-    b"foo" as *const _ as *const i8
-}
-
-const fn bar() -> i32 {
-    *&{(1, 2, 3).1}
-}
-
-fn main() {
-    assert_eq!(foo(), b"foo" as *const _ as *const i8);
-    assert_eq!(bar(), 2);
-}
diff --git a/src/test/ui/issues/issue-40847.rs b/src/test/ui/issues/issue-40847.rs
deleted file mode 100644 (file)
index 087b40a..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-// run-pass
-macro_rules! gen {
-    ($name:ident ( $($dol:tt $var:ident)* ) $($body:tt)*) => {
-        macro_rules! $name {
-            ($($dol $var:ident)*) => {
-                $($body)*
-            }
-        }
-    }
-}
-
-gen!(m($var) $var);
-
-fn main() {
-    let x = 1;
-    assert_eq!(m!(x), 1);
-}
diff --git a/src/test/ui/issues/issue-4201.rs b/src/test/ui/issues/issue-4201.rs
deleted file mode 100644 (file)
index 1f29222..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-fn main() {
-    let a = if true {
-        0
-    } else if false {
-//~^ ERROR `if` may be missing an `else` clause
-//~| expected `()`, found integer
-        1
-    };
-}
diff --git a/src/test/ui/issues/issue-4201.stderr b/src/test/ui/issues/issue-4201.stderr
deleted file mode 100644 (file)
index bc638dd..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-error[E0317]: `if` may be missing an `else` clause
-  --> $DIR/issue-4201.rs:4:12
-   |
-LL |       } else if false {
-   |  ____________^
-LL | |
-LL | |
-LL | |         1
-   | |         - found here
-LL | |     };
-   | |_____^ expected `()`, found integer
-   |
-   = note: `if` expressions without `else` evaluate to `()`
-   = help: consider adding an `else` block that evaluates to the expected type
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0317`.
diff --git a/src/test/ui/issues/issue-43784-associated-type.rs b/src/test/ui/issues/issue-43784-associated-type.rs
deleted file mode 100644 (file)
index 78815d8..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-pub trait Partial<X: ?Sized>: Copy {
-}
-
-pub trait Complete {
-    type Assoc: Partial<Self>;
-}
-
-impl<T> Partial<T> for T::Assoc where
-    T: Complete
-{
-}
-
-impl<T> Complete for T {
-    type Assoc = T; //~ ERROR the trait bound `T: Copy` is not satisfied
-}
-
-fn main() {}
diff --git a/src/test/ui/issues/issue-43784-associated-type.stderr b/src/test/ui/issues/issue-43784-associated-type.stderr
deleted file mode 100644 (file)
index d5105ae..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-error[E0277]: the trait bound `T: Copy` is not satisfied
-  --> $DIR/issue-43784-associated-type.rs:14:5
-   |
-LL |     type Assoc: Partial<Self>;
-   |                 ------------- required by this bound in `Complete::Assoc`
-...
-LL |     type Assoc = T;
-   |     ^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T`
-   |
-help: consider restricting type parameter `T`
-   |
-LL | impl<T: Copy> Complete for 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-44406.rs b/src/test/ui/issues/issue-44406.rs
deleted file mode 100644 (file)
index 83bbf88..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-macro_rules! foo {
-    ($rest: tt) => {
-        bar(baz: $rest)
-    }
-}
-
-fn main() {
-    foo!(true); //~ ERROR expected type, found keyword
-    //~^ ERROR expected identifier, found keyword
-}
diff --git a/src/test/ui/issues/issue-44406.stderr b/src/test/ui/issues/issue-44406.stderr
deleted file mode 100644 (file)
index 701c32d..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-error: expected identifier, found keyword `true`
-  --> $DIR/issue-44406.rs:8:10
-   |
-LL |     foo!(true);
-   |          ^^^^ expected identifier, found keyword
-   |
-help: you can escape reserved keywords to use them as identifiers
-   |
-LL |     foo!(r#true);
-   |          ^^^^^^
-
-error: expected type, found keyword `true`
-  --> $DIR/issue-44406.rs:8:10
-   |
-LL |         bar(baz: $rest)
-   |                - help: try using a semicolon: `;`
-...
-LL |     foo!(true);
-   |          ^^^^ expected type
-   |
-   = note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `<expr>: <type>`
-   = note: see issue #23416 <https://github.com/rust-lang/rust/issues/23416> for more information
-
-error: aborting due to 2 previous errors
-
index 4134d6aa5446898b8a7c6d7776dadce199002886..56befe3a0a75d7eff1216f6c2080a11176b488c9 100644 (file)
@@ -7,10 +7,8 @@ LL | #![allow(unused_variables)];
 error[E0601]: `main` function not found in crate `issue_49040`
   --> $DIR/issue-49040.rs:1:1
    |
-LL | / #![allow(unused_variables)];
-LL | |
-LL | | fn foo() {}
-   | |__^ consider adding a `main` function to `$DIR/issue-49040.rs`
+LL | #![allow(unused_variables)];
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ consider adding a `main` function to `$DIR/issue-49040.rs`
 
 error: aborting due to 2 previous errors
 
index 3ed27791643017ea2686427fb9b58f8dfd6f114a..baa75f28d37f32c39cef43b2226a9a8b23f94837 100644 (file)
@@ -1,13 +1,8 @@
 error: implementation of `Foo` is not general enough
   --> $DIR/issue-54302-cases.rs:63:5
    |
-LL | / trait Foo<'x, T> {
-LL | |     fn foo(self) -> &'x T;
-LL | | }
-   | |_- trait `Foo` defined here
-...
-LL |       <u32 as RefFoo<u32>>::ref_foo(a)
-   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
+LL |     <u32 as RefFoo<u32>>::ref_foo(a)
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
    |
    = note: `Foo<'static, u32>` would have to be implemented for the type `&'0 u32`, for any lifetime `'0`...
    = note: ...but `Foo<'_, u32>` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1`
@@ -15,13 +10,8 @@ LL |       <u32 as RefFoo<u32>>::ref_foo(a)
 error: implementation of `Foo` is not general enough
   --> $DIR/issue-54302-cases.rs:69:5
    |
-LL | / trait Foo<'x, T> {
-LL | |     fn foo(self) -> &'x T;
-LL | | }
-   | |_- trait `Foo` defined here
-...
-LL |       <i32 as RefFoo<i32>>::ref_foo(a)
-   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
+LL |     <i32 as RefFoo<i32>>::ref_foo(a)
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
    |
    = note: `Foo<'static, i32>` would have to be implemented for the type `&'0 i32`, for any lifetime `'0`...
    = note: ...but `Foo<'_, i32>` is actually implemented for the type `&'1 i32`, for some specific lifetime `'1`
@@ -29,13 +19,8 @@ LL |       <i32 as RefFoo<i32>>::ref_foo(a)
 error: implementation of `Foo` is not general enough
   --> $DIR/issue-54302-cases.rs:75:5
    |
-LL | / trait Foo<'x, T> {
-LL | |     fn foo(self) -> &'x T;
-LL | | }
-   | |_- trait `Foo` defined here
-...
-LL |       <u64 as RefFoo<u64>>::ref_foo(a)
-   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
+LL |     <u64 as RefFoo<u64>>::ref_foo(a)
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
    |
    = note: `Foo<'static, u64>` would have to be implemented for the type `&'0 u64`, for any lifetime `'0`...
    = note: ...but `Foo<'_, u64>` is actually implemented for the type `&'1 u64`, for some specific lifetime `'1`
@@ -43,13 +28,8 @@ LL |       <u64 as RefFoo<u64>>::ref_foo(a)
 error: implementation of `Foo` is not general enough
   --> $DIR/issue-54302-cases.rs:81:5
    |
-LL | / trait Foo<'x, T> {
-LL | |     fn foo(self) -> &'x T;
-LL | | }
-   | |_- trait `Foo` defined here
-...
-LL |       <i64 as RefFoo<i64>>::ref_foo(a)
-   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
+LL |     <i64 as RefFoo<i64>>::ref_foo(a)
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
    |
    = note: `Foo<'static, i64>` would have to be implemented for the type `&'0 i64`, for any lifetime `'0`...
    = note: ...but `Foo<'_, i64>` is actually implemented for the type `&'1 i64`, for some specific lifetime `'1`
index 1b3f57ba188a3d03da8b3145d7bb32ee0b5d514b..26c46571f9cb232d8155abcfc30a47d74d98a216 100644 (file)
@@ -1,9 +1,6 @@
 error: implementation of `Deserialize` is not general enough
   --> $DIR/issue-54302.rs:13:5
    |
-LL | trait Deserialize<'de> {}
-   | ------------------------- trait `Deserialize` defined here
-...
 LL |     assert_deserialize_owned::<&'static str>();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Deserialize` is not general enough
    |
index f44c842187cc211ea163bc701ac263a9aff21145..de327cd3cc23cc87a79129f2d39cf7465ea87fb1 100644 (file)
@@ -1,13 +1,8 @@
 error: implementation of `DistributedIteratorMulti` is not general enough
   --> $DIR/issue-55731.rs:48:5
    |
-LL | / trait DistributedIteratorMulti<Source> {
-LL | |     type Item;
-LL | | }
-   | |_- trait `DistributedIteratorMulti` defined here
-...
-LL |       multi(Map {
-   |       ^^^^^ implementation of `DistributedIteratorMulti` is not general enough
+LL |     multi(Map {
+   |     ^^^^^ implementation of `DistributedIteratorMulti` is not general enough
    |
    = note: `DistributedIteratorMulti<&'0 ()>` would have to be implemented for the type `Cloned<&()>`, for any lifetime `'0`...
    = note: ...but `DistributedIteratorMulti<&'1 ()>` is actually implemented for the type `Cloned<&'1 ()>`, for some specific lifetime `'1`
index 70310780b4330e5e2ce2686172213859ba2b690f..70d16cc9a1da66c97e16292faa5647d4b5bf5f98 100644 (file)
@@ -1,5 +1,5 @@
 error: higher-ranked subtype error
-  --> $DIR/issue-57843.rs:23:9
+  --> $DIR/issue-57843.rs:25:9
    |
 LL |     Foo(Box::new(|_| ()));
    |         ^^^^^^^^^^^^^^^^
index 466082552667b5a6916091ba124aad6ed7483991..11629690ecc5e27ac51880a80e699b529ab2a68e 100644 (file)
@@ -11,7 +11,9 @@ trait ClonableFn<T> {
 }
 
 impl<T, F: 'static> ClonableFn<T> for F
-where F: Fn(T) + Clone {
+where
+    F: Fn(T) + Clone,
+{
     fn clone(&self) -> Box<dyn Fn(T)> {
         Box::new(self.clone())
     }
@@ -20,5 +22,5 @@ fn clone(&self) -> Box<dyn Fn(T)> {
 struct Foo(Box<dyn for<'a> ClonableFn<&'a bool>>);
 
 fn main() {
-    Foo(Box::new(|_| ())); //~ ERROR mismatched types
+    Foo(Box::new(|_| ())); //~ ERROR implementation of `FnOnce` is not general enough
 }
index 7699e97da99ad2f4a9ed4939dba35963f9f6b6cc..2ab49ec61cf597ef187b72d897312e9ffd112962 100644 (file)
@@ -1,17 +1,11 @@
-error[E0308]: mismatched types
-  --> $DIR/issue-57843.rs:23:9
+error: implementation of `FnOnce` is not general enough
+  --> $DIR/issue-57843.rs:25:9
    |
 LL |     Foo(Box::new(|_| ()));
-   |         ^^^^^^^^^^^^^^^^ one type is more general than the other
+   |         ^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
    |
-   = note: expected type `FnOnce<(&'a bool,)>`
-              found type `FnOnce<(&bool,)>`
-note: this closure does not fulfill the lifetime requirements
-  --> $DIR/issue-57843.rs:23:18
-   |
-LL |     Foo(Box::new(|_| ()));
-   |                  ^^^^^^
+   = note: closure with signature `fn(&'2 bool)` must implement `FnOnce<(&'1 bool,)>`, for any lifetime `'1`...
+   = note: ...but it actually implements `FnOnce<(&'2 bool,)>`, for some specific lifetime `'2`
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/issues/issue-6157.rs b/src/test/ui/issues/issue-6157.rs
deleted file mode 100644 (file)
index b7a44ed..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-// run-pass
-// pretty-expanded FIXME #23616
-
-pub trait OpInt { fn call(&mut self, _: isize, _: isize) -> isize; }
-
-impl<F> OpInt for F where F: FnMut(isize, isize) -> isize {
-    fn call(&mut self, a:isize, b:isize) -> isize {
-        (*self)(a, b)
-    }
-}
-
-fn squarei<'a>(x: isize, op: &'a mut dyn OpInt) -> isize { op.call(x, x) }
-
-fn muli(x:isize, y:isize) -> isize { x * y }
-
-pub fn main() {
-    let mut f = |x, y| muli(x, y);
-    {
-        let g = &mut f;
-        let h = g as &mut dyn OpInt;
-        squarei(3, h);
-    }
-}
diff --git a/src/test/ui/issues/issue-77993-2.rs b/src/test/ui/issues/issue-77993-2.rs
deleted file mode 100644 (file)
index 4d554a0..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-// edition:2018
-
-async fn test() -> Result<(), Box<dyn std::error::Error>> {
-    macro!();
-    //~^ ERROR expected identifier, found `!`
-    Ok(())
-}
-
-fn main() {}
diff --git a/src/test/ui/issues/issue-77993-2.stderr b/src/test/ui/issues/issue-77993-2.stderr
deleted file mode 100644 (file)
index 64b378f..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-error: expected identifier, found `!`
-  --> $DIR/issue-77993-2.rs:4:10
-   |
-LL |     macro!();
-   |          ^ expected identifier
-
-error: aborting due to previous error
-
index bf331d8a6068e5861867161a0e6b4b1da18cc34b..2ee69ee2234eefbe9bc9b3bec3b4834061dc424c 100644 (file)
@@ -2,5 +2,5 @@ fn thing(x: impl FnOnce(&u32)) {}
 
 fn main() {
     let f = |_| ();
-    thing(f); //~ERROR mismatched types
+    thing(f); //~ERROR implementation of `FnOnce` is not general enough
 }
index 63f501e08fce4ead09fcd54677196dcb4069f226..3c0439fb660e501c7bde75e61c948e1c41f1255d 100644 (file)
@@ -1,22 +1,11 @@
-error[E0308]: mismatched types
+error: implementation of `FnOnce` is not general enough
   --> $DIR/issue-79187.rs:5:5
    |
 LL |     thing(f);
-   |     ^^^^^ lifetime mismatch
+   |     ^^^^^ implementation of `FnOnce` is not general enough
    |
-   = note: expected type `FnOnce<(&u32,)>`
-              found type `FnOnce<(&u32,)>`
-note: this closure does not fulfill the lifetime requirements
-  --> $DIR/issue-79187.rs:4:13
-   |
-LL |     let f = |_| ();
-   |             ^^^^^^
-note: the lifetime requirement is introduced here
-  --> $DIR/issue-79187.rs:1:18
-   |
-LL | fn thing(x: impl FnOnce(&u32)) {}
-   |                  ^^^^^^^^^^^^
+   = note: closure with signature `fn(&'2 u32)` must implement `FnOnce<(&'1 u32,)>`, for any lifetime `'1`...
+   = note: ...but it actually implements `FnOnce<(&'2 u32,)>`, for some specific lifetime `'2`
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/lint/issue-31924-non-snake-ffi.rs b/src/test/ui/lint/issue-31924-non-snake-ffi.rs
new file mode 100644 (file)
index 0000000..63e42b4
--- /dev/null
@@ -0,0 +1,8 @@
+// check-pass
+
+#![deny(non_snake_case)]
+
+#[no_mangle]
+pub extern "C" fn SparklingGenerationForeignFunctionInterface() {} // OK
+
+fn main() {}
diff --git a/src/test/ui/macros/html-literals.rs b/src/test/ui/macros/html-literals.rs
new file mode 100644 (file)
index 0000000..ae45e97
--- /dev/null
@@ -0,0 +1,94 @@
+// run-pass
+
+#![allow(non_camel_case_types)]
+// A test of the macro system. Can we do HTML literals?
+
+/*
+
+This is an HTML parser written as a macro. It's all CPS, and we have
+to carry around a bunch of state. The arguments to macros all look like this:
+
+{ tag_stack* # expr* # tokens }
+
+The stack keeps track of where we are in the tree. The expr is a list
+of children of the current node. The tokens are everything that's
+left.
+
+*/
+use HTMLFragment::{tag, text};
+
+macro_rules! html {
+    ( $($body:tt)* ) => (
+        parse_node!( []; []; $($body)* )
+    )
+}
+
+macro_rules! parse_node {
+    (
+        [:$head:ident ($(:$head_nodes:expr),*)
+         $(:$tags:ident ($(:$tag_nodes:expr),*))*];
+        [$(:$nodes:expr),*];
+        </$tag:ident> $($rest:tt)*
+    ) => (
+        parse_node!(
+            [$(: $tags ($(:$tag_nodes),*))*];
+            [$(:$head_nodes,)* :tag(stringify!($head).to_string(),
+                                    vec![$($nodes),*])];
+            $($rest)*
+        )
+    );
+
+    (
+        [$(:$tags:ident ($(:$tag_nodes:expr),*) )*];
+        [$(:$nodes:expr),*];
+        <$tag:ident> $($rest:tt)*
+    ) => (
+        parse_node!(
+            [:$tag ($(:$nodes)*) $(: $tags ($(:$tag_nodes),*) )*];
+            [];
+            $($rest)*
+        )
+    );
+
+    (
+        [$(:$tags:ident ($(:$tag_nodes:expr),*) )*];
+        [$(:$nodes:expr),*];
+        . $($rest:tt)*
+    ) => (
+        parse_node!(
+            [$(: $tags ($(:$tag_nodes),*))*];
+            [$(:$nodes,)* :text(".".to_string())];
+            $($rest)*
+        )
+    );
+
+    (
+        [$(:$tags:ident ($(:$tag_nodes:expr),*) )*];
+        [$(:$nodes:expr),*];
+        $word:ident $($rest:tt)*
+    ) => (
+        parse_node!(
+            [$(: $tags ($(:$tag_nodes),*))*];
+            [$(:$nodes,)* :text(stringify!($word).to_string())];
+            $($rest)*
+        )
+    );
+
+    ( []; [:$e:expr]; ) => ( $e );
+}
+
+pub fn main() {
+    let _page = html! (
+        <html>
+            <head><title>This is the title.</title></head>
+            <body>
+            <p>This is some text</p>
+            </body>
+        </html>
+    );
+}
+
+enum HTMLFragment {
+    tag(String, Vec<HTMLFragment> ),
+    text(String),
+}
index e278049c8cc42d2e4a2d61ea3f1d83429dd14a18..2d485d14a8d6b8fd963213f100da8727257c96a2 100644 (file)
@@ -8,8 +8,8 @@ fn main() {
 fn baz<F: Fn(*mut &u32)>(_: F) {}
 fn _test<'a>(f: fn(*mut &'a u32)) {
     baz(f);
-    //~^ ERROR mismatched types
-    //~| ERROR mismatched types
+    //~^ ERROR implementation of `FnOnce` is not general enough
+    //~| ERROR implementation of `FnOnce` is not general enough
     //~| ERROR mismatched types
     //~| ERROR mismatched types
 }
index 02ba60f7f4b737635a730c4a386784fa80d9e3d9..521de3742b03f510782842b8028ff6bdba5c5dcf 100644 (file)
@@ -41,24 +41,14 @@ note: the lifetime requirement is introduced here
 LL | fn baz<F: Fn(*mut &u32)>(_: F) {}
    |           ^^^^^^^^^^^^^
 
-error[E0308]: mismatched types
+error: implementation of `FnOnce` is not general enough
   --> $DIR/closure-arg-type-mismatch.rs:10:5
    |
 LL |     baz(f);
-   |     ^^^ lifetime mismatch
-   |
-   = note: expected type `FnOnce<(*mut &u32,)>`
-              found type `FnOnce<(*mut &'a u32,)>`
-note: the required lifetime does not necessarily outlive the lifetime `'a` as defined on the function body at 9:10
-  --> $DIR/closure-arg-type-mismatch.rs:9:10
-   |
-LL | fn _test<'a>(f: fn(*mut &'a u32)) {
-   |          ^^
-note: the lifetime requirement is introduced here
-  --> $DIR/closure-arg-type-mismatch.rs:8:11
+   |     ^^^ implementation of `FnOnce` is not general enough
    |
-LL | fn baz<F: Fn(*mut &u32)>(_: F) {}
-   |           ^^^^^^^^^^^^^
+   = note: `fn(*mut &'a u32)` must implement `FnOnce<(*mut &'0 u32,)>`, for any lifetime `'0`...
+   = note: ...but it actually implements `FnOnce<(*mut &'a u32,)>`
 
 error[E0308]: mismatched types
   --> $DIR/closure-arg-type-mismatch.rs:10:5
@@ -79,24 +69,14 @@ note: the lifetime requirement is introduced here
 LL | fn baz<F: Fn(*mut &u32)>(_: F) {}
    |           ^^^^^^^^^^^^^
 
-error[E0308]: mismatched types
+error: implementation of `FnOnce` is not general enough
   --> $DIR/closure-arg-type-mismatch.rs:10:5
    |
 LL |     baz(f);
-   |     ^^^ lifetime mismatch
-   |
-   = note: expected type `FnOnce<(*mut &u32,)>`
-              found type `FnOnce<(*mut &'a u32,)>`
-note: the lifetime `'a` as defined on the function body at 9:10 doesn't meet the lifetime requirements
-  --> $DIR/closure-arg-type-mismatch.rs:9:10
-   |
-LL | fn _test<'a>(f: fn(*mut &'a u32)) {
-   |          ^^
-note: the lifetime requirement is introduced here
-  --> $DIR/closure-arg-type-mismatch.rs:8:11
+   |     ^^^ implementation of `FnOnce` is not general enough
    |
-LL | fn baz<F: Fn(*mut &u32)>(_: F) {}
-   |           ^^^^^^^^^^^^^
+   = note: `fn(*mut &'a u32)` must implement `FnOnce<(*mut &'0 u32,)>`, for any lifetime `'0`...
+   = note: ...but it actually implements `FnOnce<(*mut &'a u32,)>`
 
 error: aborting due to 7 previous errors
 
diff --git a/src/test/ui/old-suffixes-are-really-forbidden.rs b/src/test/ui/old-suffixes-are-really-forbidden.rs
deleted file mode 100644 (file)
index eea95b7..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-fn main() {
-    let a = 1_is; //~ ERROR invalid suffix
-    let b = 2_us; //~ ERROR invalid suffix
-}
diff --git a/src/test/ui/old-suffixes-are-really-forbidden.stderr b/src/test/ui/old-suffixes-are-really-forbidden.stderr
deleted file mode 100644 (file)
index fb30979..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-error: invalid suffix `is` for number literal
-  --> $DIR/old-suffixes-are-really-forbidden.rs:2:13
-   |
-LL |     let a = 1_is;
-   |             ^^^^ invalid suffix `is`
-   |
-   = help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.)
-
-error: invalid suffix `us` for number literal
-  --> $DIR/old-suffixes-are-really-forbidden.rs:3:13
-   |
-LL |     let b = 2_us;
-   |             ^^^^ invalid suffix `us`
-   |
-   = help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.)
-
-error: aborting due to 2 previous errors
-
diff --git a/src/test/ui/one-tuple.rs b/src/test/ui/one-tuple.rs
deleted file mode 100644 (file)
index 00fbadc..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-// run-pass
-// Why one-tuples? Because macros.
-
-
-pub fn main() {
-    match ('c',) {
-        (x,) => {
-            assert_eq!(x, 'c');
-        }
-    }
-    // test the 1-tuple type too
-    let x: (char,) = ('d',);
-    let (y,) = x;
-    assert_eq!(y, 'd');
-}
index a9e43a4575da09d7c6f97d9098d284161a96c99e..c01d17c0b3d7e10c24e0c7d44f167123d0b54038 100644 (file)
@@ -8,10 +8,10 @@ LL |         Some(0 | 1 | 2) => {}
    = help: add `#![feature(or_patterns)]` to the crate attributes to enable
 
 error[E0658]: or-patterns syntax is experimental
-  --> $DIR/feature-gate-or_patterns.rs:28:11
+  --> $DIR/feature-gate-or_patterns.rs:28:9
    |
 LL |     let | A | B;
-   |           ^^^^^
+   |         ^^^^^^^
    |
    = note: see issue #54883 <https://github.com/rust-lang/rust/issues/54883> for more information
    = help: add `#![feature(or_patterns)]` to the crate attributes to enable
@@ -26,10 +26,10 @@ LL |     let A | B;
    = help: add `#![feature(or_patterns)]` to the crate attributes to enable
 
 error[E0658]: or-patterns syntax is experimental
-  --> $DIR/feature-gate-or_patterns.rs:30:11
+  --> $DIR/feature-gate-or_patterns.rs:30:9
    |
 LL |     for | A | B in 0 {}
-   |           ^^^^^
+   |         ^^^^^^^
    |
    = note: see issue #54883 <https://github.com/rust-lang/rust/issues/54883> for more information
    = help: add `#![feature(or_patterns)]` to the crate attributes to enable
index 08730fe8b07b74f030fc217025bc18734fc6498b..bbc75d2b411eb2ab6c244446a0e9dc8247a9a9c1 100644 (file)
@@ -11,4 +11,4 @@ enum E { A, B }
 use E::*;
 
 #[cfg(FALSE)]
-fn fun1((A | B): E) {} //~ ERROR an or-pattern parameter must be wrapped in parenthesis
+fn fun1((A | B): E) {} //~ ERROR an or-pattern parameter must be wrapped in parentheses
index ed667e0e66067b778255d8ac87952018250ba7b5..65b93dcbf7467e4a6dbaf04baad13218aeae0e58 100644 (file)
@@ -11,4 +11,4 @@ enum E { A, B }
 use E::*;
 
 #[cfg(FALSE)]
-fn fun1(A | B: E) {} //~ ERROR an or-pattern parameter must be wrapped in parenthesis
+fn fun1(A | B: E) {} //~ ERROR an or-pattern parameter must be wrapped in parentheses
index 2c6e4d9838ddcf9387a9971ddb6cee44e10031e5..0e6424a430043522ed5a3d320a157911a4dbe900 100644 (file)
@@ -1,8 +1,8 @@
-error: an or-pattern parameter must be wrapped in parenthesis
+error: an or-pattern parameter must be wrapped in parentheses
   --> $DIR/fn-param-wrap-parens.rs:14:9
    |
 LL | fn fun1(A | B: E) {}
-   |         ^^^^^ help: wrap the pattern in parenthesis: `(A | B)`
+   |         ^^^^^ help: wrap the pattern in parentheses: `(A | B)`
 
 error: aborting due to previous error
 
index 702c9573741e764f1eb6b488e12355669e66d995..4d06101044f6c1f0ceeb0c84e5818dfdd275e4d1 100644 (file)
@@ -4,41 +4,41 @@ fn main() {
     let x = 3;
 
     match x {
-        1 | 2 || 3 => (), //~ ERROR unexpected token `||` after pattern
+        1 | 2 || 3 => (), //~ ERROR unexpected token `||` in pattern
         _ => (),
     }
 
     match x {
-        (1 | 2 || 3) => (), //~ ERROR unexpected token `||` after pattern
+        (1 | 2 || 3) => (), //~ ERROR unexpected token `||` in pattern
         _ => (),
     }
 
     match (x,) {
-        (1 | 2 || 3,) => (), //~ ERROR unexpected token `||` after pattern
+        (1 | 2 || 3,) => (), //~ ERROR unexpected token `||` in pattern
         _ => (),
     }
 
     struct TS(u8);
 
     match TS(x) {
-        TS(1 | 2 || 3) => (), //~ ERROR unexpected token `||` after pattern
+        TS(1 | 2 || 3) => (), //~ ERROR unexpected token `||` in pattern
         _ => (),
     }
 
     struct NS { f: u8 }
 
     match (NS { f: x }) {
-        NS { f: 1 | 2 || 3 } => (), //~ ERROR unexpected token `||` after pattern
+        NS { f: 1 | 2 || 3 } => (), //~ ERROR unexpected token `||` in pattern
         _ => (),
     }
 
     match [x] {
-        [1 | 2 || 3] => (), //~ ERROR unexpected token `||` after pattern
+        [1 | 2 || 3] => (), //~ ERROR unexpected token `||` in pattern
         _ => (),
     }
 
     match x {
-        || 1 | 2 | 3 => (), //~ ERROR unexpected token `||` after pattern
+        || 1 | 2 | 3 => (), //~ ERROR unexpected token `||` in pattern
         _ => (),
     }
 }
index cb32068ec0d5eb61ac2af8af6d91253877d47c47..b0a82b3673b83f3f329e513518d209d95be6c10d 100644 (file)
@@ -1,4 +1,4 @@
-error: unexpected token `||` after pattern
+error: unexpected token `||` in pattern
   --> $DIR/multiple-pattern-typo.rs:7:15
    |
 LL |         1 | 2 || 3 => (),
@@ -6,7 +6,7 @@ LL |         1 | 2 || 3 => (),
    |         |
    |         while parsing this or-pattern starting here
 
-error: unexpected token `||` after pattern
+error: unexpected token `||` in pattern
   --> $DIR/multiple-pattern-typo.rs:12:16
    |
 LL |         (1 | 2 || 3) => (),
@@ -14,7 +14,7 @@ LL |         (1 | 2 || 3) => (),
    |          |
    |          while parsing this or-pattern starting here
 
-error: unexpected token `||` after pattern
+error: unexpected token `||` in pattern
   --> $DIR/multiple-pattern-typo.rs:17:16
    |
 LL |         (1 | 2 || 3,) => (),
@@ -22,7 +22,7 @@ LL |         (1 | 2 || 3,) => (),
    |          |
    |          while parsing this or-pattern starting here
 
-error: unexpected token `||` after pattern
+error: unexpected token `||` in pattern
   --> $DIR/multiple-pattern-typo.rs:24:18
    |
 LL |         TS(1 | 2 || 3) => (),
@@ -30,7 +30,7 @@ LL |         TS(1 | 2 || 3) => (),
    |            |
    |            while parsing this or-pattern starting here
 
-error: unexpected token `||` after pattern
+error: unexpected token `||` in pattern
   --> $DIR/multiple-pattern-typo.rs:31:23
    |
 LL |         NS { f: 1 | 2 || 3 } => (),
@@ -38,7 +38,7 @@ LL |         NS { f: 1 | 2 || 3 } => (),
    |                 |
    |                 while parsing this or-pattern starting here
 
-error: unexpected token `||` after pattern
+error: unexpected token `||` in pattern
   --> $DIR/multiple-pattern-typo.rs:36:16
    |
 LL |         [1 | 2 || 3] => (),
@@ -46,7 +46,7 @@ LL |         [1 | 2 || 3] => (),
    |          |
    |          while parsing this or-pattern starting here
 
-error: unexpected token `||` after pattern
+error: unexpected token `||` in pattern
   --> $DIR/multiple-pattern-typo.rs:41:9
    |
 LL |         || 1 | 2 | 3 => (),
index efe90b3e3c60c65e93a6a22ff8c8611f6962823a..cbc24eb26fa475a4545f92b1fd7fc752162df9de 100644 (file)
@@ -14,29 +14,8 @@ fn no_top_level_or_patterns() {
     //           -------- This looks like an or-pattern but is in fact `|A| (B: E | ())`.
 
     // ...and for now neither do we allow or-patterns at the top level of functions.
-    fn fun1(A | B: E) {} //~ ERROR an or-pattern parameter must be wrapped in parenthesis
+    fn fun1(A | B: E) {} //~ ERROR an or-pattern parameter must be wrapped in parentheses
 
     fn fun2(| A | B: E) {}
-    //~^ ERROR a leading `|` is not allowed in a parameter pattern
-    //~| ERROR an or-pattern parameter must be wrapped in parenthesis
-}
-
-// We also do not allow a leading `|` when not in a top level position:
-
-fn no_leading_inner() {
-    struct TS(E);
-    struct NS { f: E }
-
-    let ( | A | B) = E::A; //~ ERROR a leading `|` is only allowed in a top-level pattern
-    let ( | A | B,) = (E::B,); //~ ERROR a leading `|` is only allowed in a top-level pattern
-    let [ | A | B ] = [E::A]; //~ ERROR a leading `|` is only allowed in a top-level pattern
-    let TS( | A | B ); //~ ERROR a leading `|` is only allowed in a top-level pattern
-    let NS { f: | A | B }; //~ ERROR a leading `|` is only allowed in a top-level pattern
-
-    let ( || A | B) = E::A; //~ ERROR a leading `|` is only allowed in a top-level pattern
-    let [ || A | B ] = [E::A]; //~ ERROR a leading `|` is only allowed in a top-level pattern
-    let TS( || A | B ); //~ ERROR a leading `|` is only allowed in a top-level pattern
-    let NS { f: || A | B }; //~ ERROR a leading `|` is only allowed in a top-level pattern
-
-    let recovery_witness: String = 0; //~ ERROR mismatched types
+    //~^ ERROR an or-pattern parameter must be wrapped in parentheses
 }
index 989aeb520064568c4951bb7e93221137c29c6d37..db4d827757b036138203b402398f35ab9ba3621d 100644 (file)
@@ -1,82 +1,14 @@
-error: an or-pattern parameter must be wrapped in parenthesis
+error: an or-pattern parameter must be wrapped in parentheses
   --> $DIR/or-patterns-syntactic-fail.rs:17:13
    |
 LL |     fn fun1(A | B: E) {}
-   |             ^^^^^ help: wrap the pattern in parenthesis: `(A | B)`
+   |             ^^^^^ help: wrap the pattern in parentheses: `(A | B)`
 
-error: a leading `|` is not allowed in a parameter pattern
+error: an or-pattern parameter must be wrapped in parentheses
   --> $DIR/or-patterns-syntactic-fail.rs:19:13
    |
 LL |     fn fun2(| A | B: E) {}
-   |             ^ help: remove the `|`
-
-error: an or-pattern parameter must be wrapped in parenthesis
-  --> $DIR/or-patterns-syntactic-fail.rs:19:15
-   |
-LL |     fn fun2(| A | B: E) {}
-   |               ^^^^^ help: wrap the pattern in parenthesis: `(A | B)`
-
-error: a leading `|` is only allowed in a top-level pattern
-  --> $DIR/or-patterns-syntactic-fail.rs:30:11
-   |
-LL |     let ( | A | B) = E::A;
-   |           ^ help: remove the `|`
-
-error: a leading `|` is only allowed in a top-level pattern
-  --> $DIR/or-patterns-syntactic-fail.rs:31:11
-   |
-LL |     let ( | A | B,) = (E::B,);
-   |           ^ help: remove the `|`
-
-error: a leading `|` is only allowed in a top-level pattern
-  --> $DIR/or-patterns-syntactic-fail.rs:32:11
-   |
-LL |     let [ | A | B ] = [E::A];
-   |           ^ help: remove the `|`
-
-error: a leading `|` is only allowed in a top-level pattern
-  --> $DIR/or-patterns-syntactic-fail.rs:33:13
-   |
-LL |     let TS( | A | B );
-   |             ^ help: remove the `|`
-
-error: a leading `|` is only allowed in a top-level pattern
-  --> $DIR/or-patterns-syntactic-fail.rs:34:17
-   |
-LL |     let NS { f: | A | B };
-   |                 ^ help: remove the `|`
-
-error: a leading `|` is only allowed in a top-level pattern
-  --> $DIR/or-patterns-syntactic-fail.rs:36:11
-   |
-LL |     let ( || A | B) = E::A;
-   |           ^^ help: remove the `||`
-   |
-   = note: alternatives in or-patterns are separated with `|`, not `||`
-
-error: a leading `|` is only allowed in a top-level pattern
-  --> $DIR/or-patterns-syntactic-fail.rs:37:11
-   |
-LL |     let [ || A | B ] = [E::A];
-   |           ^^ help: remove the `||`
-   |
-   = note: alternatives in or-patterns are separated with `|`, not `||`
-
-error: a leading `|` is only allowed in a top-level pattern
-  --> $DIR/or-patterns-syntactic-fail.rs:38:13
-   |
-LL |     let TS( || A | B );
-   |             ^^ help: remove the `||`
-   |
-   = note: alternatives in or-patterns are separated with `|`, not `||`
-
-error: a leading `|` is only allowed in a top-level pattern
-  --> $DIR/or-patterns-syntactic-fail.rs:39:17
-   |
-LL |     let NS { f: || A | B };
-   |                 ^^ help: remove the `||`
-   |
-   = note: alternatives in or-patterns are separated with `|`, not `||`
+   |             ^^^^^^^ help: wrap the pattern in parentheses: `(A | B)`
 
 error[E0369]: no implementation for `E | ()`
   --> $DIR/or-patterns-syntactic-fail.rs:13:22
@@ -88,17 +20,6 @@ LL |     let _ = |A | B: E| ();
    |
    = note: an implementation of `std::ops::BitOr` might be missing for `E`
 
-error[E0308]: mismatched types
-  --> $DIR/or-patterns-syntactic-fail.rs:41:36
-   |
-LL |     let recovery_witness: String = 0;
-   |                           ------   ^
-   |                           |        |
-   |                           |        expected struct `String`, found integer
-   |                           |        help: try using a conversion method: `0.to_string()`
-   |                           expected due to this
-
-error: aborting due to 14 previous errors
+error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0308, E0369.
-For more information about an error, try `rustc --explain E0308`.
+For more information about this error, try `rustc --explain E0369`.
index 443ef398293d9900a507149595d21e32d334508d..c8fac4faa2a660b525712e112fa048b9c9a8d563 100644 (file)
@@ -9,17 +9,17 @@ fn main() {}
 
 #[cfg(FALSE)]
 fn leading() {
-    fn fun1(  A: E) {} //~ ERROR a leading `|` is not allowed in a parameter pattern
-    fn fun2(  A: E) {} //~ ERROR a leading `|` is not allowed in a parameter pattern
-    let (  A): E; //~ ERROR a leading `|` is only allowed in a top-level pattern
-    let (  A): (E); //~ ERROR a leading `|` is only allowed in a top-level pattern
-    let (  A,): (E,); //~ ERROR a leading `|` is only allowed in a top-level pattern
-    let [  A ]: [E; 1]; //~ ERROR a leading `|` is only allowed in a top-level pattern
-    let [  A ]: [E; 1]; //~ ERROR a leading `|` is only allowed in a top-level pattern
-    let TS(  A ): TS; //~ ERROR a leading `|` is only allowed in a top-level pattern
-    let TS(  A ): TS; //~ ERROR a leading `|` is only allowed in a top-level pattern
-    let NS { f:  A }: NS; //~ ERROR a leading `|` is only allowed in a top-level pattern
-    let NS { f:  A }: NS; //~ ERROR a leading `|` is only allowed in a top-level pattern
+    fn fun1( A: E) {} //~ ERROR an or-pattern parameter must be wrapped in parentheses
+    fn fun2(  A: E) {} //~ ERROR unexpected `||` before function parameter
+    let ( | A): E;
+    let ( | A): (E); //~ ERROR unexpected token `||` in pattern
+    let ( | A,): (E,);
+    let [ | A ]: [E; 1];
+    let [ | A ]: [E; 1]; //~ ERROR unexpected token `||` in pattern
+    let TS( | A ): TS;
+    let TS( | A ): TS; //~ ERROR unexpected token `||` in pattern
+    let NS { f: | A }: NS;
+    let NS { f: | A }: NS; //~ ERROR unexpected token `||` in pattern
 }
 
 #[cfg(FALSE)]
@@ -29,12 +29,12 @@ fn trailing() {
     let ( A | B  ): E; //~ ERROR a trailing `|` is not allowed in an or-pattern
     let [ A | B  ]: [E; 1]; //~ ERROR a trailing `|` is not allowed in an or-pattern
     let S { f: B  }; //~ ERROR a trailing `|` is not allowed in an or-pattern
-    let ( A | B  ): E; //~ ERROR unexpected token `||` after pattern
+    let ( A | B  ): E; //~ ERROR unexpected token `||` in pattern
     //~^ ERROR a trailing `|` is not allowed in an or-pattern
     match A {
         A  => {} //~ ERROR a trailing `|` is not allowed in an or-pattern
         A  => {} //~ ERROR a trailing `|` is not allowed in an or-pattern
-        A | B  => {} //~ ERROR unexpected token `||` after pattern
+        A | B  => {} //~ ERROR unexpected token `||` in pattern
         //~^ ERROR a trailing `|` is not allowed in an or-pattern
         | A | B  => {}
         //~^ ERROR a trailing `|` is not allowed in an or-pattern
index 3c427a6f7b23ef9ed7656617e1968d26c70865b1..2cf6b27ab1aacd75ec75dca24d6dc81cae21ed96 100644 (file)
@@ -9,17 +9,17 @@ fn main() {}
 
 #[cfg(FALSE)]
 fn leading() {
-    fn fun1( | A: E) {} //~ ERROR a leading `|` is not allowed in a parameter pattern
-    fn fun2( || A: E) {} //~ ERROR a leading `|` is not allowed in a parameter pattern
-    let ( | A): E; //~ ERROR a leading `|` is only allowed in a top-level pattern
-    let ( || A): (E); //~ ERROR a leading `|` is only allowed in a top-level pattern
-    let ( | A,): (E,); //~ ERROR a leading `|` is only allowed in a top-level pattern
-    let [ | A ]: [E; 1]; //~ ERROR a leading `|` is only allowed in a top-level pattern
-    let [ || A ]: [E; 1]; //~ ERROR a leading `|` is only allowed in a top-level pattern
-    let TS( | A ): TS; //~ ERROR a leading `|` is only allowed in a top-level pattern
-    let TS( || A ): TS; //~ ERROR a leading `|` is only allowed in a top-level pattern
-    let NS { f: | A }: NS; //~ ERROR a leading `|` is only allowed in a top-level pattern
-    let NS { f: || A }: NS; //~ ERROR a leading `|` is only allowed in a top-level pattern
+    fn fun1( | A: E) {} //~ ERROR an or-pattern parameter must be wrapped in parentheses
+    fn fun2( || A: E) {} //~ ERROR unexpected `||` before function parameter
+    let ( | A): E;
+    let ( || A): (E); //~ ERROR unexpected token `||` in pattern
+    let ( | A,): (E,);
+    let [ | A ]: [E; 1];
+    let [ || A ]: [E; 1]; //~ ERROR unexpected token `||` in pattern
+    let TS( | A ): TS;
+    let TS( || A ): TS; //~ ERROR unexpected token `||` in pattern
+    let NS { f: | A }: NS;
+    let NS { f: || A }: NS; //~ ERROR unexpected token `||` in pattern
 }
 
 #[cfg(FALSE)]
@@ -29,12 +29,12 @@ fn trailing() {
     let ( A | B | ): E; //~ ERROR a trailing `|` is not allowed in an or-pattern
     let [ A | B | ]: [E; 1]; //~ ERROR a trailing `|` is not allowed in an or-pattern
     let S { f: B | }; //~ ERROR a trailing `|` is not allowed in an or-pattern
-    let ( A || B | ): E; //~ ERROR unexpected token `||` after pattern
+    let ( A || B | ): E; //~ ERROR unexpected token `||` in pattern
     //~^ ERROR a trailing `|` is not allowed in an or-pattern
     match A {
         A | => {} //~ ERROR a trailing `|` is not allowed in an or-pattern
         A || => {} //~ ERROR a trailing `|` is not allowed in an or-pattern
-        A || B | => {} //~ ERROR unexpected token `||` after pattern
+        A || B | => {} //~ ERROR unexpected token `||` in pattern
         //~^ ERROR a trailing `|` is not allowed in an or-pattern
         | A | B | => {}
         //~^ ERROR a trailing `|` is not allowed in an or-pattern
index 53025230a63c221d99b7db8b9b874be63cb55a3d..5c9efd44a187f6513bf3795a405f17e96b90045f 100644 (file)
@@ -1,10 +1,10 @@
-error: a leading `|` is not allowed in a parameter pattern
+error: an or-pattern parameter must be wrapped in parentheses
   --> $DIR/remove-leading-vert.rs:12:14
    |
 LL |     fn fun1( | A: E) {}
-   |              ^ help: remove the `|`
+   |              ^^^ help: remove the leading `|`: `A`
 
-error: a leading `|` is not allowed in a parameter pattern
+error: unexpected `||` before function parameter
   --> $DIR/remove-leading-vert.rs:13:14
    |
 LL |     fn fun2( || A: E) {}
@@ -12,67 +12,29 @@ LL |     fn fun2( || A: E) {}
    |
    = note: alternatives in or-patterns are separated with `|`, not `||`
 
-error: a leading `|` is only allowed in a top-level pattern
-  --> $DIR/remove-leading-vert.rs:14:11
-   |
-LL |     let ( | A): E;
-   |           ^ help: remove the `|`
-
-error: a leading `|` is only allowed in a top-level pattern
+error: unexpected token `||` in pattern
   --> $DIR/remove-leading-vert.rs:15:11
    |
 LL |     let ( || A): (E);
-   |           ^^ help: remove the `||`
-   |
-   = note: alternatives in or-patterns are separated with `|`, not `||`
-
-error: a leading `|` is only allowed in a top-level pattern
-  --> $DIR/remove-leading-vert.rs:16:11
-   |
-LL |     let ( | A,): (E,);
-   |           ^ help: remove the `|`
+   |           ^^ help: use a single `|` to separate multiple alternative patterns: `|`
 
-error: a leading `|` is only allowed in a top-level pattern
-  --> $DIR/remove-leading-vert.rs:17:11
-   |
-LL |     let [ | A ]: [E; 1];
-   |           ^ help: remove the `|`
-
-error: a leading `|` is only allowed in a top-level pattern
+error: unexpected token `||` in pattern
   --> $DIR/remove-leading-vert.rs:18:11
    |
 LL |     let [ || A ]: [E; 1];
-   |           ^^ help: remove the `||`
-   |
-   = note: alternatives in or-patterns are separated with `|`, not `||`
-
-error: a leading `|` is only allowed in a top-level pattern
-  --> $DIR/remove-leading-vert.rs:19:13
-   |
-LL |     let TS( | A ): TS;
-   |             ^ help: remove the `|`
+   |           ^^ help: use a single `|` to separate multiple alternative patterns: `|`
 
-error: a leading `|` is only allowed in a top-level pattern
+error: unexpected token `||` in pattern
   --> $DIR/remove-leading-vert.rs:20:13
    |
 LL |     let TS( || A ): TS;
-   |             ^^ help: remove the `||`
-   |
-   = note: alternatives in or-patterns are separated with `|`, not `||`
-
-error: a leading `|` is only allowed in a top-level pattern
-  --> $DIR/remove-leading-vert.rs:21:17
-   |
-LL |     let NS { f: | A }: NS;
-   |                 ^ help: remove the `|`
+   |             ^^ help: use a single `|` to separate multiple alternative patterns: `|`
 
-error: a leading `|` is only allowed in a top-level pattern
+error: unexpected token `||` in pattern
   --> $DIR/remove-leading-vert.rs:22:17
    |
 LL |     let NS { f: || A }: NS;
-   |                 ^^ help: remove the `||`
-   |
-   = note: alternatives in or-patterns are separated with `|`, not `||`
+   |                 ^^ help: use a single `|` to separate multiple alternative patterns: `|`
 
 error: a trailing `|` is not allowed in an or-pattern
   --> $DIR/remove-leading-vert.rs:27:13
@@ -114,7 +76,7 @@ LL |     let S { f: B | };
    |                |
    |                while parsing this or-pattern starting here
 
-error: unexpected token `||` after pattern
+error: unexpected token `||` in pattern
   --> $DIR/remove-leading-vert.rs:32:13
    |
 LL |     let ( A || B | ): E;
@@ -148,7 +110,7 @@ LL |         A || => {}
    |
    = note: alternatives in or-patterns are separated with `|`, not `||`
 
-error: unexpected token `||` after pattern
+error: unexpected token `||` in pattern
   --> $DIR/remove-leading-vert.rs:37:11
    |
 LL |         A || B | => {}
@@ -168,9 +130,9 @@ error: a trailing `|` is not allowed in an or-pattern
   --> $DIR/remove-leading-vert.rs:39:17
    |
 LL |         | A | B | => {}
-   |           -     ^ help: remove the `|`
-   |           |
-   |           while parsing this or-pattern starting here
+   |         -       ^ help: remove the `|`
+   |         |
+   |         while parsing this or-pattern starting here
 
 error: a trailing `|` is not allowed in an or-pattern
   --> $DIR/remove-leading-vert.rs:43:11
@@ -196,5 +158,5 @@ LL |     let a | ;
    |         |
    |         while parsing this or-pattern starting here
 
-error: aborting due to 26 previous errors
+error: aborting due to 21 previous errors
 
diff --git a/src/test/ui/parser/dotdotdot-expr.rs b/src/test/ui/parser/dotdotdot-expr.rs
new file mode 100644 (file)
index 0000000..d842fb6
--- /dev/null
@@ -0,0 +1,4 @@
+fn main() {
+    let _redemptive = 1...21;
+    //~^ ERROR unexpected token
+}
diff --git a/src/test/ui/parser/dotdotdot-expr.stderr b/src/test/ui/parser/dotdotdot-expr.stderr
new file mode 100644 (file)
index 0000000..ec1335c
--- /dev/null
@@ -0,0 +1,17 @@
+error: unexpected token: `...`
+  --> $DIR/dotdotdot-expr.rs:2:24
+   |
+LL |     let _redemptive = 1...21;
+   |                        ^^^
+   |
+help: use `..` for an exclusive range
+   |
+LL |     let _redemptive = 1..21;
+   |                        ^^
+help: or `..=` for an inclusive range
+   |
+LL |     let _redemptive = 1..=21;
+   |                        ^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/parser/issue-20616-3.rs b/src/test/ui/parser/issue-20616-3.rs
new file mode 100644 (file)
index 0000000..b237105
--- /dev/null
@@ -0,0 +1,35 @@
+// We need all these 9 issue-20616-N.rs files
+// because we can only catch one parsing error at a time
+
+type Type_1_<'a, T> = &'a T;
+
+
+//type Type_1<'a T> = &'a T; // error: expected `,` or `>` after lifetime name, found `T`
+
+
+//type Type_2 = Type_1_<'static ()>; // error: expected `,` or `>` after lifetime name, found `(`
+
+
+type Type_3<T> = Box<T,,>;
+//~^ error: expected one of `>`, a const expression, lifetime, or type, found `,`
+
+
+//type Type_4<T> = Type_1_<'static,, T>; // error: expected type, found `,`
+
+
+type Type_5_<'a> = Type_1_<'a, ()>;
+
+
+//type Type_5<'a> = Type_1_<'a, (),,>; // error: expected type, found `,`
+
+
+//type Type_6 = Type_5_<'a,,>; // error: expected type, found `,`
+
+
+//type Type_7 = Box<(),,>; // error: expected type, found `,`
+
+
+//type Type_8<'a,,> = &'a (); // error: expected ident, found `,`
+
+
+//type Type_9<T,,> = Box<T>; // error: expected ident, found `,`
diff --git a/src/test/ui/parser/issue-20616-3.stderr b/src/test/ui/parser/issue-20616-3.stderr
new file mode 100644 (file)
index 0000000..b535c7a
--- /dev/null
@@ -0,0 +1,8 @@
+error: expected one of `>`, a const expression, lifetime, or type, found `,`
+  --> $DIR/issue-20616-3.rs:13:24
+   |
+LL | type Type_3<T> = Box<T,,>;
+   |                        ^ expected one of `>`, a const expression, lifetime, or type
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/parser/issue-44406.rs b/src/test/ui/parser/issue-44406.rs
new file mode 100644 (file)
index 0000000..83bbf88
--- /dev/null
@@ -0,0 +1,10 @@
+macro_rules! foo {
+    ($rest: tt) => {
+        bar(baz: $rest)
+    }
+}
+
+fn main() {
+    foo!(true); //~ ERROR expected type, found keyword
+    //~^ ERROR expected identifier, found keyword
+}
diff --git a/src/test/ui/parser/issue-44406.stderr b/src/test/ui/parser/issue-44406.stderr
new file mode 100644 (file)
index 0000000..701c32d
--- /dev/null
@@ -0,0 +1,25 @@
+error: expected identifier, found keyword `true`
+  --> $DIR/issue-44406.rs:8:10
+   |
+LL |     foo!(true);
+   |          ^^^^ expected identifier, found keyword
+   |
+help: you can escape reserved keywords to use them as identifiers
+   |
+LL |     foo!(r#true);
+   |          ^^^^^^
+
+error: expected type, found keyword `true`
+  --> $DIR/issue-44406.rs:8:10
+   |
+LL |         bar(baz: $rest)
+   |                - help: try using a semicolon: `;`
+...
+LL |     foo!(true);
+   |          ^^^^ expected type
+   |
+   = note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `<expr>: <type>`
+   = note: see issue #23416 <https://github.com/rust-lang/rust/issues/23416> for more information
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/parser/old-suffixes-are-really-forbidden.rs b/src/test/ui/parser/old-suffixes-are-really-forbidden.rs
new file mode 100644 (file)
index 0000000..eea95b7
--- /dev/null
@@ -0,0 +1,4 @@
+fn main() {
+    let a = 1_is; //~ ERROR invalid suffix
+    let b = 2_us; //~ ERROR invalid suffix
+}
diff --git a/src/test/ui/parser/old-suffixes-are-really-forbidden.stderr b/src/test/ui/parser/old-suffixes-are-really-forbidden.stderr
new file mode 100644 (file)
index 0000000..fb30979
--- /dev/null
@@ -0,0 +1,18 @@
+error: invalid suffix `is` for number literal
+  --> $DIR/old-suffixes-are-really-forbidden.rs:2:13
+   |
+LL |     let a = 1_is;
+   |             ^^^^ invalid suffix `is`
+   |
+   = help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.)
+
+error: invalid suffix `us` for number literal
+  --> $DIR/old-suffixes-are-really-forbidden.rs:3:13
+   |
+LL |     let b = 2_us;
+   |             ^^^^ invalid suffix `us`
+   |
+   = help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.)
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/parser/struct-literal-variant-in-if.rs b/src/test/ui/parser/struct-literal-variant-in-if.rs
new file mode 100644 (file)
index 0000000..4ef8eff
--- /dev/null
@@ -0,0 +1,25 @@
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+enum E {
+    V { field: bool },
+    I { field1: bool, field2: usize },
+    J { field: isize },
+    K { field: &'static str},
+}
+fn test_E(x: E) {
+    let field = true;
+    if x == E::V { field } {}
+    //~^ ERROR expected value, found struct variant `E::V`
+    //~| ERROR mismatched types
+    if x == E::I { field1: true, field2: 42 } {}
+    //~^ ERROR struct literals are not allowed here
+    if x == E::V { field: false } {}
+    //~^ ERROR struct literals are not allowed here
+    if x == E::J { field: -42 } {}
+    //~^ ERROR struct literals are not allowed here
+    if x == E::K { field: "" } {}
+    //~^ ERROR struct literals are not allowed here
+    let y: usize = ();
+    //~^ ERROR mismatched types
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/struct-literal-variant-in-if.stderr b/src/test/ui/parser/struct-literal-variant-in-if.stderr
new file mode 100644 (file)
index 0000000..a2252d4
--- /dev/null
@@ -0,0 +1,76 @@
+error: struct literals are not allowed here
+  --> $DIR/struct-literal-variant-in-if.rs:13:13
+   |
+LL |     if x == E::I { field1: true, field2: 42 } {}
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: surround the struct literal with parentheses
+   |
+LL |     if x == (E::I { field1: true, field2: 42 }) {}
+   |             ^                                 ^
+
+error: struct literals are not allowed here
+  --> $DIR/struct-literal-variant-in-if.rs:15:13
+   |
+LL |     if x == E::V { field: false } {}
+   |             ^^^^^^^^^^^^^^^^^^^^^
+   |
+help: surround the struct literal with parentheses
+   |
+LL |     if x == (E::V { field: false }) {}
+   |             ^                     ^
+
+error: struct literals are not allowed here
+  --> $DIR/struct-literal-variant-in-if.rs:17:13
+   |
+LL |     if x == E::J { field: -42 } {}
+   |             ^^^^^^^^^^^^^^^^^^^
+   |
+help: surround the struct literal with parentheses
+   |
+LL |     if x == (E::J { field: -42 }) {}
+   |             ^                   ^
+
+error: struct literals are not allowed here
+  --> $DIR/struct-literal-variant-in-if.rs:19:13
+   |
+LL |     if x == E::K { field: "" } {}
+   |             ^^^^^^^^^^^^^^^^^^
+   |
+help: surround the struct literal with parentheses
+   |
+LL |     if x == (E::K { field: "" }) {}
+   |             ^                  ^
+
+error[E0423]: expected value, found struct variant `E::V`
+  --> $DIR/struct-literal-variant-in-if.rs:10:13
+   |
+LL |     if x == E::V { field } {}
+   |             ^^^^ not a value
+   |
+help: surround the struct literal with parentheses
+   |
+LL |     if x == (E::V { field }) {}
+   |             ^              ^
+
+error[E0308]: mismatched types
+  --> $DIR/struct-literal-variant-in-if.rs:10:20
+   |
+LL |     if x == E::V { field } {}
+   |     ---------------^^^^^--- help: consider using a semicolon here
+   |     |              |
+   |     |              expected `()`, found `bool`
+   |     expected this to be `()`
+
+error[E0308]: mismatched types
+  --> $DIR/struct-literal-variant-in-if.rs:21:20
+   |
+LL |     let y: usize = ();
+   |            -----   ^^ expected `usize`, found `()`
+   |            |
+   |            expected due to this
+
+error: aborting due to 7 previous errors
+
+Some errors have detailed explanations: E0308, E0423.
+For more information about an error, try `rustc --explain E0308`.
index 6decbef1af4a266e4e6ae6bfda138aeac61e269d..e14e17c162233ac3008ef32752b00ed9d1395b1a 100644 (file)
@@ -5,6 +5,10 @@ LL |     a == b;
    |       ^^ no implementation for `&T == T`
    |
    = help: the trait `PartialEq<T>` is not implemented for `&T`
+help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
+   |
+LL | fn foo<T: PartialEq>(a: &T, b: T) where &T: PartialEq<T> {
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
index 14040c8ada67d17f54efb881af4e7a1f6e991196..7549eae7016b56844c89fde92fffafb06de1d8a8 100644 (file)
@@ -1,9 +1,17 @@
+#![feature(if_let_guard)]
+#![allow(incomplete_features)]
+
 #![deny(irrefutable_let_patterns)]
 
 fn main() {
-    if let _ = 5 {} //~ ERROR irrefutable if-let pattern
+    if let _ = 5 {} //~ ERROR irrefutable `if let` pattern
 
-    while let _ = 5 { //~ ERROR irrefutable while-let pattern
+    while let _ = 5 { //~ ERROR irrefutable `while let` pattern
         break;
     }
+
+    match 5 {
+        _ if let _ = 2 => {} //~ ERROR irrefutable `if let` guard pattern
+        _ => {}
+    }
 }
index 308a6c7c58e6631f1d9c13017203fdbe735ce741..d6926ee12eeaa6673bbe8aec2e9fd51e5cb43e2d 100644 (file)
@@ -1,22 +1,36 @@
-error: irrefutable if-let pattern
-  --> $DIR/deny-irrefutable-let-patterns.rs:4:5
+error: irrefutable `if let` pattern
+  --> $DIR/deny-irrefutable-let-patterns.rs:7:5
    |
 LL |     if let _ = 5 {}
    |     ^^^^^^^^^^^^^^^
    |
 note: the lint level is defined here
-  --> $DIR/deny-irrefutable-let-patterns.rs:1:9
+  --> $DIR/deny-irrefutable-let-patterns.rs:4:9
    |
 LL | #![deny(irrefutable_let_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: this pattern will always match, so the `if let` is useless
+   = help: consider replacing the `if let` with a `let`
 
-error: irrefutable while-let pattern
-  --> $DIR/deny-irrefutable-let-patterns.rs:6:5
+error: irrefutable `while let` pattern
+  --> $DIR/deny-irrefutable-let-patterns.rs:9:5
    |
 LL | /     while let _ = 5 {
 LL | |         break;
 LL | |     }
    | |_____^
+   |
+   = note: this pattern will always match, so the loop will never exit
+   = help: consider instead using a `loop { ... }` with a `let` inside it
+
+error: irrefutable `if let` guard pattern
+  --> $DIR/deny-irrefutable-let-patterns.rs:14:18
+   |
+LL |         _ if let _ = 2 => {}
+   |                  ^
+   |
+   = note: this pattern will always match, so the guard is useless
+   = help: consider removing the guard and adding a `let` inside the match arm
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/project-defer-unification.rs b/src/test/ui/project-defer-unification.rs
deleted file mode 100644 (file)
index 547ff45..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-// run-pass
-
-#![allow(dead_code)]
-#![allow(unused_variables)]
-#![allow(unreachable_code)]
-// A regression test extracted from image-0.3.11. The point of
-// failure was in `index_colors` below.
-
-use std::ops::{Deref, DerefMut};
-
-#[derive(Copy, Clone)]
-pub struct Luma<T: Primitive> { pub data: [T; 1] }
-
-impl<T: Primitive + 'static> Pixel for Luma<T> {
-    type Subpixel = T;
-}
-
-pub struct ImageBuffer<P: Pixel, Container> {
-    pixels: P,
-    c: Container,
-}
-
-pub trait GenericImage: Sized {
-    type Pixel: Pixel;
-}
-
-pub trait Pixel: Copy + Clone {
-    type Subpixel: Primitive;
-}
-
-pub trait Primitive: Copy + PartialOrd<Self> + Clone  {
-}
-
-impl<P, Container> GenericImage for ImageBuffer<P, Container>
-where P: Pixel + 'static,
-      Container: Deref<Target=[P::Subpixel]> + DerefMut,
-      P::Subpixel: 'static {
-
-    type Pixel = P;
-}
-
-impl Primitive for u8 { }
-
-impl<P, Container> ImageBuffer<P, Container>
-where P: Pixel + 'static,
-      P::Subpixel: 'static,
-      Container: Deref<Target=[P::Subpixel]>
-{
-    pub fn pixels<'a>(&'a self) -> Pixels<'a, Self> {
-        loop { }
-    }
-
-    pub fn pixels_mut(&mut self) -> PixelsMut<P> {
-        loop { }
-    }
-}
-
-pub struct Pixels<'a, I: 'a> {
-    image:  &'a I,
-    x:      u32,
-    y:      u32,
-    width:  u32,
-    height: u32
-}
-
-impl<'a, I: GenericImage> Iterator for Pixels<'a, I> {
-    type Item = (u32, u32, I::Pixel);
-
-    fn next(&mut self) -> Option<(u32, u32, I::Pixel)> {
-        loop { }
-    }
-}
-
-pub struct PixelsMut<'a, P: Pixel + 'a> where P::Subpixel: 'a {
-    chunks: &'a mut P::Subpixel
-}
-
-impl<'a, P: Pixel + 'a> Iterator for PixelsMut<'a, P> where P::Subpixel: 'a {
-    type Item = &'a mut P;
-
-    fn next(&mut self) -> Option<&'a mut P> {
-        loop { }
-    }
-}
-
-pub fn index_colors<Pix>(image: &ImageBuffer<Pix, Vec<u8>>)
-                         -> ImageBuffer<Luma<u8>, Vec<u8>>
-where Pix: Pixel<Subpixel=u8> + 'static,
-{
-    // When NLL-enabled, `let mut` below is deemed unnecessary (due to
-    // the remaining code being unreachable); so ignore that lint.
-    #![allow(unused_mut)]
-
-    let mut indices: ImageBuffer<_,Vec<_>> = loop { };
-    for (pixel, idx) in image.pixels().zip(indices.pixels_mut()) {
-        // failured occurred here ^^ because we were requiring that we
-        // could project Pixel or Subpixel from `T_indices` (type of
-        // `indices`), but the type is insufficiently constrained
-        // until we reach the return below.
-    }
-    indices
-}
-
-fn main() { }
diff --git a/src/test/ui/range_inclusive_gate.rs b/src/test/ui/range_inclusive_gate.rs
deleted file mode 100644 (file)
index e26e31b..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-// run-pass
-
-#![allow(unused_comparisons)]
-// Test that you only need the syntax gate if you don't mention the structs.
-// (Obsoleted since both features are stabilized)
-
-fn main() {
-    let mut count = 0;
-    for i in 0_usize..=10 {
-        assert!(i >= 0 && i <= 10);
-        count += i;
-    }
-    assert_eq!(count, 55);
-}
diff --git a/src/test/ui/regions-fn-subtyping-return-static-fail.nll.stderr b/src/test/ui/regions-fn-subtyping-return-static-fail.nll.stderr
deleted file mode 100644 (file)
index d762f55..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-error: higher-ranked subtype error
-  --> $DIR/regions-fn-subtyping-return-static-fail.rs:48:5
-   |
-LL |     want_G(baz);
-   |     ^^^^^^^^^^^
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/regions-fn-subtyping-return-static-fail.rs b/src/test/ui/regions-fn-subtyping-return-static-fail.rs
deleted file mode 100644 (file)
index 539221b..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-// In this fn, the type `F` is a function that takes a reference to a
-// struct and returns another reference with the same lifetime.
-//
-// Meanwhile, the bare fn `foo` takes a reference to a struct with
-// *ANY* lifetime and returns a reference with the 'static lifetime.
-// This can safely be considered to be an instance of `F` because all
-// lifetimes are sublifetimes of 'static.
-
-#![allow(dead_code)]
-#![allow(unused_variables)]
-
-struct S;
-
-// Given 'cx, return 'cx
-type F = for<'cx> fn(&'cx S) -> &'cx S;
-fn want_F(f: F) {}
-
-// Given anything, return 'static
-type G = for<'cx> fn(&'cx S) -> &'static S;
-fn want_G(f: G) {}
-
-// Should meet both.
-fn foo(x: &S) -> &'static S {
-    panic!()
-}
-
-// Should meet both.
-fn bar<'a, 'b>(x: &'a S) -> &'b S {
-    panic!()
-}
-
-// Meets F, but not G.
-fn baz(x: &S) -> &S {
-    panic!()
-}
-
-fn supply_F() {
-    want_F(foo);
-
-    want_F(bar);
-
-    want_F(baz);
-}
-
-fn supply_G() {
-    want_G(foo);
-    want_G(bar);
-    want_G(baz); //~ ERROR mismatched types
-}
-
-pub fn main() {}
diff --git a/src/test/ui/regions-fn-subtyping-return-static-fail.stderr b/src/test/ui/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-fn-subtyping-return-static-fail.nll.stderr b/src/test/ui/regions/regions-fn-subtyping-return-static-fail.nll.stderr
new file mode 100644 (file)
index 0000000..d762f55
--- /dev/null
@@ -0,0 +1,8 @@
+error: higher-ranked subtype error
+  --> $DIR/regions-fn-subtyping-return-static-fail.rs:48:5
+   |
+LL |     want_G(baz);
+   |     ^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/regions/regions-fn-subtyping-return-static-fail.rs b/src/test/ui/regions/regions-fn-subtyping-return-static-fail.rs
new file mode 100644 (file)
index 0000000..539221b
--- /dev/null
@@ -0,0 +1,51 @@
+// In this fn, the type `F` is a function that takes a reference to a
+// struct and returns another reference with the same lifetime.
+//
+// Meanwhile, the bare fn `foo` takes a reference to a struct with
+// *ANY* lifetime and returns a reference with the 'static lifetime.
+// This can safely be considered to be an instance of `F` because all
+// lifetimes are sublifetimes of 'static.
+
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+struct S;
+
+// Given 'cx, return 'cx
+type F = for<'cx> fn(&'cx S) -> &'cx S;
+fn want_F(f: F) {}
+
+// Given anything, return 'static
+type G = for<'cx> fn(&'cx S) -> &'static S;
+fn want_G(f: G) {}
+
+// Should meet both.
+fn foo(x: &S) -> &'static S {
+    panic!()
+}
+
+// Should meet both.
+fn bar<'a, 'b>(x: &'a S) -> &'b S {
+    panic!()
+}
+
+// Meets F, but not G.
+fn baz(x: &S) -> &S {
+    panic!()
+}
+
+fn supply_F() {
+    want_F(foo);
+
+    want_F(bar);
+
+    want_F(baz);
+}
+
+fn supply_G() {
+    want_G(foo);
+    want_G(bar);
+    want_G(baz); //~ ERROR mismatched types
+}
+
+pub fn main() {}
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
new file mode 100644 (file)
index 0000000..c9ce936
--- /dev/null
@@ -0,0 +1,12 @@
+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/repeat_count_const_in_async_fn.rs b/src/test/ui/repeat_count_const_in_async_fn.rs
deleted file mode 100644 (file)
index ebabc3f..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-// check-pass
-// edition:2018
-// compile-flags: --crate-type=lib
-
-pub async fn test() {
-    const C: usize = 4;
-    foo(&mut [0u8; C]).await;
-}
-
-async fn foo(_: &mut [u8]) {}
diff --git a/src/test/ui/resolve/issue-82156.rs b/src/test/ui/resolve/issue-82156.rs
new file mode 100644 (file)
index 0000000..6215259
--- /dev/null
@@ -0,0 +1,3 @@
+fn main() {
+    super(); //~ ERROR failed to resolve: there are too many leading `super` keywords
+}
diff --git a/src/test/ui/resolve/issue-82156.stderr b/src/test/ui/resolve/issue-82156.stderr
new file mode 100644 (file)
index 0000000..d53599d
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0433]: failed to resolve: there are too many leading `super` keywords
+  --> $DIR/issue-82156.rs:2:5
+   |
+LL |     super();
+   |     ^^^^^ there are too many leading `super` keywords
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0433`.
index 9691a12f45b05f584228a4c56a775d30736b583a..d921367b91775f3c114471e5e16b170f1025d0f4 100644 (file)
@@ -5,7 +5,7 @@
 fn irrefutable_let_guard() {
     match Some(()) {
         Some(x) if let () = x => {}
-        //~^ ERROR irrefutable if-let guard
+        //~^ ERROR irrefutable `if let` guard
         _ => {}
     }
 }
index 45720f9fbc5515ae9441b62e001f540be1af48c1..c7627f1c3c50c1c6c100d381cbb8a47c656a0926 100644 (file)
@@ -1,4 +1,4 @@
-error: irrefutable if-let guard
+error: irrefutable `if let` guard pattern
   --> $DIR/warns.rs:7:24
    |
 LL |         Some(x) if let () = x => {}
@@ -9,6 +9,8 @@ note: the lint level is defined here
    |
 LL | #[deny(irrefutable_let_patterns)]
    |        ^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: this pattern will always match, so the guard is useless
+   = help: consider removing the guard and adding a `let` inside the match arm
 
 error: unreachable pattern
   --> $DIR/warns.rs:16:25
index aa6b1c0012c933f6be3931067e83f445a7fde682..9ff4813d11286e860c0daf2a9f35dcd2c6c78789 100644 (file)
@@ -22,7 +22,7 @@ fn id<T>(t: T) -> T {
     foo: &Foo { bools: &[false, true] },
     bar: &Bar { bools: &[true, true] },
     f: &id,
-    //~^ ERROR mismatched types
+    //~^ ERROR implementation of `FnOnce` is not general enough
 };
 
 // very simple test for a 'static static with default lifetime
index 2835e47fa4515f73e615a404029026115021240f..e95e68c8e6d26c92669d517b9e78f9d6d95ae2eb 100644 (file)
@@ -1,12 +1,11 @@
-error[E0308]: mismatched types
+error: implementation of `FnOnce` is not general enough
   --> $DIR/rfc1623.rs:24:8
    |
 LL |     f: &id,
-   |        ^^^ one type is more general than the other
+   |        ^^^ implementation of `FnOnce` is not general enough
    |
-   = note: expected type `FnOnce<(&'a Foo<'b>,)>`
-              found type `FnOnce<(&Foo<'_>,)>`
+   = 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: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/rmeta/emit-artifact-notifications.nll.stderr b/src/test/ui/rmeta/emit-artifact-notifications.nll.stderr
new file mode 100644 (file)
index 0000000..ed62f30
--- /dev/null
@@ -0,0 +1 @@
+{"artifact":"$TEST_BUILD_DIR/rmeta/emit-artifact-notifications.nll/libemit_artifact_notifications.rmeta","emit":"metadata"}
diff --git a/src/test/ui/rmeta/emit-artifact-notifications.polonius.stderr b/src/test/ui/rmeta/emit-artifact-notifications.polonius.stderr
new file mode 100644 (file)
index 0000000..255c7b3
--- /dev/null
@@ -0,0 +1 @@
+{"artifact":"$TEST_BUILD_DIR/rmeta/emit-artifact-notifications.polonius/libemit_artifact_notifications.rmeta","emit":"metadata"}
diff --git a/src/test/ui/rmeta/emit-artifact-notifications.rs b/src/test/ui/rmeta/emit-artifact-notifications.rs
new file mode 100644 (file)
index 0000000..984a7fa
--- /dev/null
@@ -0,0 +1,8 @@
+// compile-flags:--emit=metadata --error-format=json --json artifacts
+// build-pass
+// ignore-pass
+// ^-- needed because `--pass check` does not emit the output needed.
+
+// A very basic test for the emission of artifact notifications in JSON output.
+
+fn main() {}
diff --git a/src/test/ui/rmeta/emit-artifact-notifications.stderr b/src/test/ui/rmeta/emit-artifact-notifications.stderr
new file mode 100644 (file)
index 0000000..b2f0aa7
--- /dev/null
@@ -0,0 +1 @@
+{"artifact":"$TEST_BUILD_DIR/rmeta/emit-artifact-notifications/libemit_artifact_notifications.rmeta","emit":"metadata"}
diff --git a/src/test/ui/rmeta/emit-metadata-obj.rs b/src/test/ui/rmeta/emit-metadata-obj.rs
new file mode 100644 (file)
index 0000000..334c7cc
--- /dev/null
@@ -0,0 +1,7 @@
+// compile-flags:--emit=metadata,obj
+// build-pass
+
+// A test for the emission of metadata + obj and other metadata + non-link
+// combinations. See issue #81117.
+
+fn main() {}
diff --git a/src/test/ui/rvalue-static-promotion.rs b/src/test/ui/rvalue-static-promotion.rs
deleted file mode 100644 (file)
index 2d7e4ab..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-// run-pass
-
-use std::cell::Cell;
-
-const NONE_CELL_STRING: Option<Cell<String>> = None;
-
-struct Foo<T>(T);
-impl<T> Foo<T> {
-    const FOO: Option<Box<T>> = None;
-}
-
-fn main() {
-    let _: &'static u32 = &42;
-    let _: &'static Option<u32> = &None;
-
-    // We should be able to peek at consts and see they're None.
-    let _: &'static Option<Cell<String>> = &NONE_CELL_STRING;
-    let _: &'static Option<Box<()>> = &Foo::FOO;
-}
diff --git a/src/test/ui/span/issue-81800.rs b/src/test/ui/span/issue-81800.rs
new file mode 100644 (file)
index 0000000..6ac66fd
--- /dev/null
@@ -0,0 +1,2 @@
+fn x˂- //~ ERROR: unknown start of token
+       //~^ ERROR: expected one of `#`, `>`, `const`, identifier, or lifetime, found `-`
diff --git a/src/test/ui/span/issue-81800.stderr b/src/test/ui/span/issue-81800.stderr
new file mode 100644 (file)
index 0000000..d37f13a
--- /dev/null
@@ -0,0 +1,19 @@
+error: unknown start of token: \u{2c2}
+  --> $DIR/issue-81800.rs:1:5
+   |
+LL | fn x˂-
+   |     ^
+   |
+help: Unicode character '˂' (Modifier Letter Left Arrowhead) looks like '<' (Less-Than Sign), but it is not
+   |
+LL | fn x<-
+   |     ^
+
+error: expected one of `#`, `>`, `const`, identifier, or lifetime, found `-`
+  --> $DIR/issue-81800.rs:1:6
+   |
+LL | fn x˂-
+   |      ^ expected one of `#`, `>`, `const`, identifier, or lifetime
+
+error: aborting due to 2 previous errors
+
index 2bc14dbe3b2e7542394faefebbe46baf19baf8c7..0e8a774bce37fde91014a3f92690b8b41f0a6ad8 100644 (file)
@@ -18,6 +18,10 @@ LL |     default type U = &'static B;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `&'static B == B`
    |
    = help: the trait `PartialEq<B>` is not implemented for `&'static B`
+help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
+   |
+LL | impl<B: 'static, T> X<B> for T where &'static B: PartialEq<B> {
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error; 1 warning emitted
 
index 715eb00974ee27a8102d06f4ac24dba9b87a9a99..03fb80bb90abcf6234c5c3c90fb791aaf78f9c6d 100644 (file)
@@ -116,5 +116,5 @@ LL | #[rustc_deprecated(since = "a", reason = "text")]
 
 error: aborting due to 19 previous errors
 
-Some errors have detailed explanations: E0539, E0541, E0542, E0543, E0546, E0547, E0550.
+Some errors have detailed explanations: E0539, E0541, E0542, E0543, E0546, E0547, E0549, E0550.
 For more information about an error, try `rustc --explain E0539`.
diff --git a/src/test/ui/struct-literal-variant-in-if.rs b/src/test/ui/struct-literal-variant-in-if.rs
deleted file mode 100644 (file)
index 4ef8eff..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
-enum E {
-    V { field: bool },
-    I { field1: bool, field2: usize },
-    J { field: isize },
-    K { field: &'static str},
-}
-fn test_E(x: E) {
-    let field = true;
-    if x == E::V { field } {}
-    //~^ ERROR expected value, found struct variant `E::V`
-    //~| ERROR mismatched types
-    if x == E::I { field1: true, field2: 42 } {}
-    //~^ ERROR struct literals are not allowed here
-    if x == E::V { field: false } {}
-    //~^ ERROR struct literals are not allowed here
-    if x == E::J { field: -42 } {}
-    //~^ ERROR struct literals are not allowed here
-    if x == E::K { field: "" } {}
-    //~^ ERROR struct literals are not allowed here
-    let y: usize = ();
-    //~^ ERROR mismatched types
-}
-
-fn main() {}
diff --git a/src/test/ui/struct-literal-variant-in-if.stderr b/src/test/ui/struct-literal-variant-in-if.stderr
deleted file mode 100644 (file)
index a2252d4..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-error: struct literals are not allowed here
-  --> $DIR/struct-literal-variant-in-if.rs:13:13
-   |
-LL |     if x == E::I { field1: true, field2: 42 } {}
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-help: surround the struct literal with parentheses
-   |
-LL |     if x == (E::I { field1: true, field2: 42 }) {}
-   |             ^                                 ^
-
-error: struct literals are not allowed here
-  --> $DIR/struct-literal-variant-in-if.rs:15:13
-   |
-LL |     if x == E::V { field: false } {}
-   |             ^^^^^^^^^^^^^^^^^^^^^
-   |
-help: surround the struct literal with parentheses
-   |
-LL |     if x == (E::V { field: false }) {}
-   |             ^                     ^
-
-error: struct literals are not allowed here
-  --> $DIR/struct-literal-variant-in-if.rs:17:13
-   |
-LL |     if x == E::J { field: -42 } {}
-   |             ^^^^^^^^^^^^^^^^^^^
-   |
-help: surround the struct literal with parentheses
-   |
-LL |     if x == (E::J { field: -42 }) {}
-   |             ^                   ^
-
-error: struct literals are not allowed here
-  --> $DIR/struct-literal-variant-in-if.rs:19:13
-   |
-LL |     if x == E::K { field: "" } {}
-   |             ^^^^^^^^^^^^^^^^^^
-   |
-help: surround the struct literal with parentheses
-   |
-LL |     if x == (E::K { field: "" }) {}
-   |             ^                  ^
-
-error[E0423]: expected value, found struct variant `E::V`
-  --> $DIR/struct-literal-variant-in-if.rs:10:13
-   |
-LL |     if x == E::V { field } {}
-   |             ^^^^ not a value
-   |
-help: surround the struct literal with parentheses
-   |
-LL |     if x == (E::V { field }) {}
-   |             ^              ^
-
-error[E0308]: mismatched types
-  --> $DIR/struct-literal-variant-in-if.rs:10:20
-   |
-LL |     if x == E::V { field } {}
-   |     ---------------^^^^^--- help: consider using a semicolon here
-   |     |              |
-   |     |              expected `()`, found `bool`
-   |     expected this to be `()`
-
-error[E0308]: mismatched types
-  --> $DIR/struct-literal-variant-in-if.rs:21:20
-   |
-LL |     let y: usize = ();
-   |            -----   ^^ expected `usize`, found `()`
-   |            |
-   |            expected due to this
-
-error: aborting due to 7 previous errors
-
-Some errors have detailed explanations: E0308, E0423.
-For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/structs-enums/type-sizes.rs b/src/test/ui/structs-enums/type-sizes.rs
new file mode 100644 (file)
index 0000000..73a11a5
--- /dev/null
@@ -0,0 +1,173 @@
+// run-pass
+
+#![allow(non_camel_case_types)]
+#![allow(dead_code)]
+#![feature(never_type)]
+
+use std::mem::size_of;
+use std::num::NonZeroU8;
+
+struct t {a: u8, b: i8}
+struct u {a: u8, b: i8, c: u8}
+struct v {a: u8, b: i8, c: v2, d: u32}
+struct v2 {u: char, v: u8}
+struct w {a: isize, b: ()}
+struct x {a: isize, b: (), c: ()}
+struct y {x: isize}
+
+enum e1 {
+    a(u8, u32), b(u32), c
+}
+enum e2 {
+    a(u32), b
+}
+
+#[repr(C, u8)]
+enum e3 {
+    a([u16; 0], u8), b
+}
+
+struct ReorderedStruct {
+    a: u8,
+    b: u16,
+    c: u8
+}
+
+enum ReorderedEnum {
+    A(u8, u16, u8),
+    B(u8, u16, u8),
+}
+
+enum ReorderedEnum2 {
+    A(u8, u32, u8),
+    B(u16, u8, u16, u8),
+
+    // 0x100 niche variants.
+    _00, _01, _02, _03, _04, _05, _06, _07, _08, _09, _0A, _0B, _0C, _0D, _0E, _0F,
+    _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _1A, _1B, _1C, _1D, _1E, _1F,
+    _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _2A, _2B, _2C, _2D, _2E, _2F,
+    _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _3A, _3B, _3C, _3D, _3E, _3F,
+    _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _4A, _4B, _4C, _4D, _4E, _4F,
+    _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _5A, _5B, _5C, _5D, _5E, _5F,
+    _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _6A, _6B, _6C, _6D, _6E, _6F,
+    _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _7A, _7B, _7C, _7D, _7E, _7F,
+    _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _8A, _8B, _8C, _8D, _8E, _8F,
+    _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _9A, _9B, _9C, _9D, _9E, _9F,
+    _A0, _A1, _A2, _A3, _A4, _A5, _A6, _A7, _A8, _A9, _AA, _AB, _AC, _AD, _AE, _AF,
+    _B0, _B1, _B2, _B3, _B4, _B5, _B6, _B7, _B8, _B9, _BA, _BB, _BC, _BD, _BE, _BF,
+    _C0, _C1, _C2, _C3, _C4, _C5, _C6, _C7, _C8, _C9, _CA, _CB, _CC, _CD, _CE, _CF,
+    _D0, _D1, _D2, _D3, _D4, _D5, _D6, _D7, _D8, _D9, _DA, _DB, _DC, _DD, _DE, _DF,
+    _E0, _E1, _E2, _E3, _E4, _E5, _E6, _E7, _E8, _E9, _EA, _EB, _EC, _ED, _EE, _EF,
+    _F0, _F1, _F2, _F3, _F4, _F5, _F6, _F7, _F8, _F9, _FA, _FB, _FC, _FD, _FE, _FF,
+}
+
+enum EnumEmpty {}
+
+enum EnumSingle1 {
+    A,
+}
+
+enum EnumSingle2 {
+    A = 42 as isize,
+}
+
+enum EnumSingle3 {
+    A,
+    B(!),
+}
+
+#[repr(u8)]
+enum EnumSingle4 {
+    A,
+}
+
+#[repr(u8)]
+enum EnumSingle5 {
+    A = 42 as u8,
+}
+
+enum EnumWithMaybeUninhabitedVariant<T> {
+    A(&'static ()),
+    B(&'static (), T),
+    C,
+}
+
+enum NicheFilledEnumWithAbsentVariant {
+    A(&'static ()),
+    B((), !),
+    C,
+}
+
+enum Option2<A, B> {
+    Some(A, B),
+    None
+}
+
+// Two layouts are considered for `CanBeNicheFilledButShouldnt`:
+//   Niche-filling:
+//     { u32 (4 bytes), NonZeroU8 + tag in niche (1 byte), padding (3 bytes) }
+//   Tagged:
+//     { tag (1 byte), NonZeroU8 (1 byte), padding (2 bytes), u32 (4 bytes) }
+// Both are the same size (due to padding),
+// but the tagged layout is better as the tag creates a niche with 254 invalid values,
+// allowing types like `Option<Option<CanBeNicheFilledButShouldnt>>` to fit into 8 bytes.
+pub enum CanBeNicheFilledButShouldnt {
+    A(NonZeroU8, u32),
+    B
+}
+pub enum AlwaysTaggedBecauseItHasNoNiche {
+    A(u8, u32),
+    B
+}
+
+pub fn main() {
+    assert_eq!(size_of::<u8>(), 1 as usize);
+    assert_eq!(size_of::<u32>(), 4 as usize);
+    assert_eq!(size_of::<char>(), 4 as usize);
+    assert_eq!(size_of::<i8>(), 1 as usize);
+    assert_eq!(size_of::<i32>(), 4 as usize);
+    assert_eq!(size_of::<t>(), 2 as usize);
+    assert_eq!(size_of::<u>(), 3 as usize);
+    // Alignment causes padding before the char and the u32.
+
+    assert_eq!(size_of::<v>(),
+                16 as usize);
+    assert_eq!(size_of::<isize>(), size_of::<usize>());
+    assert_eq!(size_of::<w>(), size_of::<isize>());
+    assert_eq!(size_of::<x>(), size_of::<isize>());
+    assert_eq!(size_of::<isize>(), size_of::<y>());
+
+    // Make sure enum types are the appropriate size, mostly
+    // around ensuring alignment is handled properly
+
+    assert_eq!(size_of::<e1>(), 8 as usize);
+    assert_eq!(size_of::<e2>(), 8 as usize);
+    assert_eq!(size_of::<e3>(), 4 as usize);
+    assert_eq!(size_of::<ReorderedStruct>(), 4);
+    assert_eq!(size_of::<ReorderedEnum>(), 6);
+    assert_eq!(size_of::<ReorderedEnum2>(), 8);
+
+
+    assert_eq!(size_of::<EnumEmpty>(), 0);
+    assert_eq!(size_of::<EnumSingle1>(), 0);
+    assert_eq!(size_of::<EnumSingle2>(), 0);
+    assert_eq!(size_of::<EnumSingle3>(), 0);
+    assert_eq!(size_of::<EnumSingle4>(), 1);
+    assert_eq!(size_of::<EnumSingle5>(), 1);
+
+    assert_eq!(size_of::<EnumWithMaybeUninhabitedVariant<!>>(),
+               size_of::<EnumWithMaybeUninhabitedVariant<()>>());
+    assert_eq!(size_of::<NicheFilledEnumWithAbsentVariant>(), size_of::<&'static ()>());
+
+    assert_eq!(size_of::<Option<Option<(bool, &())>>>(), size_of::<(bool, &())>());
+    assert_eq!(size_of::<Option<Option<(&(), bool)>>>(), size_of::<(bool, &())>());
+    assert_eq!(size_of::<Option<Option2<bool, &()>>>(), size_of::<(bool, &())>());
+    assert_eq!(size_of::<Option<Option2<&(), bool>>>(), size_of::<(bool, &())>());
+
+    assert_eq!(size_of::<CanBeNicheFilledButShouldnt>(), 8);
+    assert_eq!(size_of::<Option<CanBeNicheFilledButShouldnt>>(), 8);
+    assert_eq!(size_of::<Option<Option<CanBeNicheFilledButShouldnt>>>(), 8);
+    assert_eq!(size_of::<AlwaysTaggedBecauseItHasNoNiche>(), 8);
+    assert_eq!(size_of::<Option<AlwaysTaggedBecauseItHasNoNiche>>(), 8);
+    assert_eq!(size_of::<Option<Option<AlwaysTaggedBecauseItHasNoNiche>>>(), 8);
+}
diff --git a/src/test/ui/suggestions/auxiliary/issue-81839.rs b/src/test/ui/suggestions/auxiliary/issue-81839.rs
new file mode 100644 (file)
index 0000000..5683c45
--- /dev/null
@@ -0,0 +1,9 @@
+// edition:2018
+
+pub struct Test {}
+
+impl Test {
+    pub async fn answer_str(&self, _s: &str) -> Test {
+        Test {}
+    }
+}
diff --git a/src/test/ui/suggestions/issue-81839.rs b/src/test/ui/suggestions/issue-81839.rs
new file mode 100644 (file)
index 0000000..0b9b7ae
--- /dev/null
@@ -0,0 +1,17 @@
+// aux-build:issue-81839.rs
+// edition:2018
+
+extern crate issue_81839;
+
+async fn test(ans: &str, num: i32, cx: &issue_81839::Test) -> u32 {
+    match num {
+        1 => {
+            cx.answer_str("hi");
+        }
+        _ => cx.answer_str("hi"), //~ `match` arms have incompatible types
+    }
+
+    1
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/issue-81839.stderr b/src/test/ui/suggestions/issue-81839.stderr
new file mode 100644 (file)
index 0000000..1a289d3
--- /dev/null
@@ -0,0 +1,27 @@
+error[E0308]: `match` arms have incompatible types
+  --> $DIR/issue-81839.rs:11:14
+   |
+LL | /     match num {
+LL | |         1 => {
+LL | |             cx.answer_str("hi");
+   | |             --------------------
+   | |             |                  |
+   | |             |                  help: consider removing this semicolon
+   | |             this is found to be of type `()`
+LL | |         }
+LL | |         _ => cx.answer_str("hi"),
+   | |              ^^^^^^^^^^^^^^^^^^^ expected `()`, found opaque type
+LL | |     }
+   | |_____- `match` arms have incompatible types
+   | 
+  ::: $DIR/auxiliary/issue-81839.rs:6:49
+   |
+LL |       pub async fn answer_str(&self, _s: &str) -> Test {
+   |                                                   ---- the `Output` of this `async fn`'s found opaque type
+   |
+   = note:     expected type `()`
+           found opaque type `impl Future`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
index e9803a78f94b3c3571813648083bc03542b7d64e..fae0c498b440a0e57d3a7621dac8f7d5194447b5 100644 (file)
@@ -24,13 +24,10 @@ help: consider `await`ing on the `Future`
    |
 LL |         false => async_dummy().await,
    |                               ^^^^^^
-help: consider removing this semicolon and boxing the expressions
-   |
-LL |             Box::new(async_dummy())
-LL |
-LL |         }
-LL |         false => Box::new(async_dummy()),
+help: consider removing this semicolon
    |
+LL |             async_dummy()
+   |                         --
 
 error[E0308]: `match` arms have incompatible types
   --> $DIR/match-prev-arm-needing-semi.rs:39:18
index 8b465aae66b6e6ae771cdfa9aca07c6ec5852f04..a2bc6fd09b5663e5a8866822383338a40e9b02d0 100644 (file)
@@ -2,7 +2,7 @@
 
 use std::io::{BufRead, BufReader, Read, Write};
 
-fn issue_81421<T: Read + Write>(mut stream: T) {
+fn issue_81421<T: Read + Write>(mut stream: T) { //~ HELP consider introducing a `where` bound
     let initial_message = format!("Hello world");
     let mut buffer: Vec<u8> = Vec::new();
     let bytes_written = stream.write_all(initial_message.as_bytes());
index cb156f7c7877a0cf2c24f3172d5047fa6cb0e8ca..9b8181647a0c15790715e665241946d0e47f7b5a 100644 (file)
@@ -9,6 +9,10 @@ help: consider removing the leading `&`-reference
    |
 LL |         let mut stream_reader = BufReader::new(stream);
    |                                               --
+help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
+   |
+LL | fn issue_81421<T: Read + Write>(mut stream: T) where &T: std::io::Read {
+   |                                                ^^^^^^^^^^^^^^^^^^^^^^^
 help: consider changing this borrow's mutability
    |
 LL |         let mut stream_reader = BufReader::new(&mut stream);
index b50017afa4d63dd20465386cb4e5b5dee0ee9f53..86d589ffa9e31f726d99384540d1b0770e5357ba 100644 (file)
@@ -35,6 +35,10 @@ LL |     <u64 as From<T>>::from;
    |     ^^^^^^^^^^^^^^^^^^^^^^ the trait `From<T>` is not implemented for `u64`
    |
    = note: required by `from`
+help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
+   |
+LL | fn check<T: Iterator, U: ?Sized>() where u64: From<T> {
+   |                                    ^^^^^^^^^^^^^^^^^^
 
 error[E0277]: the trait bound `u64: From<<T as Iterator>::Item>` is not satisfied
   --> $DIR/suggest-where-clause.rs:18:5
@@ -43,6 +47,10 @@ LL |     <u64 as From<<T as Iterator>::Item>>::from;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `From<<T as Iterator>::Item>` is not implemented for `u64`
    |
    = note: required by `from`
+help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
+   |
+LL | fn check<T: Iterator, U: ?Sized>() where u64: From<<T as Iterator>::Item> {
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0277]: the trait bound `Misc<_>: From<T>` is not satisfied
   --> $DIR/suggest-where-clause.rs:23:5
diff --git a/src/test/ui/tuple/one-tuple.rs b/src/test/ui/tuple/one-tuple.rs
new file mode 100644 (file)
index 0000000..00fbadc
--- /dev/null
@@ -0,0 +1,15 @@
+// run-pass
+// Why one-tuples? Because macros.
+
+
+pub fn main() {
+    match ('c',) {
+        (x,) => {
+            assert_eq!(x, 'c');
+        }
+    }
+    // test the 1-tuple type too
+    let x: (char,) = ('d',);
+    let (y,) = x;
+    assert_eq!(y, 'd');
+}
index be1dd1a8524c803bebced010c2bc5140cb950b66..998e178966a22a30a31f43f8dc54f056043b9942 100644 (file)
@@ -24,19 +24,14 @@ note: this closure does not fulfill the lifetime requirements
 LL |         |x| x
    |         ^^^^^
 
-error[E0308]: mismatched types
+error: implementation of `FnOnce` is not general enough
   --> $DIR/issue-57611-trait-alias.rs:17:16
    |
 LL |     type Bar = impl Baz<Self, Self>;
-   |                ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+   |                ^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
    |
-   = note: expected type `FnOnce<(&X,)>`
-              found type `FnOnce<(&'static X,)>`
-note: this closure does not fulfill the lifetime requirements
-  --> $DIR/issue-57611-trait-alias.rs:25:9
-   |
-LL |         |x| x
-   |         ^^^^^
+   = note: closure with signature `fn(&'static X) -> &'static X` must implement `FnOnce<(&'0 X,)>`, for any lifetime `'0`...
+   = note: ...but it actually implements `FnOnce<(&'static X,)>`
 
 error: aborting due to 4 previous errors
 
index 3372b81404ecb4da25879f625de145602ad95201..561528c2abbd5fe2691f63c778ce06d846463abd 100644 (file)
@@ -15,9 +15,9 @@ trait Foo {
 
 impl Foo for X {
     type Bar = impl Baz<Self, Self>;
-    //~^ ERROR mismatched types
-    //~| ERROR mismatched types
-    //~| ERROR mismatched types
+    //~^ ERROR implementation of `FnOnce` is not general enough
+    //~| ERROR implementation of `FnOnce` is not general enough
+    //~| ERROR implementation of `FnOnce` is not general enough
     //~| ERROR mismatched types
     //~| ERROR mismatched types
 
index 9d9293e958eeb909069a44a2c25923ae3c513559..91c9d459ad8ce5ccdcb27d44bdb93cfe32f3f12c 100644 (file)
@@ -1,16 +1,11 @@
-error[E0308]: mismatched types
+error: implementation of `FnOnce` is not general enough
   --> $DIR/issue-57611-trait-alias.rs:17:16
    |
 LL |     type Bar = impl Baz<Self, Self>;
-   |                ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
-   |
-   = note: expected type `FnOnce<(&X,)>`
-              found type `FnOnce<(&X,)>`
-note: this closure does not fulfill the lifetime requirements
-  --> $DIR/issue-57611-trait-alias.rs:25:9
+   |                ^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
    |
-LL |         |x| x
-   |         ^^^^^
+   = note: closure with signature `fn(&'2 X) -> &X` must implement `FnOnce<(&'1 X,)>`, for any lifetime `'1`...
+   = note: ...but it actually implements `FnOnce<(&'2 X,)>`, for some specific lifetime `'2`
 
 error[E0308]: mismatched types
   --> $DIR/issue-57611-trait-alias.rs:17:16
@@ -26,19 +21,14 @@ note: this closure does not fulfill the lifetime requirements
 LL |         |x| x
    |         ^^^^^
 
-error[E0308]: mismatched types
+error: implementation of `FnOnce` is not general enough
   --> $DIR/issue-57611-trait-alias.rs:17:16
    |
 LL |     type Bar = impl Baz<Self, Self>;
-   |                ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+   |                ^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
    |
-   = note: expected type `FnOnce<(&X,)>`
-              found type `FnOnce<(&'<empty> X,)>`
-note: this closure does not fulfill the lifetime requirements
-  --> $DIR/issue-57611-trait-alias.rs:25:9
-   |
-LL |         |x| x
-   |         ^^^^^
+   = note: closure with signature `fn(&'2 X) -> &'2 X` must implement `FnOnce<(&'1 X,)>`, for any lifetime `'1`...
+   = note: ...but it actually implements `FnOnce<(&'2 X,)>`, for some specific lifetime `'2`
 
 error[E0308]: mismatched types
   --> $DIR/issue-57611-trait-alias.rs:17:16
@@ -54,19 +44,14 @@ note: this closure does not fulfill the lifetime requirements
 LL |         |x| x
    |         ^^^^^
 
-error[E0308]: mismatched types
+error: implementation of `FnOnce` is not general enough
   --> $DIR/issue-57611-trait-alias.rs:17:16
    |
 LL |     type Bar = impl Baz<Self, Self>;
-   |                ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+   |                ^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
    |
-   = note: expected type `FnOnce<(&X,)>`
-              found type `FnOnce<(&'<empty> X,)>`
-note: this closure does not fulfill the lifetime requirements
-  --> $DIR/issue-57611-trait-alias.rs:25:9
-   |
-LL |         |x| x
-   |         ^^^^^
+   = note: closure with signature `fn(&'2 X) -> &'2 X` must implement `FnOnce<(&'1 X,)>`, for any lifetime `'1`...
+   = note: ...but it actually implements `FnOnce<(&'2 X,)>`, for some specific lifetime `'2`
 
 error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/type-id-higher-rank.rs b/src/test/ui/type-id-higher-rank.rs
deleted file mode 100644 (file)
index 355d110..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-// run-pass
-// Test that type IDs correctly account for higher-rank lifetimes
-// Also acts as a regression test for an ICE (issue #19791)
-
-use std::any::{Any, TypeId};
-
-struct Struct<'a>(&'a ());
-trait Trait<'a> {}
-
-fn main() {
-    // Bare fns
-    {
-        let a = TypeId::of::<fn(&'static isize, &'static isize)>();
-        let b = TypeId::of::<for<'a> fn(&'static isize, &'a isize)>();
-        let c = TypeId::of::<for<'a, 'b> fn(&'a isize, &'b isize)>();
-        let d = TypeId::of::<for<'a, 'b> fn(&'b isize, &'a isize)>();
-        assert!(a != b);
-        assert!(a != c);
-        assert!(a != d);
-        assert!(b != c);
-        assert!(b != d);
-        assert_eq!(c, d);
-
-        // Make sure De Bruijn indices are handled correctly
-        let e = TypeId::of::<for<'a> fn(fn(&'a isize) -> &'a isize)>();
-        let f = TypeId::of::<fn(for<'a> fn(&'a isize) -> &'a isize)>();
-        assert!(e != f);
-
-        // Make sure lifetime parameters of items are not ignored.
-        let g = TypeId::of::<for<'a> fn(&'a dyn Trait<'a>) -> Struct<'a>>();
-        let h = TypeId::of::<for<'a> fn(&'a dyn Trait<'a>) -> Struct<'static>>();
-        let i = TypeId::of::<for<'a, 'b> fn(&'a dyn Trait<'b>) -> Struct<'b>>();
-        assert!(g != h);
-        assert!(g != i);
-        assert!(h != i);
-
-        // Make sure lifetime anonymization handles nesting correctly
-        let j = TypeId::of::<fn(for<'a> fn(&'a isize) -> &'a usize)>();
-        let k = TypeId::of::<fn(for<'b> fn(&'b isize) -> &'b usize)>();
-        assert_eq!(j, k);
-    }
-    // Boxed unboxed closures
-    {
-        let a = TypeId::of::<Box<dyn Fn(&'static isize, &'static isize)>>();
-        let b = TypeId::of::<Box<dyn for<'a> Fn(&'static isize, &'a isize)>>();
-        let c = TypeId::of::<Box<dyn for<'a, 'b> Fn(&'a isize, &'b isize)>>();
-        let d = TypeId::of::<Box<dyn for<'a, 'b> Fn(&'b isize, &'a isize)>>();
-        assert!(a != b);
-        assert!(a != c);
-        assert!(a != d);
-        assert!(b != c);
-        assert!(b != d);
-        assert_eq!(c, d);
-
-        // Make sure De Bruijn indices are handled correctly
-        let e = TypeId::of::<Box<dyn for<'a> Fn(Box<dyn Fn(&'a isize) -> &'a isize>)>>();
-        let f = TypeId::of::<Box<dyn Fn(Box<dyn for<'a> Fn(&'a isize) -> &'a isize>)>>();
-        assert!(e != f);
-    }
-    // Raw unboxed closures
-    // Note that every unboxed closure has its own anonymous type,
-    // so no two IDs should equal each other, even when compatible
-    {
-        let a = id(|_: &isize, _: &isize| {});
-        let b = id(|_: &isize, _: &isize| {});
-        assert!(a != b);
-    }
-
-    fn id<T:Any>(_: T) -> TypeId {
-        TypeId::of::<T>()
-    }
-}
diff --git a/src/test/ui/type-sizes.rs b/src/test/ui/type-sizes.rs
deleted file mode 100644 (file)
index 73a11a5..0000000
+++ /dev/null
@@ -1,173 +0,0 @@
-// run-pass
-
-#![allow(non_camel_case_types)]
-#![allow(dead_code)]
-#![feature(never_type)]
-
-use std::mem::size_of;
-use std::num::NonZeroU8;
-
-struct t {a: u8, b: i8}
-struct u {a: u8, b: i8, c: u8}
-struct v {a: u8, b: i8, c: v2, d: u32}
-struct v2 {u: char, v: u8}
-struct w {a: isize, b: ()}
-struct x {a: isize, b: (), c: ()}
-struct y {x: isize}
-
-enum e1 {
-    a(u8, u32), b(u32), c
-}
-enum e2 {
-    a(u32), b
-}
-
-#[repr(C, u8)]
-enum e3 {
-    a([u16; 0], u8), b
-}
-
-struct ReorderedStruct {
-    a: u8,
-    b: u16,
-    c: u8
-}
-
-enum ReorderedEnum {
-    A(u8, u16, u8),
-    B(u8, u16, u8),
-}
-
-enum ReorderedEnum2 {
-    A(u8, u32, u8),
-    B(u16, u8, u16, u8),
-
-    // 0x100 niche variants.
-    _00, _01, _02, _03, _04, _05, _06, _07, _08, _09, _0A, _0B, _0C, _0D, _0E, _0F,
-    _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _1A, _1B, _1C, _1D, _1E, _1F,
-    _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _2A, _2B, _2C, _2D, _2E, _2F,
-    _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _3A, _3B, _3C, _3D, _3E, _3F,
-    _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _4A, _4B, _4C, _4D, _4E, _4F,
-    _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _5A, _5B, _5C, _5D, _5E, _5F,
-    _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _6A, _6B, _6C, _6D, _6E, _6F,
-    _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _7A, _7B, _7C, _7D, _7E, _7F,
-    _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _8A, _8B, _8C, _8D, _8E, _8F,
-    _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _9A, _9B, _9C, _9D, _9E, _9F,
-    _A0, _A1, _A2, _A3, _A4, _A5, _A6, _A7, _A8, _A9, _AA, _AB, _AC, _AD, _AE, _AF,
-    _B0, _B1, _B2, _B3, _B4, _B5, _B6, _B7, _B8, _B9, _BA, _BB, _BC, _BD, _BE, _BF,
-    _C0, _C1, _C2, _C3, _C4, _C5, _C6, _C7, _C8, _C9, _CA, _CB, _CC, _CD, _CE, _CF,
-    _D0, _D1, _D2, _D3, _D4, _D5, _D6, _D7, _D8, _D9, _DA, _DB, _DC, _DD, _DE, _DF,
-    _E0, _E1, _E2, _E3, _E4, _E5, _E6, _E7, _E8, _E9, _EA, _EB, _EC, _ED, _EE, _EF,
-    _F0, _F1, _F2, _F3, _F4, _F5, _F6, _F7, _F8, _F9, _FA, _FB, _FC, _FD, _FE, _FF,
-}
-
-enum EnumEmpty {}
-
-enum EnumSingle1 {
-    A,
-}
-
-enum EnumSingle2 {
-    A = 42 as isize,
-}
-
-enum EnumSingle3 {
-    A,
-    B(!),
-}
-
-#[repr(u8)]
-enum EnumSingle4 {
-    A,
-}
-
-#[repr(u8)]
-enum EnumSingle5 {
-    A = 42 as u8,
-}
-
-enum EnumWithMaybeUninhabitedVariant<T> {
-    A(&'static ()),
-    B(&'static (), T),
-    C,
-}
-
-enum NicheFilledEnumWithAbsentVariant {
-    A(&'static ()),
-    B((), !),
-    C,
-}
-
-enum Option2<A, B> {
-    Some(A, B),
-    None
-}
-
-// Two layouts are considered for `CanBeNicheFilledButShouldnt`:
-//   Niche-filling:
-//     { u32 (4 bytes), NonZeroU8 + tag in niche (1 byte), padding (3 bytes) }
-//   Tagged:
-//     { tag (1 byte), NonZeroU8 (1 byte), padding (2 bytes), u32 (4 bytes) }
-// Both are the same size (due to padding),
-// but the tagged layout is better as the tag creates a niche with 254 invalid values,
-// allowing types like `Option<Option<CanBeNicheFilledButShouldnt>>` to fit into 8 bytes.
-pub enum CanBeNicheFilledButShouldnt {
-    A(NonZeroU8, u32),
-    B
-}
-pub enum AlwaysTaggedBecauseItHasNoNiche {
-    A(u8, u32),
-    B
-}
-
-pub fn main() {
-    assert_eq!(size_of::<u8>(), 1 as usize);
-    assert_eq!(size_of::<u32>(), 4 as usize);
-    assert_eq!(size_of::<char>(), 4 as usize);
-    assert_eq!(size_of::<i8>(), 1 as usize);
-    assert_eq!(size_of::<i32>(), 4 as usize);
-    assert_eq!(size_of::<t>(), 2 as usize);
-    assert_eq!(size_of::<u>(), 3 as usize);
-    // Alignment causes padding before the char and the u32.
-
-    assert_eq!(size_of::<v>(),
-                16 as usize);
-    assert_eq!(size_of::<isize>(), size_of::<usize>());
-    assert_eq!(size_of::<w>(), size_of::<isize>());
-    assert_eq!(size_of::<x>(), size_of::<isize>());
-    assert_eq!(size_of::<isize>(), size_of::<y>());
-
-    // Make sure enum types are the appropriate size, mostly
-    // around ensuring alignment is handled properly
-
-    assert_eq!(size_of::<e1>(), 8 as usize);
-    assert_eq!(size_of::<e2>(), 8 as usize);
-    assert_eq!(size_of::<e3>(), 4 as usize);
-    assert_eq!(size_of::<ReorderedStruct>(), 4);
-    assert_eq!(size_of::<ReorderedEnum>(), 6);
-    assert_eq!(size_of::<ReorderedEnum2>(), 8);
-
-
-    assert_eq!(size_of::<EnumEmpty>(), 0);
-    assert_eq!(size_of::<EnumSingle1>(), 0);
-    assert_eq!(size_of::<EnumSingle2>(), 0);
-    assert_eq!(size_of::<EnumSingle3>(), 0);
-    assert_eq!(size_of::<EnumSingle4>(), 1);
-    assert_eq!(size_of::<EnumSingle5>(), 1);
-
-    assert_eq!(size_of::<EnumWithMaybeUninhabitedVariant<!>>(),
-               size_of::<EnumWithMaybeUninhabitedVariant<()>>());
-    assert_eq!(size_of::<NicheFilledEnumWithAbsentVariant>(), size_of::<&'static ()>());
-
-    assert_eq!(size_of::<Option<Option<(bool, &())>>>(), size_of::<(bool, &())>());
-    assert_eq!(size_of::<Option<Option<(&(), bool)>>>(), size_of::<(bool, &())>());
-    assert_eq!(size_of::<Option<Option2<bool, &()>>>(), size_of::<(bool, &())>());
-    assert_eq!(size_of::<Option<Option2<&(), bool>>>(), size_of::<(bool, &())>());
-
-    assert_eq!(size_of::<CanBeNicheFilledButShouldnt>(), 8);
-    assert_eq!(size_of::<Option<CanBeNicheFilledButShouldnt>>(), 8);
-    assert_eq!(size_of::<Option<Option<CanBeNicheFilledButShouldnt>>>(), 8);
-    assert_eq!(size_of::<AlwaysTaggedBecauseItHasNoNiche>(), 8);
-    assert_eq!(size_of::<Option<AlwaysTaggedBecauseItHasNoNiche>>(), 8);
-    assert_eq!(size_of::<Option<Option<AlwaysTaggedBecauseItHasNoNiche>>>(), 8);
-}
index 5a2cbab9a15002396a4327965b7387268435717f..2db392e8b8b9f8b7f25a8a0ce2eaaa97f299597b 100644 (file)
@@ -1,5 +1,5 @@
 error: higher-ranked subtype error
-  --> $DIR/issue-30906.rs:15:5
+  --> $DIR/issue-30906.rs:18:5
    |
 LL |     test(Compose(f, |_| {}));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
index 03cce832775151a665ec8b3894255558502d0659..e2d219e470384700bdf2e95eb2c3f6a681ee5626 100644 (file)
@@ -2,9 +2,12 @@
 
 fn test<F: for<'x> FnOnce<(&'x str,)>>(_: F) {}
 
-struct Compose<F,G>(F,G);
-impl<T,F,G> FnOnce<(T,)> for Compose<F,G>
-where F: FnOnce<(T,)>, G: FnOnce<(F::Output,)> {
+struct Compose<F, G>(F, G);
+impl<T, F, G> FnOnce<(T,)> for Compose<F, G>
+where
+    F: FnOnce<(T,)>,
+    G: FnOnce<(F::Output,)>,
+{
     type Output = G::Output;
     extern "rust-call" fn call_once(self, (x,): (T,)) -> G::Output {
         (self.1)((self.0)(x))
@@ -12,7 +15,8 @@ extern "rust-call" fn call_once(self, (x,): (T,)) -> G::Output {
 }
 
 fn bad<T>(f: fn(&'static str) -> T) {
-    test(Compose(f, |_| {})); //~ ERROR: mismatched types
+    test(Compose(f, |_| {}));
+    //~^ ERROR: implementation of `FnOnce` is not general enough
 }
 
 fn main() {}
index ecf3a96b5a8dcaf1bdf41823e7d64de11e847ca5..35b1e454c02b4caf219ff4719994c9f4672beca7 100644 (file)
@@ -1,17 +1,11 @@
-error[E0308]: mismatched types
-  --> $DIR/issue-30906.rs:15:5
+error: implementation of `FnOnce` is not general enough
+  --> $DIR/issue-30906.rs:18:5
    |
 LL |     test(Compose(f, |_| {}));
-   |     ^^^^ lifetime mismatch
+   |     ^^^^ implementation of `FnOnce` is not general enough
    |
-   = note: expected type `FnOnce<(&'x str,)>`
-              found type `FnOnce<(&str,)>`
-note: the lifetime requirement is introduced here
-  --> $DIR/issue-30906.rs:3:12
-   |
-LL | fn test<F: for<'x> FnOnce<(&'x str,)>>(_: F) {}
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: `fn(&'2 str) -> T` must implement `FnOnce<(&'1 str,)>`, for any lifetime `'1`...
+   = note: ...but it actually implements `FnOnce<(&'2 str,)>`, for some specific lifetime `'2`
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/unboxed-closures/type-id-higher-rank.rs b/src/test/ui/unboxed-closures/type-id-higher-rank.rs
new file mode 100644 (file)
index 0000000..355d110
--- /dev/null
@@ -0,0 +1,72 @@
+// run-pass
+// Test that type IDs correctly account for higher-rank lifetimes
+// Also acts as a regression test for an ICE (issue #19791)
+
+use std::any::{Any, TypeId};
+
+struct Struct<'a>(&'a ());
+trait Trait<'a> {}
+
+fn main() {
+    // Bare fns
+    {
+        let a = TypeId::of::<fn(&'static isize, &'static isize)>();
+        let b = TypeId::of::<for<'a> fn(&'static isize, &'a isize)>();
+        let c = TypeId::of::<for<'a, 'b> fn(&'a isize, &'b isize)>();
+        let d = TypeId::of::<for<'a, 'b> fn(&'b isize, &'a isize)>();
+        assert!(a != b);
+        assert!(a != c);
+        assert!(a != d);
+        assert!(b != c);
+        assert!(b != d);
+        assert_eq!(c, d);
+
+        // Make sure De Bruijn indices are handled correctly
+        let e = TypeId::of::<for<'a> fn(fn(&'a isize) -> &'a isize)>();
+        let f = TypeId::of::<fn(for<'a> fn(&'a isize) -> &'a isize)>();
+        assert!(e != f);
+
+        // Make sure lifetime parameters of items are not ignored.
+        let g = TypeId::of::<for<'a> fn(&'a dyn Trait<'a>) -> Struct<'a>>();
+        let h = TypeId::of::<for<'a> fn(&'a dyn Trait<'a>) -> Struct<'static>>();
+        let i = TypeId::of::<for<'a, 'b> fn(&'a dyn Trait<'b>) -> Struct<'b>>();
+        assert!(g != h);
+        assert!(g != i);
+        assert!(h != i);
+
+        // Make sure lifetime anonymization handles nesting correctly
+        let j = TypeId::of::<fn(for<'a> fn(&'a isize) -> &'a usize)>();
+        let k = TypeId::of::<fn(for<'b> fn(&'b isize) -> &'b usize)>();
+        assert_eq!(j, k);
+    }
+    // Boxed unboxed closures
+    {
+        let a = TypeId::of::<Box<dyn Fn(&'static isize, &'static isize)>>();
+        let b = TypeId::of::<Box<dyn for<'a> Fn(&'static isize, &'a isize)>>();
+        let c = TypeId::of::<Box<dyn for<'a, 'b> Fn(&'a isize, &'b isize)>>();
+        let d = TypeId::of::<Box<dyn for<'a, 'b> Fn(&'b isize, &'a isize)>>();
+        assert!(a != b);
+        assert!(a != c);
+        assert!(a != d);
+        assert!(b != c);
+        assert!(b != d);
+        assert_eq!(c, d);
+
+        // Make sure De Bruijn indices are handled correctly
+        let e = TypeId::of::<Box<dyn for<'a> Fn(Box<dyn Fn(&'a isize) -> &'a isize>)>>();
+        let f = TypeId::of::<Box<dyn Fn(Box<dyn for<'a> Fn(&'a isize) -> &'a isize>)>>();
+        assert!(e != f);
+    }
+    // Raw unboxed closures
+    // Note that every unboxed closure has its own anonymous type,
+    // so no two IDs should equal each other, even when compatible
+    {
+        let a = id(|_: &isize, _: &isize| {});
+        let b = id(|_: &isize, _: &isize| {});
+        assert!(a != b);
+    }
+
+    fn id<T:Any>(_: T) -> TypeId {
+        TypeId::of::<T>()
+    }
+}
index 30eb78b2da4f73d1def0a8c41f4d2a81197bb935..6da46e20c09c0116b3c75818cfae55d82107f78a 100644 (file)
@@ -1,16 +1,11 @@
 error: implementation of `Bar` is not general enough
   --> $DIR/where-for-self-2.rs:23:5
    |
-LL | / trait Bar {
-LL | |     fn bar(&self);
-LL | | }
-   | |_- trait `Bar` defined here
-...
-LL |       foo(&X);
-   |       ^^^ implementation of `Bar` is not general enough
+LL |     foo(&X);
+   |     ^^^ implementation of `Bar` is not general enough
    |
-   = note: `Bar` would have to be implemented for the type `&'0 u32`, for any lifetime `'0`...
-   = note: ...but `Bar` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1`
+   = note: `&'0 u32` must implement `Bar`, for any lifetime `'0`...
+   = note: ...but `Bar` is actually implemented for the type `&'static u32`
 
 error: aborting due to previous error
 
index cfbf7565cb6c82d7b8b298f29b835afa795570f3..b9a49b47c8ff5911594d7b805de37357742f3d5d 100644 (file)
@@ -5,8 +5,8 @@ fn macros() {
     macro_rules! foo{
         ($p:pat, $e:expr, $b:block) => {{
             while let $p = $e $b
-            //~^ WARN irrefutable while-let
-            //~| WARN irrefutable while-let
+            //~^ WARN irrefutable `while let`
+            //~| WARN irrefutable `while let`
         }}
     }
     macro_rules! bar{
@@ -24,7 +24,7 @@ macro_rules! bar{
 }
 
 pub fn main() {
-    while let _a = 1 { //~ WARN irrefutable while-let
+    while let _a = 1 { //~ WARN irrefutable `while let`
         println!("irrefutable pattern");
         break;
     }
index 867c95c0e023d1f5fe82b7f28bbdd969eabfcf82..04e77bf9470a29d38d78dc9490ca081fa8932784 100644 (file)
@@ -1,4 +1,4 @@
-warning: irrefutable while-let pattern
+warning: irrefutable `while let` pattern
   --> $DIR/while-let.rs:7:13
    |
 LL |               while let $p = $e $b
@@ -10,9 +10,11 @@ LL | |     });
    | |_______- in this macro invocation
    |
    = note: `#[warn(irrefutable_let_patterns)]` on by default
+   = note: this pattern will always match, so the loop will never exit
+   = help: consider instead using a `loop { ... }` with a `let` inside it
    = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
-warning: irrefutable while-let pattern
+warning: irrefutable `while let` pattern
   --> $DIR/while-let.rs:7:13
    |
 LL |               while let $p = $e $b
@@ -23,9 +25,11 @@ LL | |         println!("irrefutable pattern");
 LL | |     });
    | |_______- in this macro invocation
    |
+   = note: this pattern will always match, so the loop will never exit
+   = help: consider instead using a `loop { ... }` with a `let` inside it
    = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
-warning: irrefutable while-let pattern
+warning: irrefutable `while let` pattern
   --> $DIR/while-let.rs:27:5
    |
 LL | /     while let _a = 1 {
@@ -33,6 +37,9 @@ LL | |         println!("irrefutable pattern");
 LL | |         break;
 LL | |     }
    | |_____^
+   |
+   = note: this pattern will always match, so the loop will never exit
+   = help: consider instead using a `loop { ... }` with a `let` inside it
 
 warning: 3 warnings emitted
 
diff --git a/src/test/ui/write-to-static-mut-in-static.rs b/src/test/ui/write-to-static-mut-in-static.rs
deleted file mode 100644 (file)
index 43c63fe..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-pub static mut A: u32 = 0;
-pub static mut B: () = unsafe { A = 1; };
-//~^ ERROR could not evaluate static initializer
-
-pub static mut C: u32 = unsafe { C = 1; 0 };
-//~^ ERROR cycle detected
-
-pub static D: u32 = D;
-
-fn main() {}
diff --git a/src/test/ui/write-to-static-mut-in-static.stderr b/src/test/ui/write-to-static-mut-in-static.stderr
deleted file mode 100644 (file)
index 789919b..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-error[E0080]: could not evaluate static initializer
-  --> $DIR/write-to-static-mut-in-static.rs:2:33
-   |
-LL | pub static mut B: () = unsafe { A = 1; };
-   |                                 ^^^^^ modifying a static's initial value from another static's initializer
-
-error[E0391]: cycle detected when const-evaluating + checking `C`
-  --> $DIR/write-to-static-mut-in-static.rs:5:1
-   |
-LL | pub static mut C: u32 = unsafe { C = 1; 0 };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: ...which requires const-evaluating + checking `C`...
-  --> $DIR/write-to-static-mut-in-static.rs:5:1
-   |
-LL | pub static mut C: u32 = unsafe { C = 1; 0 };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: ...which again requires const-evaluating + checking `C`, completing the cycle
-   = note: cycle used when running analysis passes on this crate
-
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0080, E0391.
-For more information about an error, try `rustc --explain E0080`.
index ab64d1393b5b77c66b6534ef5023a1b89ee7bf64..bf5a5d5e5d3ae842a63bfce6d070dfd438cf6070 160000 (submodule)
@@ -1 +1 @@
-Subproject commit ab64d1393b5b77c66b6534ef5023a1b89ee7bf64
+Subproject commit bf5a5d5e5d3ae842a63bfce6d070dfd438cf6070
index eb185377e209471f5bf9c34c28bb9f9001e23c28..1c9373a756c8896d3de7472131aa8839f3d16206 100644 (file)
     /// ```
     pub WHILE_LET_ON_ITERATOR,
     style,
-    "using a while-let loop instead of a for loop on an iterator"
+    "using a `while let` loop instead of a for loop on an iterator"
 }
 
 declare_clippy_lint! {
index 642326469725fce4194e31ea222a794ef92134c3..9ff7ef7cc3b55e17cb9acf107a732c5fb11e8ce5 100644 (file)
@@ -241,9 +241,12 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
                 && eq_generics(lg, rg)
                 && both(lb, rb, |l, r| eq_block(l, r))
         }
-        (Mod(l), Mod(r)) => {
-            l.inline == r.inline && over(&l.items, &r.items, |l, r| eq_item(l, r, eq_item_kind))
-        }
+        (Mod(lu, lmk), Mod(ru, rmk)) => lu == ru && match (lmk, rmk) {
+            (ModKind::Loaded(litems, linline, _), ModKind::Loaded(ritems, rinline, _)) =>
+                linline == rinline && over(litems, ritems, |l, r| eq_item(l, r, eq_item_kind)),
+            (ModKind::Unloaded, ModKind::Unloaded) => true,
+            _ => false,
+        },
         (ForeignMod(l), ForeignMod(r)) => {
             both(&l.abi, &r.abi, |l, r| eq_str_lit(l, r))
                 && over(&l.items, &r.items, |l, r| eq_item(l, r, eq_foreign_item_kind))
index 74ed2366752089ae81ab8844b1a7839d8cbb965c..659d5ae03c9d85cd85bdd53be8550c7b69d9358a 100644 (file)
@@ -7,8 +7,8 @@
 
 const ENTRY_LIMIT: usize = 1000;
 // FIXME: The following limits should be reduced eventually.
-const ROOT_ENTRY_LIMIT: usize = 1459;
-const ISSUES_ENTRY_LIMIT: usize = 2615;
+const ROOT_ENTRY_LIMIT: usize = 1418;
+const ISSUES_ENTRY_LIMIT: usize = 2582;
 
 fn check_entries(path: &Path, bad: &mut bool) {
     let dirs = walkdir::WalkDir::new(&path.join("test/ui"))