]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #107146 - compiler-errors:unsizing-params, r=cjgillot
authorDylan DPC <99973273+Dylan-DPC@users.noreply.github.com>
Mon, 30 Jan 2023 09:41:45 +0000 (15:11 +0530)
committerGitHub <noreply@github.com>
Mon, 30 Jan 2023 09:41:45 +0000 (15:11 +0530)
Make `unsizing_params_for_adt` into a query

Addresses a FIXME in confirmation.

r? ``@ghost``

264 files changed:
.github/workflows/ci.yml
compiler/rustc_borrowck/src/dataflow.rs
compiler/rustc_borrowck/src/diagnostics/mod.rs
compiler/rustc_borrowck/src/invalidation.rs
compiler/rustc_borrowck/src/lib.rs
compiler/rustc_borrowck/src/type_check/mod.rs
compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
compiler/rustc_codegen_cranelift/src/base.rs
compiler/rustc_codegen_cranelift/src/constant.rs
compiler/rustc_codegen_llvm/src/context.rs
compiler/rustc_codegen_ssa/src/mir/analyze.rs
compiler/rustc_codegen_ssa/src/mir/statement.rs
compiler/rustc_const_eval/src/const_eval/machine.rs
compiler/rustc_const_eval/src/interpret/machine.rs
compiler/rustc_const_eval/src/interpret/step.rs
compiler/rustc_const_eval/src/transform/check_consts/check.rs
compiler/rustc_const_eval/src/transform/validate.rs
compiler/rustc_data_structures/src/graph/dominators/mod.rs
compiler/rustc_driver/src/pretty.rs
compiler/rustc_error_messages/locales/en-US/lint.ftl
compiler/rustc_error_messages/locales/en-US/parse.ftl
compiler/rustc_feature/src/active.rs
compiler/rustc_hir_analysis/src/check/wfcheck.rs
compiler/rustc_hir_analysis/src/coherence/mod.rs
compiler/rustc_hir_typeck/src/coercion.rs
compiler/rustc_infer/src/infer/canonical/mod.rs
compiler/rustc_infer/src/infer/canonical/query_response.rs
compiler/rustc_infer/src/infer/canonical/substitute.rs
compiler/rustc_interface/src/tests.rs
compiler/rustc_lint/src/lib.rs
compiler/rustc_lint/src/lints.rs
compiler/rustc_lint/src/multiple_supertrait_upcastable.rs [new file with mode: 0644]
compiler/rustc_lint_defs/src/builtin.rs
compiler/rustc_metadata/src/rmeta/encoder.rs
compiler/rustc_middle/src/infer/canonical.rs
compiler/rustc_middle/src/mir/mod.rs
compiler/rustc_middle/src/mir/spanview.rs
compiler/rustc_middle/src/mir/syntax.rs
compiler/rustc_middle/src/mir/visit.rs
compiler/rustc_middle/src/query/mod.rs
compiler/rustc_middle/src/thir.rs
compiler/rustc_middle/src/thir/print.rs [new file with mode: 0644]
compiler/rustc_middle/src/ty/context.rs
compiler/rustc_middle/src/ty/mod.rs
compiler/rustc_mir_build/src/build/mod.rs
compiler/rustc_mir_build/src/lib.rs
compiler/rustc_mir_build/src/thir/cx/mod.rs
compiler/rustc_mir_dataflow/src/impls/liveness.rs
compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
compiler/rustc_mir_dataflow/src/move_paths/builder.rs
compiler/rustc_mir_dataflow/src/value_analysis.rs
compiler/rustc_mir_transform/src/check_unsafety.rs
compiler/rustc_mir_transform/src/copy_prop.rs [new file with mode: 0644]
compiler/rustc_mir_transform/src/coverage/spans.rs
compiler/rustc_mir_transform/src/ctfe_limit.rs [new file with mode: 0644]
compiler/rustc_mir_transform/src/dead_store_elimination.rs
compiler/rustc_mir_transform/src/dest_prop.rs
compiler/rustc_mir_transform/src/generator.rs
compiler/rustc_mir_transform/src/lib.rs
compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
compiler/rustc_mir_transform/src/separate_const_switch.rs
compiler/rustc_mir_transform/src/simplify.rs
compiler/rustc_mir_transform/src/ssa.rs [new file with mode: 0644]
compiler/rustc_parse/src/errors.rs
compiler/rustc_parse/src/parser/expr.rs
compiler/rustc_parse/src/parser/pat.rs
compiler/rustc_parse/src/parser/ty.rs
compiler/rustc_session/src/config.rs
compiler/rustc_session/src/options.rs
compiler/rustc_span/src/symbol.rs
compiler/rustc_trait_selection/src/solve/assembly.rs
compiler/rustc_trait_selection/src/solve/mod.rs
compiler/rustc_trait_selection/src/solve/project_goals.rs
compiler/rustc_trait_selection/src/solve/search_graph/cache.rs
compiler/rustc_trait_selection/src/solve/trait_goals.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/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/db.rs
compiler/rustc_traits/src/chalk/mod.rs
library/alloc/src/fmt.rs
library/alloc/src/lib.rs
library/core/src/error.rs
library/core/src/lib.rs
library/core/src/num/int_macros.rs
library/std/src/os/net/mod.rs
library/std/src/sys/common/alloc.rs
library/std/src/time.rs
library/test/src/console.rs
library/test/src/formatters/terse.rs
library/test/src/tests.rs
src/bootstrap/lib.rs
src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
src/ci/docker/host-x86_64/mingw-check/validate-toolstate.sh
src/ci/github-actions/ci.yml
src/ci/scripts/install-mingw.sh
src/ci/stage-build.py [new file with mode: 0644]
src/doc/unstable-book/src/compiler-flags/tiny-const-eval-limit.md [new file with mode: 0644]
src/etc/pre-push.sh
src/librustdoc/html/render/mod.rs
src/librustdoc/html/render/print_item.rs
src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
src/tools/compiletest/src/header.rs
src/tools/publish_toolstate.py
tests/debuginfo/embedded-visualizer.rs
tests/debuginfo/numeric-types.rs
tests/debuginfo/vec-slices.rs
tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff
tests/mir-opt/const_prop/bad_op_mod_by_zero.main.ConstProp.diff
tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff
tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff
tests/mir-opt/const_prop/boolean_identities.test.ConstProp.diff
tests/mir-opt/const_prop/mult_by_zero.test.ConstProp.diff
tests/mir-opt/const_prop/ref_deref.main.ConstProp.diff
tests/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff [deleted file]
tests/mir-opt/const_prop/ref_deref.rs
tests/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff
tests/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff [deleted file]
tests/mir-opt/const_prop/ref_deref_project.rs
tests/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.diff
tests/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff
tests/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff
tests/mir-opt/const_prop/slice_len.rs
tests/mir-opt/const_prop_miscompile.bar.ConstProp.diff
tests/mir-opt/const_prop_miscompile.foo.ConstProp.diff
tests/mir-opt/const_prop_miscompile.rs
tests/mir-opt/copy-prop/borrowed_local.f.CopyProp.diff [new file with mode: 0644]
tests/mir-opt/copy-prop/borrowed_local.rs [new file with mode: 0644]
tests/mir-opt/copy-prop/branch.foo.CopyProp.diff [new file with mode: 0644]
tests/mir-opt/copy-prop/branch.rs [new file with mode: 0644]
tests/mir-opt/copy-prop/copy_propagation_arg.arg_src.CopyProp.diff [new file with mode: 0644]
tests/mir-opt/copy-prop/copy_propagation_arg.bar.CopyProp.diff [new file with mode: 0644]
tests/mir-opt/copy-prop/copy_propagation_arg.baz.CopyProp.diff [new file with mode: 0644]
tests/mir-opt/copy-prop/copy_propagation_arg.foo.CopyProp.diff [new file with mode: 0644]
tests/mir-opt/copy-prop/copy_propagation_arg.rs [new file with mode: 0644]
tests/mir-opt/copy-prop/cycle.main.CopyProp.diff [new file with mode: 0644]
tests/mir-opt/copy-prop/cycle.rs [new file with mode: 0644]
tests/mir-opt/copy-prop/dead_stores_79191.f.CopyProp.after.mir [new file with mode: 0644]
tests/mir-opt/copy-prop/dead_stores_79191.rs [new file with mode: 0644]
tests/mir-opt/copy-prop/dead_stores_better.f.CopyProp.after.mir [new file with mode: 0644]
tests/mir-opt/copy-prop/dead_stores_better.rs [new file with mode: 0644]
tests/mir-opt/copy-prop/move_arg.f.CopyProp.diff [new file with mode: 0644]
tests/mir-opt/copy-prop/move_arg.rs [new file with mode: 0644]
tests/mir-opt/copy-prop/mutate_through_pointer.f.CopyProp.diff [new file with mode: 0644]
tests/mir-opt/copy-prop/mutate_through_pointer.rs [new file with mode: 0644]
tests/mir-opt/copy-prop/non_dominate.f.CopyProp.diff [new file with mode: 0644]
tests/mir-opt/copy-prop/non_dominate.rs [new file with mode: 0644]
tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.diff
tests/mir-opt/div_overflow.const_dividend.PreCodegen.after.mir
tests/mir-opt/div_overflow.const_divisor.PreCodegen.after.mir
tests/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff
tests/mir-opt/inline/dyn_trait.get_query.Inline.diff
tests/mir-opt/inline/dyn_trait.try_execute_query.Inline.diff
tests/mir-opt/inline/inline_any_operand.bar.Inline.after.mir
tests/mir-opt/inline/inline_generator.main.Inline.diff
tests/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir
tests/mir-opt/issue_101973.inner.ConstProp.diff
tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff
tests/mir-opt/lower_array_len_e2e.array_bound.PreCodegen.after.mir
tests/mir-opt/lower_array_len_e2e.array_bound_mut.PreCodegen.after.mir
tests/mir-opt/simple_option_map_e2e.ezmap.PreCodegen.after.mir
tests/mir-opt/simplify_match.main.ConstProp.diff
tests/mir-opt/slice_filter.rs [new file with mode: 0644]
tests/mir-opt/slice_filter.variant_a-{closure#0}.CopyProp.diff [new file with mode: 0644]
tests/mir-opt/slice_filter.variant_a-{closure#0}.DestinationPropagation.diff [new file with mode: 0644]
tests/mir-opt/slice_filter.variant_b-{closure#0}.CopyProp.diff [new file with mode: 0644]
tests/mir-opt/slice_filter.variant_b-{closure#0}.DestinationPropagation.diff [new file with mode: 0644]
tests/mir-opt/try_identity_e2e.new.PreCodegen.after.mir
tests/mir-opt/try_identity_e2e.old.PreCodegen.after.mir
tests/mir-opt/while_storage.while_loop.PreCodegen.after.mir
tests/pretty/issue-4264.pp
tests/run-make/native-link-modifier-bundle/Makefile
tests/run-make/raw-dylib-inline-cross-dylib/Makefile
tests/run-make/rlib-format-packed-bundled-libs-2/Makefile
tests/run-make/rlib-format-packed-bundled-libs/Makefile
tests/rustdoc-gui/src-font-size.goml
tests/rustdoc-ui/z-help.stdout
tests/rustdoc/anchors.no_const_anchor.html
tests/rustdoc/anchors.no_const_anchor2.html
tests/rustdoc/anchors.no_method_anchor.html
tests/rustdoc/anchors.no_trait_method_anchor.html
tests/rustdoc/anchors.no_tymethod_anchor.html
tests/rustdoc/anchors.no_type_anchor.html
tests/rustdoc/anchors.no_type_anchor2.html
tests/rustdoc/async-fn.rs
tests/rustdoc/const-fn.rs
tests/rustdoc/const-generics/const-generic-slice.rs
tests/rustdoc/doc-assoc-item.rs
tests/rustdoc/duplicate_impls/issue-33054.rs
tests/rustdoc/duplicated_impl.rs
tests/rustdoc/empty-impl-block-private-with-doc.rs
tests/rustdoc/empty-impl-block-private.rs
tests/rustdoc/empty-impl-block.rs
tests/rustdoc/impl-parts.rs
tests/rustdoc/inline_cross/issue-31948-1.rs
tests/rustdoc/inline_cross/issue-31948-2.rs
tests/rustdoc/inline_cross/issue-31948.rs
tests/rustdoc/issue-21474.rs
tests/rustdoc/issue-33302.rs
tests/rustdoc/issue-45584.rs
tests/rustdoc/issue-50159.rs
tests/rustdoc/issue-51236.rs
tests/rustdoc/issue-53812.rs
tests/rustdoc/issue-54705.rs
tests/rustdoc/issue-55321.rs
tests/rustdoc/issue-56822.rs
tests/rustdoc/issue-60726.rs
tests/rustdoc/issue-76501.rs
tests/rustdoc/issue-78673.rs
tests/rustdoc/mut-params.rs
tests/rustdoc/negative-impl.rs
tests/rustdoc/primitive-reference.rs
tests/rustdoc/pub-method.rs
tests/rustdoc/synthetic_auto/basic.rs
tests/rustdoc/synthetic_auto/complex.rs
tests/rustdoc/synthetic_auto/lifetimes.rs
tests/rustdoc/synthetic_auto/manual.rs
tests/rustdoc/synthetic_auto/negative.rs
tests/rustdoc/synthetic_auto/nested.rs
tests/rustdoc/synthetic_auto/no-redundancy.rs
tests/rustdoc/synthetic_auto/project.rs
tests/rustdoc/synthetic_auto/self-referential.rs
tests/rustdoc/synthetic_auto/static-region.rs
tests/rustdoc/typedef.rs
tests/rustdoc/where.rs
tests/ui/consts/const-eval/infinite_loop.stderr
tests/ui/consts/const-eval/issue-52475.rs
tests/ui/consts/const-eval/issue-52475.stderr
tests/ui/consts/const-eval/stable-metric/ctfe-fn-call.rs [new file with mode: 0644]
tests/ui/consts/const-eval/stable-metric/ctfe-fn-call.stderr [new file with mode: 0644]
tests/ui/consts/const-eval/stable-metric/ctfe-labelled-loop.rs [new file with mode: 0644]
tests/ui/consts/const-eval/stable-metric/ctfe-labelled-loop.stderr [new file with mode: 0644]
tests/ui/consts/const-eval/stable-metric/ctfe-recursion.rs [new file with mode: 0644]
tests/ui/consts/const-eval/stable-metric/ctfe-recursion.stderr [new file with mode: 0644]
tests/ui/consts/const-eval/stable-metric/ctfe-simple-loop.rs [new file with mode: 0644]
tests/ui/consts/const-eval/stable-metric/ctfe-simple-loop.stderr [new file with mode: 0644]
tests/ui/consts/const-eval/stable-metric/dominators-edge-case.rs [new file with mode: 0644]
tests/ui/consts/const_limit/const_eval_limit_reached.stderr
tests/ui/deriving/deriving-all-codegen.stdout
tests/ui/feature-gates/feature-gate-multiple_supertrait_upcastable.rs [new file with mode: 0644]
tests/ui/feature-gates/feature-gate-multiple_supertrait_upcastable.stderr [new file with mode: 0644]
tests/ui/fmt/ifmt-unimpl.stderr
tests/ui/fmt/send-sync.stderr
tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-match-arrow.rs [new file with mode: 0644]
tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-match-arrow.stderr [new file with mode: 0644]
tests/ui/mir/mir_codegen_ssa.rs [new file with mode: 0644]
tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.fixed [new file with mode: 0644]
tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.rs [new file with mode: 0644]
tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.stderr [new file with mode: 0644]
tests/ui/parser/trait-object-delimiters.rs
tests/ui/parser/trait-object-delimiters.stderr
tests/ui/thir-print/thir-flat.rs [new file with mode: 0644]
tests/ui/thir-print/thir-flat.stdout [new file with mode: 0644]
tests/ui/thir-print/thir-tree-match.rs [new file with mode: 0644]
tests/ui/thir-print/thir-tree-match.stdout [new file with mode: 0644]
tests/ui/thir-print/thir-tree.rs [new file with mode: 0644]
tests/ui/thir-print/thir-tree.stdout [new file with mode: 0644]
tests/ui/thir-tree.rs [deleted file]
tests/ui/thir-tree.stdout [deleted file]
tests/ui/traits/trait-upcasting/multiple_supertrait_upcastable.rs [new file with mode: 0644]
tests/ui/traits/trait-upcasting/multiple_supertrait_upcastable.stderr [new file with mode: 0644]

index 5f77656e5c189957be0dca0cb1047f2195795a4a..552680f06f66dd58390c69f5b1c09f3c4205acc8 100644 (file)
@@ -418,14 +418,14 @@ jobs:
             os: windows-latest-xl
           - name: i686-mingw-1
             env:
-              RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu --set llvm.allow-old-toolchain"
+              RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu"
               SCRIPT: make ci-mingw-subset-1
               NO_DOWNLOAD_CI_LLVM: 1
               CUSTOM_MINGW: 1
             os: windows-latest-xl
           - name: i686-mingw-2
             env:
-              RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu --set llvm.allow-old-toolchain"
+              RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu"
               SCRIPT: make ci-mingw-subset-2
               NO_DOWNLOAD_CI_LLVM: 1
               CUSTOM_MINGW: 1
@@ -433,21 +433,21 @@ jobs:
           - name: x86_64-mingw-1
             env:
               SCRIPT: make ci-mingw-subset-1
-              RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler --set llvm.allow-old-toolchain"
+              RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler"
               NO_DOWNLOAD_CI_LLVM: 1
               CUSTOM_MINGW: 1
             os: windows-latest-xl
           - name: x86_64-mingw-2
             env:
               SCRIPT: make ci-mingw-subset-2
-              RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler --set llvm.allow-old-toolchain"
+              RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler"
               NO_DOWNLOAD_CI_LLVM: 1
               CUSTOM_MINGW: 1
             os: windows-latest-xl
           - name: dist-x86_64-msvc
             env:
               RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --host=x86_64-pc-windows-msvc --target=x86_64-pc-windows-msvc --enable-full-tools --enable-profiler --set rust.lto=thin"
-              SCRIPT: PGO_HOST=x86_64-pc-windows-msvc src/ci/pgo.sh python x.py dist bootstrap --include-default-paths
+              SCRIPT: PGO_HOST=x86_64-pc-windows-msvc python src/ci/stage-build.py python x.py dist bootstrap --include-default-paths
               DIST_REQUIRE_ALL_TOOLS: 1
             os: windows-latest-xl
           - name: dist-i686-msvc
@@ -465,7 +465,7 @@ jobs:
             os: windows-latest-xl
           - name: dist-i686-mingw
             env:
-              RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu --enable-full-tools --enable-profiler --set llvm.allow-old-toolchain"
+              RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu --enable-full-tools --enable-profiler"
               NO_DOWNLOAD_CI_LLVM: 1
               SCRIPT: python x.py dist bootstrap --include-default-paths
               CUSTOM_MINGW: 1
@@ -474,7 +474,7 @@ jobs:
           - name: dist-x86_64-mingw
             env:
               SCRIPT: python x.py dist bootstrap --include-default-paths
-              RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-full-tools --enable-profiler --set llvm.allow-old-toolchain"
+              RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-full-tools --enable-profiler"
               NO_DOWNLOAD_CI_LLVM: 1
               CUSTOM_MINGW: 1
               DIST_REQUIRE_ALL_TOOLS: 1
index 8c4885770ad37b6d009eb450d82a7e2b47a4d057..2821677c5371f7857044cd535e24bd14bfd7ca59 100644 (file)
@@ -393,6 +393,7 @@ fn statement_effect(
             | mir::StatementKind::AscribeUserType(..)
             | mir::StatementKind::Coverage(..)
             | mir::StatementKind::Intrinsic(..)
+            | mir::StatementKind::ConstEvalCounter
             | mir::StatementKind::Nop => {}
         }
     }
index 1011794d7b3b2995671c2946070a4f59df385fcb..8c579bac7e8eb471c8dc8690eb7f7c3a7c62c5d1 100644 (file)
@@ -1128,8 +1128,12 @@ fn explain_captures(
                                 "{place_name} {partially_str}moved due to this method call{loop_message}",
                             ),
                         );
+
                         let infcx = tcx.infer_ctxt().build();
+                        // Erase and shadow everything that could be passed to the new infcx.
                         let ty = tcx.erase_regions(moved_place.ty(self.body, tcx).ty);
+                        let method_substs = tcx.erase_regions(method_substs);
+
                         if let ty::Adt(def, substs) = ty.kind()
                             && Some(def.did()) == tcx.lang_items().pin_type()
                             && let ty::Ref(_, _, hir::Mutability::Mut) = substs.type_at(0).kind()
index 6fd9290058c36383e1a5c155de33f467701ee93d..6217676d5c150f5f977ff22735f65ca1d817a86f 100644 (file)
@@ -91,7 +91,8 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
                     LocalMutationIsAllowed::Yes,
                 );
             }
-            StatementKind::Nop
+            StatementKind::ConstEvalCounter
+            | StatementKind::Nop
             | StatementKind::Retag { .. }
             | StatementKind::Deinit(..)
             | StatementKind::SetDiscriminant { .. } => {
index 73ea7314b75cc202c6a9091ed39ad2b7d4dae464..bc81abe4005c919467114d502173cf017e0ab308 100644 (file)
@@ -609,7 +609,8 @@ fn visit_statement_before_primary_effect(
             StatementKind::AscribeUserType(..)
             // Doesn't have any language semantics
             | StatementKind::Coverage(..)
-            // Does not actually affect borrowck
+            // These do not actually affect borrowck
+            | StatementKind::ConstEvalCounter
             | StatementKind::StorageLive(..) => {}
             StatementKind::StorageDead(local) => {
                 self.access_place(
index 81bd4c2a783e906b30a4d1999bbea53b62522998..06087b0c579d8c293349d82e0e847fb5a2b50da5 100644 (file)
@@ -1258,6 +1258,7 @@ fn check_stmt(&mut self, body: &Body<'tcx>, stmt: &Statement<'tcx>, location: Lo
             | StatementKind::StorageDead(..)
             | StatementKind::Retag { .. }
             | StatementKind::Coverage(..)
+            | StatementKind::ConstEvalCounter
             | StatementKind::Nop => {}
             StatementKind::Deinit(..) | StatementKind::SetDiscriminant { .. } => {
                 bug!("Statement not allowed in this MIR phase")
index c9dc89212622d70d7d6ddc2bdbfac0093a7bf263..2fc30d8e05f2c6748c4e03ed0a07d056105e3439 100644 (file)
@@ -1,7 +1,7 @@
 use crate::deriving::generic::ty::*;
 use crate::deriving::generic::*;
 use crate::deriving::{path_std, pathvec_std};
-use rustc_ast::MetaItem;
+use rustc_ast::{ExprKind, ItemKind, MetaItem, PatKind};
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
@@ -21,6 +21,27 @@ pub fn expand_deriving_partial_ord(
 
     let attrs = thin_vec![cx.attr_word(sym::inline, span)];
 
+    // Order in which to perform matching
+    let tag_then_data = if let Annotatable::Item(item) = item
+        && let ItemKind::Enum(def, _) = &item.kind {
+            let dataful: Vec<bool> = def.variants.iter().map(|v| !v.data.fields().is_empty()).collect();
+            match dataful.iter().filter(|&&b| b).count() {
+                // No data, placing the tag check first makes codegen simpler
+                0 => true,
+                1..=2 => false,
+                _ => {
+                    (0..dataful.len()-1).any(|i| {
+                        if dataful[i] && let Some(idx) = dataful[i+1..].iter().position(|v| *v) {
+                            idx >= 2
+                        } else {
+                            false
+                        }
+                    })
+                }
+            }
+        } else {
+            true
+        };
     let partial_cmp_def = MethodDef {
         name: sym::partial_cmp,
         generics: Bounds::empty(),
@@ -30,7 +51,7 @@ pub fn expand_deriving_partial_ord(
         attributes: attrs,
         fieldless_variants_strategy: FieldlessVariantsStrategy::Unify,
         combine_substructure: combine_substructure(Box::new(|cx, span, substr| {
-            cs_partial_cmp(cx, span, substr)
+            cs_partial_cmp(cx, span, substr, tag_then_data)
         })),
     };
 
@@ -47,7 +68,12 @@ pub fn expand_deriving_partial_ord(
     trait_def.expand(cx, mitem, item, push)
 }
 
-pub fn cs_partial_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr {
+fn cs_partial_cmp(
+    cx: &mut ExtCtxt<'_>,
+    span: Span,
+    substr: &Substructure<'_>,
+    tag_then_data: bool,
+) -> BlockOrExpr {
     let test_id = Ident::new(sym::cmp, span);
     let equal_path = cx.path_global(span, cx.std_path(&[sym::cmp, sym::Ordering, sym::Equal]));
     let partial_cmp_path = cx.std_path(&[sym::cmp, sym::PartialOrd, sym::partial_cmp]);
@@ -74,12 +100,50 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_
                 let args = vec![field.self_expr.clone(), other_expr.clone()];
                 cx.expr_call_global(field.span, partial_cmp_path.clone(), args)
             }
-            CsFold::Combine(span, expr1, expr2) => {
-                let eq_arm =
-                    cx.arm(span, cx.pat_some(span, cx.pat_path(span, equal_path.clone())), expr1);
-                let neq_arm =
-                    cx.arm(span, cx.pat_ident(span, test_id), cx.expr_ident(span, test_id));
-                cx.expr_match(span, expr2, vec![eq_arm, neq_arm])
+            CsFold::Combine(span, mut expr1, expr2) => {
+                // When the item is an enum, this expands to
+                // ```
+                // match (expr2) {
+                //     Some(Ordering::Equal) => expr1,
+                //     cmp => cmp
+                // }
+                // ```
+                // where `expr2` is `partial_cmp(self_tag, other_tag)`, and `expr1` is a `match`
+                //  against the enum variants. This means that we begin by comparing the enum tags,
+                // before either inspecting their contents (if they match), or returning
+                // the `cmp::Ordering` of comparing the enum tags.
+                // ```
+                // match partial_cmp(self_tag, other_tag) {
+                //     Some(Ordering::Equal) => match (self, other)  {
+                //         (Self::A(self_0), Self::A(other_0)) => partial_cmp(self_0, other_0),
+                //         (Self::B(self_0), Self::B(other_0)) => partial_cmp(self_0, other_0),
+                //         _ => Some(Ordering::Equal)
+                //     }
+                //     cmp => cmp
+                // }
+                // ```
+                // If we have any certain enum layouts, flipping this results in better codegen
+                // ```
+                // match (self, other) {
+                //     (Self::A(self_0), Self::A(other_0)) => partial_cmp(self_0, other_0),
+                //     _ => partial_cmp(self_tag, other_tag)
+                // }
+                // ```
+                // Reference: https://github.com/rust-lang/rust/pull/103659#issuecomment-1328126354
+
+                if !tag_then_data
+                    && let ExprKind::Match(_, arms) = &mut expr1.kind
+                    && let Some(last) = arms.last_mut()
+                    && let PatKind::Wild = last.pat.kind {
+                        last.body = expr2;
+                        expr1
+                } else {
+                    let eq_arm =
+                        cx.arm(span, cx.pat_some(span, cx.pat_path(span, equal_path.clone())), expr1);
+                    let neq_arm =
+                        cx.arm(span, cx.pat_ident(span, test_id), cx.expr_ident(span, test_id));
+                    cx.expr_match(span, expr2, vec![eq_arm, neq_arm])
+                }
             }
             CsFold::Fieldless => cx.expr_some(span, cx.expr_path(equal_path.clone())),
         },
index d3a8c10657e8d5cdb78f40fdc10695d7685e9c50..dffb2ed8f4f392544f5d551d1ea7105c853e55db 100644 (file)
@@ -794,6 +794,7 @@ fn is_fat_ptr<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool {
         StatementKind::StorageLive(_)
         | StatementKind::StorageDead(_)
         | StatementKind::Deinit(_)
+        | StatementKind::ConstEvalCounter
         | StatementKind::Nop
         | StatementKind::FakeRead(..)
         | StatementKind::Retag { .. }
index 51450897bfc11278afe11293a8c2e92de48ef52e..49c4f1aaaefc69a9e52a68792f55f76b68471281 100644 (file)
@@ -530,6 +530,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>(
                         | StatementKind::Retag(_, _)
                         | StatementKind::AscribeUserType(_, _)
                         | StatementKind::Coverage(_)
+                        | StatementKind::ConstEvalCounter
                         | StatementKind::Nop => {}
                     }
                 }
index d9ccba07a346a1066e93beea9981566f383b15e9..32cd3a4efa227e0b0a5a77a1e0b18a25ef417474 100644 (file)
@@ -191,7 +191,7 @@ pub unsafe fn create_module<'ll>(
         //
         // FIXME(#34960)
         let cfg_llvm_root = option_env!("CFG_LLVM_ROOT").unwrap_or("");
-        let custom_llvm_used = cfg_llvm_root.trim() != "";
+        let custom_llvm_used = !cfg_llvm_root.trim().is_empty();
 
         if !custom_llvm_used && target_data_layout != llvm_data_layout {
             bug!(
index dd1ac2c74aed4fe2d628ffc17958f407a3a0a461..95aad10fdb0f9852505cd08ebffa88f6f62ac7c2 100644 (file)
@@ -36,7 +36,7 @@ pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
 
     // Arguments get assigned to by means of the function being called
     for arg in mir.args_iter() {
-        analyzer.assign(arg, mir::START_BLOCK.start_location());
+        analyzer.assign(arg, DefLocation::Argument);
     }
 
     // If there exists a local definition that dominates all uses of that local,
@@ -64,7 +64,22 @@ enum LocalKind {
     /// A scalar or a scalar pair local that is neither defined nor used.
     Unused,
     /// A scalar or a scalar pair local with a single definition that dominates all uses.
-    SSA(mir::Location),
+    SSA(DefLocation),
+}
+
+#[derive(Copy, Clone, PartialEq, Eq)]
+enum DefLocation {
+    Argument,
+    Body(Location),
+}
+
+impl DefLocation {
+    fn dominates(self, location: Location, dominators: &Dominators<mir::BasicBlock>) -> bool {
+        match self {
+            DefLocation::Argument => true,
+            DefLocation::Body(def) => def.successor_within_block().dominates(location, dominators),
+        }
+    }
 }
 
 struct LocalAnalyzer<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
@@ -74,17 +89,13 @@ struct LocalAnalyzer<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
 }
 
 impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
-    fn assign(&mut self, local: mir::Local, location: Location) {
+    fn assign(&mut self, local: mir::Local, location: DefLocation) {
         let kind = &mut self.locals[local];
         match *kind {
             LocalKind::ZST => {}
             LocalKind::Memory => {}
-            LocalKind::Unused => {
-                *kind = LocalKind::SSA(location);
-            }
-            LocalKind::SSA(_) => {
-                *kind = LocalKind::Memory;
-            }
+            LocalKind::Unused => *kind = LocalKind::SSA(location),
+            LocalKind::SSA(_) => *kind = LocalKind::Memory,
         }
     }
 
@@ -166,7 +177,7 @@ fn visit_assign(
         debug!("visit_assign(place={:?}, rvalue={:?})", place, rvalue);
 
         if let Some(local) = place.as_local() {
-            self.assign(local, location);
+            self.assign(local, DefLocation::Body(location));
             if self.locals[local] != LocalKind::Memory {
                 let decl_span = self.fx.mir.local_decls[local].source_info.span;
                 if !self.fx.rvalue_creates_operand(rvalue, decl_span) {
@@ -189,7 +200,7 @@ fn visit_local(&mut self, local: mir::Local, context: PlaceContext, location: Lo
         match context {
             PlaceContext::MutatingUse(MutatingUseContext::Call)
             | PlaceContext::MutatingUse(MutatingUseContext::Yield) => {
-                self.assign(local, location);
+                self.assign(local, DefLocation::Body(location));
             }
 
             PlaceContext::NonUse(_) | PlaceContext::MutatingUse(MutatingUseContext::Retag) => {}
index 19452c8cdc805da6068a7b37f8a871368961588b..60fbceb344d88dd360120d8d2594375b74793c60 100644 (file)
@@ -91,6 +91,7 @@ pub fn codegen_statement(&mut self, bx: &mut Bx, statement: &mir::Statement<'tcx
             mir::StatementKind::FakeRead(..)
             | mir::StatementKind::Retag { .. }
             | mir::StatementKind::AscribeUserType(..)
+            | mir::StatementKind::ConstEvalCounter
             | mir::StatementKind::Nop => {}
         }
     }
index 4709514c82e85ab70a99727065a9c2008f26dcf0..a5bc121485d8cde6a3beb7dd0b1a601b32e1c445 100644 (file)
@@ -561,8 +561,8 @@ fn binary_ptr_op(
         throw_unsup_format!("pointer arithmetic or comparison is not supported at compile-time");
     }
 
-    fn before_terminator(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> {
-        // The step limit has already been hit in a previous call to `before_terminator`.
+    fn increment_const_eval_counter(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> {
+        // The step limit has already been hit in a previous call to `increment_const_eval_counter`.
         if ecx.machine.steps_remaining == 0 {
             return Ok(());
         }
index 248953de8672828a7889da54697268517eddd90e..76ed7b80f8d81b7a69c553a2597450cd5710572a 100644 (file)
@@ -244,12 +244,18 @@ fn access_local_mut<'a>(
     }
 
     /// Called before a basic block terminator is executed.
-    /// You can use this to detect endlessly running programs.
     #[inline]
     fn before_terminator(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> {
         Ok(())
     }
 
+    /// Called when the interpreter encounters a `StatementKind::ConstEvalCounter` instruction.
+    /// You can use this to detect long or endlessly running programs.
+    #[inline]
+    fn increment_const_eval_counter(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> {
+        Ok(())
+    }
+
     /// Called before a global allocation is accessed.
     /// `def_id` is `Some` if this is the "lazy" allocation of a static.
     #[inline]
index fad4cb06cd6fe4805f2f9dacfb3feac0bf075e22..d101937fd7406cc64f214f60b0c1073024b87bc3 100644 (file)
@@ -129,6 +129,10 @@ pub fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> InterpResult<'tcx> {
             // FIXME(#73156): Handle source code coverage in const eval
             Coverage(..) => {}
 
+            ConstEvalCounter => {
+                M::increment_const_eval_counter(self)?;
+            }
+
             // Defined to do nothing. These are added by optimization passes, to avoid changing the
             // size of MIR constantly.
             Nop => {}
index cc40c2566d2e6ad60debca45850e423b9b451425..f47e3e86ebe2e0a0eedf3b14903e62d986c2c341 100644 (file)
@@ -693,6 +693,7 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
             | StatementKind::AscribeUserType(..)
             | StatementKind::Coverage(..)
             | StatementKind::Intrinsic(..)
+            | StatementKind::ConstEvalCounter
             | StatementKind::Nop => {}
         }
     }
index fab92f6f6f3ba2c2d83f4211e45a95ab6280b6f9..a2f2457487a4fc35974cb12a8f9e9e8af998320e 100644 (file)
@@ -761,6 +761,7 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
             StatementKind::StorageLive(..)
             | StatementKind::StorageDead(..)
             | StatementKind::Coverage(_)
+            | StatementKind::ConstEvalCounter
             | StatementKind::Nop => {}
         }
 
index 6398a501983cfbd61089c6902cb9baa6d81f405e..0a21a4249c8295b94ab4b2f7db068a58e8da9ba7 100644 (file)
@@ -135,7 +135,47 @@ pub fn dominators<G: ControlFlowGraph>(graph: G) -> Dominators<G::Node> {
         // This loop computes the semi[w] for w.
         semi[w] = w;
         for v in graph.predecessors(pre_order_to_real[w]) {
-            // Reachable vertices may have unreachable predecessors, so ignore any of them
+            // TL;DR: Reachable vertices may have unreachable predecessors, so ignore any of them.
+            //
+            // Ignore blocks which are not connected to the entry block.
+            //
+            // The algorithm that was used to traverse the graph and build the
+            // `pre_order_to_real` and `real_to_pre_order` vectors does so by
+            // starting from the entry block and following the successors.
+            // Therefore, any blocks not reachable from the entry block will be
+            // set to `None` in the `pre_order_to_real` vector.
+            //
+            // For example, in this graph, A and B should be skipped:
+            //
+            //           ┌─────┐
+            //           │     │
+            //           └──┬──┘
+            //              │
+            //           ┌──▼──┐              ┌─────┐
+            //           │     │              │  A  │
+            //           └──┬──┘              └──┬──┘
+            //              │                    │
+            //      ┌───────┴───────┐            │
+            //      │               │            │
+            //   ┌──▼──┐         ┌──▼──┐      ┌──▼──┐
+            //   │     │         │     │      │  B  │
+            //   └──┬──┘         └──┬──┘      └──┬──┘
+            //      │               └──────┬─────┘
+            //   ┌──▼──┐                   │
+            //   │     │                   │
+            //   └──┬──┘                ┌──▼──┐
+            //      │                   │     │
+            //      │                   └─────┘
+            //   ┌──▼──┐
+            //   │     │
+            //   └──┬──┘
+            //      │
+            //   ┌──▼──┐
+            //   │     │
+            //   └─────┘
+            //
+            // ...this may be the case if a MirPass modifies the CFG to remove
+            // or rearrange certain blocks/edges.
             let Some(v) = real_to_pre_order[v] else {
                 continue
             };
@@ -264,13 +304,18 @@ fn compress(
     }
 }
 
+/// Tracks the list of dominators for each node.
 #[derive(Clone, Debug)]
 pub struct Dominators<N: Idx> {
     post_order_rank: IndexVec<N, usize>,
+    // Even though we track only the immediate dominator of each node, it's
+    // possible to get its full list of dominators by looking up the dominator
+    // of each dominator. (See the `impl Iterator for Iter` definition).
     immediate_dominators: IndexVec<N, Option<N>>,
 }
 
 impl<Node: Idx> Dominators<Node> {
+    /// Whether the given Node has an immediate dominator.
     pub fn is_reachable(&self, node: Node) -> bool {
         self.immediate_dominators[node].is_some()
     }
@@ -280,6 +325,8 @@ pub fn immediate_dominator(&self, node: Node) -> Node {
         self.immediate_dominators[node].unwrap()
     }
 
+    /// Provides an iterator over each dominator up the CFG, for the given Node.
+    /// See the `impl Iterator for Iter` definition to understand how this works.
     pub fn dominators(&self, node: Node) -> Iter<'_, Node> {
         assert!(self.is_reachable(node), "node {node:?} is not reachable");
         Iter { dominators: self, node: Some(node) }
index 022051e008e32cfa192c60e88655f2c6f42670ae..446c6832cb7b607657a23a63e4c628d0123867cc 100644 (file)
@@ -498,6 +498,21 @@ fn print_with_analysis(tcx: TyCtxt<'_>, ppm: PpMode) -> Result<(), ErrorGuarante
             out
         }
 
+        ThirFlat => {
+            let mut out = String::new();
+            abort_on_err(rustc_hir_analysis::check_crate(tcx), tcx.sess);
+            debug!("pretty printing THIR flat");
+            for did in tcx.hir().body_owners() {
+                let _ = writeln!(
+                    out,
+                    "{:?}:\n{}\n",
+                    did,
+                    tcx.thir_flat(ty::WithOptConstParam::unknown(did))
+                );
+            }
+            out
+        }
+
         _ => unreachable!(),
     };
 
index d63ff77d8e2558bd5decf85363d07b90258c6bef..dca678dff7a793253524fe055db88b49934f9dc1 100644 (file)
@@ -100,6 +100,8 @@ lint_cstring_ptr = getting the inner pointer of a temporary `CString`
     .note = pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
     .help = for more information, see https://doc.rust-lang.org/reference/destructors.html
 
+lint_multple_supertrait_upcastable = `{$ident}` is object-safe and has multiple supertraits
+
 lint_identifier_non_ascii_char = identifier contains non-ASCII characters
 
 lint_identifier_uncommon_codepoints = identifier contains uncommon Unicode codepoints
index a3e2002da781c230eff39d72ab2452466bf118e2..1728ef70cba0a7bd817b4db0a917b9060587c9db 100644 (file)
@@ -199,6 +199,17 @@ parse_match_arm_body_without_braces = `match` arm body without braces
         } with a body
     .suggestion_use_comma_not_semicolon = use a comma to end a `match` arm expression
 
+parse_inclusive_range_extra_equals = unexpected `=` after inclusive range
+    .suggestion_remove_eq = use `..=` instead
+    .note = inclusive ranges end with a single equals sign (`..=`)
+
+parse_inclusive_range_match_arrow = unexpected `=>` after open range
+    .suggestion_add_space = add a space between the pattern and `=>`
+
+parse_inclusive_range_no_end = inclusive range with no end
+    .suggestion_open_range = use `..` instead
+    .note = inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+
 parse_struct_literal_not_allowed_here = struct literals are not allowed here
     .suggestion = surround the struct literal with parentheses
 
index 196c31302a0d2a91d9c59aa153cb7e3d78ea2b5f..af9c40a3ba5227b249221b6a1e59a5fdfe1a2c0a 100644 (file)
@@ -160,6 +160,8 @@ pub fn set(&self, features: &mut Features, span: Span) {
     (active, intrinsics, "1.0.0", None, None),
     /// Allows using `#[lang = ".."]` attribute for linking items to special compiler logic.
     (active, lang_items, "1.0.0", None, None),
+    /// Allows the `multiple_supertrait_upcastable` lint.
+    (active, multiple_supertrait_upcastable, "CURRENT_RUSTC_VERSION", None, None),
     /// Allows using `#[omit_gdb_pretty_printer_section]`.
     (active, omit_gdb_pretty_printer_section, "1.5.0", None, None),
     /// Allows using `#[prelude_import]` on glob `use` items.
index e15b7c897302458692029128b25b579b6653b8e6..67bcfb1cb70fc0c32605101035fc35fdfdcde64c 100644 (file)
@@ -841,7 +841,7 @@ fn check_object_unsafe_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitItem
         _ => {}
     }
     if !trait_should_be_self.is_empty() {
-        if tcx.object_safety_violations(trait_def_id).is_empty() {
+        if tcx.check_is_object_safe(trait_def_id) {
             return;
         }
         let sugg = trait_should_be_self.iter().map(|span| (*span, "Self".to_string())).collect();
index d3b5778ba3b7d61130b41fde472f4d08deec7689..bbde59c953a026375ef708e93141d0691d3fd2c5 100644 (file)
@@ -169,7 +169,7 @@ fn check_object_overlap<'tcx>(
         });
 
         for component_def_id in component_def_ids {
-            if !tcx.is_object_safe(component_def_id) {
+            if !tcx.check_is_object_safe(component_def_id) {
                 // Without the 'object_safe_for_dispatch' feature this is an error
                 // which will be reported by wfcheck. Ignore it here.
                 // This is tested by `coherence-impl-trait-for-trait-object-safe.rs`.
index 1a0715a91cb0c0e8718401a00987bc54803ae36a..ade9c037c519405d04470edbf8c5741f8e9cba07 100644 (file)
@@ -1823,7 +1823,7 @@ fn add_impl_trait_explanation<'a>(
                         .trait_ref()
                         .and_then(|t| t.trait_def_id())
                         .map_or(false, |def_id| {
-                            fcx.tcx.object_safety_violations(def_id).is_empty()
+                            fcx.tcx.check_is_object_safe(def_id)
                         })
                 })
             }
index e59715b706b29c0c4da6afde7ba99fe9b5a3f737..f7e3e4a1cc09ee2583ecbce9e4c0c2269e3c8c5a 100644 (file)
@@ -26,7 +26,7 @@
 use rustc_index::vec::IndexVec;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::subst::GenericArg;
-use rustc_middle::ty::{self, BoundVar, List};
+use rustc_middle::ty::{self, List};
 use rustc_span::source_map::Span;
 
 pub use rustc_middle::infer::canonical::*;
@@ -87,12 +87,13 @@ fn instantiate_canonical_vars(
         variables: &List<CanonicalVarInfo<'tcx>>,
         universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex,
     ) -> CanonicalVarValues<'tcx> {
-        let var_values: IndexVec<BoundVar, GenericArg<'tcx>> = variables
-            .iter()
-            .map(|info| self.instantiate_canonical_var(span, info, &universe_map))
-            .collect();
-
-        CanonicalVarValues { var_values }
+        CanonicalVarValues {
+            var_values: self.tcx.mk_substs(
+                variables
+                    .iter()
+                    .map(|info| self.instantiate_canonical_var(span, info, &universe_map)),
+            ),
+        }
     }
 
     /// Given the "info" about a canonical variable, creates a fresh
index 9174bd524bee6d50b74246c8ea0e8df156907041..3e8e7734a5a5de61d34fefba70cf674f0be512d7 100644 (file)
@@ -482,11 +482,8 @@ fn query_response_substitution_guess<R>(
         // given variable in the loop above, use that. Otherwise, use
         // a fresh inference variable.
         let result_subst = CanonicalVarValues {
-            var_values: query_response
-                .variables
-                .iter()
-                .enumerate()
-                .map(|(index, info)| {
+            var_values: self.tcx.mk_substs(query_response.variables.iter().enumerate().map(
+                |(index, info)| {
                     if info.is_existential() {
                         match opt_values[BoundVar::new(index)] {
                             Some(k) => k,
@@ -499,8 +496,8 @@ fn query_response_substitution_guess<R>(
                             universe_map[u.as_usize()]
                         })
                     }
-                })
-                .collect(),
+                },
+            )),
         };
 
         let mut obligations = vec![];
index 389afe22eb7672afe16c801ca97c9b1c940390fe..e77f2d37b7dae8d5c6314c8f22092d28d05b95b1 100644 (file)
@@ -72,16 +72,15 @@ pub(super) fn substitute_value<'tcx, T>(
         value
     } else {
         let delegate = FnMutDelegate {
-            regions: &mut |br: ty::BoundRegion| match var_values.var_values[br.var].unpack() {
+            regions: &mut |br: ty::BoundRegion| match var_values[br.var].unpack() {
                 GenericArgKind::Lifetime(l) => l,
                 r => bug!("{:?} is a region but value is {:?}", br, r),
             },
-            types: &mut |bound_ty: ty::BoundTy| match var_values.var_values[bound_ty.var].unpack() {
+            types: &mut |bound_ty: ty::BoundTy| match var_values[bound_ty.var].unpack() {
                 GenericArgKind::Type(ty) => ty,
                 r => bug!("{:?} is a type but value is {:?}", bound_ty, r),
             },
-            consts: &mut |bound_ct: ty::BoundVar, _| match var_values.var_values[bound_ct].unpack()
-            {
+            consts: &mut |bound_ct: ty::BoundVar, _| match var_values[bound_ct].unpack() {
                 GenericArgKind::Const(ct) => ct,
                 c => bug!("{:?} is a const but value is {:?}", bound_ct, c),
             },
index f94bc4d4c66ac9d0fd872586a12308b6aa86731d..52a4e0e74181f78092fb85230051352b995a23ac 100644 (file)
@@ -802,6 +802,7 @@ macro_rules! tracked {
     tracked!(teach, true);
     tracked!(thinlto, Some(true));
     tracked!(thir_unsafeck, true);
+    tracked!(tiny_const_eval_limit, true);
     tracked!(tls_model, Some(TlsModel::GeneralDynamic));
     tracked!(trait_solver, TraitSolver::Chalk);
     tracked!(translate_remapped_path_to_local_path, false);
index d6be4da03286f75f1e4868e5bac454b345008a8b..ba15dbd86cfa4caff089c597a84391a69ff7a400 100644 (file)
@@ -64,6 +64,7 @@
 mod levels;
 mod lints;
 mod methods;
+mod multiple_supertrait_upcastable;
 mod non_ascii_idents;
 mod non_fmt_panic;
 mod nonstandard_style;
@@ -98,6 +99,7 @@
 use internal::*;
 use let_underscore::*;
 use methods::*;
+use multiple_supertrait_upcastable::*;
 use non_ascii_idents::*;
 use non_fmt_panic::NonPanicFmt;
 use nonstandard_style::*;
@@ -232,6 +234,7 @@ fn lint_mod(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
             InvalidAtomicOrdering: InvalidAtomicOrdering,
             NamedAsmLabels: NamedAsmLabels,
             OpaqueHiddenInferredBound: OpaqueHiddenInferredBound,
+            MultipleSupertraitUpcastable: MultipleSupertraitUpcastable,
         ]
     ]
 );
index c997d8945d16ebdf2d5ac2f4a3f9dbee0e41d8b3..0c1019545f382f8a5ce425a871a5aa1cc225f149 100644 (file)
@@ -917,6 +917,13 @@ pub struct CStringPtr {
     pub unwrap: Span,
 }
 
+// multiple_supertrait_upcastable.rs
+#[derive(LintDiagnostic)]
+#[diag(lint_multple_supertrait_upcastable)]
+pub struct MultipleSupertraitUpcastable {
+    pub ident: Ident,
+}
+
 // non_ascii_idents.rs
 #[derive(LintDiagnostic)]
 #[diag(lint_identifier_non_ascii_char)]
diff --git a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs
new file mode 100644 (file)
index 0000000..c2ed0e1
--- /dev/null
@@ -0,0 +1,60 @@
+use crate::{LateContext, LateLintPass, LintContext};
+
+use rustc_hir as hir;
+use rustc_span::sym;
+
+declare_lint! {
+    /// The `multiple_supertrait_upcastable` lint detects when an object-safe trait has multiple
+    /// supertraits.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// trait A {}
+    /// trait B {}
+    ///
+    /// #[warn(multiple_supertrait_upcastable)]
+    /// trait C: A + B {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// To support upcasting with multiple supertraits, we need to store multiple vtables and this
+    /// can result in extra space overhead, even if no code actually uses upcasting.
+    /// This lint allows users to identify when such scenarios occur and to decide whether the
+    /// additional overhead is justified.
+    pub MULTIPLE_SUPERTRAIT_UPCASTABLE,
+    Allow,
+    "detect when an object-safe trait has multiple supertraits",
+    @feature_gate = sym::multiple_supertrait_upcastable;
+}
+
+declare_lint_pass!(MultipleSupertraitUpcastable => [MULTIPLE_SUPERTRAIT_UPCASTABLE]);
+
+impl<'tcx> LateLintPass<'tcx> for MultipleSupertraitUpcastable {
+    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
+        let def_id = item.owner_id.to_def_id();
+        // NOTE(nbdd0121): use `object_safety_violations` instead of `check_is_object_safe` because
+        // the latter will report `where_clause_object_safety` lint.
+        if let hir::ItemKind::Trait(_, _, _, _, _) = item.kind
+            && cx.tcx.object_safety_violations(def_id).is_empty()
+        {
+            let direct_super_traits_iter = cx.tcx
+                    .super_predicates_of(def_id)
+                    .predicates
+                    .into_iter()
+                    .filter_map(|(pred, _)| pred.to_opt_poly_trait_pred());
+            if direct_super_traits_iter.count() > 1 {
+                cx.emit_spanned_lint(
+                    MULTIPLE_SUPERTRAIT_UPCASTABLE,
+                    cx.tcx.def_span(def_id),
+                    crate::lints::MultipleSupertraitUpcastable {
+                        ident: item.ident
+                    },
+                );
+            }
+        }
+    }
+}
index b6481d70bc8898fe2de912d9f382e90233fa28bd..4a38ab2159fddcd76f68e494f8f07b2ce4c2a147 100644 (file)
     ///
     /// ### Explanation
     ///
-    /// Previously, there were very like checks being performed on `#[doc(..)]`
-    /// unlike the other attributes. It'll now catch all the issues that it
-    /// silently ignored previously.
+    /// Previously, incorrect usage of the `#[doc(..)]` attribute was not
+    /// being validated. Usually these should be rejected as a hard error,
+    /// but this lint was introduced to avoid breaking any existing
+    /// crates which included them.
+    ///
+    /// This is a [future-incompatible] lint to transition this to a hard
+    /// error in the future. See [issue #82730] for more details.
+    ///
+    /// [issue #82730]: https://github.com/rust-lang/rust/issues/82730
     pub INVALID_DOC_ATTRIBUTES,
     Warn,
     "detects invalid `#[doc(...)]` attributes",
index 68335a9b01a56c2ce9d669c7f619098eb2b299ba..29507ff3a86c1dc2f27e66027f67e46ceea53331 100644 (file)
@@ -1415,7 +1415,7 @@ fn encode_mir(&mut self) {
             if encode_opt {
                 record!(self.tables.optimized_mir[def_id.to_def_id()] <- tcx.optimized_mir(def_id));
 
-                if let DefKind::Generator = self.tcx.def_kind(def_id) {
+                if let DefKind::Generator = self.tcx.def_kind(def_id) && tcx.sess.opts.unstable_opts.drop_tracking_mir {
                     record!(self.tables.mir_generator_witnesses[def_id.to_def_id()] <- tcx.mir_generator_witnesses(def_id));
                 }
             }
index 43583b5723e698f763e7c03f5a35b19b41e25108..6e130bbf7d8284403fccb3af90c7e1a229a08c86 100644 (file)
 use crate::mir::ConstraintCategory;
 use crate::ty::subst::GenericArg;
 use crate::ty::{self, BoundVar, List, Region, Ty, TyCtxt};
-use rustc_index::vec::IndexVec;
 use rustc_macros::HashStable;
 use smallvec::SmallVec;
-use std::iter;
 use std::ops::Index;
 
 /// A "canonicalized" type `V` is one where all free inference
@@ -62,23 +60,23 @@ fn try_fold_with<F: ty::FallibleTypeFolder<'tcx>>(
 /// vectors with the original values that were replaced by canonical
 /// variables. You will need to supply it later to instantiate the
 /// canonicalized query response.
-#[derive(Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable)]
 #[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
 pub struct CanonicalVarValues<'tcx> {
-    pub var_values: IndexVec<BoundVar, GenericArg<'tcx>>,
+    pub var_values: ty::SubstsRef<'tcx>,
 }
 
 impl CanonicalVarValues<'_> {
     pub fn is_identity(&self) -> bool {
-        self.var_values.iter_enumerated().all(|(bv, arg)| match arg.unpack() {
+        self.var_values.iter().enumerate().all(|(bv, arg)| match arg.unpack() {
             ty::GenericArgKind::Lifetime(r) => {
-                matches!(*r, ty::ReLateBound(ty::INNERMOST, br) if br.var == bv)
+                matches!(*r, ty::ReLateBound(ty::INNERMOST, br) if br.var.as_usize() == bv)
             }
             ty::GenericArgKind::Type(ty) => {
-                matches!(*ty.kind(), ty::Bound(ty::INNERMOST, bt) if bt.var == bv)
+                matches!(*ty.kind(), ty::Bound(ty::INNERMOST, bt) if bt.var.as_usize() == bv)
             }
             ty::GenericArgKind::Const(ct) => {
-                matches!(ct.kind(), ty::ConstKind::Bound(ty::INNERMOST, bc) if bc == bv)
+                matches!(ct.kind(), ty::ConstKind::Bound(ty::INNERMOST, bc) if bc.as_usize() == bv)
             }
         })
     }
@@ -339,57 +337,57 @@ pub fn unchecked_rebind<W>(self, value: W) -> Canonical<'tcx, W> {
 }
 
 impl<'tcx> CanonicalVarValues<'tcx> {
+    // Given a list of canonical variables, construct a set of values which are
+    // the identity response.
+    pub fn make_identity(
+        tcx: TyCtxt<'tcx>,
+        infos: CanonicalVarInfos<'tcx>,
+    ) -> CanonicalVarValues<'tcx> {
+        CanonicalVarValues {
+            var_values: tcx.mk_substs(infos.iter().enumerate().map(
+                |(i, info)| -> ty::GenericArg<'tcx> {
+                    match info.kind {
+                        CanonicalVarKind::Ty(_) | CanonicalVarKind::PlaceholderTy(_) => tcx
+                            .mk_ty(ty::Bound(ty::INNERMOST, ty::BoundVar::from_usize(i).into()))
+                            .into(),
+                        CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => {
+                            let br = ty::BoundRegion {
+                                var: ty::BoundVar::from_usize(i),
+                                kind: ty::BrAnon(i as u32, None),
+                            };
+                            tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)).into()
+                        }
+                        CanonicalVarKind::Const(_, ty)
+                        | CanonicalVarKind::PlaceholderConst(_, ty) => tcx
+                            .mk_const(
+                                ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from_usize(i)),
+                                ty,
+                            )
+                            .into(),
+                    }
+                },
+            )),
+        }
+    }
+
     /// Creates dummy var values which should not be used in a
     /// canonical response.
     pub fn dummy() -> CanonicalVarValues<'tcx> {
-        CanonicalVarValues { var_values: Default::default() }
+        CanonicalVarValues { var_values: ty::List::empty() }
     }
 
     #[inline]
     pub fn len(&self) -> usize {
         self.var_values.len()
     }
-
-    /// Makes an identity substitution from this one: each bound var
-    /// is matched to the same bound var, preserving the original kinds.
-    /// For example, if we have:
-    /// `self.var_values == [Type(u32), Lifetime('a), Type(u64)]`
-    /// we'll return a substitution `subst` with:
-    /// `subst.var_values == [Type(^0), Lifetime(^1), Type(^2)]`.
-    pub fn make_identity(&self, tcx: TyCtxt<'tcx>) -> Self {
-        use crate::ty::subst::GenericArgKind;
-
-        CanonicalVarValues {
-            var_values: iter::zip(&self.var_values, 0..)
-                .map(|(kind, i)| match kind.unpack() {
-                    GenericArgKind::Type(..) => {
-                        tcx.mk_ty(ty::Bound(ty::INNERMOST, ty::BoundVar::from_u32(i).into())).into()
-                    }
-                    GenericArgKind::Lifetime(..) => {
-                        let br = ty::BoundRegion {
-                            var: ty::BoundVar::from_u32(i),
-                            kind: ty::BrAnon(i, None),
-                        };
-                        tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)).into()
-                    }
-                    GenericArgKind::Const(ct) => tcx
-                        .mk_const(
-                            ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from_u32(i)),
-                            ct.ty(),
-                        )
-                        .into(),
-                })
-                .collect(),
-        }
-    }
 }
 
 impl<'a, 'tcx> IntoIterator for &'a CanonicalVarValues<'tcx> {
     type Item = GenericArg<'tcx>;
-    type IntoIter = ::std::iter::Cloned<::std::slice::Iter<'a, GenericArg<'tcx>>>;
+    type IntoIter = ::std::iter::Copied<::std::slice::Iter<'a, GenericArg<'tcx>>>;
 
     fn into_iter(self) -> Self::IntoIter {
-        self.var_values.iter().cloned()
+        self.var_values.iter()
     }
 }
 
@@ -397,6 +395,6 @@ impl<'tcx> Index<BoundVar> for CanonicalVarValues<'tcx> {
     type Output = GenericArg<'tcx>;
 
     fn index(&self, value: BoundVar) -> &GenericArg<'tcx> {
-        &self.var_values[value]
+        &self.var_values[value.as_usize()]
     }
 }
index bc3c38fdb1c2ad8427222062882f1f1823b5645d..552af589bec59b12f3b2f40516f7ef7f6dce5b37 100644 (file)
@@ -1463,6 +1463,7 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
             }
             Coverage(box ref coverage) => write!(fmt, "Coverage::{:?}", coverage.kind),
             Intrinsic(box ref intrinsic) => write!(fmt, "{intrinsic}"),
+            ConstEvalCounter => write!(fmt, "ConstEvalCounter"),
             Nop => write!(fmt, "nop"),
         }
     }
index fb1e3d233a2a5e8f00d29f4801a505dcd79b2933..1610ae1ce1480937d3b6fc1e8b155b6f4480f871 100644 (file)
@@ -250,6 +250,7 @@ pub fn statement_kind_name(statement: &Statement<'_>) -> &'static str {
         AscribeUserType(..) => "AscribeUserType",
         Coverage(..) => "Coverage",
         Intrinsic(..) => "Intrinsic",
+        ConstEvalCounter => "ConstEvalCounter",
         Nop => "Nop",
     }
 }
index 52c2b10cbbea97e286650d84ce8bf4a79be35a23..549bc65d6d79c7858a144fd038c107f1a07d85e5 100644 (file)
@@ -355,6 +355,12 @@ pub enum StatementKind<'tcx> {
     /// This avoids adding a new block and a terminator for simple intrinsics.
     Intrinsic(Box<NonDivergingIntrinsic<'tcx>>),
 
+    /// Instructs the const eval interpreter to increment a counter; this counter is used to track
+    /// how many steps the interpreter has taken. It is used to prevent the user from writing const
+    /// code that runs for too long or infinitely. Other than in the const eval interpreter, this
+    /// is a no-op.
+    ConstEvalCounter,
+
     /// No-op. Useful for deleting instructions without affecting statement indices.
     Nop,
 }
index 1a264d2d5af9a0d6ab1d8eebc2aaba14b9bde5ed..3ddac5e11fbc53bea3811686fdee4076d6d7a89e 100644 (file)
@@ -427,6 +427,7 @@ fn super_statement(&mut self,
                             }
                         }
                     }
+                    StatementKind::ConstEvalCounter => {}
                     StatementKind::Nop => {}
                 }
             }
index a8c562940e0ed990c12f8ad7409906f0f73293dd..49ad887f26d66fed282ed0b14a4720fabf9f3346 100644 (file)
         desc { |tcx| "constructing THIR tree for `{}`", tcx.def_path_str(key.did.to_def_id()) }
     }
 
+    /// Create a list-like THIR representation for debugging.
+    query thir_flat(key: ty::WithOptConstParam<LocalDefId>) -> String {
+        no_hash
+        arena_cache
+        desc { |tcx| "constructing flat THIR representation for `{}`", tcx.def_path_str(key.did.to_def_id()) }
+    }
+
     /// Set of all the `DefId`s in this crate that have MIR associated with
     /// them. This includes all the body owners, but also things like struct
     /// constructors.
     query object_safety_violations(trait_id: DefId) -> &'tcx [traits::ObjectSafetyViolation] {
         desc { |tcx| "determining object safety of trait `{}`", tcx.def_path_str(trait_id) }
     }
+    query check_is_object_safe(trait_id: DefId) -> bool {
+        desc { |tcx| "checking if trait `{}` is object safe", tcx.def_path_str(trait_id) }
+    }
 
     /// Gets the ParameterEnvironment for a given item; this environment
     /// will be in "user-facing" mode, meaning that it is suitable for
index 5f320708c8416944466a25137159b95386baee11..6f2dac467532cdfb50e2b54b24276ff7278719ee 100644 (file)
@@ -29,6 +29,7 @@
 use std::fmt;
 use std::ops::Index;
 
+pub mod print;
 pub mod visit;
 
 macro_rules! thir_with_elements {
diff --git a/compiler/rustc_middle/src/thir/print.rs b/compiler/rustc_middle/src/thir/print.rs
new file mode 100644 (file)
index 0000000..60b903e
--- /dev/null
@@ -0,0 +1,881 @@
+use crate::thir::*;
+use crate::ty::{self, TyCtxt};
+
+use std::fmt::{self, Write};
+
+impl<'tcx> TyCtxt<'tcx> {
+    pub fn thir_tree_representation<'a>(self, thir: &'a Thir<'tcx>) -> String {
+        let mut printer = ThirPrinter::new(thir);
+        printer.print();
+        printer.into_buffer()
+    }
+}
+
+struct ThirPrinter<'a, 'tcx> {
+    thir: &'a Thir<'tcx>,
+    fmt: String,
+}
+
+const INDENT: &str = "    ";
+
+macro_rules! print_indented {
+    ($writer:ident, $s:expr, $indent_lvl:expr) => {
+        let indent = (0..$indent_lvl).map(|_| INDENT).collect::<Vec<_>>().concat();
+        writeln!($writer, "{}{}", indent, $s).expect("unable to write to ThirPrinter");
+    };
+}
+
+impl<'a, 'tcx> Write for ThirPrinter<'a, 'tcx> {
+    fn write_str(&mut self, s: &str) -> fmt::Result {
+        self.fmt.push_str(s);
+        Ok(())
+    }
+}
+
+impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
+    fn new(thir: &'a Thir<'tcx>) -> Self {
+        Self { thir, fmt: String::new() }
+    }
+
+    fn print(&mut self) {
+        print_indented!(self, "params: [", 0);
+        for param in self.thir.params.iter() {
+            self.print_param(param, 1);
+        }
+        print_indented!(self, "]", 0);
+
+        print_indented!(self, "body:", 0);
+        let expr = ExprId::from_usize(self.thir.exprs.len() - 1);
+        self.print_expr(expr, 1);
+    }
+
+    fn into_buffer(self) -> String {
+        self.fmt
+    }
+
+    fn print_param(&mut self, param: &Param<'tcx>, depth_lvl: usize) {
+        let Param { pat, ty, ty_span, self_kind, hir_id } = param;
+
+        print_indented!(self, "Param {", depth_lvl);
+        print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 1);
+        print_indented!(self, format!("ty_span: {:?}", ty_span), depth_lvl + 1);
+        print_indented!(self, format!("self_kind: {:?}", self_kind), depth_lvl + 1);
+        print_indented!(self, format!("hir_id: {:?}", hir_id), depth_lvl + 1);
+
+        if let Some(pat) = pat {
+            print_indented!(self, "param: Some( ", depth_lvl + 1);
+            self.print_pat(pat, depth_lvl + 2);
+            print_indented!(self, ")", depth_lvl + 1);
+        } else {
+            print_indented!(self, "param: None", depth_lvl + 1);
+        }
+
+        print_indented!(self, "}", depth_lvl);
+    }
+
+    fn print_block(&mut self, block_id: BlockId, depth_lvl: usize) {
+        let Block {
+            targeted_by_break,
+            opt_destruction_scope,
+            span,
+            region_scope,
+            stmts,
+            expr,
+            safety_mode,
+        } = &self.thir.blocks[block_id];
+
+        print_indented!(self, "Block {", depth_lvl);
+        print_indented!(self, format!("targeted_by_break: {}", targeted_by_break), depth_lvl + 1);
+        print_indented!(
+            self,
+            format!("opt_destruction_scope: {:?}", opt_destruction_scope),
+            depth_lvl + 1
+        );
+        print_indented!(self, format!("span: {:?}", span), depth_lvl + 1);
+        print_indented!(self, format!("region_scope: {:?}", region_scope), depth_lvl + 1);
+        print_indented!(self, format!("safety_mode: {:?}", safety_mode), depth_lvl + 1);
+
+        if stmts.len() > 0 {
+            print_indented!(self, "stmts: [", depth_lvl + 1);
+            for stmt in stmts.iter() {
+                self.print_stmt(*stmt, depth_lvl + 2);
+            }
+            print_indented!(self, "]", depth_lvl + 1);
+        } else {
+            print_indented!(self, "stmts: []", depth_lvl + 1);
+        }
+
+        if let Some(expr_id) = expr {
+            print_indented!(self, "expr:", depth_lvl + 1);
+            self.print_expr(*expr_id, depth_lvl + 2);
+        } else {
+            print_indented!(self, "expr: []", depth_lvl + 1);
+        }
+
+        print_indented!(self, "}", depth_lvl);
+    }
+
+    fn print_stmt(&mut self, stmt_id: StmtId, depth_lvl: usize) {
+        let Stmt { kind, opt_destruction_scope } = &self.thir.stmts[stmt_id];
+
+        print_indented!(self, "Stmt {", depth_lvl);
+        print_indented!(
+            self,
+            format!("opt_destruction_scope: {:?}", opt_destruction_scope),
+            depth_lvl + 1
+        );
+
+        match kind {
+            StmtKind::Expr { scope, expr } => {
+                print_indented!(self, "kind: Expr {", depth_lvl + 1);
+                print_indented!(self, format!("scope: {:?}", scope), depth_lvl + 2);
+                print_indented!(self, "expr:", depth_lvl + 2);
+                self.print_expr(*expr, depth_lvl + 3);
+                print_indented!(self, "}", depth_lvl + 1);
+            }
+            StmtKind::Let {
+                remainder_scope,
+                init_scope,
+                pattern,
+                initializer,
+                else_block,
+                lint_level,
+            } => {
+                print_indented!(self, "kind: Let {", depth_lvl + 1);
+                print_indented!(
+                    self,
+                    format!("remainder_scope: {:?}", remainder_scope),
+                    depth_lvl + 2
+                );
+                print_indented!(self, format!("init_scope: {:?}", init_scope), depth_lvl + 2);
+
+                print_indented!(self, "pattern: ", depth_lvl + 2);
+                self.print_pat(pattern, depth_lvl + 3);
+                print_indented!(self, ",", depth_lvl + 2);
+
+                if let Some(init) = initializer {
+                    print_indented!(self, "initializer: Some(", depth_lvl + 2);
+                    self.print_expr(*init, depth_lvl + 3);
+                    print_indented!(self, ")", depth_lvl + 2);
+                } else {
+                    print_indented!(self, "initializer: None", depth_lvl + 2);
+                }
+
+                if let Some(else_block) = else_block {
+                    print_indented!(self, "else_block: Some(", depth_lvl + 2);
+                    self.print_block(*else_block, depth_lvl + 3);
+                    print_indented!(self, ")", depth_lvl + 2);
+                } else {
+                    print_indented!(self, "else_block: None", depth_lvl + 2);
+                }
+
+                print_indented!(self, format!("lint_level: {:?}", lint_level), depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl + 1);
+            }
+        }
+
+        print_indented!(self, "}", depth_lvl);
+    }
+
+    fn print_expr(&mut self, expr: ExprId, depth_lvl: usize) {
+        let Expr { ty, temp_lifetime, span, kind } = &self.thir[expr];
+        print_indented!(self, "Expr {", depth_lvl);
+        print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 1);
+        print_indented!(self, format!("temp_lifetime: {:?}", temp_lifetime), depth_lvl + 1);
+        print_indented!(self, format!("span: {:?}", span), depth_lvl + 1);
+        print_indented!(self, "kind: ", depth_lvl + 1);
+        self.print_expr_kind(kind, depth_lvl + 2);
+        print_indented!(self, "}", depth_lvl);
+    }
+
+    fn print_expr_kind(&mut self, expr_kind: &ExprKind<'tcx>, depth_lvl: usize) {
+        use rustc_middle::thir::ExprKind::*;
+
+        match expr_kind {
+            Scope { region_scope, value, lint_level } => {
+                print_indented!(self, "Scope {", depth_lvl);
+                print_indented!(self, format!("region_scope: {:?}", region_scope), depth_lvl + 1);
+                print_indented!(self, format!("lint_level: {:?}", lint_level), depth_lvl + 1);
+                print_indented!(self, "value:", depth_lvl + 1);
+                self.print_expr(*value, depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl);
+            }
+            Box { value } => {
+                print_indented!(self, "Box {", depth_lvl);
+                self.print_expr(*value, depth_lvl + 1);
+                print_indented!(self, "}", depth_lvl);
+            }
+            If { if_then_scope, cond, then, else_opt } => {
+                print_indented!(self, "If {", depth_lvl);
+                print_indented!(self, format!("if_then_scope: {:?}", if_then_scope), depth_lvl + 1);
+                print_indented!(self, "cond:", depth_lvl + 1);
+                self.print_expr(*cond, depth_lvl + 2);
+                print_indented!(self, "then:", depth_lvl + 1);
+                self.print_expr(*then, depth_lvl + 2);
+
+                if let Some(else_expr) = else_opt {
+                    print_indented!(self, "else:", depth_lvl + 1);
+                    self.print_expr(*else_expr, depth_lvl + 2);
+                }
+
+                print_indented!(self, "}", depth_lvl);
+            }
+            Call { fun, args, ty, from_hir_call, fn_span } => {
+                print_indented!(self, "Call {", depth_lvl);
+                print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 1);
+                print_indented!(self, format!("from_hir_call: {}", from_hir_call), depth_lvl + 1);
+                print_indented!(self, format!("fn_span: {:?}", fn_span), depth_lvl + 1);
+                print_indented!(self, "fun:", depth_lvl + 1);
+                self.print_expr(*fun, depth_lvl + 2);
+
+                if args.len() > 0 {
+                    print_indented!(self, "args: [", depth_lvl + 1);
+                    for arg in args.iter() {
+                        self.print_expr(*arg, depth_lvl + 2);
+                    }
+                    print_indented!(self, "]", depth_lvl + 1);
+                } else {
+                    print_indented!(self, "args: []", depth_lvl + 1);
+                }
+
+                print_indented!(self, "}", depth_lvl);
+            }
+            Deref { arg } => {
+                print_indented!(self, "Deref {", depth_lvl);
+                self.print_expr(*arg, depth_lvl + 1);
+                print_indented!(self, "}", depth_lvl);
+            }
+            Binary { op, lhs, rhs } => {
+                print_indented!(self, "Binary {", depth_lvl);
+                print_indented!(self, format!("op: {:?}", op), depth_lvl + 1);
+                print_indented!(self, "lhs:", depth_lvl + 1);
+                self.print_expr(*lhs, depth_lvl + 2);
+                print_indented!(self, "rhs:", depth_lvl + 1);
+                self.print_expr(*rhs, depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl);
+            }
+            LogicalOp { op, lhs, rhs } => {
+                print_indented!(self, "LogicalOp {", depth_lvl);
+                print_indented!(self, format!("op: {:?}", op), depth_lvl + 1);
+                print_indented!(self, "lhs:", depth_lvl + 1);
+                self.print_expr(*lhs, depth_lvl + 2);
+                print_indented!(self, "rhs:", depth_lvl + 1);
+                self.print_expr(*rhs, depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl);
+            }
+            Unary { op, arg } => {
+                print_indented!(self, "Unary {", depth_lvl);
+                print_indented!(self, format!("op: {:?}", op), depth_lvl + 1);
+                print_indented!(self, "arg:", depth_lvl + 1);
+                self.print_expr(*arg, depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl);
+            }
+            Cast { source } => {
+                print_indented!(self, "Cast {", depth_lvl);
+                print_indented!(self, "source:", depth_lvl + 1);
+                self.print_expr(*source, depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl);
+            }
+            Use { source } => {
+                print_indented!(self, "Use {", depth_lvl);
+                print_indented!(self, "source:", depth_lvl + 1);
+                self.print_expr(*source, depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl);
+            }
+            NeverToAny { source } => {
+                print_indented!(self, "NeverToAny {", depth_lvl);
+                print_indented!(self, "source:", depth_lvl + 1);
+                self.print_expr(*source, depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl);
+            }
+            Pointer { cast, source } => {
+                print_indented!(self, "Pointer {", depth_lvl);
+                print_indented!(self, format!("cast: {:?}", cast), depth_lvl + 1);
+                print_indented!(self, "source:", depth_lvl + 1);
+                self.print_expr(*source, depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl);
+            }
+            Loop { body } => {
+                print_indented!(self, "Loop (", depth_lvl);
+                print_indented!(self, "body:", depth_lvl + 1);
+                self.print_expr(*body, depth_lvl + 2);
+                print_indented!(self, ")", depth_lvl);
+            }
+            Let { expr, pat } => {
+                print_indented!(self, "Let {", depth_lvl);
+                print_indented!(self, "expr:", depth_lvl + 1);
+                self.print_expr(*expr, depth_lvl + 2);
+                print_indented!(self, format!("pat: {:?}", pat), depth_lvl + 1);
+                print_indented!(self, "}", depth_lvl);
+            }
+            Match { scrutinee, arms } => {
+                print_indented!(self, "Match {", depth_lvl);
+                print_indented!(self, "scrutinee:", depth_lvl + 1);
+                self.print_expr(*scrutinee, depth_lvl + 2);
+
+                print_indented!(self, "arms: [", depth_lvl + 1);
+                for arm_id in arms.iter() {
+                    self.print_arm(*arm_id, depth_lvl + 2);
+                }
+                print_indented!(self, "]", depth_lvl + 1);
+                print_indented!(self, "}", depth_lvl);
+            }
+            Block { block } => self.print_block(*block, depth_lvl),
+            Assign { lhs, rhs } => {
+                print_indented!(self, "Assign {", depth_lvl);
+                print_indented!(self, "lhs:", depth_lvl + 1);
+                self.print_expr(*lhs, depth_lvl + 2);
+                print_indented!(self, "rhs:", depth_lvl + 1);
+                self.print_expr(*rhs, depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl);
+            }
+            AssignOp { op, lhs, rhs } => {
+                print_indented!(self, "AssignOp {", depth_lvl);
+                print_indented!(self, format!("op: {:?}", op), depth_lvl + 1);
+                print_indented!(self, "lhs:", depth_lvl + 1);
+                self.print_expr(*lhs, depth_lvl + 2);
+                print_indented!(self, "rhs:", depth_lvl + 1);
+                self.print_expr(*rhs, depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl);
+            }
+            Field { lhs, variant_index, name } => {
+                print_indented!(self, "Field {", depth_lvl);
+                print_indented!(self, format!("variant_index: {:?}", variant_index), depth_lvl + 1);
+                print_indented!(self, format!("name: {:?}", name), depth_lvl + 1);
+                print_indented!(self, "lhs:", depth_lvl + 1);
+                self.print_expr(*lhs, depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl);
+            }
+            Index { lhs, index } => {
+                print_indented!(self, "Index {", depth_lvl);
+                print_indented!(self, format!("index: {:?}", index), depth_lvl + 1);
+                print_indented!(self, "lhs:", depth_lvl + 1);
+                self.print_expr(*lhs, depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl);
+            }
+            VarRef { id } => {
+                print_indented!(self, "VarRef {", depth_lvl);
+                print_indented!(self, format!("id: {:?}", id), depth_lvl + 1);
+                print_indented!(self, "}", depth_lvl);
+            }
+            UpvarRef { closure_def_id, var_hir_id } => {
+                print_indented!(self, "UpvarRef {", depth_lvl);
+                print_indented!(
+                    self,
+                    format!("closure_def_id: {:?}", closure_def_id),
+                    depth_lvl + 1
+                );
+                print_indented!(self, format!("var_hir_id: {:?}", var_hir_id), depth_lvl + 1);
+                print_indented!(self, "}", depth_lvl);
+            }
+            Borrow { borrow_kind, arg } => {
+                print_indented!(self, "Borrow (", depth_lvl);
+                print_indented!(self, format!("borrow_kind: {:?}", borrow_kind), depth_lvl + 1);
+                print_indented!(self, "arg:", depth_lvl + 1);
+                self.print_expr(*arg, depth_lvl + 2);
+                print_indented!(self, ")", depth_lvl);
+            }
+            AddressOf { mutability, arg } => {
+                print_indented!(self, "AddressOf {", depth_lvl);
+                print_indented!(self, format!("mutability: {:?}", mutability), depth_lvl + 1);
+                print_indented!(self, "arg:", depth_lvl + 1);
+                self.print_expr(*arg, depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl);
+            }
+            Break { label, value } => {
+                print_indented!(self, "Break (", depth_lvl);
+                print_indented!(self, format!("label: {:?}", label), depth_lvl + 1);
+
+                if let Some(value) = value {
+                    print_indented!(self, "value:", depth_lvl + 1);
+                    self.print_expr(*value, depth_lvl + 2);
+                }
+
+                print_indented!(self, ")", depth_lvl);
+            }
+            Continue { label } => {
+                print_indented!(self, "Continue {", depth_lvl);
+                print_indented!(self, format!("label: {:?}", label), depth_lvl + 1);
+                print_indented!(self, "}", depth_lvl);
+            }
+            Return { value } => {
+                print_indented!(self, "Return {", depth_lvl);
+                print_indented!(self, "value:", depth_lvl + 1);
+
+                if let Some(value) = value {
+                    self.print_expr(*value, depth_lvl + 2);
+                }
+
+                print_indented!(self, "}", depth_lvl);
+            }
+            ConstBlock { did, substs } => {
+                print_indented!(self, "ConstBlock {", depth_lvl);
+                print_indented!(self, format!("did: {:?}", did), depth_lvl + 1);
+                print_indented!(self, format!("substs: {:?}", substs), depth_lvl + 1);
+                print_indented!(self, "}", depth_lvl);
+            }
+            Repeat { value, count } => {
+                print_indented!(self, "Repeat {", depth_lvl);
+                print_indented!(self, format!("count: {:?}", count), depth_lvl + 1);
+                print_indented!(self, "value:", depth_lvl + 1);
+                self.print_expr(*value, depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl);
+            }
+            Array { fields } => {
+                print_indented!(self, "Array {", depth_lvl);
+                print_indented!(self, "fields: [", depth_lvl + 1);
+                for field_id in fields.iter() {
+                    self.print_expr(*field_id, depth_lvl + 2);
+                }
+                print_indented!(self, "]", depth_lvl + 1);
+                print_indented!(self, "}", depth_lvl);
+            }
+            Tuple { fields } => {
+                print_indented!(self, "Tuple {", depth_lvl);
+                print_indented!(self, "fields: [", depth_lvl + 1);
+                for field_id in fields.iter() {
+                    self.print_expr(*field_id, depth_lvl + 2);
+                }
+                print_indented!(self, "]", depth_lvl + 1);
+                print_indented!(self, "}", depth_lvl);
+            }
+            Adt(adt_expr) => {
+                print_indented!(self, "Adt {", depth_lvl);
+                self.print_adt_expr(&**adt_expr, depth_lvl + 1);
+                print_indented!(self, "}", depth_lvl);
+            }
+            PlaceTypeAscription { source, user_ty } => {
+                print_indented!(self, "PlaceTypeAscription {", depth_lvl);
+                print_indented!(self, format!("user_ty: {:?}", user_ty), depth_lvl + 1);
+                print_indented!(self, "source:", depth_lvl + 1);
+                self.print_expr(*source, depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl);
+            }
+            ValueTypeAscription { source, user_ty } => {
+                print_indented!(self, "ValueTypeAscription {", depth_lvl);
+                print_indented!(self, format!("user_ty: {:?}", user_ty), depth_lvl + 1);
+                print_indented!(self, "source:", depth_lvl + 1);
+                self.print_expr(*source, depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl);
+            }
+            Closure(closure_expr) => {
+                print_indented!(self, "Closure {", depth_lvl);
+                print_indented!(self, "closure_expr:", depth_lvl + 1);
+                self.print_closure_expr(&**closure_expr, depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl);
+            }
+            Literal { lit, neg } => {
+                print_indented!(
+                    self,
+                    format!("Literal( lit: {:?}, neg: {:?})\n", lit, neg),
+                    depth_lvl
+                );
+            }
+            NonHirLiteral { lit, user_ty } => {
+                print_indented!(self, "NonHirLiteral {", depth_lvl);
+                print_indented!(self, format!("lit: {:?}", lit), depth_lvl + 1);
+                print_indented!(self, format!("user_ty: {:?}", user_ty), depth_lvl + 1);
+                print_indented!(self, "}", depth_lvl);
+            }
+            ZstLiteral { user_ty } => {
+                print_indented!(self, format!("ZstLiteral(user_ty: {:?})", user_ty), depth_lvl);
+            }
+            NamedConst { def_id, substs, user_ty } => {
+                print_indented!(self, "NamedConst {", depth_lvl);
+                print_indented!(self, format!("def_id: {:?}", def_id), depth_lvl + 1);
+                print_indented!(self, format!("user_ty: {:?}", user_ty), depth_lvl + 1);
+                print_indented!(self, format!("substs: {:?}", substs), depth_lvl + 1);
+                print_indented!(self, "}", depth_lvl);
+            }
+            ConstParam { param, def_id } => {
+                print_indented!(self, "ConstParam {", depth_lvl);
+                print_indented!(self, format!("def_id: {:?}", def_id), depth_lvl + 1);
+                print_indented!(self, format!("param: {:?}", param), depth_lvl + 1);
+                print_indented!(self, "}", depth_lvl);
+            }
+            StaticRef { alloc_id, ty, def_id } => {
+                print_indented!(self, "StaticRef {", depth_lvl);
+                print_indented!(self, format!("def_id: {:?}", def_id), depth_lvl + 1);
+                print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 1);
+                print_indented!(self, format!("alloc_id: {:?}", alloc_id), depth_lvl + 1);
+                print_indented!(self, "}", depth_lvl);
+            }
+            InlineAsm(expr) => {
+                print_indented!(self, "InlineAsm {", depth_lvl);
+                print_indented!(self, "expr:", depth_lvl + 1);
+                self.print_inline_asm_expr(&**expr, depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl);
+            }
+            ThreadLocalRef(def_id) => {
+                print_indented!(self, "ThreadLocalRef {", depth_lvl);
+                print_indented!(self, format!("def_id: {:?}", def_id), depth_lvl + 1);
+                print_indented!(self, "}", depth_lvl);
+            }
+            Yield { value } => {
+                print_indented!(self, "Yield {", depth_lvl);
+                print_indented!(self, "value:", depth_lvl + 1);
+                self.print_expr(*value, depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl);
+            }
+        }
+    }
+
+    fn print_adt_expr(&mut self, adt_expr: &AdtExpr<'tcx>, depth_lvl: usize) {
+        print_indented!(self, "adt_def:", depth_lvl);
+        self.print_adt_def(adt_expr.adt_def, depth_lvl + 1);
+        print_indented!(
+            self,
+            format!("variant_index: {:?}", adt_expr.variant_index),
+            depth_lvl + 1
+        );
+        print_indented!(self, format!("substs: {:?}", adt_expr.substs), depth_lvl + 1);
+        print_indented!(self, format!("user_ty: {:?}", adt_expr.user_ty), depth_lvl + 1);
+
+        for (i, field_expr) in adt_expr.fields.iter().enumerate() {
+            print_indented!(self, format!("field {}:", i), depth_lvl + 1);
+            self.print_expr(field_expr.expr, depth_lvl + 2);
+        }
+
+        if let Some(ref base) = adt_expr.base {
+            print_indented!(self, "base:", depth_lvl + 1);
+            self.print_fru_info(base, depth_lvl + 2);
+        } else {
+            print_indented!(self, "base: None", depth_lvl + 1);
+        }
+    }
+
+    fn print_adt_def(&mut self, adt_def: ty::AdtDef<'tcx>, depth_lvl: usize) {
+        print_indented!(self, "AdtDef {", depth_lvl);
+        print_indented!(self, format!("did: {:?}", adt_def.did()), depth_lvl + 1);
+        print_indented!(self, format!("variants: {:?}", adt_def.variants()), depth_lvl + 1);
+        print_indented!(self, format!("flags: {:?}", adt_def.flags()), depth_lvl + 1);
+        print_indented!(self, format!("repr: {:?}", adt_def.repr()), depth_lvl + 1);
+    }
+
+    fn print_fru_info(&mut self, fru_info: &FruInfo<'tcx>, depth_lvl: usize) {
+        print_indented!(self, "FruInfo {", depth_lvl);
+        print_indented!(self, "base: ", depth_lvl + 1);
+        self.print_expr(fru_info.base, depth_lvl + 2);
+        print_indented!(self, "field_types: [", depth_lvl + 1);
+        for ty in fru_info.field_types.iter() {
+            print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 2);
+        }
+        print_indented!(self, "}", depth_lvl);
+    }
+
+    fn print_arm(&mut self, arm_id: ArmId, depth_lvl: usize) {
+        print_indented!(self, "Arm {", depth_lvl);
+
+        let arm = &self.thir.arms[arm_id];
+        let Arm { pattern, guard, body, lint_level, scope, span } = arm;
+
+        print_indented!(self, "pattern: ", depth_lvl + 1);
+        self.print_pat(pattern, depth_lvl + 2);
+
+        if let Some(guard) = guard {
+            print_indented!(self, "guard: ", depth_lvl + 1);
+            self.print_guard(guard, depth_lvl + 2);
+        } else {
+            print_indented!(self, "guard: None", depth_lvl + 1);
+        }
+
+        print_indented!(self, "body: ", depth_lvl + 1);
+        self.print_expr(*body, depth_lvl + 2);
+        print_indented!(self, format!("lint_level: {:?}", lint_level), depth_lvl + 1);
+        print_indented!(self, format!("scope: {:?}", scope), depth_lvl + 1);
+        print_indented!(self, format!("span: {:?}", span), depth_lvl + 1);
+        print_indented!(self, "}", depth_lvl);
+    }
+
+    fn print_pat(&mut self, pat: &Box<Pat<'tcx>>, depth_lvl: usize) {
+        let Pat { ty, span, kind } = &**pat;
+
+        print_indented!(self, "Pat: {", depth_lvl);
+        print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 1);
+        print_indented!(self, format!("span: {:?}", span), depth_lvl + 1);
+        self.print_pat_kind(kind, depth_lvl + 1);
+        print_indented!(self, "}", depth_lvl);
+    }
+
+    fn print_pat_kind(&mut self, pat_kind: &PatKind<'tcx>, depth_lvl: usize) {
+        print_indented!(self, "kind: PatKind {", depth_lvl);
+
+        match pat_kind {
+            PatKind::Wild => {
+                print_indented!(self, "Wild", depth_lvl + 1);
+            }
+            PatKind::AscribeUserType { ascription, subpattern } => {
+                print_indented!(self, "AscribeUserType: {", depth_lvl + 1);
+                print_indented!(self, format!("ascription: {:?}", ascription), depth_lvl + 2);
+                print_indented!(self, "subpattern: ", depth_lvl + 2);
+                self.print_pat(subpattern, depth_lvl + 3);
+                print_indented!(self, "}", depth_lvl + 1);
+            }
+            PatKind::Binding { mutability, name, mode, var, ty, subpattern, is_primary } => {
+                print_indented!(self, "Binding {", depth_lvl + 1);
+                print_indented!(self, format!("mutability: {:?}", mutability), depth_lvl + 2);
+                print_indented!(self, format!("name: {:?}", name), depth_lvl + 2);
+                print_indented!(self, format!("mode: {:?}", mode), depth_lvl + 2);
+                print_indented!(self, format!("var: {:?}", var), depth_lvl + 2);
+                print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 2);
+                print_indented!(self, format!("is_primary: {:?}", is_primary), depth_lvl + 2);
+
+                if let Some(subpattern) = subpattern {
+                    print_indented!(self, "subpattern: Some( ", depth_lvl + 2);
+                    self.print_pat(subpattern, depth_lvl + 3);
+                    print_indented!(self, ")", depth_lvl + 2);
+                } else {
+                    print_indented!(self, "subpattern: None", depth_lvl + 2);
+                }
+
+                print_indented!(self, "}", depth_lvl + 1);
+            }
+            PatKind::Variant { adt_def, substs, variant_index, subpatterns } => {
+                print_indented!(self, "Variant {", depth_lvl + 1);
+                print_indented!(self, "adt_def: ", depth_lvl + 2);
+                self.print_adt_def(*adt_def, depth_lvl + 3);
+                print_indented!(self, format!("substs: {:?}", substs), depth_lvl + 2);
+                print_indented!(self, format!("variant_index: {:?}", variant_index), depth_lvl + 2);
+
+                if subpatterns.len() > 0 {
+                    print_indented!(self, "subpatterns: [", depth_lvl + 2);
+                    for field_pat in subpatterns.iter() {
+                        self.print_pat(&field_pat.pattern, depth_lvl + 3);
+                    }
+                    print_indented!(self, "]", depth_lvl + 2);
+                } else {
+                    print_indented!(self, "subpatterns: []", depth_lvl + 2);
+                }
+
+                print_indented!(self, "}", depth_lvl + 1);
+            }
+            PatKind::Leaf { subpatterns } => {
+                print_indented!(self, "Leaf { ", depth_lvl + 1);
+                print_indented!(self, "subpatterns: [", depth_lvl + 2);
+                for field_pat in subpatterns.iter() {
+                    self.print_pat(&field_pat.pattern, depth_lvl + 3);
+                }
+                print_indented!(self, "]", depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl + 1);
+            }
+            PatKind::Deref { subpattern } => {
+                print_indented!(self, "Deref { ", depth_lvl + 1);
+                print_indented!(self, "subpattern: ", depth_lvl + 2);
+                self.print_pat(subpattern, depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl + 1);
+            }
+            PatKind::Constant { value } => {
+                print_indented!(self, "Constant {", depth_lvl + 1);
+                print_indented!(self, format!("value: {:?}", value), depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl + 1);
+            }
+            PatKind::Range(pat_range) => {
+                print_indented!(self, format!("Range ( {:?} )", pat_range), depth_lvl + 1);
+            }
+            PatKind::Slice { prefix, slice, suffix } => {
+                print_indented!(self, "Slice {", depth_lvl + 1);
+
+                print_indented!(self, "prefix: [", depth_lvl + 2);
+                for prefix_pat in prefix.iter() {
+                    self.print_pat(prefix_pat, depth_lvl + 3);
+                }
+                print_indented!(self, "]", depth_lvl + 2);
+
+                if let Some(slice) = slice {
+                    print_indented!(self, "slice: ", depth_lvl + 2);
+                    self.print_pat(slice, depth_lvl + 3);
+                }
+
+                print_indented!(self, "suffix: [", depth_lvl + 2);
+                for suffix_pat in suffix.iter() {
+                    self.print_pat(suffix_pat, depth_lvl + 3);
+                }
+                print_indented!(self, "]", depth_lvl + 2);
+
+                print_indented!(self, "}", depth_lvl + 1);
+            }
+            PatKind::Array { prefix, slice, suffix } => {
+                print_indented!(self, "Array {", depth_lvl + 1);
+
+                print_indented!(self, "prefix: [", depth_lvl + 2);
+                for prefix_pat in prefix.iter() {
+                    self.print_pat(prefix_pat, depth_lvl + 3);
+                }
+                print_indented!(self, "]", depth_lvl + 2);
+
+                if let Some(slice) = slice {
+                    print_indented!(self, "slice: ", depth_lvl + 2);
+                    self.print_pat(slice, depth_lvl + 3);
+                }
+
+                print_indented!(self, "suffix: [", depth_lvl + 2);
+                for suffix_pat in suffix.iter() {
+                    self.print_pat(suffix_pat, depth_lvl + 3);
+                }
+                print_indented!(self, "]", depth_lvl + 2);
+
+                print_indented!(self, "}", depth_lvl + 1);
+            }
+            PatKind::Or { pats } => {
+                print_indented!(self, "Or {", depth_lvl + 1);
+                print_indented!(self, "pats: [", depth_lvl + 2);
+                for pat in pats.iter() {
+                    self.print_pat(pat, depth_lvl + 3);
+                }
+                print_indented!(self, "]", depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl + 1);
+            }
+        }
+
+        print_indented!(self, "}", depth_lvl);
+    }
+
+    fn print_guard(&mut self, guard: &Guard<'tcx>, depth_lvl: usize) {
+        print_indented!(self, "Guard {", depth_lvl);
+
+        match guard {
+            Guard::If(expr_id) => {
+                print_indented!(self, "If (", depth_lvl + 1);
+                self.print_expr(*expr_id, depth_lvl + 2);
+                print_indented!(self, ")", depth_lvl + 1);
+            }
+            Guard::IfLet(pat, expr_id) => {
+                print_indented!(self, "IfLet (", depth_lvl + 1);
+                self.print_pat(pat, depth_lvl + 2);
+                print_indented!(self, ",", depth_lvl + 1);
+                self.print_expr(*expr_id, depth_lvl + 2);
+                print_indented!(self, ")", depth_lvl + 1);
+            }
+        }
+
+        print_indented!(self, "}", depth_lvl);
+    }
+
+    fn print_closure_expr(&mut self, expr: &ClosureExpr<'tcx>, depth_lvl: usize) {
+        let ClosureExpr { closure_id, substs, upvars, movability, fake_reads } = expr;
+
+        print_indented!(self, "ClosureExpr {", depth_lvl);
+        print_indented!(self, format!("closure_id: {:?}", closure_id), depth_lvl + 1);
+        print_indented!(self, format!("substs: {:?}", substs), depth_lvl + 1);
+
+        if upvars.len() > 0 {
+            print_indented!(self, "upvars: [", depth_lvl + 1);
+            for upvar in upvars.iter() {
+                self.print_expr(*upvar, depth_lvl + 2);
+                print_indented!(self, ",", depth_lvl + 1);
+            }
+            print_indented!(self, "]", depth_lvl + 1);
+        } else {
+            print_indented!(self, "upvars: []", depth_lvl + 1);
+        }
+
+        print_indented!(self, format!("movability: {:?}", movability), depth_lvl + 1);
+
+        if fake_reads.len() > 0 {
+            print_indented!(self, "fake_reads: [", depth_lvl + 1);
+            for (fake_read_expr, cause, hir_id) in fake_reads.iter() {
+                print_indented!(self, "(", depth_lvl + 2);
+                self.print_expr(*fake_read_expr, depth_lvl + 3);
+                print_indented!(self, ",", depth_lvl + 2);
+                print_indented!(self, format!("cause: {:?}", cause), depth_lvl + 3);
+                print_indented!(self, ",", depth_lvl + 2);
+                print_indented!(self, format!("hir_id: {:?}", hir_id), depth_lvl + 3);
+                print_indented!(self, "),", depth_lvl + 2);
+            }
+            print_indented!(self, "]", depth_lvl + 1);
+        } else {
+            print_indented!(self, "fake_reads: []", depth_lvl + 1);
+        }
+
+        print_indented!(self, "}", depth_lvl);
+    }
+
+    fn print_inline_asm_expr(&mut self, expr: &InlineAsmExpr<'tcx>, depth_lvl: usize) {
+        let InlineAsmExpr { template, operands, options, line_spans } = expr;
+
+        print_indented!(self, "InlineAsmExpr {", depth_lvl);
+
+        print_indented!(self, "template: [", depth_lvl + 1);
+        for template_piece in template.iter() {
+            print_indented!(self, format!("{:?}", template_piece), depth_lvl + 2);
+        }
+        print_indented!(self, "]", depth_lvl + 1);
+
+        print_indented!(self, "operands: [", depth_lvl + 1);
+        for operand in operands.iter() {
+            self.print_inline_operand(operand, depth_lvl + 2);
+        }
+        print_indented!(self, "]", depth_lvl + 1);
+
+        print_indented!(self, format!("options: {:?}", options), depth_lvl + 1);
+        print_indented!(self, format!("line_spans: {:?}", line_spans), depth_lvl + 1);
+    }
+
+    fn print_inline_operand(&mut self, operand: &InlineAsmOperand<'tcx>, depth_lvl: usize) {
+        match operand {
+            InlineAsmOperand::In { reg, expr } => {
+                print_indented!(self, "InlineAsmOperand::In {", depth_lvl);
+                print_indented!(self, format!("reg: {:?}", reg), depth_lvl + 1);
+                print_indented!(self, "expr: ", depth_lvl + 1);
+                self.print_expr(*expr, depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl + 1);
+            }
+            InlineAsmOperand::Out { reg, late, expr } => {
+                print_indented!(self, "InlineAsmOperand::Out {", depth_lvl);
+                print_indented!(self, format!("reg: {:?}", reg), depth_lvl + 1);
+                print_indented!(self, format!("late: {:?}", late), depth_lvl + 1);
+
+                if let Some(out) = expr {
+                    print_indented!(self, "place: Some( ", depth_lvl + 1);
+                    self.print_expr(*out, depth_lvl + 2);
+                    print_indented!(self, ")", depth_lvl + 1);
+                } else {
+                    print_indented!(self, "place: None", depth_lvl + 1);
+                }
+                print_indented!(self, "}", depth_lvl + 1);
+            }
+            InlineAsmOperand::InOut { reg, late, expr } => {
+                print_indented!(self, "InlineAsmOperand::InOut {", depth_lvl);
+                print_indented!(self, format!("reg: {:?}", reg), depth_lvl + 1);
+                print_indented!(self, format!("late: {:?}", late), depth_lvl + 1);
+                print_indented!(self, "expr: ", depth_lvl + 1);
+                self.print_expr(*expr, depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl + 1);
+            }
+            InlineAsmOperand::SplitInOut { reg, late, in_expr, out_expr } => {
+                print_indented!(self, "InlineAsmOperand::SplitInOut {", depth_lvl);
+                print_indented!(self, format!("reg: {:?}", reg), depth_lvl + 1);
+                print_indented!(self, format!("late: {:?}", late), depth_lvl + 1);
+                print_indented!(self, "in_expr: ", depth_lvl + 1);
+                self.print_expr(*in_expr, depth_lvl + 2);
+
+                if let Some(out_expr) = out_expr {
+                    print_indented!(self, "out_expr: Some( ", depth_lvl + 1);
+                    self.print_expr(*out_expr, depth_lvl + 2);
+                    print_indented!(self, ")", depth_lvl + 1);
+                } else {
+                    print_indented!(self, "out_expr: None", depth_lvl + 1);
+                }
+
+                print_indented!(self, "}", depth_lvl + 1);
+            }
+            InlineAsmOperand::Const { value, span } => {
+                print_indented!(self, "InlineAsmOperand::Const {", depth_lvl);
+                print_indented!(self, format!("value: {:?}", value), depth_lvl + 1);
+                print_indented!(self, format!("span: {:?}", span), depth_lvl + 1);
+                print_indented!(self, "}", depth_lvl + 1);
+            }
+            InlineAsmOperand::SymFn { value, span } => {
+                print_indented!(self, "InlineAsmOperand::SymFn {", depth_lvl);
+                print_indented!(self, format!("value: {:?}", *value), depth_lvl + 1);
+                print_indented!(self, format!("span: {:?}", span), depth_lvl + 1);
+                print_indented!(self, "}", depth_lvl + 1);
+            }
+            InlineAsmOperand::SymStatic { def_id } => {
+                print_indented!(self, "InlineAsmOperand::SymStatic {", depth_lvl);
+                print_indented!(self, format!("def_id: {:?}", def_id), depth_lvl + 1);
+                print_indented!(self, "}", depth_lvl + 1);
+            }
+        }
+    }
+}
index 526df090a3cd90f1a7e9a77d30caac14a88d7b5e..b63b9e754cf466a963adc68740971e5f6fa0e0ff 100644 (file)
@@ -77,6 +77,8 @@
 use std::mem;
 use std::ops::{Bound, Deref};
 
+const TINY_CONST_EVAL_LIMIT: Limit = Limit(20);
+
 pub trait OnDiskCache<'tcx>: rustc_data_structures::sync::Sync {
     /// Creates a new `OnDiskCache` instance from the serialized data in `data`.
     fn new(sess: &'tcx Session, data: Mmap, start_pos: usize) -> Self
@@ -1104,7 +1106,11 @@ pub fn move_size_limit(self) -> Limit {
     }
 
     pub fn const_eval_limit(self) -> Limit {
-        self.limits(()).const_eval_limit
+        if self.sess.opts.unstable_opts.tiny_const_eval_limit {
+            TINY_CONST_EVAL_LIMIT
+        } else {
+            self.limits(()).const_eval_limit
+        }
     }
 
     pub fn all_traits(self) -> impl Iterator<Item = DefId> + 'tcx {
index 7001f81aa77502fea419f94595502fadbedd26b0..25c6777a14c7084aa65ecdc7a933d66e78421056 100644 (file)
@@ -2458,10 +2458,6 @@ pub fn should_collapse_debuginfo(self, span: Span) -> bool {
             }
     }
 
-    pub fn is_object_safe(self, key: DefId) -> bool {
-        self.object_safety_violations(key).is_empty()
-    }
-
     #[inline]
     pub fn is_const_fn_raw(self, def_id: DefId) -> bool {
         matches!(
index f85831b4fc6b57c106881d557ae3b9e39cceba83..1655e224ddbb5b68f16f9710bdf509f18607d922 100644 (file)
@@ -439,6 +439,10 @@ fn construct_fn<'tcx>(
     let fn_id = tcx.hir().local_def_id_to_hir_id(fn_def.did);
     let generator_kind = tcx.generator_kind(fn_def.did);
 
+    // The representation of thir for `-Zunpretty=thir-tree` relies on
+    // the entry expression being the last element of `thir.exprs`.
+    assert_eq!(expr.as_usize(), thir.exprs.len() - 1);
+
     // Figure out what primary body this item has.
     let body_id = tcx.hir().body_owned_by(fn_def.did);
     let span_with_body = tcx.hir().span_with_body(fn_id);
index a428180a4fa8295bb5bac16f0030fd5de8c31406..94dae36154c26181757616366db754e6412999b6 100644 (file)
@@ -34,4 +34,5 @@ pub fn provide(providers: &mut Providers) {
     providers.thir_check_unsafety_for_const_arg = check_unsafety::thir_check_unsafety_for_const_arg;
     providers.thir_body = thir::cx::thir_body;
     providers.thir_tree = thir::cx::thir_tree;
+    providers.thir_flat = thir::cx::thir_flat;
 }
index a355e1bdab5f51c78d865660833d0faafe83e33a..10df4b229520f3bd1f8f572353b994cb14ae273e 100644 (file)
@@ -53,6 +53,16 @@ pub(crate) fn thir_body(
 }
 
 pub(crate) fn thir_tree(tcx: TyCtxt<'_>, owner_def: ty::WithOptConstParam<LocalDefId>) -> String {
+    match thir_body(tcx, owner_def) {
+        Ok((thir, _)) => {
+            let thir = thir.steal();
+            tcx.thir_tree_representation(&thir)
+        }
+        Err(_) => "error".into(),
+    }
+}
+
+pub(crate) fn thir_flat(tcx: TyCtxt<'_>, owner_def: ty::WithOptConstParam<LocalDefId>) -> String {
     match thir_body(tcx, owner_def) {
         Ok((thir, _)) => format!("{:#?}", thir.steal()),
         Err(_) => "error".into(),
index 923dc16c11b077268e175de33677bb58400649c3..2890fa32cc915fdf540f2ee66ce73d7afc44c31b 100644 (file)
@@ -271,6 +271,7 @@ fn apply_statement_effect(
             | StatementKind::AscribeUserType(..)
             | StatementKind::Coverage(..)
             | StatementKind::Intrinsic(..)
+            | StatementKind::ConstEvalCounter
             | StatementKind::Nop => None,
         };
         if let Some(destination) = destination {
index 8d379b90a86db28194b2946df68bc564b8e84961..fcf0ce9d82118815eadbb0229be5bac3e49afe21 100644 (file)
@@ -141,6 +141,7 @@ fn before_statement_effect(
             StatementKind::AscribeUserType(..)
             | StatementKind::Coverage(..)
             | StatementKind::FakeRead(..)
+            | StatementKind::ConstEvalCounter
             | StatementKind::Nop
             | StatementKind::Retag(..)
             | StatementKind::Intrinsic(..)
index f46fd118bde5d165106bfcb047dd7d2d5f494232..0195693a7cb0e6d9bf8639e83d8e96a5b59797a3 100644 (file)
@@ -331,6 +331,7 @@ fn gather_statement(&mut self, stmt: &Statement<'tcx>) {
             | StatementKind::AscribeUserType(..)
             | StatementKind::Coverage(..)
             | StatementKind::Intrinsic(..)
+            | StatementKind::ConstEvalCounter
             | StatementKind::Nop => {}
         }
     }
index 0522c657939f5e100c7827dd319862ce3eedaf09..6bdbda909d7bdf02da963730db84fa2a3d2be991 100644 (file)
@@ -84,7 +84,8 @@ fn super_statement(&self, statement: &Statement<'tcx>, state: &mut State<Self::V
             StatementKind::Retag(..) => {
                 // We don't track references.
             }
-            StatementKind::Nop
+            StatementKind::ConstEvalCounter
+            | StatementKind::Nop
             | StatementKind::FakeRead(..)
             | StatementKind::Coverage(..)
             | StatementKind::AscribeUserType(..) => (),
index 9f006a76162a6be007b2aea6c2dffa94f05a0e39..8afa53313fc2840e838cc13e8d5d4170a3151de3 100644 (file)
@@ -104,6 +104,7 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
             | StatementKind::AscribeUserType(..)
             | StatementKind::Coverage(..)
             | StatementKind::Intrinsic(..)
+            | StatementKind::ConstEvalCounter
             | StatementKind::Nop => {
                 // safe (at least as emitted during MIR construction)
             }
diff --git a/compiler/rustc_mir_transform/src/copy_prop.rs b/compiler/rustc_mir_transform/src/copy_prop.rs
new file mode 100644 (file)
index 0000000..182b301
--- /dev/null
@@ -0,0 +1,178 @@
+use rustc_index::bit_set::BitSet;
+use rustc_index::vec::IndexVec;
+use rustc_middle::mir::visit::*;
+use rustc_middle::mir::*;
+use rustc_middle::ty::TyCtxt;
+use rustc_mir_dataflow::impls::borrowed_locals;
+
+use crate::ssa::SsaLocals;
+use crate::MirPass;
+
+/// Unify locals that copy each other.
+///
+/// We consider patterns of the form
+///   _a = rvalue
+///   _b = move? _a
+///   _c = move? _a
+///   _d = move? _c
+/// where each of the locals is only assigned once.
+///
+/// We want to replace all those locals by `_a`, either copied or moved.
+pub struct CopyProp;
+
+impl<'tcx> MirPass<'tcx> for CopyProp {
+    fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+        sess.mir_opt_level() >= 4
+    }
+
+    #[instrument(level = "trace", skip(self, tcx, body))]
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+        debug!(def_id = ?body.source.def_id());
+        propagate_ssa(tcx, body);
+    }
+}
+
+fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+    let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
+    let borrowed_locals = borrowed_locals(body);
+    let ssa = SsaLocals::new(tcx, param_env, body, &borrowed_locals);
+
+    let fully_moved = fully_moved_locals(&ssa, body);
+    debug!(?fully_moved);
+
+    let mut storage_to_remove = BitSet::new_empty(fully_moved.domain_size());
+    for (local, &head) in ssa.copy_classes().iter_enumerated() {
+        if local != head {
+            storage_to_remove.insert(head);
+        }
+    }
+
+    let any_replacement = ssa.copy_classes().iter_enumerated().any(|(l, &h)| l != h);
+
+    Replacer {
+        tcx,
+        copy_classes: &ssa.copy_classes(),
+        fully_moved,
+        borrowed_locals,
+        storage_to_remove,
+    }
+    .visit_body_preserves_cfg(body);
+
+    if any_replacement {
+        crate::simplify::remove_unused_definitions(body);
+    }
+}
+
+/// `SsaLocals` computed equivalence classes between locals considering copy/move assignments.
+///
+/// This function also returns whether all the `move?` in the pattern are `move` and not copies.
+/// A local which is in the bitset can be replaced by `move _a`. Otherwise, it must be
+/// replaced by `copy _a`, as we cannot move multiple times from `_a`.
+///
+/// If an operand copies `_c`, it must happen before the assignment `_d = _c`, otherwise it is UB.
+/// This means that replacing it by a copy of `_a` if ok, since this copy happens before `_c` is
+/// moved, and therefore that `_d` is moved.
+#[instrument(level = "trace", skip(ssa, body))]
+fn fully_moved_locals(ssa: &SsaLocals, body: &Body<'_>) -> BitSet<Local> {
+    let mut fully_moved = BitSet::new_filled(body.local_decls.len());
+
+    for (_, rvalue) in ssa.assignments(body) {
+        let (Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) | Rvalue::CopyForDeref(place))
+            = rvalue
+        else { continue };
+
+        let Some(rhs) = place.as_local() else { continue };
+        if !ssa.is_ssa(rhs) {
+            continue;
+        }
+
+        if let Rvalue::Use(Operand::Copy(_)) | Rvalue::CopyForDeref(_) = rvalue {
+            fully_moved.remove(rhs);
+        }
+    }
+
+    ssa.meet_copy_equivalence(&mut fully_moved);
+
+    fully_moved
+}
+
+/// Utility to help performing subtitution of `*pattern` by `target`.
+struct Replacer<'a, 'tcx> {
+    tcx: TyCtxt<'tcx>,
+    fully_moved: BitSet<Local>,
+    storage_to_remove: BitSet<Local>,
+    borrowed_locals: BitSet<Local>,
+    copy_classes: &'a IndexVec<Local, Local>,
+}
+
+impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> {
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
+    fn visit_local(&mut self, local: &mut Local, ctxt: PlaceContext, _: Location) {
+        let new_local = self.copy_classes[*local];
+        match ctxt {
+            // Do not modify the local in storage statements.
+            PlaceContext::NonUse(NonUseContext::StorageLive | NonUseContext::StorageDead) => {}
+            // The local should have been marked as non-SSA.
+            PlaceContext::MutatingUse(_) => assert_eq!(*local, new_local),
+            // We access the value.
+            _ => *local = new_local,
+        }
+    }
+
+    fn visit_place(&mut self, place: &mut Place<'tcx>, ctxt: PlaceContext, loc: Location) {
+        if let Some(new_projection) = self.process_projection(&place.projection, loc) {
+            place.projection = self.tcx().intern_place_elems(&new_projection);
+        }
+
+        let observes_address = match ctxt {
+            PlaceContext::NonMutatingUse(
+                NonMutatingUseContext::SharedBorrow
+                | NonMutatingUseContext::ShallowBorrow
+                | NonMutatingUseContext::UniqueBorrow
+                | NonMutatingUseContext::AddressOf,
+            ) => true,
+            // For debuginfo, merging locals is ok.
+            PlaceContext::NonUse(NonUseContext::VarDebugInfo) => {
+                self.borrowed_locals.contains(place.local)
+            }
+            _ => false,
+        };
+        if observes_address && !place.is_indirect() {
+            // We observe the address of `place.local`. Do not replace it.
+        } else {
+            self.visit_local(
+                &mut place.local,
+                PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
+                loc,
+            )
+        }
+    }
+
+    fn visit_operand(&mut self, operand: &mut Operand<'tcx>, loc: Location) {
+        if let Operand::Move(place) = *operand
+            && let Some(local) = place.as_local()
+            && !self.fully_moved.contains(local)
+        {
+            *operand = Operand::Copy(place);
+        }
+        self.super_operand(operand, loc);
+    }
+
+    fn visit_statement(&mut self, stmt: &mut Statement<'tcx>, loc: Location) {
+        if let StatementKind::StorageDead(l) = stmt.kind
+            && self.storage_to_remove.contains(l)
+        {
+            stmt.make_nop();
+        } else if let StatementKind::Assign(box (ref place, ref mut rvalue)) = stmt.kind
+            && place.as_local().is_some()
+        {
+            // Do not replace assignments.
+            self.visit_rvalue(rvalue, loc)
+        } else {
+            self.super_statement(stmt, loc);
+        }
+    }
+}
index 31d5541a31b6b7a26c95d44ab7a3fb0b53f9e9d9..f973c1ed28f4a639b7bd17351a76f6ace8f34499 100644 (file)
@@ -802,6 +802,8 @@ pub(super) fn filtered_statement_span(statement: &Statement<'_>) -> Option<Span>
         | StatementKind::StorageDead(_)
         // Coverage should not be encountered, but don't inject coverage coverage
         | StatementKind::Coverage(_)
+        // Ignore `ConstEvalCounter`s
+        | StatementKind::ConstEvalCounter
         // Ignore `Nop`s
         | StatementKind::Nop => None,
 
diff --git a/compiler/rustc_mir_transform/src/ctfe_limit.rs b/compiler/rustc_mir_transform/src/ctfe_limit.rs
new file mode 100644 (file)
index 0000000..7d12703
--- /dev/null
@@ -0,0 +1,59 @@
+//! A pass that inserts the `ConstEvalCounter` instruction into any blocks that have a back edge
+//! (thus indicating there is a loop in the CFG), or whose terminator is a function call.
+use crate::MirPass;
+
+use rustc_data_structures::graph::dominators::Dominators;
+use rustc_middle::mir::{
+    BasicBlock, BasicBlockData, Body, Statement, StatementKind, TerminatorKind,
+};
+use rustc_middle::ty::TyCtxt;
+
+pub struct CtfeLimit;
+
+impl<'tcx> MirPass<'tcx> for CtfeLimit {
+    #[instrument(skip(self, _tcx, body))]
+    fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+        let doms = body.basic_blocks.dominators();
+        let indices: Vec<BasicBlock> = body
+            .basic_blocks
+            .iter_enumerated()
+            .filter_map(|(node, node_data)| {
+                if matches!(node_data.terminator().kind, TerminatorKind::Call { .. })
+                    // Back edges in a CFG indicate loops
+                    || has_back_edge(&doms, node, &node_data)
+                {
+                    Some(node)
+                } else {
+                    None
+                }
+            })
+            .collect();
+        for index in indices {
+            insert_counter(
+                body.basic_blocks_mut()
+                    .get_mut(index)
+                    .expect("basic_blocks index {index} should exist"),
+            );
+        }
+    }
+}
+
+fn has_back_edge(
+    doms: &Dominators<BasicBlock>,
+    node: BasicBlock,
+    node_data: &BasicBlockData<'_>,
+) -> bool {
+    if !doms.is_reachable(node) {
+        return false;
+    }
+    // Check if any of the dominators of the node are also the node's successor.
+    doms.dominators(node)
+        .any(|dom| node_data.terminator().successors().into_iter().any(|succ| succ == dom))
+}
+
+fn insert_counter(basic_block_data: &mut BasicBlockData<'_>) {
+    basic_block_data.statements.push(Statement {
+        source_info: basic_block_data.terminator().source_info,
+        kind: StatementKind::ConstEvalCounter,
+    });
+}
index 09546330cec92672a2a5c906ba1d1847c108e7ed..9dbfb089dc665428340c5fc4272e4f494a3def45 100644 (file)
@@ -53,6 +53,7 @@ pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitS
                 | StatementKind::StorageDead(_)
                 | StatementKind::Coverage(_)
                 | StatementKind::Intrinsic(_)
+                | StatementKind::ConstEvalCounter
                 | StatementKind::Nop => (),
 
                 StatementKind::FakeRead(_) | StatementKind::AscribeUserType(_, _) => {
index 08e296a837127b72911b152275b7c242ca47d0f9..5c5baa68e5889362e359aacc23ca9e7706e43666 100644 (file)
@@ -328,7 +328,8 @@ fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Locatio
         match &statement.kind {
             StatementKind::Assign(box (dest, rvalue)) => {
                 match rvalue {
-                    Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) => {
+                    Rvalue::CopyForDeref(place)
+                    | Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) => {
                         // These might've been turned into self-assignments by the replacement
                         // (this includes the original statement we wanted to eliminate).
                         if dest == place {
@@ -577,6 +578,7 @@ fn for_statement<'tcx>(&mut self, statement: &StatementKind<'tcx>, body: &Body<'
                 self.add_place(**place);
             }
             StatementKind::Intrinsic(_)
+            | StatementKind::ConstEvalCounter
             | StatementKind::Nop
             | StatementKind::Coverage(_)
             | StatementKind::StorageLive(_)
@@ -754,7 +756,7 @@ impl<'tcx> Visitor<'tcx> for FindAssignments<'_, '_, 'tcx> {
     fn visit_statement(&mut self, statement: &Statement<'tcx>, _: Location) {
         if let StatementKind::Assign(box (
             lhs,
-            Rvalue::Use(Operand::Copy(rhs) | Operand::Move(rhs)),
+            Rvalue::CopyForDeref(rhs) | Rvalue::Use(Operand::Copy(rhs) | Operand::Move(rhs)),
         )) = &statement.kind
         {
             let Some((src, dest)) = places_to_candidate_pair(*lhs, *rhs, self.body) else {
index e8871ff37f24ab2d3e67740fc2ffd4f8d354b9cf..5624e312da1cbe8eeabe9cbc82d219ebea390f86 100644 (file)
@@ -1390,6 +1390,7 @@ pub(crate) fn mir_generator_witnesses<'tcx>(
     tcx: TyCtxt<'tcx>,
     def_id: DefId,
 ) -> GeneratorLayout<'tcx> {
+    assert!(tcx.sess.opts.unstable_opts.drop_tracking_mir);
     let def_id = def_id.expect_local();
 
     let (body, _) = tcx.mir_promoted(ty::WithOptConstParam::unknown(def_id));
@@ -1400,15 +1401,8 @@ pub(crate) fn mir_generator_witnesses<'tcx>(
     let gen_ty = body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty;
 
     // Get the interior types and substs which typeck computed
-    let (upvars, interior, movable) = match *gen_ty.kind() {
-        ty::Generator(_, substs, movability) => {
-            let substs = substs.as_generator();
-            (
-                substs.upvar_tys().collect::<Vec<_>>(),
-                substs.witness(),
-                movability == hir::Movability::Movable,
-            )
-        }
+    let movable = match *gen_ty.kind() {
+        ty::Generator(_, _, movability) => movability == hir::Movability::Movable,
         _ => span_bug!(body.span, "unexpected generator type {}", gen_ty),
     };
 
@@ -1422,11 +1416,7 @@ pub(crate) fn mir_generator_witnesses<'tcx>(
     // `storage_liveness` tells us which locals have live storage at suspension points
     let (_, generator_layout, _) = compute_layout(tcx, liveness_info, body);
 
-    if tcx.sess.opts.unstable_opts.drop_tracking_mir {
-        check_suspend_tys(tcx, &generator_layout, &body);
-    } else {
-        sanitize_witness(tcx, body, interior, upvars, &generator_layout);
-    }
+    check_suspend_tys(tcx, &generator_layout, &body);
 
     generator_layout
 }
@@ -1444,10 +1434,15 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         let gen_ty = body.local_decls.raw[1].ty;
 
         // Get the discriminant type and substs which typeck computed
-        let (discr_ty, movable) = match *gen_ty.kind() {
+        let (discr_ty, upvars, interior, movable) = match *gen_ty.kind() {
             ty::Generator(_, substs, movability) => {
                 let substs = substs.as_generator();
-                (substs.discr_ty(tcx), movability == hir::Movability::Movable)
+                (
+                    substs.discr_ty(tcx),
+                    substs.upvar_tys().collect::<Vec<_>>(),
+                    substs.witness(),
+                    movability == hir::Movability::Movable,
+                )
             }
             _ => {
                 tcx.sess
@@ -1524,6 +1519,12 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         // `storage_liveness` tells us which locals have live storage at suspension points
         let (remap, layout, storage_liveness) = compute_layout(tcx, liveness_info, body);
 
+        if tcx.sess.opts.unstable_opts.validate_mir
+            && !tcx.sess.opts.unstable_opts.drop_tracking_mir
+        {
+            sanitize_witness(tcx, body, interior, upvars, &layout);
+        }
+
         let can_return = can_return(tcx, body, tcx.param_env(body.source.def_id()));
 
         // Run the transformation which converts Places from Local to generator struct
@@ -1656,6 +1657,7 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
             | StatementKind::AscribeUserType(..)
             | StatementKind::Coverage(..)
             | StatementKind::Intrinsic(..)
+            | StatementKind::ConstEvalCounter
             | StatementKind::Nop => {}
         }
     }
index fe3d5b1cce4589470872382c17aa82a06d77af5f..abf89e550b14922973d1afeb584eb79ebd97bc97 100644 (file)
@@ -54,7 +54,9 @@
 mod const_goto;
 mod const_prop;
 mod const_prop_lint;
+mod copy_prop;
 mod coverage;
+mod ctfe_limit;
 mod dataflow_const_prop;
 mod dead_store_elimination;
 mod deaggregator;
@@ -86,6 +88,7 @@
 mod reveal_all;
 mod separate_const_switch;
 mod shim;
+mod ssa;
 // This pass is public to allow external drivers to perform MIR cleanup
 pub mod simplify;
 mod simplify_branches;
@@ -410,6 +413,8 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -
         }
     }
 
+    pm::run_passes(tcx, &mut body, &[&ctfe_limit::CtfeLimit], None);
+
     debug_assert!(!body.has_free_regions(), "Free regions in MIR for CTFE");
 
     body
@@ -426,7 +431,7 @@ fn mir_drops_elaborated_and_const_checked(
         return tcx.mir_drops_elaborated_and_const_checked(def);
     }
 
-    if tcx.generator_kind(def.did).is_some() {
+    if tcx.generator_kind(def.did).is_some() && tcx.sess.opts.unstable_opts.drop_tracking_mir {
         tcx.ensure().mir_generator_witnesses(def.did);
     }
     let mir_borrowck = tcx.mir_borrowck_opt_const_arg(def);
@@ -560,6 +565,7 @@ fn o1<T>(x: T) -> WithMinOptLevel<T> {
             &instcombine::InstCombine,
             &separate_const_switch::SeparateConstSwitch,
             &simplify::SimplifyLocals::new("before-const-prop"),
+            &copy_prop::CopyProp,
             //
             // FIXME(#70073): This pass is responsible for both optimization as well as some lints.
             &const_prop::ConstProp,
index f1bbf2ea7e8ea3aaf7b40307ba110dcd7346b4a3..e3a03aa08af4bdf87db93f780da21ff176657674 100644 (file)
@@ -35,6 +35,7 @@ fn is_nop_landing_pad(
                 | StatementKind::StorageDead(_)
                 | StatementKind::AscribeUserType(..)
                 | StatementKind::Coverage(..)
+                | StatementKind::ConstEvalCounter
                 | StatementKind::Nop => {
                     // These are all noops in a landing pad
                 }
index 2f116aaa95849bd075b94179109e2bc1a210d1d9..a24d2d34d791b96e53a654610d52ef95f5ce035e 100644 (file)
@@ -250,6 +250,7 @@ fn is_likely_const<'tcx>(mut tracked_place: Place<'tcx>, block: &BasicBlockData<
             | StatementKind::Coverage(_)
             | StatementKind::StorageDead(_)
             | StatementKind::Intrinsic(_)
+            | StatementKind::ConstEvalCounter
             | StatementKind::Nop => {}
         }
     }
@@ -318,6 +319,7 @@ fn find_determining_place<'tcx>(
             | StatementKind::AscribeUserType(_, _)
             | StatementKind::Coverage(_)
             | StatementKind::Intrinsic(_)
+            | StatementKind::ConstEvalCounter
             | StatementKind::Nop => {}
 
             // If the discriminant is set, it is always set
index 8f6abe7a912feefefadb5ac24abbc8dbe97c3af9..ced97b2c788426f607bb59602b7d83adb43bd113 100644 (file)
@@ -404,6 +404,18 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
     }
 }
 
+pub fn remove_unused_definitions<'tcx>(body: &mut Body<'tcx>) {
+    // First, we're going to get a count of *actual* uses for every `Local`.
+    let mut used_locals = UsedLocals::new(body);
+
+    // Next, we're going to remove any `Local` with zero actual uses. When we remove those
+    // `Locals`, we're also going to subtract any uses of other `Locals` from the `used_locals`
+    // count. For example, if we removed `_2 = discriminant(_1)`, then we'll subtract one from
+    // `use_counts[_1]`. That in turn might make `_1` unused, so we loop until we hit a
+    // fixedpoint where there are no more unused locals.
+    remove_unused_definitions_helper(&mut used_locals, body);
+}
+
 pub fn simplify_locals<'tcx>(body: &mut Body<'tcx>, tcx: TyCtxt<'tcx>) {
     // First, we're going to get a count of *actual* uses for every `Local`.
     let mut used_locals = UsedLocals::new(body);
@@ -413,7 +425,7 @@ pub fn simplify_locals<'tcx>(body: &mut Body<'tcx>, tcx: TyCtxt<'tcx>) {
     // count. For example, if we removed `_2 = discriminant(_1)`, then we'll subtract one from
     // `use_counts[_1]`. That in turn might make `_1` unused, so we loop until we hit a
     // fixedpoint where there are no more unused locals.
-    remove_unused_definitions(&mut used_locals, body);
+    remove_unused_definitions_helper(&mut used_locals, body);
 
     // Finally, we'll actually do the work of shrinking `body.local_decls` and remapping the `Local`s.
     let map = make_local_map(&mut body.local_decls, &used_locals);
@@ -517,7 +529,7 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
                 self.super_statement(statement, location);
             }
 
-            StatementKind::Nop => {}
+            StatementKind::ConstEvalCounter | StatementKind::Nop => {}
 
             StatementKind::StorageLive(_local) | StatementKind::StorageDead(_local) => {}
 
@@ -548,7 +560,7 @@ fn visit_local(&mut self, local: Local, _ctx: PlaceContext, _location: Location)
 }
 
 /// Removes unused definitions. Updates the used locals to reflect the changes made.
-fn remove_unused_definitions(used_locals: &mut UsedLocals, body: &mut Body<'_>) {
+fn remove_unused_definitions_helper(used_locals: &mut UsedLocals, body: &mut Body<'_>) {
     // The use counts are updated as we remove the statements. A local might become unused
     // during the retain operation, leading to a temporary inconsistency (storage statements or
     // definitions referencing the local might remain). For correctness it is crucial that this
diff --git a/compiler/rustc_mir_transform/src/ssa.rs b/compiler/rustc_mir_transform/src/ssa.rs
new file mode 100644 (file)
index 0000000..bc3fe65
--- /dev/null
@@ -0,0 +1,222 @@
+use either::Either;
+use rustc_data_structures::graph::dominators::Dominators;
+use rustc_index::bit_set::BitSet;
+use rustc_index::vec::IndexVec;
+use rustc_middle::middle::resolve_lifetime::Set1;
+use rustc_middle::mir::visit::*;
+use rustc_middle::mir::*;
+use rustc_middle::ty::{ParamEnv, TyCtxt};
+
+#[derive(Debug)]
+pub struct SsaLocals {
+    /// Assignments to each local. This defines whether the local is SSA.
+    assignments: IndexVec<Local, Set1<LocationExtended>>,
+    /// We visit the body in reverse postorder, to ensure each local is assigned before it is used.
+    /// We remember the order in which we saw the assignments to compute the SSA values in a single
+    /// pass.
+    assignment_order: Vec<Local>,
+    /// Copy equivalence classes between locals. See `copy_classes` for documentation.
+    copy_classes: IndexVec<Local, Local>,
+}
+
+impl SsaLocals {
+    pub fn new<'tcx>(
+        tcx: TyCtxt<'tcx>,
+        param_env: ParamEnv<'tcx>,
+        body: &Body<'tcx>,
+        borrowed_locals: &BitSet<Local>,
+    ) -> SsaLocals {
+        let assignment_order = Vec::new();
+
+        let assignments = IndexVec::from_elem(Set1::Empty, &body.local_decls);
+        let dominators = body.basic_blocks.dominators();
+        let mut visitor = SsaVisitor { assignments, assignment_order, dominators };
+
+        for (local, decl) in body.local_decls.iter_enumerated() {
+            if matches!(body.local_kind(local), LocalKind::Arg) {
+                visitor.assignments[local] = Set1::One(LocationExtended::Arg);
+            }
+            if borrowed_locals.contains(local) && !decl.ty.is_freeze(tcx, param_env) {
+                visitor.assignments[local] = Set1::Many;
+            }
+        }
+
+        for (bb, data) in traversal::reverse_postorder(body) {
+            visitor.visit_basic_block_data(bb, data);
+        }
+
+        for var_debug_info in &body.var_debug_info {
+            visitor.visit_var_debug_info(var_debug_info);
+        }
+
+        debug!(?visitor.assignments);
+
+        visitor
+            .assignment_order
+            .retain(|&local| matches!(visitor.assignments[local], Set1::One(_)));
+        debug!(?visitor.assignment_order);
+
+        let copy_classes = compute_copy_classes(&visitor, body);
+
+        SsaLocals {
+            assignments: visitor.assignments,
+            assignment_order: visitor.assignment_order,
+            copy_classes,
+        }
+    }
+
+    pub fn is_ssa(&self, local: Local) -> bool {
+        matches!(self.assignments[local], Set1::One(_))
+    }
+
+    pub fn assignments<'a, 'tcx>(
+        &'a self,
+        body: &'a Body<'tcx>,
+    ) -> impl Iterator<Item = (Local, &'a Rvalue<'tcx>)> + 'a {
+        self.assignment_order.iter().filter_map(|&local| {
+            if let Set1::One(LocationExtended::Plain(loc)) = self.assignments[local] {
+                // `loc` must point to a direct assignment to `local`.
+                let Either::Left(stmt) = body.stmt_at(loc) else { bug!() };
+                let Some((target, rvalue)) = stmt.kind.as_assign() else { bug!() };
+                assert_eq!(target.as_local(), Some(local));
+                Some((local, rvalue))
+            } else {
+                None
+            }
+        })
+    }
+
+    /// Compute the equivalence classes for locals, based on copy statements.
+    ///
+    /// The returned vector maps each local to the one it copies. In the following case:
+    ///   _a = &mut _0
+    ///   _b = move? _a
+    ///   _c = move? _a
+    ///   _d = move? _c
+    /// We return the mapping
+    ///   _a => _a // not a copy so, represented by itself
+    ///   _b => _a
+    ///   _c => _a
+    ///   _d => _a // transitively through _c
+    ///
+    /// Exception: we do not see through the return place, as it cannot be substituted.
+    pub fn copy_classes(&self) -> &IndexVec<Local, Local> {
+        &self.copy_classes
+    }
+
+    /// Make a property uniform on a copy equivalence class by removing elements.
+    pub fn meet_copy_equivalence(&self, property: &mut BitSet<Local>) {
+        // Consolidate to have a local iff all its copies are.
+        //
+        // `copy_classes` defines equivalence classes between locals. The `local`s that recursively
+        // move/copy the same local all have the same `head`.
+        for (local, &head) in self.copy_classes.iter_enumerated() {
+            // If any copy does not have `property`, then the head is not.
+            if !property.contains(local) {
+                property.remove(head);
+            }
+        }
+        for (local, &head) in self.copy_classes.iter_enumerated() {
+            // If any copy does not have `property`, then the head doesn't either,
+            // then no copy has `property`.
+            if !property.contains(head) {
+                property.remove(local);
+            }
+        }
+
+        // Verify that we correctly computed equivalence classes.
+        #[cfg(debug_assertions)]
+        for (local, &head) in self.copy_classes.iter_enumerated() {
+            assert_eq!(property.contains(local), property.contains(head));
+        }
+    }
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+enum LocationExtended {
+    Plain(Location),
+    Arg,
+}
+
+struct SsaVisitor {
+    dominators: Dominators<BasicBlock>,
+    assignments: IndexVec<Local, Set1<LocationExtended>>,
+    assignment_order: Vec<Local>,
+}
+
+impl<'tcx> Visitor<'tcx> for SsaVisitor {
+    fn visit_local(&mut self, local: Local, ctxt: PlaceContext, loc: Location) {
+        match ctxt {
+            PlaceContext::MutatingUse(MutatingUseContext::Store) => {
+                self.assignments[local].insert(LocationExtended::Plain(loc));
+                self.assignment_order.push(local);
+            }
+            // Anything can happen with raw pointers, so remove them.
+            PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf)
+            | PlaceContext::MutatingUse(_) => self.assignments[local] = Set1::Many,
+            // Immutable borrows are taken into account in `SsaLocals::new` by
+            // removing non-freeze locals.
+            PlaceContext::NonMutatingUse(_) => {
+                let set = &mut self.assignments[local];
+                let assign_dominates = match *set {
+                    Set1::Empty | Set1::Many => false,
+                    Set1::One(LocationExtended::Arg) => true,
+                    Set1::One(LocationExtended::Plain(assign)) => {
+                        assign.successor_within_block().dominates(loc, &self.dominators)
+                    }
+                };
+                // We are visiting a use that is not dominated by an assignment.
+                // Either there is a cycle involved, or we are reading for uninitialized local.
+                // Bail out.
+                if !assign_dominates {
+                    *set = Set1::Many;
+                }
+            }
+            PlaceContext::NonUse(_) => {}
+        }
+    }
+}
+
+#[instrument(level = "trace", skip(ssa, body))]
+fn compute_copy_classes(ssa: &SsaVisitor, body: &Body<'_>) -> IndexVec<Local, Local> {
+    let mut copies = IndexVec::from_fn_n(|l| l, body.local_decls.len());
+
+    for &local in &ssa.assignment_order {
+        debug!(?local);
+
+        if local == RETURN_PLACE {
+            // `_0` is special, we cannot rename it.
+            continue;
+        }
+
+        // This is not SSA: mark that we don't know the value.
+        debug!(assignments = ?ssa.assignments[local]);
+        let Set1::One(LocationExtended::Plain(loc)) = ssa.assignments[local] else { continue };
+
+        // `loc` must point to a direct assignment to `local`.
+        let Either::Left(stmt) = body.stmt_at(loc) else { bug!() };
+        let Some((_target, rvalue)) = stmt.kind.as_assign() else { bug!() };
+        assert_eq!(_target.as_local(), Some(local));
+
+        let (Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) | Rvalue::CopyForDeref(place))
+            = rvalue
+        else { continue };
+
+        let Some(rhs) = place.as_local() else { continue };
+        let Set1::One(_) = ssa.assignments[rhs] else { continue };
+
+        // We visit in `assignment_order`, ie. reverse post-order, so `rhs` has been
+        // visited before `local`, and we just have to copy the representing local.
+        copies[local] = copies[rhs];
+    }
+
+    debug!(?copies);
+
+    // Invariant: `copies` must point to the head of an equivalence class.
+    #[cfg(debug_assertions)]
+    for &head in copies.iter() {
+        assert_eq!(copies[head], head);
+    }
+
+    copies
+}
index 40763da0bb5470ce20924fd76da86713e47e21dd..054b41b478d60516d53c729faa2f1ecdcd1bb5d9 100644 (file)
@@ -649,6 +649,48 @@ pub(crate) struct MatchArmBodyWithoutBraces {
     pub sub: MatchArmBodyWithoutBracesSugg,
 }
 
+#[derive(Diagnostic)]
+#[diag(parse_inclusive_range_extra_equals)]
+#[note]
+pub(crate) struct InclusiveRangeExtraEquals {
+    #[primary_span]
+    #[suggestion(
+        suggestion_remove_eq,
+        style = "short",
+        code = "..=",
+        applicability = "maybe-incorrect"
+    )]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_inclusive_range_match_arrow)]
+pub(crate) struct InclusiveRangeMatchArrow {
+    #[primary_span]
+    pub span: Span,
+    #[suggestion(
+        suggestion_add_space,
+        style = "verbose",
+        code = " ",
+        applicability = "machine-applicable"
+    )]
+    pub after_pat: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_inclusive_range_no_end, code = "E0586")]
+#[note]
+pub(crate) struct InclusiveRangeNoEnd {
+    #[primary_span]
+    #[suggestion(
+        suggestion_open_range,
+        code = "..",
+        applicability = "machine-applicable",
+        style = "short"
+    )]
+    pub span: Span,
+}
+
 #[derive(Subdiagnostic)]
 pub(crate) enum MatchArmBodyWithoutBracesSugg {
     #[multipart_suggestion(suggestion_add_braces, applicability = "machine-applicable")]
index 3225a309a319b6286ce8baf02c8a3dd63a23a4cb..17d1e200b41aab6bd677a8e0c9e19d7104194056 100644 (file)
@@ -3168,7 +3168,7 @@ fn mk_range(
         limits: RangeLimits,
     ) -> ExprKind {
         if end.is_none() && limits == RangeLimits::Closed {
-            self.inclusive_range_with_incorrect_end(self.prev_token.span);
+            self.inclusive_range_with_incorrect_end();
             ExprKind::Err
         } else {
             ExprKind::Range(start, end, limits)
index e5411538eea220ce5ff179026be98d677b08dc67..912f7cc14f6cc238589469007013becf9d6239c2 100644 (file)
@@ -1,5 +1,7 @@
 use super::{ForceCollect, Parser, PathStyle, TrailingToken};
-use crate::errors::RemoveLet;
+use crate::errors::{
+    InclusiveRangeExtraEquals, InclusiveRangeMatchArrow, InclusiveRangeNoEnd, RemoveLet,
+};
 use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
 use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor};
 use rustc_ast::ptr::P;
@@ -9,7 +11,7 @@
     PatField, PatKind, Path, QSelf, RangeEnd, RangeSyntax,
 };
 use rustc_ast_pretty::pprust;
-use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, PResult};
+use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, PResult};
 use rustc_session::errors::ExprParenthesesNeeded;
 use rustc_span::source_map::{respan, Span, Spanned};
 use rustc_span::symbol::{kw, sym, Ident};
@@ -746,47 +748,52 @@ fn parse_pat_range_begin_with(
             // Parsing e.g. `X..`.
             if let RangeEnd::Included(_) = re.node {
                 // FIXME(Centril): Consider semantic errors instead in `ast_validation`.
-                self.inclusive_range_with_incorrect_end(re.span);
+                self.inclusive_range_with_incorrect_end();
             }
             None
         };
         Ok(PatKind::Range(Some(begin), end, re))
     }
 
-    pub(super) fn inclusive_range_with_incorrect_end(&mut self, span: Span) {
+    pub(super) fn inclusive_range_with_incorrect_end(&mut self) {
         let tok = &self.token;
-
+        let span = self.prev_token.span;
         // If the user typed "..==" instead of "..=", we want to give them
         // a specific error message telling them to use "..=".
+        // If they typed "..=>", suggest they use ".. =>".
         // Otherwise, we assume that they meant to type a half open exclusive
         // range and give them an error telling them to do that instead.
-        if matches!(tok.kind, token::Eq) && tok.span.lo() == span.hi() {
-            let span_with_eq = span.to(tok.span);
+        let no_space = tok.span.lo() == span.hi();
+        match tok.kind {
+            token::Eq if no_space => {
+                let span_with_eq = span.to(tok.span);
 
-            // Ensure the user doesn't receive unhelpful unexpected token errors
-            self.bump();
-            if self.is_pat_range_end_start(0) {
-                let _ = self.parse_pat_range_end().map_err(|e| e.cancel());
-            }
+                // Ensure the user doesn't receive unhelpful unexpected token errors
+                self.bump();
+                if self.is_pat_range_end_start(0) {
+                    let _ = self.parse_pat_range_end().map_err(|e| e.cancel());
+                }
 
-            self.error_inclusive_range_with_extra_equals(span_with_eq);
-        } else {
-            self.error_inclusive_range_with_no_end(span);
+                self.error_inclusive_range_with_extra_equals(span_with_eq);
+            }
+            token::Gt if no_space => {
+                self.error_inclusive_range_match_arrow(span);
+            }
+            _ => self.error_inclusive_range_with_no_end(span),
         }
     }
 
     fn error_inclusive_range_with_extra_equals(&self, span: Span) {
-        self.struct_span_err(span, "unexpected `=` after inclusive range")
-            .span_suggestion_short(span, "use `..=` instead", "..=", Applicability::MaybeIncorrect)
-            .note("inclusive ranges end with a single equals sign (`..=`)")
-            .emit();
+        self.sess.emit_err(InclusiveRangeExtraEquals { span });
+    }
+
+    fn error_inclusive_range_match_arrow(&self, span: Span) {
+        let after_pat = span.with_hi(span.hi() - rustc_span::BytePos(1)).shrink_to_hi();
+        self.sess.emit_err(InclusiveRangeMatchArrow { span, after_pat });
     }
 
     fn error_inclusive_range_with_no_end(&self, span: Span) {
-        struct_span_err!(self.sess.span_diagnostic, span, E0586, "inclusive range with no end")
-            .span_suggestion_short(span, "use `..` instead", "..", Applicability::MachineApplicable)
-            .note("inclusive ranges must be bounded at the end (`..=b` or `a..=b`)")
-            .emit();
+        self.sess.emit_err(InclusiveRangeNoEnd { span });
     }
 
     /// Parse a range-to pattern, `..X` or `..=X` where `X` remains to be parsed.
index 25de0a9e75014ae019b680aedaf410e4563bcc5d..82d9138c7a331948c16e4c50bf711f558a845d33 100644 (file)
@@ -1048,7 +1048,7 @@ fn parse_generic_ty_bound(
                 self.parse_remaining_bounds(bounds, true)?;
                 self.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
                 let sp = vec![lo, self.prev_token.span];
-                let sugg: Vec<_> = sp.iter().map(|sp| (*sp, String::new())).collect();
+                let sugg = vec![(lo, String::from(" ")), (self.prev_token.span, String::new())];
                 self.struct_span_err(sp, "incorrect braces around trait bounds")
                     .multipart_suggestion(
                         "remove the parentheses",
index db95b8bca2f8ce78791f77dfd1cb801dd9151c50..c49c5fa990413d1aa3a109612c2773f3b646b65f 100644 (file)
@@ -2573,6 +2573,7 @@ fn parse_pretty(unstable_opts: &UnstableOptions, efmt: ErrorOutputType) -> Optio
         "hir,typed" => Hir(PpHirMode::Typed),
         "hir-tree" => HirTree,
         "thir-tree" => ThirTree,
+        "thir-flat" => ThirFlat,
         "mir" => Mir,
         "mir-cfg" => MirCFG,
         name => early_error(
@@ -2581,7 +2582,8 @@ fn parse_pretty(unstable_opts: &UnstableOptions, efmt: ErrorOutputType) -> Optio
                 "argument to `unpretty` must be one of `normal`, `identified`, \
                             `expanded`, `expanded,identified`, `expanded,hygiene`, \
                             `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \
-                            `hir,typed`, `hir-tree`, `thir-tree`, `mir` or `mir-cfg`; got {name}"
+                            `hir,typed`, `hir-tree`, `thir-tree`, `thir-flat`, `mir` or \
+                            `mir-cfg`; got {name}"
             ),
         ),
     };
@@ -2736,6 +2738,8 @@ pub enum PpMode {
     HirTree,
     /// `-Zunpretty=thir-tree`
     ThirTree,
+    /// `-Zunpretty=`thir-flat`
+    ThirFlat,
     /// `-Zunpretty=mir`
     Mir,
     /// `-Zunpretty=mir-cfg`
@@ -2754,6 +2758,7 @@ pub fn needs_ast_map(&self) -> bool {
             | Hir(_)
             | HirTree
             | ThirTree
+            | ThirFlat
             | Mir
             | MirCFG => true,
         }
@@ -2763,13 +2768,13 @@ pub fn needs_hir(&self) -> bool {
         match *self {
             Source(_) | AstTree(_) => false,
 
-            Hir(_) | HirTree | ThirTree | Mir | MirCFG => true,
+            Hir(_) | HirTree | ThirTree | ThirFlat | Mir | MirCFG => true,
         }
     }
 
     pub fn needs_analysis(&self) -> bool {
         use PpMode::*;
-        matches!(*self, Mir | MirCFG | ThirTree)
+        matches!(*self, Mir | MirCFG | ThirTree | ThirFlat)
     }
 }
 
index 66b100c103e4528292ae973b7e8bb0b8517e9704..0db4d85ff4b679f4934bfe5a0ee7edef577454fe 100644 (file)
@@ -1618,6 +1618,8 @@ pub(crate) fn parse_proc_macro_execution_strategy(
         "measure time of each LLVM pass (default: no)"),
     time_passes: bool = (false, parse_bool, [UNTRACKED],
         "measure time of each rustc pass (default: no)"),
+    tiny_const_eval_limit: bool = (false, parse_bool, [TRACKED],
+        "sets a tiny, non-configurable limit for const eval; useful for compiler tests"),
     #[rustc_lint_opt_deny_field_access("use `Session::tls_model` instead of this field")]
     tls_model: Option<TlsModel> = (None, parse_tls_model, [TRACKED],
         "choose the TLS model to use (`rustc --print tls-models` for details)"),
index 30ca0b8060d22b2bdfbd5668aafe03c41ff20109..f1119214be44db4e7d61615bfa9f488253c2f634 100644 (file)
         mul,
         mul_assign,
         mul_with_overflow,
+        multiple_supertrait_upcastable,
         must_not_suspend,
         must_use,
         naked,
index f7cf81da497529af14920277b0bb892aa9323ae6..e44fd82ba22362d1b26e06032c275027e36c39a2 100644 (file)
@@ -78,7 +78,7 @@ pub(super) enum CandidateSource {
     ///     let _y = x.clone();
     /// }
     /// ```
-    AliasBound(usize),
+    AliasBound,
 }
 
 pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy + Eq {
@@ -242,8 +242,6 @@ fn assemble_candidates_after_normalizing_self_ty<G: GoalKind<'tcx>>(
             // NOTE: Alternatively we could call `evaluate_goal` here and only have a `Normalized` candidate.
             // This doesn't work as long as we use `CandidateSource` in winnowing.
             let goal = goal.with(tcx, goal.predicate.with_self_ty(tcx, normalized_ty));
-            // FIXME: This is broken if we care about the `usize` of `AliasBound` because the self type
-            // could be normalized to yet another projection with different item bounds.
             let normalized_candidates = self.assemble_and_evaluate_candidates(goal);
             for mut normalized_candidate in normalized_candidates {
                 normalized_candidate.result =
@@ -368,15 +366,14 @@ fn assemble_alias_bound_candidates<G: GoalKind<'tcx>>(
             ty::Alias(_, alias_ty) => alias_ty,
         };
 
-        for (i, (assumption, _)) in self
+        for (assumption, _) in self
             .tcx()
             .bound_explicit_item_bounds(alias_ty.def_id)
             .subst_iter_copied(self.tcx(), alias_ty.substs)
-            .enumerate()
         {
             match G::consider_assumption(self, goal, assumption) {
                 Ok(result) => {
-                    candidates.push(Candidate { source: CandidateSource::AliasBound(i), result })
+                    candidates.push(Candidate { source: CandidateSource::AliasBound, result })
                 }
                 Err(NoSolution) => (),
             }
index e240dd5a2257a062f2b8e117e104c7a34b952f79..dd16672cc7a0110fe6917dd9d73f45c7cbf925f4 100644 (file)
 // preserves universes and creates a unique var (in the highest universe) for each
 // appearance of a region.
 
-// FIXME: `CanonicalVarValues` should be interned and `Copy`.
-
 // FIXME: uses of `infcx.at` need to enable deferred projection equality once that's implemented.
 
 use std::mem;
 
 use rustc_hir::def_id::DefId;
-use rustc_infer::infer::canonical::{Canonical, CanonicalVarKind, CanonicalVarValues};
+use rustc_infer::infer::canonical::{Canonical, CanonicalVarValues};
 use rustc_infer::infer::canonical::{OriginalQueryValues, QueryRegionConstraints, QueryResponse};
 use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt};
 use rustc_infer::traits::query::NoSolution;
@@ -225,7 +223,7 @@ fn make_canonical_response(&self, certainty: Certainty) -> QueryResult<'tcx> {
         let external_constraints = take_external_constraints(self.infcx)?;
 
         Ok(self.infcx.canonicalize_response(Response {
-            var_values: self.var_values.clone(),
+            var_values: self.var_values,
             external_constraints,
             certainty,
         }))
@@ -363,7 +361,7 @@ fn compute_closure_kind_goal(
     }
 
     fn compute_object_safe_goal(&mut self, trait_def_id: DefId) -> QueryResult<'tcx> {
-        if self.tcx().is_object_safe(trait_def_id) {
+        if self.tcx().check_is_object_safe(trait_def_id) {
             self.make_canonical_response(Certainty::Yes)
         } else {
             Err(NoSolution)
@@ -483,32 +481,11 @@ pub(super) fn response_no_constraints<'tcx>(
     goal: Canonical<'tcx, impl Sized>,
     certainty: Certainty,
 ) -> QueryResult<'tcx> {
-    let var_values = goal
-        .variables
-        .iter()
-        .enumerate()
-        .map(|(i, info)| match info.kind {
-            CanonicalVarKind::Ty(_) | CanonicalVarKind::PlaceholderTy(_) => {
-                tcx.mk_ty(ty::Bound(ty::INNERMOST, ty::BoundVar::from_usize(i).into())).into()
-            }
-            CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => {
-                let br = ty::BoundRegion {
-                    var: ty::BoundVar::from_usize(i),
-                    kind: ty::BrAnon(i as u32, None),
-                };
-                tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)).into()
-            }
-            CanonicalVarKind::Const(_, ty) | CanonicalVarKind::PlaceholderConst(_, ty) => tcx
-                .mk_const(ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from_usize(i)), ty)
-                .into(),
-        })
-        .collect();
-
     Ok(Canonical {
         max_universe: goal.max_universe,
         variables: goal.variables,
         value: Response {
-            var_values: CanonicalVarValues { var_values },
+            var_values: CanonicalVarValues::make_identity(tcx, goal.variables),
             external_constraints: Default::default(),
             certainty,
         },
index 1961344e8385f18e9aa938369dae9c4c4cdfdd2a..b175a6dde179f1378ab0570c69607a5bbce246df 100644 (file)
@@ -171,7 +171,7 @@ fn project_candidate_should_be_dropped_in_favor_of(
             (CandidateSource::Impl(_), _)
             | (CandidateSource::ParamEnv(_), _)
             | (CandidateSource::BuiltinImpl, _)
-            | (CandidateSource::AliasBound(_), _) => unimplemented!(),
+            | (CandidateSource::AliasBound, _) => unimplemented!(),
         }
     }
 }
index 730a8e6125887ae6fcdfb1e7379f38df33d2016e..80a388b8498b9784677f17ee2fdf7bb39f0a0761 100644 (file)
@@ -95,6 +95,7 @@ pub(super) fn depth(&self, entry_index: EntryIndex) -> StackDepth {
     }
 
     pub(super) fn provisional_result(&self, entry_index: EntryIndex) -> QueryResult<'tcx> {
+        // FIXME: Responses should probably be `Copy` as well
         self.entries[entry_index].response.clone()
     }
 }
index 45b6a5f4ec578b3ce19b4c9f60a03c9649fc88b5..1ea8fb8fd3dcc8d0d40a2c9dd415e46d808bc101 100644 (file)
@@ -322,7 +322,7 @@ fn trait_candidate_should_be_dropped_in_favor_of(
         match (candidate.source, other.source) {
             (CandidateSource::Impl(_), _)
             | (CandidateSource::ParamEnv(_), _)
-            | (CandidateSource::AliasBound(_), _)
+            | (CandidateSource::AliasBound, _)
             | (CandidateSource::BuiltinImpl, _) => unimplemented!(),
         }
     }
index ee0c07e15a3add65ba31bac75870c6ec01f2f3ec..b35b9d62759c73267bf4d3f217616a6305b23592 100644 (file)
@@ -1748,7 +1748,7 @@ fn suggest_impl_trait(
                 // If the `dyn Trait` is not object safe, do not suggest `Box<dyn Trait>`.
                 predicates
                     .principal_def_id()
-                    .map_or(true, |def_id| self.tcx.object_safety_violations(def_id).is_empty())
+                    .map_or(true, |def_id| self.tcx.check_is_object_safe(def_id))
             }
             // We only want to suggest `impl Trait` to `dyn Trait`s.
             // For example, `fn foo() -> str` needs to be filtered out.
index 6c18bf8d22df830235169bac1a2ca38614cf8ce4..18d30771035fdbcebf4bdf961ff9bbccd2993ed1 100644 (file)
@@ -369,7 +369,7 @@ fn process_obligation(
                 }
 
                 ty::PredicateKind::ObjectSafe(trait_def_id) => {
-                    if !self.selcx.tcx().is_object_safe(trait_def_id) {
+                    if !self.selcx.tcx().check_is_object_safe(trait_def_id) {
                         ProcessResult::Error(CodeSelectionError(Unimplemented))
                     } else {
                         ProcessResult::Changed(vec![])
index 55c2f7e2e358d0433d51fcf36ee5fde45137551b..565cfca9090e19c2c5e41d7d24fd0eb874661733 100644 (file)
@@ -62,6 +62,37 @@ fn object_safety_violations(tcx: TyCtxt<'_>, trait_def_id: DefId) -> &'_ [Object
     )
 }
 
+fn check_is_object_safe(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {
+    let violations = tcx.object_safety_violations(trait_def_id);
+
+    if violations.is_empty() {
+        return true;
+    }
+
+    // If the trait contains any other violations, then let the error reporting path
+    // report it instead of emitting a warning here.
+    if violations.iter().all(|violation| {
+        matches!(
+            violation,
+            ObjectSafetyViolation::Method(_, MethodViolationCode::WhereClauseReferencesSelf, _)
+        )
+    }) {
+        for violation in violations {
+            if let ObjectSafetyViolation::Method(
+                _,
+                MethodViolationCode::WhereClauseReferencesSelf,
+                span,
+            ) = violation
+            {
+                lint_object_unsafe_trait(tcx, *span, trait_def_id, &violation);
+            }
+        }
+        return true;
+    }
+
+    false
+}
+
 /// We say a method is *vtable safe* if it can be invoked on a trait
 /// object. Note that object-safe traits can have some
 /// non-vtable-safe methods, so long as they require `Self: Sized` or
@@ -93,19 +124,6 @@ fn object_safety_violations_for_trait(
             object_safety_violation_for_method(tcx, trait_def_id, &item)
                 .map(|(code, span)| ObjectSafetyViolation::Method(item.name, code, span))
         })
-        .filter(|violation| {
-            if let ObjectSafetyViolation::Method(
-                _,
-                MethodViolationCode::WhereClauseReferencesSelf,
-                span,
-            ) = violation
-            {
-                lint_object_unsafe_trait(tcx, *span, trait_def_id, &violation);
-                false
-            } else {
-                true
-            }
-        })
         .collect();
 
     // Check the trait itself.
@@ -866,5 +884,6 @@ pub fn contains_illegal_impl_trait_in_trait<'tcx>(
 }
 
 pub fn provide(providers: &mut ty::query::Providers) {
-    *providers = ty::query::Providers { object_safety_violations, ..*providers };
+    *providers =
+        ty::query::Providers { object_safety_violations, check_is_object_safe, ..*providers };
 }
index 52f4d29181d2922005e6bfa99a31ae30dd6ecbdd..7b7abcf552ab7da31b513f5346fbad37e814113a 100644 (file)
@@ -466,7 +466,7 @@ fn assemble_candidates_from_object_ty(
                     if let Some(principal) = data.principal() {
                         if !self.infcx.tcx.features().object_safe_for_dispatch {
                             principal.with_self_ty(self.tcx(), self_ty)
-                        } else if self.tcx().is_object_safe(principal.def_id()) {
+                        } else if self.tcx().check_is_object_safe(principal.def_id()) {
                             principal.with_self_ty(self.tcx(), self_ty)
                         } else {
                             return;
index 2c41d28400c8258e1d643fc4bc730b9cbbd89ea0..89a8fdbac1cbc7794ae63b2d01c47a6da3da3d95 100644 (file)
@@ -1008,7 +1008,7 @@ fn confirm_builtin_unsize_candidate(
             // `T` -> `Trait`
             (_, &ty::Dynamic(ref data, r, ty::Dyn)) => {
                 let mut object_dids = data.auto_traits().chain(data.principal_def_id());
-                if let Some(did) = object_dids.find(|did| !tcx.is_object_safe(*did)) {
+                if let Some(did) = object_dids.find(|did| !tcx.check_is_object_safe(*did)) {
                     return Err(TraitNotObjectSafe(did));
                 }
 
index efd21b979ceb58289dfc7933dd5145841bda46d7..b8f5aeee2d593f4386107e3d11b4f9a2144cffa4 100644 (file)
@@ -797,7 +797,7 @@ fn evaluate_predicate_recursively<'o>(
                 }
 
                 ty::PredicateKind::ObjectSafe(trait_def_id) => {
-                    if self.tcx().is_object_safe(trait_def_id) {
+                    if self.tcx().check_is_object_safe(trait_def_id) {
                         Ok(EvaluatedToOk)
                     } else {
                         Ok(EvaluatedToErr)
index 2e9107e153c2a96a1d39b03e39b86915e68f3c13..84f7e8362081871f9321492d60eaef815efeee43 100644 (file)
@@ -580,7 +580,7 @@ fn well_known_trait_id(
     }
 
     fn is_object_safe(&self, trait_id: chalk_ir::TraitId<RustInterner<'tcx>>) -> bool {
-        self.interner.tcx.is_object_safe(trait_id.0)
+        self.interner.tcx.check_is_object_safe(trait_id.0)
     }
 
     fn hidden_opaque_type(
index f76386fa720dfaa6b2e9e5dbe95ba8ccae81ba10..13d83b92689415f84fee9a26f9c96069c1822981 100644 (file)
@@ -8,13 +8,10 @@
 
 use rustc_data_structures::fx::FxHashMap;
 
-use rustc_index::vec::IndexVec;
-
 use rustc_middle::infer::canonical::{CanonicalTyVarKind, CanonicalVarKind};
 use rustc_middle::traits::ChalkRustInterner;
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::subst::GenericArg;
-use rustc_middle::ty::{self, BoundVar, ParamTy, TyCtxt, TypeFoldable, TypeVisitable};
+use rustc_middle::ty::{self, ParamTy, TyCtxt, TypeFoldable, TypeVisitable};
 
 use rustc_infer::infer::canonical::{
     Canonical, CanonicalVarValues, Certainty, QueryRegionConstraints, QueryResponse,
@@ -100,11 +97,13 @@ pub(crate) fn evaluate_goal<'tcx>(
                          binders: chalk_ir::CanonicalVarKinds<_>| {
         use rustc_middle::infer::canonical::CanonicalVarInfo;
 
-        let mut var_values: IndexVec<BoundVar, GenericArg<'tcx>> = IndexVec::new();
         let mut reverse_param_substitutor = ReverseParamsSubstitutor::new(tcx, params);
-        subst.as_slice(interner).iter().for_each(|p| {
-            var_values.push(p.lower_into(interner).fold_with(&mut reverse_param_substitutor));
-        });
+        let var_values = tcx.mk_substs(
+            subst
+                .as_slice(interner)
+                .iter()
+                .map(|p| p.lower_into(interner).fold_with(&mut reverse_param_substitutor)),
+        );
         let variables: Vec<_> = binders
             .iter(interner)
             .map(|var| {
@@ -159,8 +158,7 @@ pub(crate) fn evaluate_goal<'tcx>(
                             max_universe: ty::UniverseIndex::from_usize(0),
                             variables: obligation.variables,
                             value: QueryResponse {
-                                var_values: CanonicalVarValues { var_values: IndexVec::new() }
-                                    .make_identity(tcx),
+                                var_values: CanonicalVarValues::dummy(),
                                 region_constraints: QueryRegionConstraints::default(),
                                 certainty: Certainty::Ambiguous,
                                 opaque_types: vec![],
index eadb35cb96d422cfcdc84250b820b7cef65ea54c..1da86e1a46a572149937f8fcd7de92c942da5cfe 100644 (file)
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::fmt::Error;
 #[stable(feature = "rust1", since = "1.0.0")]
-pub use core::fmt::{write, ArgumentV1, Arguments};
+pub use core::fmt::{write, Arguments};
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::fmt::{Binary, Octal};
 #[stable(feature = "rust1", since = "1.0.0")]
index ca75c3895f41f61547be83491e0c042102a4a927..76dabfb429dd503ab945ff002028f0a7f2d375dc 100644 (file)
@@ -87,6 +87,7 @@
 #![warn(missing_debug_implementations)]
 #![warn(missing_docs)]
 #![allow(explicit_outlives_requirements)]
+#![cfg_attr(not(bootstrap), warn(multiple_supertrait_upcastable))]
 //
 // Library features:
 #![feature(alloc_layout_extra)]
 #![feature(c_unwind)]
 #![feature(with_negative_coherence)]
 #![cfg_attr(test, feature(panic_update_hook))]
+#![cfg_attr(not(bootstrap), feature(multiple_supertrait_upcastable))]
 //
 // Rustdoc features:
 #![feature(doc_cfg)]
index 7152300abcbf3a446cca031d797040d23abb2353..d2fac23ff18be7542729e0b6793d796daad17dd5 100644 (file)
@@ -28,6 +28,7 @@
 #[stable(feature = "rust1", since = "1.0.0")]
 #[cfg_attr(not(test), rustc_diagnostic_item = "Error")]
 #[rustc_has_incoherent_inherent_impls]
+#[cfg_attr(not(bootstrap), allow(multiple_supertrait_upcastable))]
 pub trait Error: Debug + Display {
     /// The lower-level source of this error, if any.
     ///
index 8790649abe6f1b90433171f95816072ecd05a4ca..6dfe36e6926ef057759d23d198abd83910688ada 100644 (file)
@@ -95,6 +95,7 @@
 #![warn(missing_docs)]
 #![allow(explicit_outlives_requirements)]
 #![allow(incomplete_features)]
+#![cfg_attr(not(bootstrap), warn(multiple_supertrait_upcastable))]
 //
 // Library features:
 #![feature(const_align_offset)]
 #![feature(unsized_fn_params)]
 #![feature(asm_const)]
 #![feature(const_transmute_copy)]
+#![cfg_attr(not(bootstrap), feature(multiple_supertrait_upcastable))]
 //
 // Target features:
 #![feature(arm_target_feature)]
index 2cae98b8e494334e640b3c936181cb1c6db32555..acd0fea4bc4105a03a1d793098e0a45a866a5166 100644 (file)
@@ -2574,12 +2574,13 @@ pub const fn abs_diff(self, other: Self) -> $UnsignedT {
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline(always)]
+        #[rustc_allow_const_fn_unstable(const_cmp)]
         pub const fn signum(self) -> Self {
-            match self {
-                n if n > 0 =>  1,
-                0          =>  0,
-                _          => -1,
-            }
+            // Picking the right way to phrase this is complicated
+            // (<https://graphics.stanford.edu/~seander/bithacks.html#CopyIntegerSign>)
+            // so delegate it to `Ord` which is already producing -1/0/+1
+            // exactly like we need and can be the place to deal with the complexity.
+            self.cmp(&0) as _
         }
 
         /// Returns `true` if `self` is positive and `false` if the number is zero or
index 5ec267c41e97ca77a5e3a920b30c918633e2fd77..b7046dd7c598c923f80b9bf470d957ebd64851f1 100644 (file)
@@ -1,4 +1,13 @@
 //! OS-specific networking functionality.
 
+// See cfg macros in `library/std/src/os/mod.rs` for why these platforms must
+// be special-cased during rustdoc generation.
+#[cfg(not(all(
+    doc,
+    any(
+        all(target_arch = "wasm32", not(target_os = "wasi")),
+        all(target_vendor = "fortanix", target_env = "sgx")
+    )
+)))]
 #[cfg(any(target_os = "linux", target_os = "android", doc))]
 pub(super) mod linux_ext;
index 3edbe7280774d44d75ff56e5bb4100ff6b10d272..403a5e627f1e7fe6b2b6b71c0c2c13ede23a3f5a 100644 (file)
@@ -7,6 +7,7 @@
 #[cfg(any(
     target_arch = "x86",
     target_arch = "arm",
+    target_arch = "m68k",
     target_arch = "mips",
     target_arch = "powerpc",
     target_arch = "powerpc64",
index ecd06ebf743ab49969617210f0b326e6b45aaf5a..acf9c29083f62ce26518f3be9fbf3b22bfa67e91 100644 (file)
@@ -1,6 +1,6 @@
 //! Temporal quantification.
 //!
-//! # Examples:
+//! # Examples
 //!
 //! There are multiple ways to create a new [`Duration`]:
 //!
index 24cbe035f2fa7e3e9082d38a6c44355dd47711da..1ee68c8540bcc39518f81c7609c08fb036314bd8 100644 (file)
@@ -53,6 +53,7 @@ pub struct ConsoleTestState {
     pub metrics: MetricMap,
     pub failures: Vec<(TestDesc, Vec<u8>)>,
     pub not_failures: Vec<(TestDesc, Vec<u8>)>,
+    pub ignores: Vec<(TestDesc, Vec<u8>)>,
     pub time_failures: Vec<(TestDesc, Vec<u8>)>,
     pub options: Options,
 }
@@ -76,6 +77,7 @@ pub fn new(opts: &TestOpts) -> io::Result<ConsoleTestState> {
             metrics: MetricMap::new(),
             failures: Vec::new(),
             not_failures: Vec::new(),
+            ignores: Vec::new(),
             time_failures: Vec::new(),
             options: opts.options,
         })
@@ -194,7 +196,10 @@ fn handle_test_result(st: &mut ConsoleTestState, completed_test: CompletedTest)
             st.passed += 1;
             st.not_failures.push((test, stdout));
         }
-        TestResult::TrIgnored => st.ignored += 1,
+        TestResult::TrIgnored => {
+            st.ignored += 1;
+            st.ignores.push((test, stdout));
+        }
         TestResult::TrBench(bs) => {
             st.metrics.insert_metric(
                 test.name.as_slice(),
index 0837ab16905130c18cd6c5086af909075c3d8feb..a431acfbc27538944219c626f48e10a0e7b0ec72 100644 (file)
@@ -254,6 +254,15 @@ fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result<bool> {
 
         self.write_plain("\n\n")?;
 
+        // Custom handling of cases where there is only 1 test to execute and that test was ignored.
+        // We want to show more detailed information(why was the test ignored) for investigation purposes.
+        if self.total_test_count == 1 && state.ignores.len() == 1 {
+            let test_desc = &state.ignores[0].0;
+            if let Some(im) = test_desc.ignore_message {
+                self.write_plain(format!("test: {}, ignore_message: {}\n\n", test_desc.name, im))?;
+            }
+        }
+
         Ok(success)
     }
 }
index 3a0260f86cf5d081f08a4b6122a0f40c3ed77b38..44776fb0a316df90b0198076335e2b323f976d2b 100644 (file)
@@ -790,6 +790,7 @@ fn should_sort_failures_before_printing_them() {
         failures: vec![(test_b, Vec::new()), (test_a, Vec::new())],
         options: Options::new(),
         not_failures: Vec::new(),
+        ignores: Vec::new(),
         time_failures: Vec::new(),
     };
 
index d44b96cfb991ece07a53944f225a0624737b2921..3a0be7a85356f9ab1f89e083a6d989ea5cbd25dd 100644 (file)
 use std::io;
 use std::io::ErrorKind;
 use std::path::{Path, PathBuf};
-use std::process::Command;
+use std::process::{Command, Stdio};
 use std::str;
 
 use build_helper::ci::CiEnv;
@@ -662,12 +662,32 @@ fn dir_is_empty(dir: &Path) -> bool {
 
         // Try passing `--progress` to start, then run git again without if that fails.
         let update = |progress: bool| {
-            let mut git = Command::new("git");
+            // Git is buggy and will try to fetch submodules from the tracking branch for *this* repository,
+            // even though that has no relation to the upstream for the submodule.
+            let current_branch = {
+                let output = self
+                    .config
+                    .git()
+                    .args(["symbolic-ref", "--short", "HEAD"])
+                    .stderr(Stdio::inherit())
+                    .output();
+                let output = t!(output);
+                if output.status.success() {
+                    Some(String::from_utf8(output.stdout).unwrap().trim().to_owned())
+                } else {
+                    None
+                }
+            };
+
+            let mut git = self.config.git();
+            if let Some(branch) = current_branch {
+                git.arg("-c").arg(format!("branch.{branch}.remote=origin"));
+            }
             git.args(&["submodule", "update", "--init", "--recursive", "--depth=1"]);
             if progress {
                 git.arg("--progress");
             }
-            git.arg(relative_path).current_dir(&self.config.src);
+            git.arg(relative_path);
             git
         };
         // NOTE: doesn't use `try_run` because this shouldn't print an error if it fails.
@@ -1431,6 +1451,14 @@ fn read_stamp_file(&self, stamp: &Path) -> Vec<(PathBuf, DependencyType)> {
             return Vec::new();
         }
 
+        if !stamp.exists() {
+            eprintln!(
+                "Error: Unable to find the stamp file {}, did you try to keep a nonexistent build stage?",
+                stamp.display()
+            );
+            crate::detail_exit(1);
+        }
+
         let mut paths = Vec::new();
         let contents = t!(fs::read(stamp), &stamp);
         // This is the method we use for extracting paths from the stamp file passed to us. See
index 6bdc88e18f530f8d9e2dc64ce6f41564a354c65f..5feba4e0605ecb55b2b04bcaa30576014c5492ee 100644 (file)
@@ -81,7 +81,7 @@ ENV RUST_CONFIGURE_ARGS \
       --set rust.jemalloc \
       --set rust.use-lld=true \
       --set rust.lto=thin
-ENV SCRIPT ../src/ci/pgo.sh python3 ../x.py dist \
+ENV SCRIPT python3 ../src/ci/stage-build.py python3 ../x.py dist \
     --host $HOSTS --target $HOSTS \
     --include-default-paths \
     build-manifest bootstrap
index c6d728eb80dd080377bf0a575b30cd828b49ab26..0b06f5e3623e31ac7ce3a892fecaaac3065e96fa 100755 (executable)
@@ -9,11 +9,5 @@ git clone --depth=1 https://github.com/rust-lang-nursery/rust-toolstate.git
 cd rust-toolstate
 python3 "../../src/tools/publish_toolstate.py" "$(git rev-parse HEAD)" \
     "$(git log --format=%s -n1 HEAD)" "" ""
-# Only check maintainers if this build is supposed to publish toolstate.
-# Builds that are not supposed to publish don't have the access token.
-if [ -n "${TOOLSTATE_PUBLISH+is_set}" ]; then
-  TOOLSTATE_VALIDATE_MAINTAINERS_REPO=rust-lang/rust python3 \
-      "../../src/tools/publish_toolstate.py"
-fi
 cd ..
 rm -rf rust-toolstate
index a466777dd46f85766125d8ec2a5e12655f32953a..5e676a470a034e2a8ea842da13b4ee2b94761308 100644 (file)
@@ -629,9 +629,7 @@ jobs:
 
           - name: i686-mingw-1
             env:
-              RUST_CONFIGURE_ARGS: >-
-                --build=i686-pc-windows-gnu
-                --set llvm.allow-old-toolchain
+              RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu
               SCRIPT: make ci-mingw-subset-1
               # We are intentionally allowing an old toolchain on this builder (and that's
               # incompatible with LLVM downloads today).
@@ -641,9 +639,7 @@ jobs:
 
           - name: i686-mingw-2
             env:
-              RUST_CONFIGURE_ARGS: >-
-                --build=i686-pc-windows-gnu
-                --set llvm.allow-old-toolchain
+              RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu
               SCRIPT: make ci-mingw-subset-2
               # We are intentionally allowing an old toolchain on this builder (and that's
               # incompatible with LLVM downloads today).
@@ -657,7 +653,6 @@ jobs:
               RUST_CONFIGURE_ARGS: >-
                 --build=x86_64-pc-windows-gnu
                 --enable-profiler
-                --set llvm.allow-old-toolchain
               # We are intentionally allowing an old toolchain on this builder (and that's
               # incompatible with LLVM downloads today).
               NO_DOWNLOAD_CI_LLVM: 1
@@ -670,7 +665,6 @@ jobs:
               RUST_CONFIGURE_ARGS: >-
                 --build=x86_64-pc-windows-gnu
                 --enable-profiler
-                --set llvm.allow-old-toolchain
               # We are intentionally allowing an old toolchain on this builder (and that's
               # incompatible with LLVM downloads today).
               NO_DOWNLOAD_CI_LLVM: 1
@@ -686,7 +680,7 @@ jobs:
                 --enable-full-tools
                 --enable-profiler
                 --set rust.lto=thin
-              SCRIPT: PGO_HOST=x86_64-pc-windows-msvc src/ci/pgo.sh python x.py dist bootstrap --include-default-paths
+              SCRIPT: PGO_HOST=x86_64-pc-windows-msvc python src/ci/stage-build.py python x.py dist bootstrap --include-default-paths
               DIST_REQUIRE_ALL_TOOLS: 1
             <<: *job-windows-xl
 
@@ -722,7 +716,6 @@ jobs:
                 --build=i686-pc-windows-gnu
                 --enable-full-tools
                 --enable-profiler
-                --set llvm.allow-old-toolchain
               # We are intentionally allowing an old toolchain on this builder (and that's
               # incompatible with LLVM downloads today).
               NO_DOWNLOAD_CI_LLVM: 1
@@ -738,7 +731,6 @@ jobs:
                 --build=x86_64-pc-windows-gnu
                 --enable-full-tools
                 --enable-profiler
-                --set llvm.allow-old-toolchain
               # We are intentionally allowing an old toolchain on this builder (and that's
               # incompatible with LLVM downloads today).
               NO_DOWNLOAD_CI_LLVM: 1
index 1685fbbbbba15435aa5115c1547c9650e5d871f5..7eccb9b86502cdfec0743b2adedaf433827f543c 100755 (executable)
@@ -2,24 +2,6 @@
 # If we need to download a custom MinGW, do so here and set the path
 # appropriately.
 #
-# Here we also do a pretty heinous thing which is to mangle the MinGW
-# installation we just downloaded. Currently, as of this writing, we're using
-# MinGW-w64 builds of gcc, and that's currently at 6.3.0. We use 6.3.0 as it
-# appears to be the first version which contains a fix for #40546, builds
-# randomly failing during LLVM due to ar.exe/ranlib.exe failures.
-#
-# Unfortunately, though, 6.3.0 *also* is the first version of MinGW-w64 builds
-# to contain a regression in gdb (#40184). As a result if we were to use the
-# gdb provided (7.11.1) then we would fail all debuginfo tests.
-#
-# In order to fix spurious failures (pretty high priority) we use 6.3.0. To
-# avoid disabling gdb tests we download an *old* version of gdb, specifically
-# that found inside the 6.2.0 distribution. We then overwrite the 6.3.0 gdb
-# with the 6.2.0 gdb to get tests passing.
-#
-# Note that we don't literally overwrite the gdb.exe binary because it appears
-# to just use gdborig.exe, so that's the binary we deal with instead.
-#
 # Otherwise install MinGW through `pacman`
 
 set -euo pipefail
@@ -27,8 +9,8 @@ IFS=$'\n\t'
 
 source "$(cd "$(dirname "$0")" && pwd)/../shared.sh"
 
-MINGW_ARCHIVE_32="i686-6.3.0-release-posix-dwarf-rt_v5-rev2.7z"
-MINGW_ARCHIVE_64="x86_64-6.3.0-release-posix-seh-rt_v5-rev2.7z"
+MINGW_ARCHIVE_32="i686-12.2.0-release-posix-dwarf-rt_v10-rev0.7z"
+MINGW_ARCHIVE_64="x86_64-12.2.0-release-posix-seh-rt_v10-rev0.7z"
 
 if isWindows; then
     case "${CI_JOB_NAME}" in
@@ -66,7 +48,6 @@ if isWindows; then
 
         curl -o mingw.7z "${MIRRORS_BASE}/${mingw_archive}"
         7z x -y mingw.7z > /dev/null
-        curl -o "${mingw_dir}/bin/gdborig.exe" "${MIRRORS_BASE}/2017-04-20-${bits}bit-gdborig.exe"
         ciCommandAddPath "$(pwd)/${mingw_dir}/bin"
     fi
 fi
diff --git a/src/ci/stage-build.py b/src/ci/stage-build.py
new file mode 100644 (file)
index 0000000..c373edf
--- /dev/null
@@ -0,0 +1,663 @@
+#!/usr/bin/env python3
+# ignore-tidy-linelength
+
+# Compatible with Python 3.6+
+
+import contextlib
+import getpass
+import glob
+import logging
+import os
+import pprint
+import shutil
+import subprocess
+import sys
+import time
+import traceback
+import urllib.request
+from collections import OrderedDict
+from io import StringIO
+from pathlib import Path
+from typing import Callable, Dict, Iterable, List, Optional, Union
+
+PGO_HOST = os.environ["PGO_HOST"]
+
+LOGGER = logging.getLogger("stage-build")
+
+LLVM_PGO_CRATES = [
+    "syn-1.0.89",
+    "cargo-0.60.0",
+    "serde-1.0.136",
+    "ripgrep-13.0.0",
+    "regex-1.5.5",
+    "clap-3.1.6",
+    "hyper-0.14.18"
+]
+
+RUSTC_PGO_CRATES = [
+    "externs",
+    "ctfe-stress-5",
+    "cargo-0.60.0",
+    "token-stream-stress",
+    "match-stress",
+    "tuple-stress",
+    "diesel-1.4.8",
+    "bitmaps-3.1.0"
+]
+
+LLVM_BOLT_CRATES = LLVM_PGO_CRATES
+
+
+class Pipeline:
+    # Paths
+    def checkout_path(self) -> Path:
+        """
+        The root checkout, where the source is located.
+        """
+        raise NotImplementedError
+
+    def downloaded_llvm_dir(self) -> Path:
+        """
+        Directory where the host LLVM is located.
+        """
+        raise NotImplementedError
+
+    def build_root(self) -> Path:
+        """
+        The main directory where the build occurs.
+        """
+        raise NotImplementedError
+
+    def build_artifacts(self) -> Path:
+        return self.build_root() / "build" / PGO_HOST
+
+    def rustc_stage_0(self) -> Path:
+        return self.build_artifacts() / "stage0" / "bin" / "rustc"
+
+    def cargo_stage_0(self) -> Path:
+        return self.build_artifacts() / "stage0" / "bin" / "cargo"
+
+    def rustc_stage_2(self) -> Path:
+        return self.build_artifacts() / "stage2" / "bin" / "rustc"
+
+    def opt_artifacts(self) -> Path:
+        raise NotImplementedError
+
+    def llvm_profile_dir_root(self) -> Path:
+        return self.opt_artifacts() / "llvm-pgo"
+
+    def llvm_profile_merged_file(self) -> Path:
+        return self.opt_artifacts() / "llvm-pgo.profdata"
+
+    def rustc_perf_dir(self) -> Path:
+        return self.opt_artifacts() / "rustc-perf"
+
+    def build_rustc_perf(self):
+        raise NotImplementedError()
+
+    def rustc_profile_dir_root(self) -> Path:
+        return self.opt_artifacts() / "rustc-pgo"
+
+    def rustc_profile_merged_file(self) -> Path:
+        return self.opt_artifacts() / "rustc-pgo.profdata"
+
+    def rustc_profile_template_path(self) -> Path:
+        """
+        The profile data is written into a single filepath that is being repeatedly merged when each
+        rustc invocation ends. Empirically, this can result in some profiling data being lost. That's
+        why we override the profile path to include the PID. This will produce many more profiling
+        files, but the resulting profile will produce a slightly faster rustc binary.
+        """
+        return self.rustc_profile_dir_root() / "default_%m_%p.profraw"
+
+    def supports_bolt(self) -> bool:
+        raise NotImplementedError
+
+    def llvm_bolt_profile_merged_file(self) -> Path:
+        return self.opt_artifacts() / "bolt.profdata"
+
+
+class LinuxPipeline(Pipeline):
+    def checkout_path(self) -> Path:
+        return Path("/checkout")
+
+    def downloaded_llvm_dir(self) -> Path:
+        return Path("/rustroot")
+
+    def build_root(self) -> Path:
+        return self.checkout_path() / "obj"
+
+    def opt_artifacts(self) -> Path:
+        return Path("/tmp/tmp-multistage/opt-artifacts")
+
+    def build_rustc_perf(self):
+        # /tmp/rustc-perf comes from the Dockerfile
+        shutil.copytree("/tmp/rustc-perf", self.rustc_perf_dir())
+        cmd(["chown", "-R", f"{getpass.getuser()}:", self.rustc_perf_dir()])
+
+        with change_cwd(self.rustc_perf_dir()):
+            cmd([self.cargo_stage_0(), "build", "-p", "collector"], env=dict(
+                RUSTC=str(self.rustc_stage_0()),
+                RUSTC_BOOTSTRAP="1"
+            ))
+
+    def supports_bolt(self) -> bool:
+        return True
+
+
+class WindowsPipeline(Pipeline):
+    def __init__(self):
+        self.checkout_dir = Path(os.getcwd())
+
+    def checkout_path(self) -> Path:
+        return self.checkout_dir
+
+    def downloaded_llvm_dir(self) -> Path:
+        return self.checkout_path() / "citools" / "clang-rust"
+
+    def build_root(self) -> Path:
+        return self.checkout_path()
+
+    def opt_artifacts(self) -> Path:
+        return self.checkout_path() / "opt-artifacts"
+
+    def rustc_stage_0(self) -> Path:
+        return super().rustc_stage_0().with_suffix(".exe")
+
+    def cargo_stage_0(self) -> Path:
+        return super().cargo_stage_0().with_suffix(".exe")
+
+    def rustc_stage_2(self) -> Path:
+        return super().rustc_stage_2().with_suffix(".exe")
+
+    def build_rustc_perf(self):
+        # rustc-perf version from 2022-07-22
+        perf_commit = "3c253134664fdcba862c539d37f0de18557a9a4c"
+        rustc_perf_zip_path = self.opt_artifacts() / "perf.zip"
+
+        def download_rustc_perf():
+            download_file(
+                f"https://github.com/rust-lang/rustc-perf/archive/{perf_commit}.zip",
+                rustc_perf_zip_path
+            )
+            with change_cwd(self.opt_artifacts()):
+                unpack_archive(rustc_perf_zip_path)
+                move_path(Path(f"rustc-perf-{perf_commit}"), self.rustc_perf_dir())
+                delete_file(rustc_perf_zip_path)
+
+        retry_action(download_rustc_perf, "Download rustc-perf")
+
+        with change_cwd(self.rustc_perf_dir()):
+            cmd([self.cargo_stage_0(), "build", "-p", "collector"], env=dict(
+                RUSTC=str(self.rustc_stage_0()),
+                RUSTC_BOOTSTRAP="1"
+            ))
+
+    def rustc_profile_template_path(self) -> Path:
+        """
+        On Windows, we don't have enough space to use separate files for each rustc invocation.
+        Therefore, we use a single file for the generated profiles.
+        """
+        return self.rustc_profile_dir_root() / "default_%m.profraw"
+
+    def supports_bolt(self) -> bool:
+        return False
+
+
+class Timer:
+    def __init__(self):
+        # We want this dictionary to be ordered by insertion.
+        # We use `OrderedDict` for compatibility with older Python versions.
+        self.stages = OrderedDict()
+
+    @contextlib.contextmanager
+    def stage(self, name: str):
+        assert name not in self.stages
+
+        start = time.time()
+        exc = None
+        try:
+            LOGGER.info(f"Stage `{name}` starts")
+            yield
+        except BaseException as exception:
+            exc = exception
+            raise
+        finally:
+            end = time.time()
+            duration = end - start
+            self.stages[name] = duration
+            if exc is None:
+                LOGGER.info(f"Stage `{name}` ended: OK ({duration:.2f}s)")
+            else:
+                LOGGER.info(f"Stage `{name}` ended: FAIL ({duration:.2f}s)")
+
+    def print_stats(self):
+        total_duration = sum(self.stages.values())
+
+        # 57 is the width of the whole table
+        divider = "-" * 57
+
+        with StringIO() as output:
+            print(divider, file=output)
+            for (name, duration) in self.stages.items():
+                pct = (duration / total_duration) * 100
+                name_str = f"{name}:"
+                print(f"{name_str:<34} {duration:>12.2f}s ({pct:>5.2f}%)", file=output)
+
+            total_duration_label = "Total duration:"
+            print(f"{total_duration_label:<34} {total_duration:>12.2f}s", file=output)
+            print(divider, file=output, end="")
+            LOGGER.info(f"Timer results\n{output.getvalue()}")
+
+
+@contextlib.contextmanager
+def change_cwd(dir: Path):
+    """
+    Temporarily change working directory to `dir`.
+    """
+    cwd = os.getcwd()
+    LOGGER.debug(f"Changing working dir from `{cwd}` to `{dir}`")
+    os.chdir(dir)
+    try:
+        yield
+    finally:
+        LOGGER.debug(f"Reverting working dir to `{cwd}`")
+        os.chdir(cwd)
+
+
+def move_path(src: Path, dst: Path):
+    LOGGER.info(f"Moving `{src}` to `{dst}`")
+    shutil.move(src, dst)
+
+
+def delete_file(path: Path):
+    LOGGER.info(f"Deleting file `{path}`")
+    os.unlink(path)
+
+
+def delete_directory(path: Path):
+    LOGGER.info(f"Deleting directory `{path}`")
+    shutil.rmtree(path)
+
+
+def unpack_archive(archive: Path):
+    LOGGER.info(f"Unpacking archive `{archive}`")
+    shutil.unpack_archive(archive)
+
+
+def download_file(src: str, target: Path):
+    LOGGER.info(f"Downloading `{src}` into `{target}`")
+    urllib.request.urlretrieve(src, str(target))
+
+
+def retry_action(action, name: str, max_fails: int = 5):
+    LOGGER.info(f"Attempting to perform action `{name}` with retry")
+    for iteration in range(max_fails):
+        LOGGER.info(f"Attempt {iteration + 1}/{max_fails}")
+        try:
+            action()
+            return
+        except:
+            LOGGER.error(f"Action `{name}` has failed\n{traceback.format_exc()}")
+
+    raise Exception(f"Action `{name}` has failed after {max_fails} attempts")
+
+
+def cmd(
+        args: List[Union[str, Path]],
+        env: Optional[Dict[str, str]] = None,
+        output_path: Optional[Path] = None
+):
+    args = [str(arg) for arg in args]
+
+    environment = os.environ.copy()
+
+    cmd_str = ""
+    if env is not None:
+        environment.update(env)
+        cmd_str += " ".join(f"{k}={v}" for (k, v) in (env or {}).items())
+        cmd_str += " "
+    cmd_str += " ".join(args)
+    if output_path is not None:
+        cmd_str += f" > {output_path}"
+    LOGGER.info(f"Executing `{cmd_str}`")
+
+    if output_path is not None:
+        with open(output_path, "w") as f:
+            return subprocess.run(
+                args,
+                env=environment,
+                check=True,
+                stdout=f
+            )
+    return subprocess.run(args, env=environment, check=True)
+
+
+def run_compiler_benchmarks(
+        pipeline: Pipeline,
+        profiles: List[str],
+        scenarios: List[str],
+        crates: List[str],
+        env: Optional[Dict[str, str]] = None
+):
+    env = env if env is not None else {}
+
+    # Compile libcore, both in opt-level=0 and opt-level=3
+    with change_cwd(pipeline.build_root()):
+        cmd([
+            pipeline.rustc_stage_2(),
+            "--edition", "2021",
+            "--crate-type", "lib",
+            str(pipeline.checkout_path() / "library/core/src/lib.rs"),
+            "--out-dir", pipeline.opt_artifacts()
+        ], env=dict(RUSTC_BOOTSTRAP="1", **env))
+
+        cmd([
+            pipeline.rustc_stage_2(),
+            "--edition", "2021",
+            "--crate-type", "lib",
+            "-Copt-level=3",
+            str(pipeline.checkout_path() / "library/core/src/lib.rs"),
+            "--out-dir", pipeline.opt_artifacts()
+        ], env=dict(RUSTC_BOOTSTRAP="1", **env))
+
+    # Run rustc-perf benchmarks
+    # Benchmark using profile_local with eprintln, which essentially just means
+    # don't actually benchmark -- just make sure we run rustc a bunch of times.
+    with change_cwd(pipeline.rustc_perf_dir()):
+        cmd([
+            pipeline.cargo_stage_0(),
+            "run",
+            "-p", "collector", "--bin", "collector", "--",
+            "profile_local", "eprintln",
+            pipeline.rustc_stage_2(),
+            "--id", "Test",
+            "--cargo", pipeline.cargo_stage_0(),
+            "--profiles", ",".join(profiles),
+            "--scenarios", ",".join(scenarios),
+            "--include", ",".join(crates)
+        ], env=dict(
+            RUST_LOG="collector=debug",
+            RUSTC=str(pipeline.rustc_stage_0()),
+            RUSTC_BOOTSTRAP="1",
+            **env
+        ))
+
+
+# https://stackoverflow.com/a/31631711/1107768
+def format_bytes(size: int) -> str:
+    """Return the given bytes as a human friendly KiB, MiB or GiB string."""
+    KB = 1024
+    MB = KB ** 2  # 1,048,576
+    GB = KB ** 3  # 1,073,741,824
+    TB = KB ** 4  # 1,099,511,627,776
+
+    if size < KB:
+        return f"{size} B"
+    elif KB <= size < MB:
+        return f"{size / KB:.2f} KiB"
+    elif MB <= size < GB:
+        return f"{size / MB:.2f} MiB"
+    elif GB <= size < TB:
+        return f"{size / GB:.2f} GiB"
+    else:
+        return str(size)
+
+
+# https://stackoverflow.com/a/63307131/1107768
+def count_files(path: Path) -> int:
+    return sum(1 for p in path.rglob("*") if p.is_file())
+
+
+def count_files_with_prefix(path: Path) -> int:
+    return sum(1 for p in glob.glob(f"{path}*") if Path(p).is_file())
+
+
+# https://stackoverflow.com/a/55659577/1107768
+def get_path_size(path: Path) -> int:
+    if path.is_dir():
+        return sum(p.stat().st_size for p in path.rglob("*"))
+    return path.stat().st_size
+
+
+def get_path_prefix_size(path: Path) -> int:
+    """
+    Get size of all files beginning with the prefix `path`.
+    Alternative to shell `du -sh <path>*`.
+    """
+    return sum(Path(p).stat().st_size for p in glob.glob(f"{path}*"))
+
+
+def get_files(directory: Path, filter: Optional[Callable[[Path], bool]] = None) -> Iterable[Path]:
+    for file in os.listdir(directory):
+        path = directory / file
+        if filter is None or filter(path):
+            yield path
+
+
+def build_rustc(
+        pipeline: Pipeline,
+        args: List[str],
+        env: Optional[Dict[str, str]] = None
+):
+    arguments = [
+                    sys.executable,
+                    pipeline.checkout_path() / "x.py",
+                    "build",
+                    "--target", PGO_HOST,
+                    "--host", PGO_HOST,
+                    "--stage", "2",
+                    "library/std"
+                ] + args
+    cmd(arguments, env=env)
+
+
+def create_pipeline() -> Pipeline:
+    if sys.platform == "linux":
+        return LinuxPipeline()
+    elif sys.platform in ("cygwin", "win32"):
+        return WindowsPipeline()
+    else:
+        raise Exception(f"Optimized build is not supported for platform {sys.platform}")
+
+
+def gather_llvm_profiles(pipeline: Pipeline):
+    LOGGER.info("Running benchmarks with PGO instrumented LLVM")
+    run_compiler_benchmarks(
+        pipeline,
+        profiles=["Debug", "Opt"],
+        scenarios=["Full"],
+        crates=LLVM_PGO_CRATES
+    )
+
+    profile_path = pipeline.llvm_profile_merged_file()
+    LOGGER.info(f"Merging LLVM PGO profiles to {profile_path}")
+    cmd([
+        pipeline.downloaded_llvm_dir() / "bin" / "llvm-profdata",
+        "merge",
+        "-o", profile_path,
+        pipeline.llvm_profile_dir_root()
+    ])
+
+    LOGGER.info("LLVM PGO statistics")
+    LOGGER.info(f"{profile_path}: {format_bytes(get_path_size(profile_path))}")
+    LOGGER.info(
+        f"{pipeline.llvm_profile_dir_root()}: {format_bytes(get_path_size(pipeline.llvm_profile_dir_root()))}")
+    LOGGER.info(f"Profile file count: {count_files(pipeline.llvm_profile_dir_root())}")
+
+    # We don't need the individual .profraw files now that they have been merged
+    # into a final .profdata
+    delete_directory(pipeline.llvm_profile_dir_root())
+
+
+def gather_rustc_profiles(pipeline: Pipeline):
+    LOGGER.info("Running benchmarks with PGO instrumented rustc")
+
+    # Here we're profiling the `rustc` frontend, so we also include `Check`.
+    # The benchmark set includes various stress tests that put the frontend under pressure.
+    run_compiler_benchmarks(
+        pipeline,
+        profiles=["Check", "Debug", "Opt"],
+        scenarios=["All"],
+        crates=RUSTC_PGO_CRATES,
+        env=dict(
+            LLVM_PROFILE_FILE=str(pipeline.rustc_profile_template_path())
+        )
+    )
+
+    profile_path = pipeline.rustc_profile_merged_file()
+    LOGGER.info(f"Merging Rustc PGO profiles to {profile_path}")
+    cmd([
+        pipeline.build_artifacts() / "llvm" / "bin" / "llvm-profdata",
+        "merge",
+        "-o", profile_path,
+        pipeline.rustc_profile_dir_root()
+    ])
+
+    LOGGER.info("Rustc PGO statistics")
+    LOGGER.info(f"{profile_path}: {format_bytes(get_path_size(profile_path))}")
+    LOGGER.info(
+        f"{pipeline.rustc_profile_dir_root()}: {format_bytes(get_path_size(pipeline.rustc_profile_dir_root()))}")
+    LOGGER.info(f"Profile file count: {count_files(pipeline.rustc_profile_dir_root())}")
+
+    # We don't need the individual .profraw files now that they have been merged
+    # into a final .profdata
+    delete_directory(pipeline.rustc_profile_dir_root())
+
+
+def gather_llvm_bolt_profiles(pipeline: Pipeline):
+    LOGGER.info("Running benchmarks with BOLT instrumented LLVM")
+    run_compiler_benchmarks(
+        pipeline,
+        profiles=["Check", "Debug", "Opt"],
+        scenarios=["Full"],
+        crates=LLVM_BOLT_CRATES
+    )
+
+    merged_profile_path = pipeline.llvm_bolt_profile_merged_file()
+    profile_files_path = Path("/tmp/prof.fdata")
+    LOGGER.info(f"Merging LLVM BOLT profiles to {merged_profile_path}")
+
+    profile_files = sorted(glob.glob(f"{profile_files_path}*"))
+    cmd([
+        "merge-fdata",
+        *profile_files,
+    ], output_path=merged_profile_path)
+
+    LOGGER.info("LLVM BOLT statistics")
+    LOGGER.info(f"{merged_profile_path}: {format_bytes(get_path_size(merged_profile_path))}")
+    LOGGER.info(
+        f"{profile_files_path}: {format_bytes(get_path_prefix_size(profile_files_path))}")
+    LOGGER.info(f"Profile file count: {count_files_with_prefix(profile_files_path)}")
+
+
+def clear_llvm_files(pipeline: Pipeline):
+    """
+    Rustbuild currently doesn't support rebuilding LLVM when PGO options
+    change (or any other llvm-related options); so just clear out the relevant
+    directories ourselves.
+    """
+    LOGGER.info("Clearing LLVM build files")
+    delete_directory(pipeline.build_artifacts() / "llvm")
+    delete_directory(pipeline.build_artifacts() / "lld")
+
+
+def print_binary_sizes(pipeline: Pipeline):
+    bin_dir = pipeline.build_artifacts() / "stage2" / "bin"
+    binaries = get_files(bin_dir)
+
+    lib_dir = pipeline.build_artifacts() / "stage2" / "lib"
+    libraries = get_files(lib_dir, lambda p: p.suffix == ".so")
+
+    paths = sorted(binaries) + sorted(libraries)
+    with StringIO() as output:
+        for path in paths:
+            path_str = f"{path.name}:"
+            print(f"{path_str:<30}{format_bytes(path.stat().st_size):>14}", file=output)
+        LOGGER.info(f"Rustc binary size\n{output.getvalue()}")
+
+
+def execute_build_pipeline(timer: Timer, pipeline: Pipeline, final_build_args: List[str]):
+    # Clear and prepare tmp directory
+    shutil.rmtree(pipeline.opt_artifacts(), ignore_errors=True)
+    os.makedirs(pipeline.opt_artifacts(), exist_ok=True)
+
+    pipeline.build_rustc_perf()
+
+    # Stage 1: Build rustc + PGO instrumented LLVM
+    with timer.stage("Build rustc (LLVM PGO)"):
+        build_rustc(pipeline, args=[
+            "--llvm-profile-generate"
+        ], env=dict(
+            LLVM_PROFILE_DIR=str(pipeline.llvm_profile_dir_root() / "prof-%p")
+        ))
+
+    with timer.stage("Gather profiles (LLVM PGO)"):
+        gather_llvm_profiles(pipeline)
+
+    clear_llvm_files(pipeline)
+    final_build_args += [
+        "--llvm-profile-use",
+        pipeline.llvm_profile_merged_file()
+    ]
+
+    # Stage 2: Build PGO instrumented rustc + LLVM
+    with timer.stage("Build rustc (rustc PGO)"):
+        build_rustc(pipeline, args=[
+            "--rust-profile-generate",
+            pipeline.rustc_profile_dir_root()
+        ])
+
+    with timer.stage("Gather profiles (rustc PGO)"):
+        gather_rustc_profiles(pipeline)
+
+    clear_llvm_files(pipeline)
+    final_build_args += [
+        "--rust-profile-use",
+        pipeline.rustc_profile_merged_file()
+    ]
+
+    # Stage 3: Build rustc + BOLT instrumented LLVM
+    if pipeline.supports_bolt():
+        with timer.stage("Build rustc (LLVM BOLT)"):
+            build_rustc(pipeline, args=[
+                "--llvm-profile-use",
+                pipeline.llvm_profile_merged_file(),
+                "--llvm-bolt-profile-generate",
+            ])
+        with timer.stage("Gather profiles (LLVM BOLT)"):
+            gather_llvm_bolt_profiles(pipeline)
+
+        clear_llvm_files(pipeline)
+        final_build_args += [
+            "--llvm-bolt-profile-use",
+            pipeline.llvm_bolt_profile_merged_file()
+        ]
+
+    # Stage 4: Build PGO optimized rustc + PGO/BOLT optimized LLVM
+    with timer.stage("Final build"):
+        cmd(final_build_args)
+
+
+if __name__ == "__main__":
+    logging.basicConfig(
+        level=logging.DEBUG,
+        format="%(name)s %(levelname)-4s: %(message)s",
+    )
+
+    LOGGER.info(f"Running multi-stage build using Python {sys.version}")
+    LOGGER.info(f"Environment values\n{pprint.pformat(dict(os.environ), indent=2)}")
+
+    build_args = sys.argv[1:]
+
+    timer = Timer()
+    pipeline = create_pipeline()
+    try:
+        execute_build_pipeline(timer, pipeline, build_args)
+    except BaseException as e:
+        LOGGER.error("The multi-stage build has failed")
+        raise e
+    finally:
+        timer.print_stats()
+
+    print_binary_sizes(pipeline)
diff --git a/src/doc/unstable-book/src/compiler-flags/tiny-const-eval-limit.md b/src/doc/unstable-book/src/compiler-flags/tiny-const-eval-limit.md
new file mode 100644 (file)
index 0000000..51c5fd6
--- /dev/null
@@ -0,0 +1,6 @@
+# `tiny-const-eval-limit`
+
+--------------------
+
+The `-Ztiny-const-eval-limit` compiler flag sets a tiny, non-configurable limit for const eval.
+This flag should only be used by const eval tests in the rustc test suite.
index 7a846d44ad6a8e9484b51aaf41705683feef5742..ff17931115cd038bd164cd171b9567d2768d60b4 100755 (executable)
@@ -14,4 +14,4 @@ ROOT_DIR="$(git rev-parse --show-toplevel)"
 echo "Running pre-push script $ROOT_DIR/x test tidy"
 
 cd "$ROOT_DIR"
-./x test tidy
+CARGOFLAGS="--locked" ./x test tidy
index d644293d3ef12c0174da5c7f83fb499ab8373983..be6de231854ba1198b32710da0bc41467dbeb6e7 100644 (file)
@@ -1528,11 +1528,7 @@ fn doc_impl_item(
                             })
                         })
                         .map(|item| format!("{}.{}", item.type_(), name));
-                    write!(
-                        w,
-                        "<section id=\"{}\" class=\"{}{} has-srclink\">",
-                        id, item_type, in_trait_class,
-                    );
+                    write!(w, "<section id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class,);
                     render_rightside(w, cx, item, containing_item, render_mode);
                     if trait_.is_some() {
                         // Anchors are only used on trait impls.
@@ -1554,11 +1550,7 @@ fn doc_impl_item(
             kind @ (clean::TyAssocConstItem(ty) | clean::AssocConstItem(ty, _)) => {
                 let source_id = format!("{}.{}", item_type, name);
                 let id = cx.derive_id(source_id.clone());
-                write!(
-                    w,
-                    "<section id=\"{}\" class=\"{}{} has-srclink\">",
-                    id, item_type, in_trait_class
-                );
+                write!(w, "<section id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class);
                 render_rightside(w, cx, item, containing_item, render_mode);
                 if trait_.is_some() {
                     // Anchors are only used on trait impls.
@@ -1606,11 +1598,7 @@ fn doc_impl_item(
             clean::AssocTypeItem(tydef, _bounds) => {
                 let source_id = format!("{}.{}", item_type, name);
                 let id = cx.derive_id(source_id.clone());
-                write!(
-                    w,
-                    "<section id=\"{}\" class=\"{}{} has-srclink\">",
-                    id, item_type, in_trait_class
-                );
+                write!(w, "<section id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class);
                 if trait_.is_some() {
                     // Anchors are only used on trait impls.
                     write!(w, "<a href=\"#{}\" class=\"anchor\">§</a>", id);
@@ -1844,7 +1832,7 @@ pub(crate) fn render_impl_summary(
     } else {
         format!(" data-aliases=\"{}\"", aliases.join(","))
     };
-    write!(w, "<section id=\"{}\" class=\"impl has-srclink\"{}>", id, aliases);
+    write!(w, "<section id=\"{}\" class=\"impl\"{}>", id, aliases);
     render_rightside(w, cx, &i.impl_item, containing_item, RenderMode::Normal);
     write!(w, "<a href=\"#{}\" class=\"anchor\">§</a>", id);
     write!(w, "<h3 class=\"code-header\">");
index 508b2bab0eb643e4d1592f731ac59aff7b4295fe..b0288d55c256ad84e90c04ab8bc3eb9ff992092b 100644 (file)
@@ -735,7 +735,7 @@ fn trait_item(w: &mut Buffer, cx: &mut Context<'_>, m: &clean::Item, t: &clean::
             let method_toggle_class = if item_type.is_method() { " method-toggle" } else { "" };
             write!(w, "<details class=\"toggle{method_toggle_class}\" open><summary>");
         }
-        write!(w, "<section id=\"{}\" class=\"method has-srclink\">", id);
+        write!(w, "<section id=\"{}\" class=\"method\">", id);
         render_rightside(w, cx, m, t, RenderMode::Normal);
         write!(w, "<h4 class=\"code-header\">");
         render_assoc_item(
index 13de780b71095e9a1fbbd04b4b18995ebb309530..727058780752e226ce6c06381e30570a5e228325 100644 (file)
@@ -240,6 +240,7 @@ fn check_statement<'tcx>(
         | StatementKind::Retag { .. }
         | StatementKind::AscribeUserType(..)
         | StatementKind::Coverage(..)
+        | StatementKind::ConstEvalCounter
         | StatementKind::Nop => Ok(()),
     }
 }
index dc30e4bb1bef793171358affe8acb3d156dd0c43..45fd87bea9bb5ac72437553c8c2de59c01741239 100644 (file)
@@ -926,7 +926,7 @@ pub fn make_test_description<R: Read>(
     cfg: Option<&str>,
 ) -> test::TestDesc {
     let mut ignore = false;
-    let ignore_message = None;
+    let mut ignore_message = None;
     let mut should_fail = false;
 
     let rustc_has_profiler_support = env::var_os("RUSTC_PROFILER_SUPPORT").is_some();
@@ -966,41 +966,67 @@ pub fn make_test_description<R: Read>(
         if revision.is_some() && revision != cfg {
             return;
         }
+        macro_rules! reason {
+            ($e:expr) => {
+                ignore |= match $e {
+                    true => {
+                        ignore_message = Some(stringify!($e));
+                        true
+                    }
+                    false => ignore,
+                }
+            };
+        }
         ignore = match config.parse_cfg_name_directive(ln, "ignore") {
-            ParsedNameDirective::Match => true,
+            ParsedNameDirective::Match => {
+                ignore_message = Some("cfg -> ignore => Match");
+                true
+            }
             ParsedNameDirective::NoMatch => ignore,
         };
+
         if config.has_cfg_prefix(ln, "only") {
             ignore = match config.parse_cfg_name_directive(ln, "only") {
                 ParsedNameDirective::Match => ignore,
-                ParsedNameDirective::NoMatch => true,
+                ParsedNameDirective::NoMatch => {
+                    ignore_message = Some("cfg -> only => NoMatch");
+                    true
+                }
             };
         }
-        ignore |= ignore_llvm(config, ln);
-        ignore |=
-            config.run_clang_based_tests_with.is_none() && config.parse_needs_matching_clang(ln);
-        ignore |= !has_asm_support && config.parse_name_directive(ln, "needs-asm-support");
-        ignore |= !rustc_has_profiler_support && config.parse_needs_profiler_support(ln);
-        ignore |= !config.run_enabled() && config.parse_name_directive(ln, "needs-run-enabled");
-        ignore |= !rustc_has_sanitizer_support
-            && config.parse_name_directive(ln, "needs-sanitizer-support");
-        ignore |= !has_asan && config.parse_name_directive(ln, "needs-sanitizer-address");
-        ignore |= !has_cfi && config.parse_name_directive(ln, "needs-sanitizer-cfi");
-        ignore |= !has_kcfi && config.parse_name_directive(ln, "needs-sanitizer-kcfi");
-        ignore |= !has_lsan && config.parse_name_directive(ln, "needs-sanitizer-leak");
-        ignore |= !has_msan && config.parse_name_directive(ln, "needs-sanitizer-memory");
-        ignore |= !has_tsan && config.parse_name_directive(ln, "needs-sanitizer-thread");
-        ignore |= !has_hwasan && config.parse_name_directive(ln, "needs-sanitizer-hwaddress");
-        ignore |= !has_memtag && config.parse_name_directive(ln, "needs-sanitizer-memtag");
-        ignore |= !has_shadow_call_stack
-            && config.parse_name_directive(ln, "needs-sanitizer-shadow-call-stack");
-        ignore |= !config.can_unwind() && config.parse_name_directive(ln, "needs-unwind");
-        ignore |= config.target == "wasm32-unknown-unknown"
-            && config.parse_name_directive(ln, directives::CHECK_RUN_RESULTS);
-        ignore |= config.debugger == Some(Debugger::Cdb) && ignore_cdb(config, ln);
-        ignore |= config.debugger == Some(Debugger::Gdb) && ignore_gdb(config, ln);
-        ignore |= config.debugger == Some(Debugger::Lldb) && ignore_lldb(config, ln);
-        ignore |= !has_rust_lld && config.parse_name_directive(ln, "needs-rust-lld");
+
+        reason!(ignore_llvm(config, ln));
+        reason!(
+            config.run_clang_based_tests_with.is_none() && config.parse_needs_matching_clang(ln)
+        );
+        reason!(!has_asm_support && config.parse_name_directive(ln, "needs-asm-support"));
+        reason!(!rustc_has_profiler_support && config.parse_needs_profiler_support(ln));
+        reason!(!config.run_enabled() && config.parse_name_directive(ln, "needs-run-enabled"));
+        reason!(
+            !rustc_has_sanitizer_support
+                && config.parse_name_directive(ln, "needs-sanitizer-support")
+        );
+        reason!(!has_asan && config.parse_name_directive(ln, "needs-sanitizer-address"));
+        reason!(!has_cfi && config.parse_name_directive(ln, "needs-sanitizer-cfi"));
+        reason!(!has_kcfi && config.parse_name_directive(ln, "needs-sanitizer-kcfi"));
+        reason!(!has_lsan && config.parse_name_directive(ln, "needs-sanitizer-leak"));
+        reason!(!has_msan && config.parse_name_directive(ln, "needs-sanitizer-memory"));
+        reason!(!has_tsan && config.parse_name_directive(ln, "needs-sanitizer-thread"));
+        reason!(!has_hwasan && config.parse_name_directive(ln, "needs-sanitizer-hwaddress"));
+        reason!(!has_memtag && config.parse_name_directive(ln, "needs-sanitizer-memtag"));
+        reason!(
+            !has_shadow_call_stack
+                && config.parse_name_directive(ln, "needs-sanitizer-shadow-call-stack")
+        );
+        reason!(!config.can_unwind() && config.parse_name_directive(ln, "needs-unwind"));
+        reason!(
+            config.target == "wasm32-unknown-unknown"
+                && config.parse_name_directive(ln, directives::CHECK_RUN_RESULTS)
+        );
+        reason!(config.debugger == Some(Debugger::Cdb) && ignore_cdb(config, ln));
+        reason!(config.debugger == Some(Debugger::Gdb) && ignore_gdb(config, ln));
+        reason!(config.debugger == Some(Debugger::Lldb) && ignore_lldb(config, ln));
+        reason!(!has_rust_lld && config.parse_name_directive(ln, "needs-rust-lld"));
         should_fail |= config.parse_name_directive(ln, "should-fail");
     });
 
index 9c16ef2cbeccca1e91a4491f95341d7203dc1724..395bcc745f8dd75edf9654a324f26268e2479444 100755 (executable)
@@ -68,52 +68,6 @@ def load_json_from_response(resp):
         print("Refusing to decode " + str(type(content)) + " to str")
     return json.loads(content_str)
 
-def validate_maintainers(repo, github_token):
-    # type: (str, str) -> None
-    '''Ensure all maintainers are assignable on a GitHub repo'''
-    next_link_re = re.compile(r'<([^>]+)>; rel="next"')
-
-    # Load the list of assignable people in the GitHub repo
-    assignable = [] # type: typing.List[str]
-    url = 'https://api.github.com/repos/' \
-        + '%s/collaborators?per_page=100' % repo # type: typing.Optional[str]
-    while url is not None:
-        response = urllib2.urlopen(urllib2.Request(url, headers={
-            'Authorization': 'token ' + github_token,
-            # Properly load nested teams.
-            'Accept': 'application/vnd.github.hellcat-preview+json',
-        }))
-        assignable.extend(user['login'] for user in load_json_from_response(response))
-        # Load the next page if available
-        url = None
-        link_header = response.headers.get('Link')
-        if link_header:
-            matches = next_link_re.match(link_header)
-            if matches is not None:
-                url = matches.group(1)
-
-    errors = False
-    for tool, maintainers in MAINTAINERS.items():
-        for maintainer in maintainers:
-            if maintainer not in assignable:
-                errors = True
-                print(
-                    "error: %s maintainer @%s is not assignable in the %s repo"
-                    % (tool, maintainer, repo),
-                )
-
-    if errors:
-        print()
-        print("  To be assignable, a person needs to be explicitly listed as a")
-        print("  collaborator in the repository settings. The simple way to")
-        print("  fix this is to ask someone with 'admin' privileges on the repo")
-        print("  to add the person or whole team as a collaborator with 'read'")
-        print("  privileges. Those privileges don't grant any extra permissions")
-        print("  so it's safe to apply them.")
-        print()
-        print("The build will fail due to this.")
-        exit(1)
-
 
 def read_current_status(current_commit, path):
     # type: (str, str) -> typing.Mapping[str, typing.Any]
@@ -280,21 +234,6 @@ def update_latest(
 try:
     if __name__ != '__main__':
         exit(0)
-    repo = os.environ.get('TOOLSTATE_VALIDATE_MAINTAINERS_REPO')
-    if repo:
-        github_token = os.environ.get('TOOLSTATE_REPO_ACCESS_TOKEN')
-        if github_token:
-            # FIXME: This is currently broken. Starting on 2021-09-15, GitHub
-            # seems to have changed it so that to list the collaborators
-            # requires admin permissions. I think this will probably just need
-            # to be removed since we are probably not going to use an admin
-            # token, and I don't see another way to do this.
-            print('maintainer validation disabled')
-            # validate_maintainers(repo, github_token)
-        else:
-            print('skipping toolstate maintainers validation since no GitHub token is present')
-        # When validating maintainers don't run the full script.
-        exit(0)
 
     cur_commit = sys.argv[1]
     cur_datetime = datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ')
index 0269015b46617521ce9deba5392e52f69d72b6d4..2898e75e0ee367696eac4cecf9533dfd6fd97643 100644 (file)
@@ -1,6 +1,7 @@
 // compile-flags:-g
 // min-gdb-version: 8.1
 // ignore-lldb
+// ignore-windows-gnu // emit_debug_gdb_scripts is disabled on Windows
 
 // === CDB TESTS ==================================================================================
 
index c41c9ee21df892c2bde379b70a5c8386f3209a81..c122112e6c77a339dd4b17ac229899b523cbe1e7 100644 (file)
@@ -1,6 +1,7 @@
 // compile-flags:-g
 
 // min-gdb-version: 8.1
+// ignore-windows-gnu // emit_debug_gdb_scripts is disabled on Windows
 
 // Tests the visualizations for `NonZero{I,U}{8,16,32,64,128,size}`, `Wrapping<T>` and
 // `Atomic{Bool,I8,I16,I32,I64,Isize,U8,U16,U32,U64,Usize}` located in `libcore.natvis`.
index 7d88e45caf2576cdedb2cce5115832d63844ac8e..de4099a7f50cb174f5cd8862b8bdd9cba7a02cee 100644 (file)
@@ -1,4 +1,3 @@
-// ignore-windows
 // min-lldb-version: 310
 
 // compile-flags:-g
index dd548adde7e5fe0f05f5ddd7b8d6c642e92d7762..5e587be1f1653f482d6bb3a8678ce14bf847cfda 100644 (file)
           _3 = const 3_u8;                 // scope 2 at $DIR/const_debuginfo.rs:+3:13: +3:16
           StorageLive(_4);                 // scope 3 at $DIR/const_debuginfo.rs:+4:9: +4:12
           StorageLive(_5);                 // scope 3 at $DIR/const_debuginfo.rs:+4:15: +4:20
-          StorageLive(_6);                 // scope 3 at $DIR/const_debuginfo.rs:+4:15: +4:16
-          _6 = const 1_u8;                 // scope 3 at $DIR/const_debuginfo.rs:+4:15: +4:16
-          StorageLive(_7);                 // scope 3 at $DIR/const_debuginfo.rs:+4:19: +4:20
-          _7 = const 2_u8;                 // scope 3 at $DIR/const_debuginfo.rs:+4:19: +4:20
           _5 = const 3_u8;                 // scope 3 at $DIR/const_debuginfo.rs:+4:15: +4:20
-          StorageDead(_7);                 // scope 3 at $DIR/const_debuginfo.rs:+4:19: +4:20
-          StorageDead(_6);                 // scope 3 at $DIR/const_debuginfo.rs:+4:19: +4:20
-          StorageLive(_8);                 // scope 3 at $DIR/const_debuginfo.rs:+4:23: +4:24
-          _8 = const 3_u8;                 // scope 3 at $DIR/const_debuginfo.rs:+4:23: +4:24
           _4 = const 6_u8;                 // scope 3 at $DIR/const_debuginfo.rs:+4:15: +4:24
-          StorageDead(_8);                 // scope 3 at $DIR/const_debuginfo.rs:+4:23: +4:24
           StorageDead(_5);                 // scope 3 at $DIR/const_debuginfo.rs:+4:23: +4:24
           StorageLive(_9);                 // scope 4 at $DIR/const_debuginfo.rs:+6:9: +6:10
           _9 = const "hello, world!";      // scope 4 at $DIR/const_debuginfo.rs:+6:13: +6:28
           StorageDead(_16);                // scope 5 at $DIR/const_debuginfo.rs:+14:1: +14:2
           StorageDead(_9);                 // scope 4 at $DIR/const_debuginfo.rs:+14:1: +14:2
           StorageDead(_4);                 // scope 3 at $DIR/const_debuginfo.rs:+14:1: +14:2
-          StorageDead(_3);                 // scope 2 at $DIR/const_debuginfo.rs:+14:1: +14:2
-          StorageDead(_2);                 // scope 1 at $DIR/const_debuginfo.rs:+14:1: +14:2
-          StorageDead(_1);                 // scope 0 at $DIR/const_debuginfo.rs:+14:1: +14:2
           return;                          // scope 0 at $DIR/const_debuginfo.rs:+14:2: +14:2
       }
   }
index 8485703e39f2c5b1b68261bf650caf15ef2f49c8..e085a88b2da8ba155f44730090f1545df43ce64b 100644 (file)
           StorageLive(_1);                 // scope 0 at $DIR/bad_op_mod_by_zero.rs:+1:9: +1:10
           _1 = const 0_i32;                // scope 0 at $DIR/bad_op_mod_by_zero.rs:+1:13: +1:14
           StorageLive(_2);                 // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:9: +2:11
-          StorageLive(_3);                 // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:18: +2:19
--         _3 = _1;                         // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:18: +2:19
--         _4 = Eq(_3, const 0_i32);        // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
+-         _4 = Eq(_1, const 0_i32);        // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
 -         assert(!move _4, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
-+         _3 = const 0_i32;                // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:18: +2:19
 +         _4 = const true;                 // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
 +         assert(!const true, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
       }
   
       bb1: {
--         _5 = Eq(_3, const -1_i32);       // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
+          _5 = Eq(_1, const -1_i32);       // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
 -         _6 = Eq(const 1_i32, const i32::MIN); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
 -         _7 = BitAnd(move _5, move _6);   // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
--         assert(!move _7, "attempt to compute the remainder of `{} % {}`, which would overflow", const 1_i32, _3) -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
-+         _5 = const false;                // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
+-         assert(!move _7, "attempt to compute the remainder of `{} % {}`, which would overflow", const 1_i32, _1) -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
 +         _6 = const false;                // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
 +         _7 = const false;                // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
-+         assert(!const false, "attempt to compute the remainder of `{} % {}`, which would overflow", const 1_i32, const 0_i32) -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
++         assert(!const false, "attempt to compute the remainder of `{} % {}`, which would overflow", const 1_i32, _1) -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
       }
   
       bb2: {
--         _2 = Rem(const 1_i32, move _3);  // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
-+         _2 = Rem(const 1_i32, const 0_i32); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
-          StorageDead(_3);                 // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:18: +2:19
+          _2 = Rem(const 1_i32, _1);       // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
           StorageDead(_2);                 // scope 1 at $DIR/bad_op_mod_by_zero.rs:+3:1: +3:2
-          StorageDead(_1);                 // scope 0 at $DIR/bad_op_mod_by_zero.rs:+3:1: +3:2
           return;                          // scope 0 at $DIR/bad_op_mod_by_zero.rs:+3:2: +3:2
       }
   }
index 27e41d4869d759b74f8cad5bbc981311a0b7cb26..4bd0aa09872398959e3fbe0a1ea2c12050020756 100644 (file)
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:9: +1:10
           StorageLive(_2);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
-          StorageLive(_3);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
           _8 = const _;                    // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
                                            // mir::Constant
                                            // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
                                            // + literal: Const { ty: &[i32; 3], val: Unevaluated(main, [], Some(promoted[0])) }
-          _3 = _8;                         // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
-          _2 = &raw const (*_3);           // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
+          _2 = &raw const (*_8);           // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
           _1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
           StorageDead(_2);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:34: +1:35
-          StorageDead(_3);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:35: +1:36
           StorageLive(_4);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
           StorageLive(_5);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
           _5 = const 3_usize;              // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
index 27e41d4869d759b74f8cad5bbc981311a0b7cb26..4bd0aa09872398959e3fbe0a1ea2c12050020756 100644 (file)
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:9: +1:10
           StorageLive(_2);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
-          StorageLive(_3);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
           _8 = const _;                    // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
                                            // mir::Constant
                                            // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
                                            // + literal: Const { ty: &[i32; 3], val: Unevaluated(main, [], Some(promoted[0])) }
-          _3 = _8;                         // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
-          _2 = &raw const (*_3);           // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
+          _2 = &raw const (*_8);           // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
           _1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
           StorageDead(_2);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:34: +1:35
-          StorageDead(_3);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:35: +1:36
           StorageLive(_4);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
           StorageLive(_5);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
           _5 = const 3_usize;              // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
index 0de800917534a4492ffc9c886036880d1dd99659..549b4711e874d281f62050ad68226ced07af3c9f 100644 (file)
   
       bb0: {
           StorageLive(_3);                 // scope 0 at $DIR/boolean_identities.rs:+1:5: +1:15
-          StorageLive(_4);                 // scope 0 at $DIR/boolean_identities.rs:+1:6: +1:7
-          _4 = _2;                         // scope 0 at $DIR/boolean_identities.rs:+1:6: +1:7
--         _3 = BitOr(move _4, const true); // scope 0 at $DIR/boolean_identities.rs:+1:5: +1:15
+-         _3 = BitOr(_2, const true);      // scope 0 at $DIR/boolean_identities.rs:+1:5: +1:15
 +         _3 = const true;                 // scope 0 at $DIR/boolean_identities.rs:+1:5: +1:15
-          StorageDead(_4);                 // scope 0 at $DIR/boolean_identities.rs:+1:14: +1:15
           StorageLive(_5);                 // scope 0 at $DIR/boolean_identities.rs:+1:18: +1:29
-          StorageLive(_6);                 // scope 0 at $DIR/boolean_identities.rs:+1:19: +1:20
-          _6 = _1;                         // scope 0 at $DIR/boolean_identities.rs:+1:19: +1:20
--         _5 = BitAnd(move _6, const false); // scope 0 at $DIR/boolean_identities.rs:+1:18: +1:29
-+         _5 = const false;                // scope 0 at $DIR/boolean_identities.rs:+1:18: +1:29
-          StorageDead(_6);                 // scope 0 at $DIR/boolean_identities.rs:+1:28: +1:29
+-         _5 = BitAnd(_1, const false);    // scope 0 at $DIR/boolean_identities.rs:+1:18: +1:29
 -         _0 = BitAnd(move _3, move _5);   // scope 0 at $DIR/boolean_identities.rs:+1:5: +1:29
++         _5 = const false;                // scope 0 at $DIR/boolean_identities.rs:+1:18: +1:29
 +         _0 = const false;                // scope 0 at $DIR/boolean_identities.rs:+1:5: +1:29
           StorageDead(_5);                 // scope 0 at $DIR/boolean_identities.rs:+1:28: +1:29
           StorageDead(_3);                 // scope 0 at $DIR/boolean_identities.rs:+1:28: +1:29
index 629c8e60148fdbd8fdf465cedaa593b51e1643b3..1cfe47d0a86124a119b2ecd87221cbc9d2a4f38e 100644 (file)
@@ -7,11 +7,8 @@
       let mut _2: i32;                     // in scope 0 at $DIR/mult_by_zero.rs:+1:3: +1:4
   
       bb0: {
-          StorageLive(_2);                 // scope 0 at $DIR/mult_by_zero.rs:+1:3: +1:4
-          _2 = _1;                         // scope 0 at $DIR/mult_by_zero.rs:+1:3: +1:4
--         _0 = Mul(move _2, const 0_i32);  // scope 0 at $DIR/mult_by_zero.rs:+1:3: +1:8
+-         _0 = Mul(_1, const 0_i32);       // scope 0 at $DIR/mult_by_zero.rs:+1:3: +1:8
 +         _0 = const 0_i32;                // scope 0 at $DIR/mult_by_zero.rs:+1:3: +1:8
-          StorageDead(_2);                 // scope 0 at $DIR/mult_by_zero.rs:+1:7: +1:8
           return;                          // scope 0 at $DIR/mult_by_zero.rs:+2:2: +2:2
       }
   }
index 8a73f0390e122fab4b66423fe548ef3ac0759051..924a267f3d8ffe5089f03bb6940d144a50d4defb 100644 (file)
           StorageLive(_2);                 // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10
           _4 = const _;                    // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10
                                            // mir::Constant
-                                           // + span: $DIR/ref_deref.rs:6:6: 6:10
+                                           // + span: $DIR/ref_deref.rs:5:6: 5:10
                                            // + literal: Const { ty: &i32, val: Unevaluated(main, [], Some(promoted[0])) }
-          _2 = _4;                         // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10
--         _1 = (*_2);                      // scope 0 at $DIR/ref_deref.rs:+1:5: +1:10
-+         _1 = const 4_i32;                // scope 0 at $DIR/ref_deref.rs:+1:5: +1:10
+          _2 = &(*_4);                     // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10
+          _1 = (*_2);                      // scope 0 at $DIR/ref_deref.rs:+1:5: +1:10
           StorageDead(_2);                 // scope 0 at $DIR/ref_deref.rs:+1:10: +1:11
           StorageDead(_1);                 // scope 0 at $DIR/ref_deref.rs:+1:10: +1:11
-          nop;                             // scope 0 at $DIR/ref_deref.rs:+0:11: +2:2
+          _0 = const ();                   // scope 0 at $DIR/ref_deref.rs:+0:11: +2:2
           return;                          // scope 0 at $DIR/ref_deref.rs:+2:2: +2:2
       }
   }
diff --git a/tests/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff b/tests/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff
deleted file mode 100644 (file)
index 015ec4d..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-- // MIR for `main` before PromoteTemps
-+ // MIR for `main` after PromoteTemps
-  
-  fn main() -> () {
-      let mut _0: ();                      // return place in scope 0 at $DIR/ref_deref.rs:+0:11: +0:11
-      let _1: i32;                         // in scope 0 at $DIR/ref_deref.rs:+1:5: +1:10
-      let mut _2: &i32;                    // in scope 0 at $DIR/ref_deref.rs:+1:6: +1:10
-      let _3: i32;                         // in scope 0 at $DIR/ref_deref.rs:+1:8: +1:9
-+     let mut _4: &i32;                    // in scope 0 at $DIR/ref_deref.rs:+1:6: +1:10
-  
-      bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/ref_deref.rs:+1:5: +1:10
-          StorageLive(_2);                 // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10
--         StorageLive(_3);                 // scope 0 at $DIR/ref_deref.rs:+1:8: +1:9
--         _3 = const 4_i32;                // scope 0 at $DIR/ref_deref.rs:+1:8: +1:9
--         _2 = &_3;                        // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10
-+         _4 = const _;                    // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10
-+                                          // mir::Constant
-+                                          // + span: $DIR/ref_deref.rs:6:6: 6:10
-+                                          // + literal: Const { ty: &i32, val: Unevaluated(main, [], Some(promoted[0])) }
-+         _2 = &(*_4);                     // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10
-          _1 = (*_2);                      // scope 0 at $DIR/ref_deref.rs:+1:5: +1:10
--         StorageDead(_3);                 // scope 0 at $DIR/ref_deref.rs:+1:10: +1:11
-          StorageDead(_2);                 // scope 0 at $DIR/ref_deref.rs:+1:10: +1:11
-          StorageDead(_1);                 // scope 0 at $DIR/ref_deref.rs:+1:10: +1:11
-          _0 = const ();                   // scope 0 at $DIR/ref_deref.rs:+0:11: +2:2
-          return;                          // scope 0 at $DIR/ref_deref.rs:+2:2: +2:2
-      }
-  }
-  
index d2549c8b6aa5aa13277bcc168dc6edb04f277264..76e56916af09aa32606552cdfc5b83c92c81f84f 100644 (file)
@@ -1,5 +1,4 @@
-// compile-flags: -Zmir-enable-passes=-SimplifyLocals-before-const-prop
-// EMIT_MIR ref_deref.main.PromoteTemps.diff
+// unit-test: ConstProp
 // EMIT_MIR ref_deref.main.ConstProp.diff
 
 fn main() {
index ec3d90433159db1b596990220f44be4458e051cb..59095b4483713cc3fd806fadb83baae288c0b3a6 100644 (file)
           StorageLive(_2);                 // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17
           _4 = const _;                    // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17
                                            // mir::Constant
-                                           // + span: $DIR/ref_deref_project.rs:6:6: 6:17
+                                           // + span: $DIR/ref_deref_project.rs:5:6: 5:17
                                            // + literal: Const { ty: &(i32, i32), val: Unevaluated(main, [], Some(promoted[0])) }
           _2 = &((*_4).1: i32);            // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17
           _1 = (*_2);                      // scope 0 at $DIR/ref_deref_project.rs:+1:5: +1:17
           StorageDead(_2);                 // scope 0 at $DIR/ref_deref_project.rs:+1:17: +1:18
           StorageDead(_1);                 // scope 0 at $DIR/ref_deref_project.rs:+1:17: +1:18
-          nop;                             // scope 0 at $DIR/ref_deref_project.rs:+0:11: +2:2
+          _0 = const ();                   // scope 0 at $DIR/ref_deref_project.rs:+0:11: +2:2
           return;                          // scope 0 at $DIR/ref_deref_project.rs:+2:2: +2:2
       }
   }
diff --git a/tests/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff b/tests/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff
deleted file mode 100644 (file)
index cd0616e..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-- // MIR for `main` before PromoteTemps
-+ // MIR for `main` after PromoteTemps
-  
-  fn main() -> () {
-      let mut _0: ();                      // return place in scope 0 at $DIR/ref_deref_project.rs:+0:11: +0:11
-      let _1: i32;                         // in scope 0 at $DIR/ref_deref_project.rs:+1:5: +1:17
-      let mut _2: &i32;                    // in scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17
-      let _3: (i32, i32);                  // in scope 0 at $DIR/ref_deref_project.rs:+1:8: +1:14
-+     let mut _4: &(i32, i32);             // in scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17
-  
-      bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/ref_deref_project.rs:+1:5: +1:17
-          StorageLive(_2);                 // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17
--         StorageLive(_3);                 // scope 0 at $DIR/ref_deref_project.rs:+1:8: +1:14
--         _3 = (const 4_i32, const 5_i32); // scope 0 at $DIR/ref_deref_project.rs:+1:8: +1:14
--         _2 = &(_3.1: i32);               // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17
-+         _4 = const _;                    // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17
-+                                          // mir::Constant
-+                                          // + span: $DIR/ref_deref_project.rs:6:6: 6:17
-+                                          // + literal: Const { ty: &(i32, i32), val: Unevaluated(main, [], Some(promoted[0])) }
-+         _2 = &((*_4).1: i32);            // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17
-          _1 = (*_2);                      // scope 0 at $DIR/ref_deref_project.rs:+1:5: +1:17
--         StorageDead(_3);                 // scope 0 at $DIR/ref_deref_project.rs:+1:17: +1:18
-          StorageDead(_2);                 // scope 0 at $DIR/ref_deref_project.rs:+1:17: +1:18
-          StorageDead(_1);                 // scope 0 at $DIR/ref_deref_project.rs:+1:17: +1:18
-          _0 = const ();                   // scope 0 at $DIR/ref_deref_project.rs:+0:11: +2:2
-          return;                          // scope 0 at $DIR/ref_deref_project.rs:+2:2: +2:2
-      }
-  }
-  
index 2fdd4e15319014cd28efabf768483b81bcd84044..04fc7f8daa1240b9eb5ca2bc02797ca1154fcbaf 100644 (file)
@@ -1,5 +1,4 @@
-// compile-flags: -Zmir-enable-passes=-SimplifyLocals-before-const-prop
-// EMIT_MIR ref_deref_project.main.PromoteTemps.diff
+// unit-test: ConstProp
 // EMIT_MIR ref_deref_project.main.ConstProp.diff
 
 fn main() {
index d518eff04eba21af52d1036f9ba2c6a2f808b444..e3f5b120a3234d8bb12f2eb2b99fe3199f04422d 100644 (file)
           StorageLive(_1);                 // scope 0 at $DIR/scalar_literal_propagation.rs:+1:9: +1:10
           _1 = const 1_u32;                // scope 0 at $DIR/scalar_literal_propagation.rs:+1:13: +1:14
           StorageLive(_2);                 // scope 1 at $DIR/scalar_literal_propagation.rs:+2:5: +2:15
-          StorageLive(_3);                 // scope 1 at $DIR/scalar_literal_propagation.rs:+2:13: +2:14
--         _3 = _1;                         // scope 1 at $DIR/scalar_literal_propagation.rs:+2:13: +2:14
--         _2 = consume(move _3) -> bb1;    // scope 1 at $DIR/scalar_literal_propagation.rs:+2:5: +2:15
-+         _3 = const 1_u32;                // scope 1 at $DIR/scalar_literal_propagation.rs:+2:13: +2:14
+-         _2 = consume(_1) -> bb1;         // scope 1 at $DIR/scalar_literal_propagation.rs:+2:5: +2:15
 +         _2 = consume(const 1_u32) -> bb1; // scope 1 at $DIR/scalar_literal_propagation.rs:+2:5: +2:15
                                            // mir::Constant
                                            // + span: $DIR/scalar_literal_propagation.rs:4:5: 4:12
@@ -25,9 +22,7 @@
       }
   
       bb1: {
-          StorageDead(_3);                 // scope 1 at $DIR/scalar_literal_propagation.rs:+2:14: +2:15
           StorageDead(_2);                 // scope 1 at $DIR/scalar_literal_propagation.rs:+2:15: +2:16
-          StorageDead(_1);                 // scope 0 at $DIR/scalar_literal_propagation.rs:+3:1: +3:2
           return;                          // scope 0 at $DIR/scalar_literal_propagation.rs:+3:2: +3:2
       }
   }
index 9017fd18e48752f510e3326a1fbcfdcc1d49f6c9..b99b83b0cba8540144dc76fd70b47477e79fa405 100644 (file)
@@ -20,7 +20,7 @@
           StorageLive(_4);                 // scope 0 at $DIR/slice_len.rs:+1:6: +1:19
           _9 = const _;                    // scope 0 at $DIR/slice_len.rs:+1:6: +1:19
                                            // mir::Constant
-                                           // + span: $DIR/slice_len.rs:6:6: 6:19
+                                           // + span: $DIR/slice_len.rs:7:6: 7:19
                                            // + literal: Const { ty: &[u32; 3], val: Unevaluated(main, [], Some(promoted[0])) }
           _4 = _9;                         // scope 0 at $DIR/slice_len.rs:+1:6: +1:19
           _3 = _4;                         // scope 0 at $DIR/slice_len.rs:+1:6: +1:19
@@ -33,7 +33,7 @@
 -         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33
 +         _7 = const 3_usize;              // scope 0 at $DIR/slice_len.rs:+1:5: +1:33
 +         _8 = const true;                 // scope 0 at $DIR/slice_len.rs:+1:5: +1:33
-+         assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> bb1; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33
++         assert(const true, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33
       }
   
       bb1: {
@@ -43,7 +43,7 @@
           StorageDead(_4);                 // scope 0 at $DIR/slice_len.rs:+1:33: +1:34
           StorageDead(_2);                 // scope 0 at $DIR/slice_len.rs:+1:33: +1:34
           StorageDead(_1);                 // scope 0 at $DIR/slice_len.rs:+1:33: +1:34
-          nop;                             // scope 0 at $DIR/slice_len.rs:+0:11: +2:2
+          _0 = const ();                   // scope 0 at $DIR/slice_len.rs:+0:11: +2:2
           return;                          // scope 0 at $DIR/slice_len.rs:+2:2: +2:2
       }
   }
index 9017fd18e48752f510e3326a1fbcfdcc1d49f6c9..b99b83b0cba8540144dc76fd70b47477e79fa405 100644 (file)
@@ -20,7 +20,7 @@
           StorageLive(_4);                 // scope 0 at $DIR/slice_len.rs:+1:6: +1:19
           _9 = const _;                    // scope 0 at $DIR/slice_len.rs:+1:6: +1:19
                                            // mir::Constant
-                                           // + span: $DIR/slice_len.rs:6:6: 6:19
+                                           // + span: $DIR/slice_len.rs:7:6: 7:19
                                            // + literal: Const { ty: &[u32; 3], val: Unevaluated(main, [], Some(promoted[0])) }
           _4 = _9;                         // scope 0 at $DIR/slice_len.rs:+1:6: +1:19
           _3 = _4;                         // scope 0 at $DIR/slice_len.rs:+1:6: +1:19
@@ -33,7 +33,7 @@
 -         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33
 +         _7 = const 3_usize;              // scope 0 at $DIR/slice_len.rs:+1:5: +1:33
 +         _8 = const true;                 // scope 0 at $DIR/slice_len.rs:+1:5: +1:33
-+         assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> bb1; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33
++         assert(const true, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33
       }
   
       bb1: {
@@ -43,7 +43,7 @@
           StorageDead(_4);                 // scope 0 at $DIR/slice_len.rs:+1:33: +1:34
           StorageDead(_2);                 // scope 0 at $DIR/slice_len.rs:+1:33: +1:34
           StorageDead(_1);                 // scope 0 at $DIR/slice_len.rs:+1:33: +1:34
-          nop;                             // scope 0 at $DIR/slice_len.rs:+0:11: +2:2
+          _0 = const ();                   // scope 0 at $DIR/slice_len.rs:+0:11: +2:2
           return;                          // scope 0 at $DIR/slice_len.rs:+2:2: +2:2
       }
   }
index eaaf34b960eb66a84bd0ef5f43aa95c3b26e3bcc..8183def0c63dbda29ffd08a43dd70fa1fb8cfcfb 100644 (file)
@@ -1,4 +1,5 @@
-// compile-flags: -Zmir-enable-passes=-SimplifyLocals-before-const-prop
+// unit-test: ConstProp
+// compile-flags: -Zmir-enable-passes=+InstCombine
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
 
 // EMIT_MIR slice_len.main.ConstProp.diff
index ea9fec0aa15d1a6f0c09371fbbe1ecacb9bc2a98..b6b542fb79436d3ce1b3b8dacdb4202e57e0aa01 100644 (file)
@@ -4,15 +4,16 @@
   fn bar() -> () {
       let mut _0: ();                      // return place in scope 0 at $DIR/const_prop_miscompile.rs:+0:10: +0:10
       let mut _1: (i32,);                  // in scope 0 at $DIR/const_prop_miscompile.rs:+1:9: +1:14
-      let mut _2: *mut i32;                // in scope 0 at $DIR/const_prop_miscompile.rs:+3:10: +3:22
-      let mut _4: i32;                     // in scope 0 at $DIR/const_prop_miscompile.rs:+5:13: +5:20
+      let _2: ();                          // in scope 0 at $DIR/const_prop_miscompile.rs:+2:5: +4:6
+      let mut _3: *mut i32;                // in scope 0 at $DIR/const_prop_miscompile.rs:+3:10: +3:22
+      let mut _5: i32;                     // in scope 0 at $DIR/const_prop_miscompile.rs:+5:13: +5:20
       scope 1 {
           debug v => _1;                   // in scope 1 at $DIR/const_prop_miscompile.rs:+1:9: +1:14
-          let _3: bool;                    // in scope 1 at $DIR/const_prop_miscompile.rs:+5:9: +5:10
+          let _4: bool;                    // in scope 1 at $DIR/const_prop_miscompile.rs:+5:9: +5:10
           scope 2 {
           }
           scope 3 {
-              debug y => _3;               // in scope 3 at $DIR/const_prop_miscompile.rs:+5:9: +5:10
+              debug y => _4;               // in scope 3 at $DIR/const_prop_miscompile.rs:+5:9: +5:10
           }
       }
   
           StorageLive(_1);                 // scope 0 at $DIR/const_prop_miscompile.rs:+1:9: +1:14
           Deinit(_1);                      // scope 0 at $DIR/const_prop_miscompile.rs:+1:17: +1:21
           (_1.0: i32) = const 1_i32;       // scope 0 at $DIR/const_prop_miscompile.rs:+1:17: +1:21
-          StorageLive(_2);                 // scope 2 at $DIR/const_prop_miscompile.rs:+3:10: +3:22
-          _2 = &raw mut (_1.0: i32);       // scope 2 at $DIR/const_prop_miscompile.rs:+3:10: +3:22
-          (*_2) = const 5_i32;             // scope 2 at $DIR/const_prop_miscompile.rs:+3:9: +3:26
-          StorageDead(_2);                 // scope 2 at $DIR/const_prop_miscompile.rs:+3:26: +3:27
-          StorageLive(_3);                 // scope 1 at $DIR/const_prop_miscompile.rs:+5:9: +5:10
-          StorageLive(_4);                 // scope 1 at $DIR/const_prop_miscompile.rs:+5:13: +5:20
-          _4 = (_1.0: i32);                // scope 1 at $DIR/const_prop_miscompile.rs:+5:15: +5:18
-          _3 = Eq(move _4, const 5_i32);   // scope 1 at $DIR/const_prop_miscompile.rs:+5:13: +5:25
-          StorageDead(_4);                 // scope 1 at $DIR/const_prop_miscompile.rs:+5:24: +5:25
-          StorageDead(_3);                 // scope 1 at $DIR/const_prop_miscompile.rs:+6:1: +6:2
+          StorageLive(_2);                 // scope 1 at $DIR/const_prop_miscompile.rs:+2:5: +4:6
+          StorageLive(_3);                 // scope 2 at $DIR/const_prop_miscompile.rs:+3:10: +3:22
+          _3 = &raw mut (_1.0: i32);       // scope 2 at $DIR/const_prop_miscompile.rs:+3:10: +3:22
+          (*_3) = const 5_i32;             // scope 2 at $DIR/const_prop_miscompile.rs:+3:9: +3:26
+          StorageDead(_3);                 // scope 2 at $DIR/const_prop_miscompile.rs:+3:26: +3:27
+          _2 = const ();                   // scope 2 at $DIR/const_prop_miscompile.rs:+2:5: +4:6
+          StorageDead(_2);                 // scope 1 at $DIR/const_prop_miscompile.rs:+4:5: +4:6
+          StorageLive(_4);                 // scope 1 at $DIR/const_prop_miscompile.rs:+5:9: +5:10
+          StorageLive(_5);                 // scope 1 at $DIR/const_prop_miscompile.rs:+5:13: +5:20
+          _5 = (_1.0: i32);                // scope 1 at $DIR/const_prop_miscompile.rs:+5:15: +5:18
+          _4 = Eq(move _5, const 5_i32);   // scope 1 at $DIR/const_prop_miscompile.rs:+5:13: +5:25
+          StorageDead(_5);                 // scope 1 at $DIR/const_prop_miscompile.rs:+5:24: +5:25
+          _0 = const ();                   // scope 0 at $DIR/const_prop_miscompile.rs:+0:10: +6:2
+          StorageDead(_4);                 // scope 1 at $DIR/const_prop_miscompile.rs:+6:1: +6:2
           StorageDead(_1);                 // scope 0 at $DIR/const_prop_miscompile.rs:+6:1: +6:2
           return;                          // scope 0 at $DIR/const_prop_miscompile.rs:+6:2: +6:2
       }
index 043f404741710a9af58bb2d0f7d7781e350659f9..e43735fd9e145057c6ea8395c378fc5aeb5e2657 100644 (file)
@@ -27,6 +27,7 @@
           _4 = (_1.0: i32);                // scope 1 at $DIR/const_prop_miscompile.rs:+3:15: +3:18
           _3 = Eq(move _4, const 5_i32);   // scope 1 at $DIR/const_prop_miscompile.rs:+3:13: +3:25
           StorageDead(_4);                 // scope 1 at $DIR/const_prop_miscompile.rs:+3:24: +3:25
+          _0 = const ();                   // scope 0 at $DIR/const_prop_miscompile.rs:+0:10: +4:2
           StorageDead(_3);                 // scope 1 at $DIR/const_prop_miscompile.rs:+4:1: +4:2
           StorageDead(_1);                 // scope 0 at $DIR/const_prop_miscompile.rs:+4:1: +4:2
           return;                          // scope 0 at $DIR/const_prop_miscompile.rs:+4:2: +4:2
index bc54556b34947293028575a8a033d3153924cc3b..dbbe5ee08408f4b9c7d4ea1a783bf4cac5566da6 100644 (file)
@@ -1,3 +1,4 @@
+// unit-test: ConstProp
 #![feature(raw_ref_op)]
 
 // EMIT_MIR const_prop_miscompile.foo.ConstProp.diff
diff --git a/tests/mir-opt/copy-prop/borrowed_local.f.CopyProp.diff b/tests/mir-opt/copy-prop/borrowed_local.f.CopyProp.diff
new file mode 100644 (file)
index 0000000..b183865
--- /dev/null
@@ -0,0 +1,34 @@
+- // MIR for `f` before CopyProp
++ // MIR for `f` after CopyProp
+  
+  fn f() -> bool {
+      let mut _0: bool;                    // return place in scope 0 at $DIR/borrowed_local.rs:+0:11: +0:15
+      let mut _1: u8;                      // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+      let mut _2: &u8;                     // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+      let mut _3: u8;                      // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+      let mut _4: &u8;                     // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+  
+      bb0: {
+          _1 = const 5_u8;                 // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+          _2 = &_1;                        // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+          _3 = _1;                         // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+          _4 = &_3;                        // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+          _0 = cmp_ref(_2, _4) -> bb1;     // scope 0 at $DIR/borrowed_local.rs:+8:13: +8:45
+                                           // mir::Constant
+                                           // + span: $DIR/borrowed_local.rs:23:29: 23:36
+                                           // + literal: Const { ty: for<'a, 'b> fn(&'a u8, &'b u8) -> bool {cmp_ref}, val: Value(<ZST>) }
+      }
+  
+      bb1: {
+-         _0 = opaque::<u8>(_3) -> bb2;    // scope 0 at $DIR/borrowed_local.rs:+12:13: +12:38
++         _0 = opaque::<u8>(_1) -> bb2;    // scope 0 at $DIR/borrowed_local.rs:+12:13: +12:38
+                                           // mir::Constant
+                                           // + span: $DIR/borrowed_local.rs:27:28: 27:34
+                                           // + literal: Const { ty: fn(u8) -> bool {opaque::<u8>}, val: Value(<ZST>) }
+      }
+  
+      bb2: {
+          return;                          // scope 0 at $DIR/borrowed_local.rs:+15:13: +15:21
+      }
+  }
+  
diff --git a/tests/mir-opt/copy-prop/borrowed_local.rs b/tests/mir-opt/copy-prop/borrowed_local.rs
new file mode 100644 (file)
index 0000000..c4b980e
--- /dev/null
@@ -0,0 +1,39 @@
+// unit-test: CopyProp
+
+#![feature(custom_mir, core_intrinsics)]
+#![allow(unused_assignments)]
+extern crate core;
+use core::intrinsics::mir::*;
+
+fn opaque(_: impl Sized) -> bool { true }
+
+fn cmp_ref(a: &u8, b: &u8) -> bool {
+    std::ptr::eq(a as *const u8, b as *const u8)
+}
+
+#[custom_mir(dialect = "analysis", phase = "post-cleanup")]
+fn f() -> bool {
+    mir!(
+        {
+            let a = 5_u8;
+            let r1 = &a;
+            let b = a;
+            // We cannot propagate the place `a`.
+            let r2 = &b;
+            Call(RET, next, cmp_ref(r1, r2))
+        }
+        next = {
+            // But we can propagate the value `a`.
+            Call(RET, ret, opaque(b))
+        }
+        ret = {
+            Return()
+        }
+    )
+}
+
+fn main() {
+    assert!(!f());
+}
+
+// EMIT_MIR borrowed_local.f.CopyProp.diff
diff --git a/tests/mir-opt/copy-prop/branch.foo.CopyProp.diff b/tests/mir-opt/copy-prop/branch.foo.CopyProp.diff
new file mode 100644 (file)
index 0000000..8b11653
--- /dev/null
@@ -0,0 +1,65 @@
+- // MIR for `foo` before CopyProp
++ // MIR for `foo` after CopyProp
+  
+  fn foo() -> i32 {
+      let mut _0: i32;                     // return place in scope 0 at $DIR/branch.rs:+0:13: +0:16
+      let _1: i32;                         // in scope 0 at $DIR/branch.rs:+1:9: +1:10
+      let mut _3: bool;                    // in scope 0 at $DIR/branch.rs:+3:16: +3:22
+      let _4: i32;                         // in scope 0 at $DIR/branch.rs:+6:9: +6:14
+      scope 1 {
+          debug x => _1;                   // in scope 1 at $DIR/branch.rs:+1:9: +1:10
+          let _2: i32;                     // in scope 1 at $DIR/branch.rs:+3:9: +3:10
+          scope 2 {
+              debug y => _2;               // in scope 2 at $DIR/branch.rs:+3:9: +3:10
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/branch.rs:+1:9: +1:10
+          _1 = val() -> bb1;               // scope 0 at $DIR/branch.rs:+1:13: +1:18
+                                           // mir::Constant
+                                           // + span: $DIR/branch.rs:13:13: 13:16
+                                           // + literal: Const { ty: fn() -> i32 {val}, val: Value(<ZST>) }
+      }
+  
+      bb1: {
+          StorageLive(_2);                 // scope 1 at $DIR/branch.rs:+3:9: +3:10
+          StorageLive(_3);                 // scope 1 at $DIR/branch.rs:+3:16: +3:22
+          _3 = cond() -> bb2;              // scope 1 at $DIR/branch.rs:+3:16: +3:22
+                                           // mir::Constant
+                                           // + span: $DIR/branch.rs:15:16: 15:20
+                                           // + literal: Const { ty: fn() -> bool {cond}, val: Value(<ZST>) }
+      }
+  
+      bb2: {
+          switchInt(move _3) -> [0: bb4, otherwise: bb3]; // scope 1 at $DIR/branch.rs:+3:16: +3:22
+      }
+  
+      bb3: {
+          _2 = _1;                         // scope 1 at $DIR/branch.rs:+4:9: +4:10
+          goto -> bb6;                     // scope 1 at $DIR/branch.rs:+3:13: +8:6
+      }
+  
+      bb4: {
+          StorageLive(_4);                 // scope 1 at $DIR/branch.rs:+6:9: +6:14
+          _4 = val() -> bb5;               // scope 1 at $DIR/branch.rs:+6:9: +6:14
+                                           // mir::Constant
+                                           // + span: $DIR/branch.rs:18:9: 18:12
+                                           // + literal: Const { ty: fn() -> i32 {val}, val: Value(<ZST>) }
+      }
+  
+      bb5: {
+          StorageDead(_4);                 // scope 1 at $DIR/branch.rs:+6:14: +6:15
+          _2 = _1;                         // scope 1 at $DIR/branch.rs:+7:9: +7:10
+          goto -> bb6;                     // scope 1 at $DIR/branch.rs:+3:13: +8:6
+      }
+  
+      bb6: {
+          StorageDead(_3);                 // scope 1 at $DIR/branch.rs:+8:5: +8:6
+          _0 = _2;                         // scope 2 at $DIR/branch.rs:+10:5: +10:6
+          StorageDead(_2);                 // scope 1 at $DIR/branch.rs:+11:1: +11:2
+          StorageDead(_1);                 // scope 0 at $DIR/branch.rs:+11:1: +11:2
+          return;                          // scope 0 at $DIR/branch.rs:+11:2: +11:2
+      }
+  }
+  
diff --git a/tests/mir-opt/copy-prop/branch.rs b/tests/mir-opt/copy-prop/branch.rs
new file mode 100644 (file)
index 0000000..50b1e00
--- /dev/null
@@ -0,0 +1,27 @@
+//! Tests that we bail out when there are multiple assignments to the same local.
+// unit-test: CopyProp
+fn val() -> i32 {
+    1
+}
+
+fn cond() -> bool {
+    true
+}
+
+// EMIT_MIR branch.foo.CopyProp.diff
+fn foo() -> i32 {
+    let x = val();
+
+    let y = if cond() {
+        x
+    } else {
+        val();
+        x
+    };
+
+    y
+}
+
+fn main() {
+    foo();
+}
diff --git a/tests/mir-opt/copy-prop/copy_propagation_arg.arg_src.CopyProp.diff b/tests/mir-opt/copy-prop/copy_propagation_arg.arg_src.CopyProp.diff
new file mode 100644 (file)
index 0000000..69acebf
--- /dev/null
@@ -0,0 +1,21 @@
+- // MIR for `arg_src` before CopyProp
++ // MIR for `arg_src` after CopyProp
+  
+  fn arg_src(_1: i32) -> i32 {
+      debug x => _1;                       // in scope 0 at $DIR/copy_propagation_arg.rs:+0:12: +0:17
+      let mut _0: i32;                     // return place in scope 0 at $DIR/copy_propagation_arg.rs:+0:27: +0:30
+      let _2: i32;                         // in scope 0 at $DIR/copy_propagation_arg.rs:+1:9: +1:10
+      scope 1 {
+          debug y => _2;                   // in scope 1 at $DIR/copy_propagation_arg.rs:+1:9: +1:10
+      }
+  
+      bb0: {
+          StorageLive(_2);                 // scope 0 at $DIR/copy_propagation_arg.rs:+1:9: +1:10
+          _2 = _1;                         // scope 0 at $DIR/copy_propagation_arg.rs:+1:13: +1:14
+          _1 = const 123_i32;              // scope 1 at $DIR/copy_propagation_arg.rs:+2:5: +2:12
+          _0 = _2;                         // scope 1 at $DIR/copy_propagation_arg.rs:+3:5: +3:6
+          StorageDead(_2);                 // scope 0 at $DIR/copy_propagation_arg.rs:+4:1: +4:2
+          return;                          // scope 0 at $DIR/copy_propagation_arg.rs:+4:2: +4:2
+      }
+  }
+  
diff --git a/tests/mir-opt/copy-prop/copy_propagation_arg.bar.CopyProp.diff b/tests/mir-opt/copy-prop/copy_propagation_arg.bar.CopyProp.diff
new file mode 100644 (file)
index 0000000..ac4e9a2
--- /dev/null
@@ -0,0 +1,28 @@
+- // MIR for `bar` before CopyProp
++ // MIR for `bar` after CopyProp
+  
+  fn bar(_1: u8) -> () {
+      debug x => _1;                       // in scope 0 at $DIR/copy_propagation_arg.rs:+0:8: +0:13
+      let mut _0: ();                      // return place in scope 0 at $DIR/copy_propagation_arg.rs:+0:19: +0:19
+      let _2: u8;                          // in scope 0 at $DIR/copy_propagation_arg.rs:+1:5: +1:13
+      let mut _3: u8;                      // in scope 0 at $DIR/copy_propagation_arg.rs:+1:11: +1:12
+  
+      bb0: {
+          StorageLive(_2);                 // scope 0 at $DIR/copy_propagation_arg.rs:+1:5: +1:13
+          StorageLive(_3);                 // scope 0 at $DIR/copy_propagation_arg.rs:+1:11: +1:12
+          _3 = _1;                         // scope 0 at $DIR/copy_propagation_arg.rs:+1:11: +1:12
+          _2 = dummy(move _3) -> bb1;      // scope 0 at $DIR/copy_propagation_arg.rs:+1:5: +1:13
+                                           // mir::Constant
+                                           // + span: $DIR/copy_propagation_arg.rs:16:5: 16:10
+                                           // + literal: Const { ty: fn(u8) -> u8 {dummy}, val: Value(<ZST>) }
+      }
+  
+      bb1: {
+          StorageDead(_3);                 // scope 0 at $DIR/copy_propagation_arg.rs:+1:12: +1:13
+          StorageDead(_2);                 // scope 0 at $DIR/copy_propagation_arg.rs:+1:13: +1:14
+          _1 = const 5_u8;                 // scope 0 at $DIR/copy_propagation_arg.rs:+2:5: +2:10
+          _0 = const ();                   // scope 0 at $DIR/copy_propagation_arg.rs:+0:19: +3:2
+          return;                          // scope 0 at $DIR/copy_propagation_arg.rs:+3:2: +3:2
+      }
+  }
+  
diff --git a/tests/mir-opt/copy-prop/copy_propagation_arg.baz.CopyProp.diff b/tests/mir-opt/copy-prop/copy_propagation_arg.baz.CopyProp.diff
new file mode 100644 (file)
index 0000000..7ab6ebb
--- /dev/null
@@ -0,0 +1,18 @@
+- // MIR for `baz` before CopyProp
++ // MIR for `baz` after CopyProp
+  
+  fn baz(_1: i32) -> i32 {
+      debug x => _1;                       // in scope 0 at $DIR/copy_propagation_arg.rs:+0:8: +0:13
+      let mut _0: i32;                     // return place in scope 0 at $DIR/copy_propagation_arg.rs:+0:23: +0:26
+      let mut _2: i32;                     // in scope 0 at $DIR/copy_propagation_arg.rs:+2:9: +2:10
+  
+      bb0: {
+          StorageLive(_2);                 // scope 0 at $DIR/copy_propagation_arg.rs:+2:9: +2:10
+          _2 = _1;                         // scope 0 at $DIR/copy_propagation_arg.rs:+2:9: +2:10
+          _1 = move _2;                    // scope 0 at $DIR/copy_propagation_arg.rs:+2:5: +2:10
+          StorageDead(_2);                 // scope 0 at $DIR/copy_propagation_arg.rs:+2:9: +2:10
+          _0 = _1;                         // scope 0 at $DIR/copy_propagation_arg.rs:+3:5: +3:6
+          return;                          // scope 0 at $DIR/copy_propagation_arg.rs:+4:2: +4:2
+      }
+  }
+  
diff --git a/tests/mir-opt/copy-prop/copy_propagation_arg.foo.CopyProp.diff b/tests/mir-opt/copy-prop/copy_propagation_arg.foo.CopyProp.diff
new file mode 100644 (file)
index 0000000..0a3e985
--- /dev/null
@@ -0,0 +1,28 @@
+- // MIR for `foo` before CopyProp
++ // MIR for `foo` after CopyProp
+  
+  fn foo(_1: u8) -> () {
+      debug x => _1;                       // in scope 0 at $DIR/copy_propagation_arg.rs:+0:8: +0:13
+      let mut _0: ();                      // return place in scope 0 at $DIR/copy_propagation_arg.rs:+0:19: +0:19
+      let mut _2: u8;                      // in scope 0 at $DIR/copy_propagation_arg.rs:+2:9: +2:17
+      let mut _3: u8;                      // in scope 0 at $DIR/copy_propagation_arg.rs:+2:15: +2:16
+  
+      bb0: {
+          StorageLive(_2);                 // scope 0 at $DIR/copy_propagation_arg.rs:+2:9: +2:17
+          StorageLive(_3);                 // scope 0 at $DIR/copy_propagation_arg.rs:+2:15: +2:16
+          _3 = _1;                         // scope 0 at $DIR/copy_propagation_arg.rs:+2:15: +2:16
+          _2 = dummy(move _3) -> bb1;      // scope 0 at $DIR/copy_propagation_arg.rs:+2:9: +2:17
+                                           // mir::Constant
+                                           // + span: $DIR/copy_propagation_arg.rs:11:9: 11:14
+                                           // + literal: Const { ty: fn(u8) -> u8 {dummy}, val: Value(<ZST>) }
+      }
+  
+      bb1: {
+          StorageDead(_3);                 // scope 0 at $DIR/copy_propagation_arg.rs:+2:16: +2:17
+          _1 = move _2;                    // scope 0 at $DIR/copy_propagation_arg.rs:+2:5: +2:17
+          StorageDead(_2);                 // scope 0 at $DIR/copy_propagation_arg.rs:+2:16: +2:17
+          _0 = const ();                   // scope 0 at $DIR/copy_propagation_arg.rs:+0:19: +3:2
+          return;                          // scope 0 at $DIR/copy_propagation_arg.rs:+3:2: +3:2
+      }
+  }
+  
diff --git a/tests/mir-opt/copy-prop/copy_propagation_arg.rs b/tests/mir-opt/copy-prop/copy_propagation_arg.rs
new file mode 100644 (file)
index 0000000..cc98985
--- /dev/null
@@ -0,0 +1,40 @@
+// Check that CopyProp does not propagate an assignment to a function argument
+// (doing so can break usages of the original argument value)
+// unit-test: CopyProp
+fn dummy(x: u8) -> u8 {
+    x
+}
+
+// EMIT_MIR copy_propagation_arg.foo.CopyProp.diff
+fn foo(mut x: u8) {
+    // calling `dummy` to make a use of `x` that copyprop cannot eliminate
+    x = dummy(x); // this will assign a local to `x`
+}
+
+// EMIT_MIR copy_propagation_arg.bar.CopyProp.diff
+fn bar(mut x: u8) {
+    dummy(x);
+    x = 5;
+}
+
+// EMIT_MIR copy_propagation_arg.baz.CopyProp.diff
+fn baz(mut x: i32) -> i32 {
+    // self-assignment to a function argument should be eliminated
+    x = x;
+    x
+}
+
+// EMIT_MIR copy_propagation_arg.arg_src.CopyProp.diff
+fn arg_src(mut x: i32) -> i32 {
+    let y = x;
+    x = 123; // Don't propagate this assignment to `y`
+    y
+}
+
+fn main() {
+    // Make sure the function actually gets instantiated.
+    foo(0);
+    bar(0);
+    baz(0);
+    arg_src(0);
+}
diff --git a/tests/mir-opt/copy-prop/cycle.main.CopyProp.diff b/tests/mir-opt/copy-prop/cycle.main.CopyProp.diff
new file mode 100644 (file)
index 0000000..bc5083e
--- /dev/null
@@ -0,0 +1,60 @@
+- // MIR for `main` before CopyProp
++ // MIR for `main` after CopyProp
+  
+  fn main() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/cycle.rs:+0:11: +0:11
+      let mut _1: i32;                     // in scope 0 at $DIR/cycle.rs:+1:9: +1:14
+      let mut _4: i32;                     // in scope 0 at $DIR/cycle.rs:+4:9: +4:10
+      let _5: ();                          // in scope 0 at $DIR/cycle.rs:+6:5: +6:12
+      let mut _6: i32;                     // in scope 0 at $DIR/cycle.rs:+6:10: +6:11
+      scope 1 {
+          debug x => _1;                   // in scope 1 at $DIR/cycle.rs:+1:9: +1:14
+          let _2: i32;                     // in scope 1 at $DIR/cycle.rs:+2:9: +2:10
+          scope 2 {
+              debug y => _2;               // in scope 2 at $DIR/cycle.rs:+2:9: +2:10
+              let _3: i32;                 // in scope 2 at $DIR/cycle.rs:+3:9: +3:10
+              scope 3 {
+-                 debug z => _3;           // in scope 3 at $DIR/cycle.rs:+3:9: +3:10
++                 debug z => _2;           // in scope 3 at $DIR/cycle.rs:+3:9: +3:10
+              }
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/cycle.rs:+1:9: +1:14
+          _1 = val() -> bb1;               // scope 0 at $DIR/cycle.rs:+1:17: +1:22
+                                           // mir::Constant
+                                           // + span: $DIR/cycle.rs:9:17: 9:20
+                                           // + literal: Const { ty: fn() -> i32 {val}, val: Value(<ZST>) }
+      }
+  
+      bb1: {
+          StorageLive(_2);                 // scope 1 at $DIR/cycle.rs:+2:9: +2:10
+          _2 = _1;                         // scope 1 at $DIR/cycle.rs:+2:13: +2:14
+-         StorageLive(_3);                 // scope 2 at $DIR/cycle.rs:+3:9: +3:10
+-         _3 = _2;                         // scope 2 at $DIR/cycle.rs:+3:13: +3:14
+-         StorageLive(_4);                 // scope 3 at $DIR/cycle.rs:+4:9: +4:10
+-         _4 = _3;                         // scope 3 at $DIR/cycle.rs:+4:9: +4:10
+-         _1 = move _4;                    // scope 3 at $DIR/cycle.rs:+4:5: +4:10
+-         StorageDead(_4);                 // scope 3 at $DIR/cycle.rs:+4:9: +4:10
++         _1 = _2;                         // scope 3 at $DIR/cycle.rs:+4:5: +4:10
+          StorageLive(_5);                 // scope 3 at $DIR/cycle.rs:+6:5: +6:12
+          StorageLive(_6);                 // scope 3 at $DIR/cycle.rs:+6:10: +6:11
+          _6 = _1;                         // scope 3 at $DIR/cycle.rs:+6:10: +6:11
+          _5 = std::mem::drop::<i32>(move _6) -> bb2; // scope 3 at $DIR/cycle.rs:+6:5: +6:12
+                                           // mir::Constant
+                                           // + span: $DIR/cycle.rs:14:5: 14:9
+                                           // + literal: Const { ty: fn(i32) {std::mem::drop::<i32>}, val: Value(<ZST>) }
+      }
+  
+      bb2: {
+          StorageDead(_6);                 // scope 3 at $DIR/cycle.rs:+6:11: +6:12
+          StorageDead(_5);                 // scope 3 at $DIR/cycle.rs:+6:12: +6:13
+          _0 = const ();                   // scope 0 at $DIR/cycle.rs:+0:11: +7:2
+-         StorageDead(_3);                 // scope 2 at $DIR/cycle.rs:+7:1: +7:2
+-         StorageDead(_2);                 // scope 1 at $DIR/cycle.rs:+7:1: +7:2
+          StorageDead(_1);                 // scope 0 at $DIR/cycle.rs:+7:1: +7:2
+          return;                          // scope 0 at $DIR/cycle.rs:+7:2: +7:2
+      }
+  }
+  
diff --git a/tests/mir-opt/copy-prop/cycle.rs b/tests/mir-opt/copy-prop/cycle.rs
new file mode 100644 (file)
index 0000000..b74c397
--- /dev/null
@@ -0,0 +1,15 @@
+//! Tests that cyclic assignments don't hang CopyProp, and result in reasonable code.
+// unit-test: CopyProp
+fn val() -> i32 {
+    1
+}
+
+// EMIT_MIR cycle.main.CopyProp.diff
+fn main() {
+    let mut x = val();
+    let y = x;
+    let z = y;
+    x = z;
+
+    drop(x);
+}
diff --git a/tests/mir-opt/copy-prop/dead_stores_79191.f.CopyProp.after.mir b/tests/mir-opt/copy-prop/dead_stores_79191.f.CopyProp.after.mir
new file mode 100644 (file)
index 0000000..918817d
--- /dev/null
@@ -0,0 +1,30 @@
+// MIR for `f` after CopyProp
+
+fn f(_1: usize) -> usize {
+    debug a => _1;                       // in scope 0 at $DIR/dead_stores_79191.rs:+0:6: +0:11
+    let mut _0: usize;                   // return place in scope 0 at $DIR/dead_stores_79191.rs:+0:23: +0:28
+    let _2: usize;                       // in scope 0 at $DIR/dead_stores_79191.rs:+1:9: +1:10
+    let mut _3: usize;                   // in scope 0 at $DIR/dead_stores_79191.rs:+3:9: +3:10
+    let mut _4: usize;                   // in scope 0 at $DIR/dead_stores_79191.rs:+4:8: +4:9
+    scope 1 {
+        debug b => _2;                   // in scope 1 at $DIR/dead_stores_79191.rs:+1:9: +1:10
+    }
+
+    bb0: {
+        StorageLive(_2);                 // scope 0 at $DIR/dead_stores_79191.rs:+1:9: +1:10
+        _2 = _1;                         // scope 0 at $DIR/dead_stores_79191.rs:+1:13: +1:14
+        _1 = const 5_usize;              // scope 1 at $DIR/dead_stores_79191.rs:+2:5: +2:10
+        _1 = _2;                         // scope 1 at $DIR/dead_stores_79191.rs:+3:5: +3:10
+        StorageLive(_4);                 // scope 1 at $DIR/dead_stores_79191.rs:+4:8: +4:9
+        _4 = _1;                         // scope 1 at $DIR/dead_stores_79191.rs:+4:8: +4:9
+        _0 = id::<usize>(move _4) -> bb1; // scope 1 at $DIR/dead_stores_79191.rs:+4:5: +4:10
+                                         // mir::Constant
+                                         // + span: $DIR/dead_stores_79191.rs:12:5: 12:7
+                                         // + literal: Const { ty: fn(usize) -> usize {id::<usize>}, val: Value(<ZST>) }
+    }
+
+    bb1: {
+        StorageDead(_4);                 // scope 1 at $DIR/dead_stores_79191.rs:+4:9: +4:10
+        return;                          // scope 0 at $DIR/dead_stores_79191.rs:+5:2: +5:2
+    }
+}
diff --git a/tests/mir-opt/copy-prop/dead_stores_79191.rs b/tests/mir-opt/copy-prop/dead_stores_79191.rs
new file mode 100644 (file)
index 0000000..e3493b8
--- /dev/null
@@ -0,0 +1,17 @@
+// unit-test: CopyProp
+
+fn id<T>(x: T) -> T {
+    x
+}
+
+// EMIT_MIR dead_stores_79191.f.CopyProp.after.mir
+fn f(mut a: usize) -> usize {
+    let b = a;
+    a = 5;
+    a = b;
+    id(a)
+}
+
+fn main() {
+    f(0);
+}
diff --git a/tests/mir-opt/copy-prop/dead_stores_better.f.CopyProp.after.mir b/tests/mir-opt/copy-prop/dead_stores_better.f.CopyProp.after.mir
new file mode 100644 (file)
index 0000000..cf21fad
--- /dev/null
@@ -0,0 +1,30 @@
+// MIR for `f` after CopyProp
+
+fn f(_1: usize) -> usize {
+    debug a => _1;                       // in scope 0 at $DIR/dead_stores_better.rs:+0:10: +0:15
+    let mut _0: usize;                   // return place in scope 0 at $DIR/dead_stores_better.rs:+0:27: +0:32
+    let _2: usize;                       // in scope 0 at $DIR/dead_stores_better.rs:+1:9: +1:10
+    let mut _3: usize;                   // in scope 0 at $DIR/dead_stores_better.rs:+3:9: +3:10
+    let mut _4: usize;                   // in scope 0 at $DIR/dead_stores_better.rs:+4:8: +4:9
+    scope 1 {
+        debug b => _2;                   // in scope 1 at $DIR/dead_stores_better.rs:+1:9: +1:10
+    }
+
+    bb0: {
+        StorageLive(_2);                 // scope 0 at $DIR/dead_stores_better.rs:+1:9: +1:10
+        _2 = _1;                         // scope 0 at $DIR/dead_stores_better.rs:+1:13: +1:14
+        _1 = const 5_usize;              // scope 1 at $DIR/dead_stores_better.rs:+2:5: +2:10
+        _1 = _2;                         // scope 1 at $DIR/dead_stores_better.rs:+3:5: +3:10
+        StorageLive(_4);                 // scope 1 at $DIR/dead_stores_better.rs:+4:8: +4:9
+        _4 = _1;                         // scope 1 at $DIR/dead_stores_better.rs:+4:8: +4:9
+        _0 = id::<usize>(move _4) -> bb1; // scope 1 at $DIR/dead_stores_better.rs:+4:5: +4:10
+                                         // mir::Constant
+                                         // + span: $DIR/dead_stores_better.rs:16:5: 16:7
+                                         // + literal: Const { ty: fn(usize) -> usize {id::<usize>}, val: Value(<ZST>) }
+    }
+
+    bb1: {
+        StorageDead(_4);                 // scope 1 at $DIR/dead_stores_better.rs:+4:9: +4:10
+        return;                          // scope 0 at $DIR/dead_stores_better.rs:+5:2: +5:2
+    }
+}
diff --git a/tests/mir-opt/copy-prop/dead_stores_better.rs b/tests/mir-opt/copy-prop/dead_stores_better.rs
new file mode 100644 (file)
index 0000000..8465b3c
--- /dev/null
@@ -0,0 +1,21 @@
+// This is a copy of the `dead_stores_79191` test, except that we turn on DSE. This demonstrates
+// that that pass enables this one to do more optimizations.
+
+// unit-test: CopyProp
+// compile-flags: -Zmir-enable-passes=+DeadStoreElimination
+
+fn id<T>(x: T) -> T {
+    x
+}
+
+// EMIT_MIR dead_stores_better.f.CopyProp.after.mir
+pub fn f(mut a: usize) -> usize {
+    let b = a;
+    a = 5;
+    a = b;
+    id(a)
+}
+
+fn main() {
+    f(0);
+}
diff --git a/tests/mir-opt/copy-prop/move_arg.f.CopyProp.diff b/tests/mir-opt/copy-prop/move_arg.f.CopyProp.diff
new file mode 100644 (file)
index 0000000..d76bf1c
--- /dev/null
@@ -0,0 +1,40 @@
+- // MIR for `f` before CopyProp
++ // MIR for `f` after CopyProp
+  
+  fn f(_1: T) -> () {
+      debug a => _1;                       // in scope 0 at $DIR/move_arg.rs:+0:19: +0:20
+      let mut _0: ();                      // return place in scope 0 at $DIR/move_arg.rs:+0:25: +0:25
+      let _2: T;                           // in scope 0 at $DIR/move_arg.rs:+1:9: +1:10
+      let _3: ();                          // in scope 0 at $DIR/move_arg.rs:+2:5: +2:12
+      let mut _4: T;                       // in scope 0 at $DIR/move_arg.rs:+2:7: +2:8
+      let mut _5: T;                       // in scope 0 at $DIR/move_arg.rs:+2:10: +2:11
+      scope 1 {
+-         debug b => _2;                   // in scope 1 at $DIR/move_arg.rs:+1:9: +1:10
++         debug b => _1;                   // in scope 1 at $DIR/move_arg.rs:+1:9: +1:10
+      }
+  
+      bb0: {
+-         StorageLive(_2);                 // scope 0 at $DIR/move_arg.rs:+1:9: +1:10
+-         _2 = _1;                         // scope 0 at $DIR/move_arg.rs:+1:13: +1:14
+          StorageLive(_3);                 // scope 1 at $DIR/move_arg.rs:+2:5: +2:12
+-         StorageLive(_4);                 // scope 1 at $DIR/move_arg.rs:+2:7: +2:8
+-         _4 = _1;                         // scope 1 at $DIR/move_arg.rs:+2:7: +2:8
+-         StorageLive(_5);                 // scope 1 at $DIR/move_arg.rs:+2:10: +2:11
+-         _5 = _2;                         // scope 1 at $DIR/move_arg.rs:+2:10: +2:11
+-         _3 = g::<T>(move _4, move _5) -> bb1; // scope 1 at $DIR/move_arg.rs:+2:5: +2:12
++         _3 = g::<T>(_1, _1) -> bb1;      // scope 1 at $DIR/move_arg.rs:+2:5: +2:12
+                                           // mir::Constant
+                                           // + span: $DIR/move_arg.rs:7:5: 7:6
+                                           // + literal: Const { ty: fn(T, T) {g::<T>}, val: Value(<ZST>) }
+      }
+  
+      bb1: {
+-         StorageDead(_5);                 // scope 1 at $DIR/move_arg.rs:+2:11: +2:12
+-         StorageDead(_4);                 // scope 1 at $DIR/move_arg.rs:+2:11: +2:12
+          StorageDead(_3);                 // scope 1 at $DIR/move_arg.rs:+2:12: +2:13
+          _0 = const ();                   // scope 0 at $DIR/move_arg.rs:+0:25: +3:2
+-         StorageDead(_2);                 // scope 0 at $DIR/move_arg.rs:+3:1: +3:2
+          return;                          // scope 0 at $DIR/move_arg.rs:+3:2: +3:2
+      }
+  }
+  
diff --git a/tests/mir-opt/copy-prop/move_arg.rs b/tests/mir-opt/copy-prop/move_arg.rs
new file mode 100644 (file)
index 0000000..40ae1d8
--- /dev/null
@@ -0,0 +1,15 @@
+// Test that we do not move multiple times from the same local.
+// unit-test: CopyProp
+
+// EMIT_MIR move_arg.f.CopyProp.diff
+pub fn f<T: Copy>(a: T) {
+    let b = a;
+    g(a, b);
+}
+
+#[inline(never)]
+pub fn g<T: Copy>(_: T, _: T) {}
+
+fn main() {
+    f(5)
+}
diff --git a/tests/mir-opt/copy-prop/mutate_through_pointer.f.CopyProp.diff b/tests/mir-opt/copy-prop/mutate_through_pointer.f.CopyProp.diff
new file mode 100644 (file)
index 0000000..61fdd6f
--- /dev/null
@@ -0,0 +1,19 @@
+- // MIR for `f` before CopyProp
++ // MIR for `f` after CopyProp
+  
+  fn f(_1: bool) -> bool {
+      let mut _0: bool;                    // return place in scope 0 at $DIR/mutate_through_pointer.rs:+0:18: +0:22
+      let mut _2: bool;                    // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+      let mut _3: *const bool;             // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+      let mut _4: *mut bool;               // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+  
+      bb0: {
+          _2 = _1;                         // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+          _3 = &raw const _2;              // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+          _4 = &raw mut (*_3);             // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+          (*_4) = const false;             // scope 0 at $DIR/mutate_through_pointer.rs:+5:9: +5:20
+          _0 = _1;                         // scope 0 at $DIR/mutate_through_pointer.rs:+6:9: +6:16
+          return;                          // scope 0 at $DIR/mutate_through_pointer.rs:+7:9: +7:17
+      }
+  }
+  
diff --git a/tests/mir-opt/copy-prop/mutate_through_pointer.rs b/tests/mir-opt/copy-prop/mutate_through_pointer.rs
new file mode 100644 (file)
index 0000000..609e49d
--- /dev/null
@@ -0,0 +1,22 @@
+#![feature(custom_mir, core_intrinsics)]
+#![allow(unused_assignments)]
+extern crate core;
+use core::intrinsics::mir::*;
+
+#[custom_mir(dialect = "analysis", phase = "post-cleanup")]
+fn f(c: bool) -> bool {
+    mir!({
+        let a = c;
+        let p = core::ptr::addr_of!(a);
+        let p2 = core::ptr::addr_of_mut!(*p);
+        *p2 = false;
+        RET = c;
+        Return()
+    })
+}
+
+fn main() {
+    assert_eq!(true, f(true));
+}
+
+// EMIT_MIR mutate_through_pointer.f.CopyProp.diff
diff --git a/tests/mir-opt/copy-prop/non_dominate.f.CopyProp.diff b/tests/mir-opt/copy-prop/non_dominate.f.CopyProp.diff
new file mode 100644 (file)
index 0000000..9760fd3
--- /dev/null
@@ -0,0 +1,29 @@
+- // MIR for `f` before CopyProp
++ // MIR for `f` after CopyProp
+  
+  fn f(_1: bool) -> bool {
+      let mut _0: bool;                    // return place in scope 0 at $DIR/non_dominate.rs:+0:18: +0:22
+      let mut _2: bool;                    // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+      let mut _3: bool;                    // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+  
+      bb0: {
+          goto -> bb1;                     // scope 0 at $DIR/non_dominate.rs:+4:11: +4:20
+      }
+  
+      bb1: {
+          _3 = _1;                         // scope 0 at $DIR/non_dominate.rs:+5:17: +5:22
+          switchInt(_3) -> [0: bb3, otherwise: bb2]; // scope 0 at $DIR/non_dominate.rs:+5:24: +5:58
+      }
+  
+      bb2: {
+          _2 = _3;                         // scope 0 at $DIR/non_dominate.rs:+8:17: +8:22
+          _1 = const false;                // scope 0 at $DIR/non_dominate.rs:+8:24: +8:33
+          goto -> bb1;                     // scope 0 at $DIR/non_dominate.rs:+8:35: +8:44
+      }
+  
+      bb3: {
+          _0 = _2;                         // scope 0 at $DIR/non_dominate.rs:+9:17: +9:24
+          return;                          // scope 0 at $DIR/non_dominate.rs:+9:26: +9:34
+      }
+  }
+  
diff --git a/tests/mir-opt/copy-prop/non_dominate.rs b/tests/mir-opt/copy-prop/non_dominate.rs
new file mode 100644 (file)
index 0000000..c0ea838
--- /dev/null
@@ -0,0 +1,26 @@
+// unit-test: CopyProp
+
+#![feature(custom_mir, core_intrinsics)]
+#![allow(unused_assignments)]
+extern crate core;
+use core::intrinsics::mir::*;
+
+#[custom_mir(dialect = "analysis", phase = "post-cleanup")]
+fn f(c: bool) -> bool {
+    mir!(
+        let a: bool;
+        let b: bool;
+        { Goto(bb1) }
+        bb1 = { b = c; match b { false => bb3, _ => bb2 }}
+        // This assignment to `a` does not dominate the use in `bb3`.
+        // It should not be replaced by `b`.
+        bb2 = { a = b; c = false; Goto(bb1) }
+        bb3 = { RET = a; Return() }
+    )
+}
+
+fn main() {
+    assert_eq!(true, f(true));
+}
+
+// EMIT_MIR non_dominate.f.CopyProp.diff
index 02aafd7acc4ca5660cae57c17a18394031362f13..6870d7d6c45b457b8459dce4a63f514fdb4cbdc8 100644 (file)
           _1 = const u8::MAX;              // scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47
           StorageLive(_2);                 // scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47
           _2 = const 1_u8;                 // scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47
-          StorageLive(_3);                 // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
-          _3 = const u8::MAX;              // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
-          StorageLive(_4);                 // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
-          _4 = const 1_u8;                 // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
           _5 = CheckedAdd(const u8::MAX, const 1_u8); // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
           assert(!move (_5.1: bool), "attempt to compute `{} + {}`, which would overflow", const u8::MAX, const 1_u8) -> bb1; // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
       }
   
       bb1: {
-          StorageDead(_4);                 // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
-          StorageDead(_3);                 // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
-          StorageDead(_2);                 // scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47
-          StorageDead(_1);                 // scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47
           return;                          // scope 0 at $DIR/inherit_overflow.rs:+4:2: +4:2
       }
   }
index d7f66a6bf4d56816ba163731a309910cfe2d39c6..1a7fb916e56dbaf3d8ba15a4e84b422557117c16 100644 (file)
@@ -11,7 +11,7 @@ fn const_dividend(_1: i32) -> i32 {
     }
 
     bb1: {
-        _0 = Div(const 256_i32, move _1); // scope 0 at $DIR/div_overflow.rs:+1:5: +1:12
+        _0 = Div(const 256_i32, _1);     // scope 0 at $DIR/div_overflow.rs:+1:5: +1:12
         return;                          // scope 0 at $DIR/div_overflow.rs:+2:2: +2:2
     }
 }
index 7b7ab1978258fe21c9adf5f2c2e49e79b473ca5e..5526a194be563cb8ab98f4c0b4cab1669ed90ef4 100644 (file)
@@ -5,7 +5,7 @@ fn const_divisor(_1: i32) -> i32 {
     let mut _0: i32;                     // return place in scope 0 at $DIR/div_overflow.rs:+0:33: +0:36
 
     bb0: {
-        _0 = Div(move _1, const 256_i32); // scope 0 at $DIR/div_overflow.rs:+1:5: +1:12
+        _0 = Div(_1, const 256_i32);     // scope 0 at $DIR/div_overflow.rs:+1:5: +1:12
         return;                          // scope 0 at $DIR/div_overflow.rs:+2:2: +2:2
     }
 }
index c1c2cde71ab5b38f485885cd7f3a60bc4f13ad37..df9f8dcf1a407b7496b9f719db0d88d374162b5c 100644 (file)
           _10 = ((_7 as Some).0: usize);   // scope 3 at $DIR/funky_arms.rs:+13:17: +13:26
           StorageLive(_11);                // scope 3 at $DIR/funky_arms.rs:+15:43: +15:46
           _11 = &mut (*_1);                // scope 3 at $DIR/funky_arms.rs:+15:43: +15:46
-          StorageLive(_12);                // scope 3 at $DIR/funky_arms.rs:+15:48: +15:51
-          _12 = _2;                        // scope 3 at $DIR/funky_arms.rs:+15:48: +15:51
           StorageLive(_13);                // scope 3 at $DIR/funky_arms.rs:+15:53: +15:57
           _13 = _6;                        // scope 3 at $DIR/funky_arms.rs:+15:53: +15:57
           StorageLive(_14);                // scope 3 at $DIR/funky_arms.rs:+15:59: +15:79
           StorageLive(_15);                // scope 3 at $DIR/funky_arms.rs:+15:59: +15:75
-          StorageLive(_16);                // scope 3 at $DIR/funky_arms.rs:+15:59: +15:68
-          _16 = _10;                       // scope 3 at $DIR/funky_arms.rs:+15:59: +15:68
-          _15 = move _16 as u32 (IntToInt); // scope 3 at $DIR/funky_arms.rs:+15:59: +15:75
-          StorageDead(_16);                // scope 3 at $DIR/funky_arms.rs:+15:74: +15:75
+          _15 = _10 as u32 (IntToInt);     // scope 3 at $DIR/funky_arms.rs:+15:59: +15:75
           _14 = Add(move _15, const 1_u32); // scope 3 at $DIR/funky_arms.rs:+15:59: +15:79
           StorageDead(_15);                // scope 3 at $DIR/funky_arms.rs:+15:78: +15:79
-          StorageLive(_17);                // scope 3 at $DIR/funky_arms.rs:+15:81: +15:86
-          _17 = _3;                        // scope 3 at $DIR/funky_arms.rs:+15:81: +15:86
-          _0 = float_to_exponential_common_exact::<T>(move _11, move _12, move _13, move _14, move _17) -> bb7; // scope 3 at $DIR/funky_arms.rs:+15:9: +15:87
+          _0 = float_to_exponential_common_exact::<T>(move _11, _2, move _13, move _14, _3) -> bb7; // scope 3 at $DIR/funky_arms.rs:+15:9: +15:87
                                            // mir::Constant
                                            // + span: $DIR/funky_arms.rs:26:9: 26:42
                                            // + literal: Const { ty: for<'a, 'b, 'c> fn(&'a mut Formatter<'b>, &'c T, Sign, u32, bool) -> Result<(), std::fmt::Error> {float_to_exponential_common_exact::<T>}, val: Value(<ZST>) }
       }
   
       bb7: {
-          StorageDead(_17);                // scope 3 at $DIR/funky_arms.rs:+15:86: +15:87
           StorageDead(_14);                // scope 3 at $DIR/funky_arms.rs:+15:86: +15:87
           StorageDead(_13);                // scope 3 at $DIR/funky_arms.rs:+15:86: +15:87
-          StorageDead(_12);                // scope 3 at $DIR/funky_arms.rs:+15:86: +15:87
           StorageDead(_11);                // scope 3 at $DIR/funky_arms.rs:+15:86: +15:87
-          StorageDead(_10);                // scope 2 at $DIR/funky_arms.rs:+16:5: +16:6
           goto -> bb10;                    // scope 2 at $DIR/funky_arms.rs:+13:5: +18:6
       }
   
       bb8: {
           StorageLive(_18);                // scope 2 at $DIR/funky_arms.rs:+17:46: +17:49
           _18 = &mut (*_1);                // scope 2 at $DIR/funky_arms.rs:+17:46: +17:49
-          StorageLive(_19);                // scope 2 at $DIR/funky_arms.rs:+17:51: +17:54
-          _19 = _2;                        // scope 2 at $DIR/funky_arms.rs:+17:51: +17:54
           StorageLive(_20);                // scope 2 at $DIR/funky_arms.rs:+17:56: +17:60
           _20 = _6;                        // scope 2 at $DIR/funky_arms.rs:+17:56: +17:60
-          StorageLive(_21);                // scope 2 at $DIR/funky_arms.rs:+17:62: +17:67
-          _21 = _3;                        // scope 2 at $DIR/funky_arms.rs:+17:62: +17:67
-          _0 = float_to_exponential_common_shortest::<T>(move _18, move _19, move _20, move _21) -> bb9; // scope 2 at $DIR/funky_arms.rs:+17:9: +17:68
+          _0 = float_to_exponential_common_shortest::<T>(move _18, _2, move _20, _3) -> bb9; // scope 2 at $DIR/funky_arms.rs:+17:9: +17:68
                                            // mir::Constant
                                            // + span: $DIR/funky_arms.rs:28:9: 28:45
                                            // + literal: Const { ty: for<'a, 'b, 'c> fn(&'a mut Formatter<'b>, &'c T, Sign, bool) -> Result<(), std::fmt::Error> {float_to_exponential_common_shortest::<T>}, val: Value(<ZST>) }
       }
   
       bb9: {
-          StorageDead(_21);                // scope 2 at $DIR/funky_arms.rs:+17:67: +17:68
           StorageDead(_20);                // scope 2 at $DIR/funky_arms.rs:+17:67: +17:68
-          StorageDead(_19);                // scope 2 at $DIR/funky_arms.rs:+17:67: +17:68
           StorageDead(_18);                // scope 2 at $DIR/funky_arms.rs:+17:67: +17:68
           goto -> bb10;                    // scope 2 at $DIR/funky_arms.rs:+13:5: +18:6
       }
index 8ea1a0757f2f028ee79cb76c8ddd08f4f29dc5d2..64c3e47ff46edb7b40ca5853b413e2773923d3ac 100644 (file)
@@ -35,8 +35,8 @@
           _4 = &(*_2);                     // scope 1 at $DIR/dyn_trait.rs:+2:23: +2:24
 -         _0 = try_execute_query::<<Q as Query>::C>(move _4) -> bb2; // scope 1 at $DIR/dyn_trait.rs:+2:5: +2:25
 +         StorageLive(_5);                 // scope 2 at $DIR/dyn_trait.rs:27:14: 27:15
-+         _5 = move _4 as &dyn Cache<V = <Q as Query>::V> (Pointer(Unsize)); // scope 2 at $DIR/dyn_trait.rs:27:14: 27:15
-+         _0 = <dyn Cache<V = <Q as Query>::V> as Cache>::store_nocache(move _5) -> bb2; // scope 3 at $DIR/dyn_trait.rs:21:5: 21:22
++         _5 = _4 as &dyn Cache<V = <Q as Query>::V> (Pointer(Unsize)); // scope 2 at $DIR/dyn_trait.rs:27:14: 27:15
++         _0 = <dyn Cache<V = <Q as Query>::V> as Cache>::store_nocache(_5) -> bb2; // scope 3 at $DIR/dyn_trait.rs:21:5: 21:22
                                            // mir::Constant
 -                                          // + span: $DIR/dyn_trait.rs:34:5: 34:22
 -                                          // + literal: Const { ty: for<'a> fn(&'a <Q as Query>::C) {try_execute_query::<<Q as Query>::C>}, val: Value(<ZST>) }
index a71d73b7453544464922e3434b41b858aa18836b..3fa9c3e88f6349b265f00d3f0d3b91eb9707f50d 100644 (file)
@@ -17,7 +17,7 @@
           _2 = move _3 as &dyn Cache<V = <C as Cache>::V> (Pointer(Unsize)); // scope 0 at $DIR/dyn_trait.rs:+1:14: +1:15
           StorageDead(_3);                 // scope 0 at $DIR/dyn_trait.rs:+1:14: +1:15
 -         _0 = mk_cycle::<<C as Cache>::V>(move _2) -> bb1; // scope 0 at $DIR/dyn_trait.rs:+1:5: +1:16
-+         _0 = <dyn Cache<V = <C as Cache>::V> as Cache>::store_nocache(move _2) -> bb1; // scope 1 at $DIR/dyn_trait.rs:21:5: 21:22
++         _0 = <dyn Cache<V = <C as Cache>::V> as Cache>::store_nocache(_2) -> bb1; // scope 1 at $DIR/dyn_trait.rs:21:5: 21:22
                                            // mir::Constant
 -                                          // + span: $DIR/dyn_trait.rs:27:5: 27:13
 -                                          // + literal: Const { ty: for<'a> fn(&'a (dyn Cache<V = <C as Cache>::V> + 'a)) {mk_cycle::<<C as Cache>::V>}, val: Value(<ZST>) }
index 3502c25864bf9fffe84742a443c7876e4a770b95..20f737cc29f62904d92d2c6eaed05d054610357b 100644 (file)
@@ -26,7 +26,7 @@ fn bar() -> bool {
         _3 = const 1_i32;                // scope 1 at $DIR/inline_any_operand.rs:+2:5: +2:13
         StorageLive(_4);                 // scope 1 at $DIR/inline_any_operand.rs:+2:5: +2:13
         _4 = const -1_i32;               // scope 1 at $DIR/inline_any_operand.rs:+2:5: +2:13
-        _0 = Eq(move _3, move _4);       // scope 2 at $DIR/inline_any_operand.rs:17:5: 17:11
+        _0 = Eq(_3, _4);                 // scope 2 at $DIR/inline_any_operand.rs:17:5: 17:11
         StorageDead(_4);                 // scope 1 at $DIR/inline_any_operand.rs:+2:5: +2:13
         StorageDead(_3);                 // scope 1 at $DIR/inline_any_operand.rs:+2:5: +2:13
         StorageDead(_2);                 // scope 1 at $DIR/inline_any_operand.rs:+2:12: +2:13
index f27b64c305457a14b2da1b198d86a2b922980875..57574acf92354e375130f3997eb20351aa41309d 100644 (file)
@@ -92,7 +92,7 @@
 + 
 +     bb3: {
 +         StorageLive(_8);                 // scope 6 at $DIR/inline_generator.rs:15:17: 15:39
-+         switchInt(move _7) -> [0: bb5, otherwise: bb4]; // scope 6 at $DIR/inline_generator.rs:15:20: 15:21
++         switchInt(_7) -> [0: bb5, otherwise: bb4]; // scope 6 at $DIR/inline_generator.rs:15:20: 15:21
 +     }
 + 
 +     bb4: {
 +         StorageLive(_8);                 // scope 6 at $DIR/inline_generator.rs:15:5: 15:41
 +         StorageDead(_8);                 // scope 6 at $DIR/inline_generator.rs:15:38: 15:39
 +         Deinit(_1);                      // scope 6 at $DIR/inline_generator.rs:15:41: 15:41
-+         ((_1 as Complete).0: bool) = move _7; // scope 6 at $DIR/inline_generator.rs:15:41: 15:41
++         ((_1 as Complete).0: bool) = _7; // scope 6 at $DIR/inline_generator.rs:15:41: 15:41
 +         discriminant(_1) = 1;            // scope 6 at $DIR/inline_generator.rs:15:41: 15:41
 +         _12 = deref_copy (_2.0: &mut [generator@$DIR/inline_generator.rs:15:5: 15:8]); // scope 6 at $DIR/inline_generator.rs:15:41: 15:41
 +         discriminant((*_12)) = 1;        // scope 6 at $DIR/inline_generator.rs:15:41: 15:41
index 73aea719eed51956d3996950160b124a2217a360..b7c5bbecb6883a97306779d8f5e65278fe511dea 100644 (file)
@@ -15,7 +15,7 @@ fn test2(_1: &dyn X) -> bool {
         _3 = &(*_1);                     // scope 0 at $DIR/inline_trait_method_2.rs:+1:10: +1:11
         _2 = move _3 as &dyn X (Pointer(Unsize)); // scope 0 at $DIR/inline_trait_method_2.rs:+1:10: +1:11
         StorageDead(_3);                 // scope 0 at $DIR/inline_trait_method_2.rs:+1:10: +1:11
-        _0 = <dyn X as X>::y(move _2) -> bb1; // scope 1 at $DIR/inline_trait_method_2.rs:10:5: 10:10
+        _0 = <dyn X as X>::y(_2) -> bb1; // scope 1 at $DIR/inline_trait_method_2.rs:10:5: 10:10
                                          // mir::Constant
                                          // + span: $DIR/inline_trait_method_2.rs:10:7: 10:8
                                          // + literal: Const { ty: for<'a> fn(&'a dyn X) -> bool {<dyn X as X>::y}, val: Value(<ZST>) }
index b2706e5a436e2f02ae3084d8a75cb49b68a2c563..30bf2c0684e52525ba75d3da0232559318bd75f4 100644 (file)
@@ -15,7 +15,7 @@
       let mut _10: (u32, bool);            // in scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
       let mut _11: (u32, bool);            // in scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
       scope 1 (inlined imm8) {             // at $DIR/issue_101973.rs:14:5: 14:17
-          debug x => _5;                   // in scope 1 at $DIR/issue_101973.rs:5:13: 5:14
+          debug x => _1;                   // in scope 1 at $DIR/issue_101973.rs:5:13: 5:14
           let mut _12: u32;                // in scope 1 at $DIR/issue_101973.rs:7:12: 7:27
           let mut _13: u32;                // in scope 1 at $DIR/issue_101973.rs:7:12: 7:20
           let mut _14: (u32, bool);        // in scope 1 at $DIR/issue_101973.rs:7:12: 7:20
           StorageLive(_2);                 // scope 0 at $DIR/issue_101973.rs:+1:5: +1:65
           StorageLive(_3);                 // scope 0 at $DIR/issue_101973.rs:+1:5: +1:58
           StorageLive(_4);                 // scope 0 at $DIR/issue_101973.rs:+1:5: +1:17
-          StorageLive(_5);                 // scope 0 at $DIR/issue_101973.rs:+1:10: +1:16
-          _5 = _1;                         // scope 0 at $DIR/issue_101973.rs:+1:10: +1:16
           StorageLive(_12);                // scope 2 at $DIR/issue_101973.rs:7:12: 7:27
           StorageLive(_13);                // scope 2 at $DIR/issue_101973.rs:7:12: 7:20
-          _14 = CheckedShr(_5, const 0_i32); // scope 2 at $DIR/issue_101973.rs:7:12: 7:20
+          _14 = CheckedShr(_1, const 0_i32); // scope 2 at $DIR/issue_101973.rs:7:12: 7:20
           assert(!move (_14.1: bool), "attempt to shift right by `{}`, which would overflow", const 0_i32) -> bb3; // scope 2 at $DIR/issue_101973.rs:7:12: 7:20
       }
   
       bb1: {
           _8 = move (_10.0: u32);          // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
-          StorageDead(_9);                 // scope 0 at $DIR/issue_101973.rs:+1:44: +1:45
           _7 = BitAnd(move _8, const 15_u32); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:52
           StorageDead(_8);                 // scope 0 at $DIR/issue_101973.rs:+1:51: +1:52
           _11 = CheckedShl(_7, const 1_i32); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
       bb2: {
           _6 = move (_11.0: u32);          // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
           StorageDead(_7);                 // scope 0 at $DIR/issue_101973.rs:+1:56: +1:57
-          StorageLive(_15);                // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
-          _15 = _4;                        // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
-          StorageLive(_16);                // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
-          _16 = _6;                        // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
-          _3 = rotate_right::<u32>(move _15, move _16) -> bb4; // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
+          _3 = rotate_right::<u32>(_4, _6) -> bb4; // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
                                            // + literal: Const { ty: extern "rust-intrinsic" fn(u32, u32) -> u32 {rotate_right::<u32>}, val: Value(<ZST>) }
           StorageDead(_13);                // scope 2 at $DIR/issue_101973.rs:7:26: 7:27
           _4 = BitOr(const 0_u32, move _12); // scope 2 at $DIR/issue_101973.rs:7:5: 7:27
           StorageDead(_12);                // scope 2 at $DIR/issue_101973.rs:7:26: 7:27
-          StorageDead(_5);                 // scope 0 at $DIR/issue_101973.rs:+1:16: +1:17
           StorageLive(_6);                 // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
           StorageLive(_7);                 // scope 0 at $DIR/issue_101973.rs:+1:31: +1:52
           StorageLive(_8);                 // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
-          StorageLive(_9);                 // scope 0 at $DIR/issue_101973.rs:+1:33: +1:39
-          _9 = _1;                         // scope 0 at $DIR/issue_101973.rs:+1:33: +1:39
-          _10 = CheckedShr(_9, const 8_i32); // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
+          _10 = CheckedShr(_1, const 8_i32); // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
           assert(!move (_10.1: bool), "attempt to shift right by `{}`, which would overflow", const 8_i32) -> bb1; // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
       }
   
       bb4: {
-          StorageDead(_16);                // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
-          StorageDead(_15);                // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
-          StorageDead(_6);                 // scope 0 at $DIR/issue_101973.rs:+1:57: +1:58
-          StorageDead(_4);                 // scope 0 at $DIR/issue_101973.rs:+1:57: +1:58
           _2 = move _3 as i32 (IntToInt);  // scope 0 at $DIR/issue_101973.rs:+1:5: +1:65
           StorageDead(_3);                 // scope 0 at $DIR/issue_101973.rs:+1:64: +1:65
           _0 = move _2 as i64 (IntToInt);  // scope 0 at $DIR/issue_101973.rs:+1:5: +1:72
index c24543daeacb7939e50261e7f38a4ba7dab1e932..c14780052fb091f257fefbd178c0c05357f2c7c7 100644 (file)
   
       bb0: {
           StorageLive(_2);                 // scope 0 at $DIR/issue_76432.rs:+1:9: +1:10
-          StorageLive(_3);                 // scope 0 at $DIR/issue_76432.rs:+1:19: +1:29
           StorageLive(_4);                 // scope 0 at $DIR/issue_76432.rs:+1:19: +1:29
           StorageLive(_5);                 // scope 0 at $DIR/issue_76432.rs:+1:20: +1:29
-          StorageLive(_6);                 // scope 0 at $DIR/issue_76432.rs:+1:21: +1:22
-          _6 = _1;                         // scope 0 at $DIR/issue_76432.rs:+1:21: +1:22
-          StorageLive(_7);                 // scope 0 at $DIR/issue_76432.rs:+1:24: +1:25
-          _7 = _1;                         // scope 0 at $DIR/issue_76432.rs:+1:24: +1:25
-          StorageLive(_8);                 // scope 0 at $DIR/issue_76432.rs:+1:27: +1:28
-          _8 = _1;                         // scope 0 at $DIR/issue_76432.rs:+1:27: +1:28
-          _5 = [move _6, move _7, move _8]; // scope 0 at $DIR/issue_76432.rs:+1:20: +1:29
-          StorageDead(_8);                 // scope 0 at $DIR/issue_76432.rs:+1:28: +1:29
-          StorageDead(_7);                 // scope 0 at $DIR/issue_76432.rs:+1:28: +1:29
-          StorageDead(_6);                 // scope 0 at $DIR/issue_76432.rs:+1:28: +1:29
+          _5 = [_1, _1, _1];               // scope 0 at $DIR/issue_76432.rs:+1:20: +1:29
           _4 = &_5;                        // scope 0 at $DIR/issue_76432.rs:+1:19: +1:29
-          _3 = _4;                         // scope 0 at $DIR/issue_76432.rs:+1:19: +1:29
-          _2 = move _3 as &[T] (Pointer(Unsize)); // scope 0 at $DIR/issue_76432.rs:+1:19: +1:29
-          StorageDead(_3);                 // scope 0 at $DIR/issue_76432.rs:+1:28: +1:29
-          StorageDead(_4);                 // scope 0 at $DIR/issue_76432.rs:+1:29: +1:30
+          _2 = _4 as &[T] (Pointer(Unsize)); // scope 0 at $DIR/issue_76432.rs:+1:19: +1:29
           _9 = Len((*_2));                 // scope 1 at $DIR/issue_76432.rs:+3:9: +3:33
           _10 = const 3_usize;             // scope 1 at $DIR/issue_76432.rs:+3:9: +3:33
 -         _11 = Eq(move _9, const 3_usize); // scope 1 at $DIR/issue_76432.rs:+3:9: +3:33
index 701c2ad705af2997fdf4e501f706819260a5bd27..dee1d538395ef86b9b5ec4b86666ae6478b72943 100644 (file)
@@ -5,27 +5,23 @@ fn array_bound(_1: usize, _2: &[u8; N]) -> u8 {
     debug slice => _2;                   // in scope 0 at $DIR/lower_array_len_e2e.rs:+0:50: +0:55
     let mut _0: u8;                      // return place in scope 0 at $DIR/lower_array_len_e2e.rs:+0:70: +0:72
     let mut _3: bool;                    // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
-    let mut _4: usize;                   // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:13
-    let mut _5: usize;                   // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
-    let mut _6: usize;                   // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
-    let mut _7: bool;                    // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+    let mut _4: usize;                   // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
+    let mut _5: usize;                   // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+    let mut _6: bool;                    // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
 
     bb0: {
         StorageLive(_3);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
-        StorageLive(_4);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:13
-        _4 = _1;                         // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:13
-        StorageLive(_5);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
-        _5 = const N;                    // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
-        _3 = Lt(move _4, move _5);       // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
-        StorageDead(_5);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+1:26: +1:27
+        StorageLive(_4);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
+        _4 = const N;                    // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
+        _3 = Lt(_1, move _4);            // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
         StorageDead(_4);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+1:26: +1:27
         switchInt(move _3) -> [0: bb3, otherwise: bb1]; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
     }
 
     bb1: {
-        _6 = const N;                    // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
-        _7 = Lt(_1, _6);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
-        assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, _1) -> bb2; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+        _5 = const N;                    // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+        _6 = Lt(_1, _5);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+        assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _1) -> bb2; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
     }
 
     bb2: {
index 0440cfce2893f152437667e746632f89763ecb4b..e35fe758ab12ddea899bddedcba028e5e02fc4c3 100644 (file)
@@ -5,30 +5,26 @@ fn array_bound_mut(_1: usize, _2: &mut [u8; N]) -> u8 {
     debug slice => _2;                   // in scope 0 at $DIR/lower_array_len_e2e.rs:+0:54: +0:59
     let mut _0: u8;                      // return place in scope 0 at $DIR/lower_array_len_e2e.rs:+0:78: +0:80
     let mut _3: bool;                    // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
-    let mut _4: usize;                   // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:13
-    let mut _5: usize;                   // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
-    let mut _6: usize;                   // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
-    let mut _7: bool;                    // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
-    let _8: usize;                       // in scope 0 at $DIR/lower_array_len_e2e.rs:+4:15: +4:16
-    let mut _9: usize;                   // in scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17
-    let mut _10: bool;                   // in scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17
+    let mut _4: usize;                   // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
+    let mut _5: usize;                   // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+    let mut _6: bool;                    // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+    let _7: usize;                       // in scope 0 at $DIR/lower_array_len_e2e.rs:+4:15: +4:16
+    let mut _8: usize;                   // in scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17
+    let mut _9: bool;                    // in scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17
 
     bb0: {
         StorageLive(_3);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
-        StorageLive(_4);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:13
-        _4 = _1;                         // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:13
-        StorageLive(_5);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
-        _5 = const N;                    // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
-        _3 = Lt(move _4, move _5);       // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
-        StorageDead(_5);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+1:26: +1:27
+        StorageLive(_4);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
+        _4 = const N;                    // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
+        _3 = Lt(_1, move _4);            // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
         StorageDead(_4);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+1:26: +1:27
         switchInt(move _3) -> [0: bb3, otherwise: bb1]; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
     }
 
     bb1: {
-        _6 = const N;                    // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
-        _7 = Lt(_1, _6);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
-        assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, _1) -> bb2; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+        _5 = const N;                    // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+        _6 = Lt(_1, _5);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+        assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _1) -> bb2; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
     }
 
     bb2: {
@@ -37,16 +33,16 @@ fn array_bound_mut(_1: usize, _2: &mut [u8; N]) -> u8 {
     }
 
     bb3: {
-        StorageLive(_8);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+4:15: +4:16
-        _8 = const 0_usize;              // scope 0 at $DIR/lower_array_len_e2e.rs:+4:15: +4:16
-        _9 = const N;                    // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17
-        _10 = Lt(const 0_usize, _9);     // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17
-        assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, const 0_usize) -> bb4; // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17
+        StorageLive(_7);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+4:15: +4:16
+        _7 = const 0_usize;              // scope 0 at $DIR/lower_array_len_e2e.rs:+4:15: +4:16
+        _8 = const N;                    // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17
+        _9 = Lt(const 0_usize, _8);      // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17
+        assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, const 0_usize) -> bb4; // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17
     }
 
     bb4: {
-        (*_2)[_8] = const 42_u8;         // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:22
-        StorageDead(_8);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+4:22: +4:23
+        (*_2)[_7] = const 42_u8;         // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:22
+        StorageDead(_7);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+4:22: +4:23
         _0 = const 42_u8;                // scope 0 at $DIR/lower_array_len_e2e.rs:+6:9: +6:11
         goto -> bb5;                     // scope 0 at $DIR/lower_array_len_e2e.rs:+1:5: +7:6
     }
index 916f99049c60ab0161473913f89681a1ed0d88d7..760f48d956d6288b3d72ea8edc06ed83e0e3ed90 100644 (file)
@@ -37,7 +37,7 @@ fn ezmap(_1: Option<i32>) -> Option<i32> {
     bb3: {
         _5 = move ((_1 as Some).0: i32); // scope 1 at $DIR/simple_option_map_e2e.rs:7:14: 7:15
         StorageLive(_4);                 // scope 2 at $DIR/simple_option_map_e2e.rs:7:25: 7:29
-        _4 = Add(move _5, const 1_i32);  // scope 3 at $DIR/simple_option_map_e2e.rs:+1:16: +1:21
+        _4 = Add(_5, const 1_i32);       // scope 3 at $DIR/simple_option_map_e2e.rs:+1:16: +1:21
         Deinit(_0);                      // scope 2 at $DIR/simple_option_map_e2e.rs:7:20: 7:30
         ((_0 as Some).0: i32) = move _4; // scope 2 at $DIR/simple_option_map_e2e.rs:7:20: 7:30
         discriminant(_0) = 1;            // scope 2 at $DIR/simple_option_map_e2e.rs:7:20: 7:30
index 70bfbf1b3e366473e3dd9fed7c2e3c0500a84790..35ffc4963cb63b4f8d707e2d633ceca9a720548e 100644 (file)
       }
   
       bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/simplify_match.rs:+1:11: +1:31
           StorageLive(_2);                 // scope 0 at $DIR/simplify_match.rs:+1:17: +1:18
           _2 = const false;                // scope 0 at $DIR/simplify_match.rs:+1:21: +1:26
--         _1 = _2;                         // scope 1 at $DIR/simplify_match.rs:+1:28: +1:29
-+         _1 = const false;                // scope 1 at $DIR/simplify_match.rs:+1:28: +1:29
-          StorageDead(_2);                 // scope 0 at $DIR/simplify_match.rs:+1:30: +1:31
--         switchInt(_1) -> [0: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_match.rs:+1:5: +1:31
+-         switchInt(_2) -> [0: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_match.rs:+1:5: +1:31
 +         switchInt(const false) -> [0: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_match.rs:+1:5: +1:31
       }
   
@@ -32,7 +28,6 @@
       }
   
       bb3: {
-          StorageDead(_1);                 // scope 0 at $DIR/simplify_match.rs:+5:1: +5:2
           return;                          // scope 0 at $DIR/simplify_match.rs:+5:2: +5:2
       }
   }
diff --git a/tests/mir-opt/slice_filter.rs b/tests/mir-opt/slice_filter.rs
new file mode 100644 (file)
index 0000000..97c18af
--- /dev/null
@@ -0,0 +1,18 @@
+fn main() {
+    let input = vec![];
+    let _variant_a_result = variant_a(&input);
+    let _variant_b_result = variant_b(&input);
+}
+
+pub fn variant_a(input: &[(usize, usize, usize, usize)]) -> usize {
+    input.iter().filter(|(a, b, c, d)| a <= c && d <= b || c <= a && b <= d).count()
+}
+
+pub fn variant_b(input: &[(usize, usize, usize, usize)]) -> usize {
+    input.iter().filter(|&&(a, b, c, d)| a <= c && d <= b || c <= a && b <= d).count()
+}
+
+// EMIT_MIR slice_filter.variant_a-{closure#0}.CopyProp.diff
+// EMIT_MIR slice_filter.variant_a-{closure#0}.DestinationPropagation.diff
+// EMIT_MIR slice_filter.variant_b-{closure#0}.CopyProp.diff
+// EMIT_MIR slice_filter.variant_b-{closure#0}.DestinationPropagation.diff
diff --git a/tests/mir-opt/slice_filter.variant_a-{closure#0}.CopyProp.diff b/tests/mir-opt/slice_filter.variant_a-{closure#0}.CopyProp.diff
new file mode 100644 (file)
index 0000000..d1f6fd9
--- /dev/null
@@ -0,0 +1,279 @@
+- // MIR for `variant_a::{closure#0}` before CopyProp
++ // MIR for `variant_a::{closure#0}` after CopyProp
+  
+  fn variant_a::{closure#0}(_1: &mut [closure@$DIR/slice_filter.rs:8:25: 8:39], _2: &&(usize, usize, usize, usize)) -> bool {
+      let mut _0: bool;                    // return place in scope 0 at $DIR/slice_filter.rs:+0:40: +0:40
+      let _3: &usize;                      // in scope 0 at $DIR/slice_filter.rs:+0:27: +0:28
+      let _4: &usize;                      // in scope 0 at $DIR/slice_filter.rs:+0:30: +0:31
+      let _5: &usize;                      // in scope 0 at $DIR/slice_filter.rs:+0:33: +0:34
+      let _6: &usize;                      // in scope 0 at $DIR/slice_filter.rs:+0:36: +0:37
+      let mut _7: bool;                    // in scope 0 at $DIR/slice_filter.rs:+0:40: +0:56
+      let mut _8: bool;                    // in scope 0 at $DIR/slice_filter.rs:+0:40: +0:46
+      let mut _9: &&usize;                 // in scope 0 at $DIR/slice_filter.rs:+0:40: +0:41
+      let mut _10: &&usize;                // in scope 0 at $DIR/slice_filter.rs:+0:45: +0:46
+      let _11: &usize;                     // in scope 0 at $DIR/slice_filter.rs:+0:45: +0:46
+      let mut _12: bool;                   // in scope 0 at $DIR/slice_filter.rs:+0:50: +0:56
+      let mut _13: &&usize;                // in scope 0 at $DIR/slice_filter.rs:+0:50: +0:51
+      let mut _14: &&usize;                // in scope 0 at $DIR/slice_filter.rs:+0:55: +0:56
+      let _15: &usize;                     // in scope 0 at $DIR/slice_filter.rs:+0:55: +0:56
+      let mut _16: bool;                   // in scope 0 at $DIR/slice_filter.rs:+0:60: +0:76
+      let mut _17: bool;                   // in scope 0 at $DIR/slice_filter.rs:+0:60: +0:66
+      let mut _18: &&usize;                // in scope 0 at $DIR/slice_filter.rs:+0:60: +0:61
+      let mut _19: &&usize;                // in scope 0 at $DIR/slice_filter.rs:+0:65: +0:66
+      let _20: &usize;                     // in scope 0 at $DIR/slice_filter.rs:+0:65: +0:66
+      let mut _21: bool;                   // in scope 0 at $DIR/slice_filter.rs:+0:70: +0:76
+      let mut _22: &&usize;                // in scope 0 at $DIR/slice_filter.rs:+0:70: +0:71
+      let mut _23: &&usize;                // in scope 0 at $DIR/slice_filter.rs:+0:75: +0:76
+      let _24: &usize;                     // in scope 0 at $DIR/slice_filter.rs:+0:75: +0:76
+      let mut _25: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:38
+      let mut _26: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:38
+      let mut _27: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:38
+      let mut _28: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:38
+      scope 1 {
+          debug a => _3;                   // in scope 1 at $DIR/slice_filter.rs:+0:27: +0:28
+          debug b => _4;                   // in scope 1 at $DIR/slice_filter.rs:+0:30: +0:31
+          debug c => _5;                   // in scope 1 at $DIR/slice_filter.rs:+0:33: +0:34
+          debug d => _6;                   // in scope 1 at $DIR/slice_filter.rs:+0:36: +0:37
+          scope 2 (inlined cmp::impls::<impl PartialOrd for &usize>::le) { // at $DIR/slice_filter.rs:8:40: 8:46
+              debug self => _9;            // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              debug other => _10;          // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              let mut _29: &usize;         // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              let mut _30: &usize;         // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              let mut _31: &usize;         // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              let mut _32: &usize;         // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              scope 3 (inlined cmp::impls::<impl PartialOrd for usize>::le) { // at $SRC_DIR/core/src/cmp.rs:LL:COL
+-                 debug self => _29;       // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-                 debug other => _30;      // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
++                 debug self => _31;       // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
++                 debug other => _32;      // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+                  let mut _33: usize;      // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+                  let mut _34: usize;      // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              }
+          }
+          scope 4 (inlined cmp::impls::<impl PartialOrd for &usize>::le) { // at $DIR/slice_filter.rs:8:60: 8:66
+              debug self => _18;           // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              debug other => _19;          // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              let mut _35: &usize;         // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              let mut _36: &usize;         // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              let mut _37: &usize;         // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              let mut _38: &usize;         // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              scope 5 (inlined cmp::impls::<impl PartialOrd for usize>::le) { // at $SRC_DIR/core/src/cmp.rs:LL:COL
+-                 debug self => _35;       // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-                 debug other => _36;      // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
++                 debug self => _37;       // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
++                 debug other => _38;      // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+                  let mut _39: usize;      // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+                  let mut _40: usize;      // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              }
+          }
+          scope 6 (inlined cmp::impls::<impl PartialOrd for &usize>::le) { // at $DIR/slice_filter.rs:8:50: 8:56
+              debug self => _13;           // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              debug other => _14;          // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              let mut _41: &usize;         // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              let mut _42: &usize;         // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              let mut _43: &usize;         // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              let mut _44: &usize;         // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              scope 7 (inlined cmp::impls::<impl PartialOrd for usize>::le) { // at $SRC_DIR/core/src/cmp.rs:LL:COL
+-                 debug self => _41;       // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-                 debug other => _42;      // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
++                 debug self => _43;       // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
++                 debug other => _44;      // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+                  let mut _45: usize;      // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+                  let mut _46: usize;      // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              }
+          }
+          scope 8 (inlined cmp::impls::<impl PartialOrd for &usize>::le) { // at $DIR/slice_filter.rs:8:70: 8:76
+              debug self => _22;           // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              debug other => _23;          // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              let mut _47: &usize;         // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              let mut _48: &usize;         // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              let mut _49: &usize;         // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              let mut _50: &usize;         // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              scope 9 (inlined cmp::impls::<impl PartialOrd for usize>::le) { // at $SRC_DIR/core/src/cmp.rs:LL:COL
+-                 debug self => _47;       // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-                 debug other => _48;      // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
++                 debug self => _49;       // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
++                 debug other => _50;      // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+                  let mut _51: usize;      // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+                  let mut _52: usize;      // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              }
+          }
+      }
+  
+      bb0: {
+          StorageLive(_3);                 // scope 0 at $DIR/slice_filter.rs:+0:27: +0:28
+          _25 = deref_copy (*_2);          // scope 0 at $DIR/slice_filter.rs:+0:27: +0:28
+          _3 = &((*_25).0: usize);         // scope 0 at $DIR/slice_filter.rs:+0:27: +0:28
+          StorageLive(_4);                 // scope 0 at $DIR/slice_filter.rs:+0:30: +0:31
+          _26 = deref_copy (*_2);          // scope 0 at $DIR/slice_filter.rs:+0:30: +0:31
+          _4 = &((*_26).1: usize);         // scope 0 at $DIR/slice_filter.rs:+0:30: +0:31
+          StorageLive(_5);                 // scope 0 at $DIR/slice_filter.rs:+0:33: +0:34
+          _27 = deref_copy (*_2);          // scope 0 at $DIR/slice_filter.rs:+0:33: +0:34
+          _5 = &((*_27).2: usize);         // scope 0 at $DIR/slice_filter.rs:+0:33: +0:34
+          StorageLive(_6);                 // scope 0 at $DIR/slice_filter.rs:+0:36: +0:37
+          _28 = deref_copy (*_2);          // scope 0 at $DIR/slice_filter.rs:+0:36: +0:37
+          _6 = &((*_28).3: usize);         // scope 0 at $DIR/slice_filter.rs:+0:36: +0:37
+          StorageLive(_7);                 // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56
+          StorageLive(_8);                 // scope 1 at $DIR/slice_filter.rs:+0:40: +0:46
+          StorageLive(_9);                 // scope 1 at $DIR/slice_filter.rs:+0:40: +0:41
+          _9 = &_3;                        // scope 1 at $DIR/slice_filter.rs:+0:40: +0:41
+          StorageLive(_10);                // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46
+          StorageLive(_11);                // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46
+          _11 = _5;                        // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46
+          _10 = &_11;                      // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46
+-         StorageLive(_29);                // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _31 = deref_copy (*_9);          // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         _29 = _31;                       // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         StorageLive(_30);                // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _32 = deref_copy (*_10);         // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         _30 = _32;                       // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageLive(_33);                // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         _33 = (*_29);                    // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
++         _33 = (*_31);                    // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageLive(_34);                // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         _34 = (*_30);                    // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
++         _34 = (*_32);                    // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _8 = Le(move _33, move _34);     // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageDead(_34);                // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageDead(_33);                // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         StorageDead(_30);                // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         StorageDead(_29);                // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageDead(_11);                // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46
+          StorageDead(_10);                // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46
+          StorageDead(_9);                 // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46
+          switchInt(move _8) -> [0: bb4, otherwise: bb5]; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56
+      }
+  
+      bb1: {
+          _0 = const true;                 // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76
+          goto -> bb3;                     // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76
+      }
+  
+      bb2: {
+          StorageLive(_16);                // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76
+          StorageLive(_17);                // scope 1 at $DIR/slice_filter.rs:+0:60: +0:66
+          StorageLive(_18);                // scope 1 at $DIR/slice_filter.rs:+0:60: +0:61
+          _18 = &_5;                       // scope 1 at $DIR/slice_filter.rs:+0:60: +0:61
+          StorageLive(_19);                // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66
+          StorageLive(_20);                // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66
+          _20 = _3;                        // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66
+          _19 = &_20;                      // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66
+-         StorageLive(_35);                // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _37 = deref_copy (*_18);         // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         _35 = _37;                       // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         StorageLive(_36);                // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _38 = deref_copy (*_19);         // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         _36 = _38;                       // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageLive(_39);                // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         _39 = (*_35);                    // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
++         _39 = (*_37);                    // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageLive(_40);                // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         _40 = (*_36);                    // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
++         _40 = (*_38);                    // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _17 = Le(move _39, move _40);    // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageDead(_40);                // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageDead(_39);                // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         StorageDead(_36);                // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         StorageDead(_35);                // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageDead(_20);                // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66
+          StorageDead(_19);                // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66
+          StorageDead(_18);                // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66
+          switchInt(move _17) -> [0: bb6, otherwise: bb7]; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76
+      }
+  
+      bb3: {
+          StorageDead(_16);                // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+          StorageDead(_7);                 // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+-         StorageDead(_6);                 // scope 0 at $DIR/slice_filter.rs:+0:75: +0:76
+-         StorageDead(_5);                 // scope 0 at $DIR/slice_filter.rs:+0:75: +0:76
+-         StorageDead(_4);                 // scope 0 at $DIR/slice_filter.rs:+0:75: +0:76
+-         StorageDead(_3);                 // scope 0 at $DIR/slice_filter.rs:+0:75: +0:76
+          return;                          // scope 0 at $DIR/slice_filter.rs:+0:76: +0:76
+      }
+  
+      bb4: {
+          _7 = const false;                // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56
+          StorageDead(_12);                // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+          StorageDead(_8);                 // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+          goto -> bb2;                     // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56
+      }
+  
+      bb5: {
+          StorageLive(_12);                // scope 1 at $DIR/slice_filter.rs:+0:50: +0:56
+          StorageLive(_13);                // scope 1 at $DIR/slice_filter.rs:+0:50: +0:51
+          _13 = &_6;                       // scope 1 at $DIR/slice_filter.rs:+0:50: +0:51
+          StorageLive(_14);                // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+          StorageLive(_15);                // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+          _15 = _4;                        // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+          _14 = &_15;                      // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+-         StorageLive(_41);                // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _43 = deref_copy (*_13);         // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         _41 = _43;                       // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         StorageLive(_42);                // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _44 = deref_copy (*_14);         // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         _42 = _44;                       // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageLive(_45);                // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         _45 = (*_41);                    // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
++         _45 = (*_43);                    // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageLive(_46);                // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         _46 = (*_42);                    // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
++         _46 = (*_44);                    // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _12 = Le(move _45, move _46);    // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageDead(_46);                // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageDead(_45);                // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         StorageDead(_42);                // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         StorageDead(_41);                // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageDead(_15);                // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+          StorageDead(_14);                // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+          StorageDead(_13);                // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+          _7 = move _12;                   // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56
+          StorageDead(_12);                // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+          StorageDead(_8);                 // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+          switchInt(move _7) -> [0: bb2, otherwise: bb1]; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76
+      }
+  
+      bb6: {
+          _16 = const false;               // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76
+          goto -> bb8;                     // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76
+      }
+  
+      bb7: {
+          StorageLive(_21);                // scope 1 at $DIR/slice_filter.rs:+0:70: +0:76
+          StorageLive(_22);                // scope 1 at $DIR/slice_filter.rs:+0:70: +0:71
+          _22 = &_4;                       // scope 1 at $DIR/slice_filter.rs:+0:70: +0:71
+          StorageLive(_23);                // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+          StorageLive(_24);                // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+          _24 = _6;                        // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+          _23 = &_24;                      // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+-         StorageLive(_47);                // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _49 = deref_copy (*_22);         // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         _47 = _49;                       // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         StorageLive(_48);                // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _50 = deref_copy (*_23);         // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         _48 = _50;                       // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageLive(_51);                // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         _51 = (*_47);                    // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
++         _51 = (*_49);                    // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageLive(_52);                // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         _52 = (*_48);                    // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
++         _52 = (*_50);                    // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _21 = Le(move _51, move _52);    // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageDead(_52);                // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageDead(_51);                // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         StorageDead(_48);                // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         StorageDead(_47);                // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageDead(_24);                // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+          StorageDead(_23);                // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+          StorageDead(_22);                // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+          _16 = move _21;                  // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76
+          goto -> bb8;                     // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76
+      }
+  
+      bb8: {
+          StorageDead(_21);                // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+          StorageDead(_17);                // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+          _0 = move _16;                   // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76
+          goto -> bb3;                     // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76
+      }
+  }
+  
diff --git a/tests/mir-opt/slice_filter.variant_a-{closure#0}.DestinationPropagation.diff b/tests/mir-opt/slice_filter.variant_a-{closure#0}.DestinationPropagation.diff
new file mode 100644 (file)
index 0000000..259cd41
--- /dev/null
@@ -0,0 +1,241 @@
+- // MIR for `variant_a::{closure#0}` before DestinationPropagation
++ // MIR for `variant_a::{closure#0}` after DestinationPropagation
+  
+  fn variant_a::{closure#0}(_1: &mut [closure@$DIR/slice_filter.rs:8:25: 8:39], _2: &&(usize, usize, usize, usize)) -> bool {
+      let mut _0: bool;                    // return place in scope 0 at $DIR/slice_filter.rs:+0:40: +0:40
+      let _3: &usize;                      // in scope 0 at $DIR/slice_filter.rs:+0:27: +0:28
+      let _4: &usize;                      // in scope 0 at $DIR/slice_filter.rs:+0:30: +0:31
+      let _5: &usize;                      // in scope 0 at $DIR/slice_filter.rs:+0:33: +0:34
+      let _6: &usize;                      // in scope 0 at $DIR/slice_filter.rs:+0:36: +0:37
+      let mut _7: bool;                    // in scope 0 at $DIR/slice_filter.rs:+0:40: +0:56
+      let mut _8: bool;                    // in scope 0 at $DIR/slice_filter.rs:+0:40: +0:46
+      let mut _9: &&usize;                 // in scope 0 at $DIR/slice_filter.rs:+0:40: +0:41
+      let mut _10: &&usize;                // in scope 0 at $DIR/slice_filter.rs:+0:45: +0:46
+      let _11: &usize;                     // in scope 0 at $DIR/slice_filter.rs:+0:45: +0:46
+      let mut _12: bool;                   // in scope 0 at $DIR/slice_filter.rs:+0:50: +0:56
+      let mut _13: &&usize;                // in scope 0 at $DIR/slice_filter.rs:+0:50: +0:51
+      let mut _14: &&usize;                // in scope 0 at $DIR/slice_filter.rs:+0:55: +0:56
+      let _15: &usize;                     // in scope 0 at $DIR/slice_filter.rs:+0:55: +0:56
+      let mut _16: bool;                   // in scope 0 at $DIR/slice_filter.rs:+0:60: +0:76
+      let mut _17: bool;                   // in scope 0 at $DIR/slice_filter.rs:+0:60: +0:66
+      let mut _18: &&usize;                // in scope 0 at $DIR/slice_filter.rs:+0:60: +0:61
+      let mut _19: &&usize;                // in scope 0 at $DIR/slice_filter.rs:+0:65: +0:66
+      let _20: &usize;                     // in scope 0 at $DIR/slice_filter.rs:+0:65: +0:66
+      let mut _21: bool;                   // in scope 0 at $DIR/slice_filter.rs:+0:70: +0:76
+      let mut _22: &&usize;                // in scope 0 at $DIR/slice_filter.rs:+0:70: +0:71
+      let mut _23: &&usize;                // in scope 0 at $DIR/slice_filter.rs:+0:75: +0:76
+      let _24: &usize;                     // in scope 0 at $DIR/slice_filter.rs:+0:75: +0:76
+      let mut _25: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:38
+      let mut _26: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:38
+      let mut _27: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:38
+      let mut _28: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:38
+      scope 1 {
+          debug a => _3;                   // in scope 1 at $DIR/slice_filter.rs:+0:27: +0:28
+          debug b => _4;                   // in scope 1 at $DIR/slice_filter.rs:+0:30: +0:31
+          debug c => _5;                   // in scope 1 at $DIR/slice_filter.rs:+0:33: +0:34
+          debug d => _6;                   // in scope 1 at $DIR/slice_filter.rs:+0:36: +0:37
+          scope 2 (inlined cmp::impls::<impl PartialOrd for &usize>::le) { // at $DIR/slice_filter.rs:8:40: 8:46
+              debug self => _9;            // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              debug other => _10;          // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              let mut _29: &usize;         // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              let mut _30: &usize;         // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              scope 3 (inlined cmp::impls::<impl PartialOrd for usize>::le) { // at $SRC_DIR/core/src/cmp.rs:LL:COL
+                  debug self => _29;       // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+                  debug other => _30;      // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+                  let mut _31: usize;      // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+                  let mut _32: usize;      // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              }
+          }
+          scope 4 (inlined cmp::impls::<impl PartialOrd for &usize>::le) { // at $DIR/slice_filter.rs:8:60: 8:66
+              debug self => _18;           // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              debug other => _19;          // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              let mut _33: &usize;         // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              let mut _34: &usize;         // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              scope 5 (inlined cmp::impls::<impl PartialOrd for usize>::le) { // at $SRC_DIR/core/src/cmp.rs:LL:COL
+                  debug self => _33;       // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+                  debug other => _34;      // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+                  let mut _35: usize;      // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+                  let mut _36: usize;      // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              }
+          }
+          scope 6 (inlined cmp::impls::<impl PartialOrd for &usize>::le) { // at $DIR/slice_filter.rs:8:50: 8:56
+              debug self => _13;           // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              debug other => _14;          // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              let mut _37: &usize;         // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              let mut _38: &usize;         // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              scope 7 (inlined cmp::impls::<impl PartialOrd for usize>::le) { // at $SRC_DIR/core/src/cmp.rs:LL:COL
+                  debug self => _37;       // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+                  debug other => _38;      // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+                  let mut _39: usize;      // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+                  let mut _40: usize;      // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              }
+          }
+          scope 8 (inlined cmp::impls::<impl PartialOrd for &usize>::le) { // at $DIR/slice_filter.rs:8:70: 8:76
+              debug self => _22;           // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              debug other => _23;          // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              let mut _41: &usize;         // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              let mut _42: &usize;         // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              scope 9 (inlined cmp::impls::<impl PartialOrd for usize>::le) { // at $SRC_DIR/core/src/cmp.rs:LL:COL
+                  debug self => _41;       // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+                  debug other => _42;      // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+                  let mut _43: usize;      // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+                  let mut _44: usize;      // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              }
+          }
+      }
+  
+      bb0: {
+          StorageLive(_3);                 // scope 0 at $DIR/slice_filter.rs:+0:27: +0:28
+          _25 = deref_copy (*_2);          // scope 0 at $DIR/slice_filter.rs:+0:27: +0:28
+          _3 = &((*_25).0: usize);         // scope 0 at $DIR/slice_filter.rs:+0:27: +0:28
+          StorageLive(_4);                 // scope 0 at $DIR/slice_filter.rs:+0:30: +0:31
+          _26 = deref_copy (*_2);          // scope 0 at $DIR/slice_filter.rs:+0:30: +0:31
+          _4 = &((*_26).1: usize);         // scope 0 at $DIR/slice_filter.rs:+0:30: +0:31
+          StorageLive(_5);                 // scope 0 at $DIR/slice_filter.rs:+0:33: +0:34
+          _27 = deref_copy (*_2);          // scope 0 at $DIR/slice_filter.rs:+0:33: +0:34
+          _5 = &((*_27).2: usize);         // scope 0 at $DIR/slice_filter.rs:+0:33: +0:34
+          StorageLive(_6);                 // scope 0 at $DIR/slice_filter.rs:+0:36: +0:37
+          _28 = deref_copy (*_2);          // scope 0 at $DIR/slice_filter.rs:+0:36: +0:37
+          _6 = &((*_28).3: usize);         // scope 0 at $DIR/slice_filter.rs:+0:36: +0:37
+-         StorageLive(_7);                 // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56
++         nop;                             // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56
+          StorageLive(_8);                 // scope 1 at $DIR/slice_filter.rs:+0:40: +0:46
+          StorageLive(_9);                 // scope 1 at $DIR/slice_filter.rs:+0:40: +0:41
+          _9 = &_3;                        // scope 1 at $DIR/slice_filter.rs:+0:40: +0:41
+          StorageLive(_10);                // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46
+          StorageLive(_11);                // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46
+          _11 = _5;                        // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46
+          _10 = &_11;                      // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46
+          _29 = deref_copy (*_9);          // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _30 = deref_copy (*_10);         // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageLive(_31);                // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _31 = (*_29);                    // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageLive(_32);                // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _32 = (*_30);                    // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _8 = Le(move _31, move _32);     // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageDead(_32);                // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageDead(_31);                // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageDead(_11);                // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46
+          StorageDead(_10);                // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46
+          StorageDead(_9);                 // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46
+          switchInt(move _8) -> [0: bb4, otherwise: bb5]; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56
+      }
+  
+      bb1: {
+          _0 = const true;                 // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76
+          goto -> bb3;                     // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76
+      }
+  
+      bb2: {
+-         StorageLive(_16);                // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76
++         nop;                             // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76
+          StorageLive(_17);                // scope 1 at $DIR/slice_filter.rs:+0:60: +0:66
+          StorageLive(_18);                // scope 1 at $DIR/slice_filter.rs:+0:60: +0:61
+          _18 = &_5;                       // scope 1 at $DIR/slice_filter.rs:+0:60: +0:61
+          StorageLive(_19);                // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66
+          StorageLive(_20);                // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66
+          _20 = _3;                        // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66
+          _19 = &_20;                      // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66
+          _33 = deref_copy (*_18);         // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _34 = deref_copy (*_19);         // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageLive(_35);                // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _35 = (*_33);                    // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageLive(_36);                // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _36 = (*_34);                    // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _17 = Le(move _35, move _36);    // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageDead(_36);                // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageDead(_35);                // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageDead(_20);                // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66
+          StorageDead(_19);                // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66
+          StorageDead(_18);                // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66
+          switchInt(move _17) -> [0: bb6, otherwise: bb7]; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76
+      }
+  
+      bb3: {
+-         StorageDead(_16);                // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+-         StorageDead(_7);                 // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
++         nop;                             // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
++         nop;                             // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+          return;                          // scope 0 at $DIR/slice_filter.rs:+0:76: +0:76
+      }
+  
+      bb4: {
+-         StorageDead(_12);                // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
++         nop;                             // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+          StorageDead(_8);                 // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+          goto -> bb2;                     // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56
+      }
+  
+      bb5: {
+-         StorageLive(_12);                // scope 1 at $DIR/slice_filter.rs:+0:50: +0:56
++         nop;                             // scope 1 at $DIR/slice_filter.rs:+0:50: +0:56
+          StorageLive(_13);                // scope 1 at $DIR/slice_filter.rs:+0:50: +0:51
+          _13 = &_6;                       // scope 1 at $DIR/slice_filter.rs:+0:50: +0:51
+          StorageLive(_14);                // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+          StorageLive(_15);                // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+          _15 = _4;                        // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+          _14 = &_15;                      // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+          _37 = deref_copy (*_13);         // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _38 = deref_copy (*_14);         // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageLive(_39);                // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _39 = (*_37);                    // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageLive(_40);                // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _40 = (*_38);                    // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _12 = Le(move _39, move _40);    // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageDead(_40);                // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageDead(_39);                // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageDead(_15);                // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+          StorageDead(_14);                // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+          StorageDead(_13);                // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+-         _7 = move _12;                   // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56
+-         StorageDead(_12);                // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
++         nop;                             // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56
++         nop;                             // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+          StorageDead(_8);                 // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+-         switchInt(move _7) -> [0: bb2, otherwise: bb1]; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76
++         switchInt(move _12) -> [0: bb2, otherwise: bb1]; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76
+      }
+  
+      bb6: {
+-         _16 = const false;               // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76
++         _0 = const false;                // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76
+          goto -> bb8;                     // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76
+      }
+  
+      bb7: {
+-         StorageLive(_21);                // scope 1 at $DIR/slice_filter.rs:+0:70: +0:76
++         nop;                             // scope 1 at $DIR/slice_filter.rs:+0:70: +0:76
+          StorageLive(_22);                // scope 1 at $DIR/slice_filter.rs:+0:70: +0:71
+          _22 = &_4;                       // scope 1 at $DIR/slice_filter.rs:+0:70: +0:71
+          StorageLive(_23);                // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+          StorageLive(_24);                // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+          _24 = _6;                        // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+          _23 = &_24;                      // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+          _41 = deref_copy (*_22);         // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _42 = deref_copy (*_23);         // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageLive(_43);                // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _43 = (*_41);                    // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageLive(_44);                // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _44 = (*_42);                    // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         _21 = Le(move _43, move _44);    // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
++         _0 = Le(move _43, move _44);     // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageDead(_44);                // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageDead(_43);                // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageDead(_24);                // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+          StorageDead(_23);                // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+          StorageDead(_22);                // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+-         _16 = move _21;                  // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76
++         nop;                             // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76
+          goto -> bb8;                     // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76
+      }
+  
+      bb8: {
+-         StorageDead(_21);                // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
++         nop;                             // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+          StorageDead(_17);                // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+-         _0 = move _16;                   // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76
++         nop;                             // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76
+          goto -> bb3;                     // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76
+      }
+  }
+  
diff --git a/tests/mir-opt/slice_filter.variant_b-{closure#0}.CopyProp.diff b/tests/mir-opt/slice_filter.variant_b-{closure#0}.CopyProp.diff
new file mode 100644 (file)
index 0000000..c3b8e7d
--- /dev/null
@@ -0,0 +1,139 @@
+- // MIR for `variant_b::{closure#0}` before CopyProp
++ // MIR for `variant_b::{closure#0}` after CopyProp
+  
+  fn variant_b::{closure#0}(_1: &mut [closure@$DIR/slice_filter.rs:12:25: 12:41], _2: &&(usize, usize, usize, usize)) -> bool {
+      let mut _0: bool;                    // return place in scope 0 at $DIR/slice_filter.rs:+0:42: +0:42
+      let _3: usize;                       // in scope 0 at $DIR/slice_filter.rs:+0:29: +0:30
+      let _4: usize;                       // in scope 0 at $DIR/slice_filter.rs:+0:32: +0:33
+      let _5: usize;                       // in scope 0 at $DIR/slice_filter.rs:+0:35: +0:36
+      let _6: usize;                       // in scope 0 at $DIR/slice_filter.rs:+0:38: +0:39
+      let mut _7: bool;                    // in scope 0 at $DIR/slice_filter.rs:+0:42: +0:58
+      let mut _8: bool;                    // in scope 0 at $DIR/slice_filter.rs:+0:42: +0:48
+      let mut _9: usize;                   // in scope 0 at $DIR/slice_filter.rs:+0:42: +0:43
+      let mut _10: usize;                  // in scope 0 at $DIR/slice_filter.rs:+0:47: +0:48
+      let mut _11: bool;                   // in scope 0 at $DIR/slice_filter.rs:+0:52: +0:58
+      let mut _12: usize;                  // in scope 0 at $DIR/slice_filter.rs:+0:52: +0:53
+      let mut _13: usize;                  // in scope 0 at $DIR/slice_filter.rs:+0:57: +0:58
+      let mut _14: bool;                   // in scope 0 at $DIR/slice_filter.rs:+0:62: +0:78
+      let mut _15: bool;                   // in scope 0 at $DIR/slice_filter.rs:+0:62: +0:68
+      let mut _16: usize;                  // in scope 0 at $DIR/slice_filter.rs:+0:62: +0:63
+      let mut _17: usize;                  // in scope 0 at $DIR/slice_filter.rs:+0:67: +0:68
+      let mut _18: bool;                   // in scope 0 at $DIR/slice_filter.rs:+0:72: +0:78
+      let mut _19: usize;                  // in scope 0 at $DIR/slice_filter.rs:+0:72: +0:73
+      let mut _20: usize;                  // in scope 0 at $DIR/slice_filter.rs:+0:77: +0:78
+      let mut _21: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:40
+      let mut _22: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:40
+      let mut _23: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:40
+      let mut _24: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:40
+      scope 1 {
+          debug a => _3;                   // in scope 1 at $DIR/slice_filter.rs:+0:29: +0:30
+          debug b => _4;                   // in scope 1 at $DIR/slice_filter.rs:+0:32: +0:33
+          debug c => _5;                   // in scope 1 at $DIR/slice_filter.rs:+0:35: +0:36
+          debug d => _6;                   // in scope 1 at $DIR/slice_filter.rs:+0:38: +0:39
+      }
+  
+      bb0: {
+          StorageLive(_3);                 // scope 0 at $DIR/slice_filter.rs:+0:29: +0:30
+          _21 = deref_copy (*_2);          // scope 0 at $DIR/slice_filter.rs:+0:29: +0:30
+          _3 = ((*_21).0: usize);          // scope 0 at $DIR/slice_filter.rs:+0:29: +0:30
+          StorageLive(_4);                 // scope 0 at $DIR/slice_filter.rs:+0:32: +0:33
+          _22 = deref_copy (*_2);          // scope 0 at $DIR/slice_filter.rs:+0:32: +0:33
+          _4 = ((*_22).1: usize);          // scope 0 at $DIR/slice_filter.rs:+0:32: +0:33
+          StorageLive(_5);                 // scope 0 at $DIR/slice_filter.rs:+0:35: +0:36
+          _23 = deref_copy (*_2);          // scope 0 at $DIR/slice_filter.rs:+0:35: +0:36
+          _5 = ((*_23).2: usize);          // scope 0 at $DIR/slice_filter.rs:+0:35: +0:36
+          StorageLive(_6);                 // scope 0 at $DIR/slice_filter.rs:+0:38: +0:39
+          _24 = deref_copy (*_2);          // scope 0 at $DIR/slice_filter.rs:+0:38: +0:39
+          _6 = ((*_24).3: usize);          // scope 0 at $DIR/slice_filter.rs:+0:38: +0:39
+          StorageLive(_7);                 // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58
+          StorageLive(_8);                 // scope 1 at $DIR/slice_filter.rs:+0:42: +0:48
+-         StorageLive(_9);                 // scope 1 at $DIR/slice_filter.rs:+0:42: +0:43
+-         _9 = _3;                         // scope 1 at $DIR/slice_filter.rs:+0:42: +0:43
+-         StorageLive(_10);                // scope 1 at $DIR/slice_filter.rs:+0:47: +0:48
+-         _10 = _5;                        // scope 1 at $DIR/slice_filter.rs:+0:47: +0:48
+-         _8 = Le(move _9, move _10);      // scope 1 at $DIR/slice_filter.rs:+0:42: +0:48
+-         StorageDead(_10);                // scope 1 at $DIR/slice_filter.rs:+0:47: +0:48
+-         StorageDead(_9);                 // scope 1 at $DIR/slice_filter.rs:+0:47: +0:48
++         _8 = Le(_3, _5);                 // scope 1 at $DIR/slice_filter.rs:+0:42: +0:48
+          switchInt(move _8) -> [0: bb4, otherwise: bb5]; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58
+      }
+  
+      bb1: {
+          _0 = const true;                 // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78
+          goto -> bb3;                     // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78
+      }
+  
+      bb2: {
+          StorageLive(_14);                // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78
+          StorageLive(_15);                // scope 1 at $DIR/slice_filter.rs:+0:62: +0:68
+-         StorageLive(_16);                // scope 1 at $DIR/slice_filter.rs:+0:62: +0:63
+-         _16 = _5;                        // scope 1 at $DIR/slice_filter.rs:+0:62: +0:63
+-         StorageLive(_17);                // scope 1 at $DIR/slice_filter.rs:+0:67: +0:68
+-         _17 = _3;                        // scope 1 at $DIR/slice_filter.rs:+0:67: +0:68
+-         _15 = Le(move _16, move _17);    // scope 1 at $DIR/slice_filter.rs:+0:62: +0:68
+-         StorageDead(_17);                // scope 1 at $DIR/slice_filter.rs:+0:67: +0:68
+-         StorageDead(_16);                // scope 1 at $DIR/slice_filter.rs:+0:67: +0:68
++         _15 = Le(_5, _3);                // scope 1 at $DIR/slice_filter.rs:+0:62: +0:68
+          switchInt(move _15) -> [0: bb6, otherwise: bb7]; // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78
+      }
+  
+      bb3: {
+          StorageDead(_14);                // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78
+          StorageDead(_7);                 // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78
+-         StorageDead(_6);                 // scope 0 at $DIR/slice_filter.rs:+0:77: +0:78
+-         StorageDead(_5);                 // scope 0 at $DIR/slice_filter.rs:+0:77: +0:78
+-         StorageDead(_4);                 // scope 0 at $DIR/slice_filter.rs:+0:77: +0:78
+-         StorageDead(_3);                 // scope 0 at $DIR/slice_filter.rs:+0:77: +0:78
+          return;                          // scope 0 at $DIR/slice_filter.rs:+0:78: +0:78
+      }
+  
+      bb4: {
+          _7 = const false;                // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58
+          StorageDead(_11);                // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58
+          StorageDead(_8);                 // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58
+          goto -> bb2;                     // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58
+      }
+  
+      bb5: {
+          StorageLive(_11);                // scope 1 at $DIR/slice_filter.rs:+0:52: +0:58
+-         StorageLive(_12);                // scope 1 at $DIR/slice_filter.rs:+0:52: +0:53
+-         _12 = _6;                        // scope 1 at $DIR/slice_filter.rs:+0:52: +0:53
+-         StorageLive(_13);                // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58
+-         _13 = _4;                        // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58
+-         _11 = Le(move _12, move _13);    // scope 1 at $DIR/slice_filter.rs:+0:52: +0:58
+-         StorageDead(_13);                // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58
+-         StorageDead(_12);                // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58
++         _11 = Le(_6, _4);                // scope 1 at $DIR/slice_filter.rs:+0:52: +0:58
+          _7 = move _11;                   // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58
+          StorageDead(_11);                // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58
+          StorageDead(_8);                 // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58
+          switchInt(move _7) -> [0: bb2, otherwise: bb1]; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78
+      }
+  
+      bb6: {
+          _14 = const false;               // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78
+          goto -> bb8;                     // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78
+      }
+  
+      bb7: {
+          StorageLive(_18);                // scope 1 at $DIR/slice_filter.rs:+0:72: +0:78
+-         StorageLive(_19);                // scope 1 at $DIR/slice_filter.rs:+0:72: +0:73
+-         _19 = _4;                        // scope 1 at $DIR/slice_filter.rs:+0:72: +0:73
+-         StorageLive(_20);                // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78
+-         _20 = _6;                        // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78
+-         _18 = Le(move _19, move _20);    // scope 1 at $DIR/slice_filter.rs:+0:72: +0:78
+-         StorageDead(_20);                // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78
+-         StorageDead(_19);                // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78
++         _18 = Le(_4, _6);                // scope 1 at $DIR/slice_filter.rs:+0:72: +0:78
+          _14 = move _18;                  // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78
+          goto -> bb8;                     // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78
+      }
+  
+      bb8: {
+          StorageDead(_18);                // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78
+          StorageDead(_15);                // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78
+          _0 = move _14;                   // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78
+          goto -> bb3;                     // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78
+      }
+  }
+  
diff --git a/tests/mir-opt/slice_filter.variant_b-{closure#0}.DestinationPropagation.diff b/tests/mir-opt/slice_filter.variant_b-{closure#0}.DestinationPropagation.diff
new file mode 100644 (file)
index 0000000..a43e84d
--- /dev/null
@@ -0,0 +1,113 @@
+- // MIR for `variant_b::{closure#0}` before DestinationPropagation
++ // MIR for `variant_b::{closure#0}` after DestinationPropagation
+  
+  fn variant_b::{closure#0}(_1: &mut [closure@$DIR/slice_filter.rs:12:25: 12:41], _2: &&(usize, usize, usize, usize)) -> bool {
+      let mut _0: bool;                    // return place in scope 0 at $DIR/slice_filter.rs:+0:42: +0:42
+      let _3: usize;                       // in scope 0 at $DIR/slice_filter.rs:+0:29: +0:30
+      let _4: usize;                       // in scope 0 at $DIR/slice_filter.rs:+0:32: +0:33
+      let _5: usize;                       // in scope 0 at $DIR/slice_filter.rs:+0:35: +0:36
+      let _6: usize;                       // in scope 0 at $DIR/slice_filter.rs:+0:38: +0:39
+      let mut _7: bool;                    // in scope 0 at $DIR/slice_filter.rs:+0:42: +0:58
+      let mut _8: bool;                    // in scope 0 at $DIR/slice_filter.rs:+0:42: +0:48
+      let mut _9: bool;                    // in scope 0 at $DIR/slice_filter.rs:+0:52: +0:58
+      let mut _10: bool;                   // in scope 0 at $DIR/slice_filter.rs:+0:62: +0:78
+      let mut _11: bool;                   // in scope 0 at $DIR/slice_filter.rs:+0:62: +0:68
+      let mut _12: bool;                   // in scope 0 at $DIR/slice_filter.rs:+0:72: +0:78
+      let mut _13: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:40
+      let mut _14: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:40
+      let mut _15: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:40
+      let mut _16: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:40
+      scope 1 {
+          debug a => _3;                   // in scope 1 at $DIR/slice_filter.rs:+0:29: +0:30
+          debug b => _4;                   // in scope 1 at $DIR/slice_filter.rs:+0:32: +0:33
+          debug c => _5;                   // in scope 1 at $DIR/slice_filter.rs:+0:35: +0:36
+          debug d => _6;                   // in scope 1 at $DIR/slice_filter.rs:+0:38: +0:39
+      }
+  
+      bb0: {
+          StorageLive(_3);                 // scope 0 at $DIR/slice_filter.rs:+0:29: +0:30
+          _13 = deref_copy (*_2);          // scope 0 at $DIR/slice_filter.rs:+0:29: +0:30
+          _3 = ((*_13).0: usize);          // scope 0 at $DIR/slice_filter.rs:+0:29: +0:30
+          StorageLive(_4);                 // scope 0 at $DIR/slice_filter.rs:+0:32: +0:33
+          _14 = deref_copy (*_2);          // scope 0 at $DIR/slice_filter.rs:+0:32: +0:33
+          _4 = ((*_14).1: usize);          // scope 0 at $DIR/slice_filter.rs:+0:32: +0:33
+          StorageLive(_5);                 // scope 0 at $DIR/slice_filter.rs:+0:35: +0:36
+          _15 = deref_copy (*_2);          // scope 0 at $DIR/slice_filter.rs:+0:35: +0:36
+          _5 = ((*_15).2: usize);          // scope 0 at $DIR/slice_filter.rs:+0:35: +0:36
+          StorageLive(_6);                 // scope 0 at $DIR/slice_filter.rs:+0:38: +0:39
+          _16 = deref_copy (*_2);          // scope 0 at $DIR/slice_filter.rs:+0:38: +0:39
+          _6 = ((*_16).3: usize);          // scope 0 at $DIR/slice_filter.rs:+0:38: +0:39
+-         StorageLive(_7);                 // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58
++         nop;                             // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58
+          StorageLive(_8);                 // scope 1 at $DIR/slice_filter.rs:+0:42: +0:48
+          _8 = Le(_3, _5);                 // scope 1 at $DIR/slice_filter.rs:+0:42: +0:48
+          switchInt(move _8) -> [0: bb4, otherwise: bb5]; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58
+      }
+  
+      bb1: {
+          _0 = const true;                 // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78
+          goto -> bb3;                     // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78
+      }
+  
+      bb2: {
+-         StorageLive(_10);                // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78
++         nop;                             // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78
+          StorageLive(_11);                // scope 1 at $DIR/slice_filter.rs:+0:62: +0:68
+          _11 = Le(_5, _3);                // scope 1 at $DIR/slice_filter.rs:+0:62: +0:68
+          switchInt(move _11) -> [0: bb6, otherwise: bb7]; // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78
+      }
+  
+      bb3: {
+-         StorageDead(_10);                // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78
+-         StorageDead(_7);                 // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78
++         nop;                             // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78
++         nop;                             // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78
+          return;                          // scope 0 at $DIR/slice_filter.rs:+0:78: +0:78
+      }
+  
+      bb4: {
+-         StorageDead(_9);                 // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58
++         nop;                             // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58
+          StorageDead(_8);                 // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58
+          goto -> bb2;                     // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58
+      }
+  
+      bb5: {
+-         StorageLive(_9);                 // scope 1 at $DIR/slice_filter.rs:+0:52: +0:58
++         nop;                             // scope 1 at $DIR/slice_filter.rs:+0:52: +0:58
+          _9 = Le(_6, _4);                 // scope 1 at $DIR/slice_filter.rs:+0:52: +0:58
+-         _7 = move _9;                    // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58
+-         StorageDead(_9);                 // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58
++         nop;                             // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58
++         nop;                             // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58
+          StorageDead(_8);                 // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58
+-         switchInt(move _7) -> [0: bb2, otherwise: bb1]; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78
++         switchInt(move _9) -> [0: bb2, otherwise: bb1]; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78
+      }
+  
+      bb6: {
+-         _10 = const false;               // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78
++         _0 = const false;                // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78
+          goto -> bb8;                     // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78
+      }
+  
+      bb7: {
+-         StorageLive(_12);                // scope 1 at $DIR/slice_filter.rs:+0:72: +0:78
+-         _12 = Le(_4, _6);                // scope 1 at $DIR/slice_filter.rs:+0:72: +0:78
+-         _10 = move _12;                  // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78
++         nop;                             // scope 1 at $DIR/slice_filter.rs:+0:72: +0:78
++         _0 = Le(_4, _6);                 // scope 1 at $DIR/slice_filter.rs:+0:72: +0:78
++         nop;                             // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78
+          goto -> bb8;                     // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78
+      }
+  
+      bb8: {
+-         StorageDead(_12);                // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78
++         nop;                             // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78
+          StorageDead(_11);                // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78
+-         _0 = move _10;                   // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78
++         nop;                             // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78
+          goto -> bb3;                     // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78
+      }
+  }
+  
index b254bfeb7c992500212de9570d51fd6ae98b8dbc..7c67d2abcf7c37ccf1e0997d8550779a58c4d52f 100644 (file)
@@ -5,11 +5,11 @@ fn new(_1: Result<T, E>) -> Result<T, E> {
     let mut _0: std::result::Result<T, E>; // return place in scope 0 at $DIR/try_identity_e2e.rs:+0:34: +0:46
     let mut _2: std::ops::ControlFlow<E, T>; // in scope 0 at $DIR/try_identity_e2e.rs:+2:15: +7:10
     let mut _3: isize;                   // in scope 0 at $DIR/try_identity_e2e.rs:+4:17: +4:22
-    let mut _4: T;                       // in scope 0 at $DIR/try_identity_e2e.rs:+4:48: +4:49
-    let mut _5: E;                       // in scope 0 at $DIR/try_identity_e2e.rs:+5:46: +5:47
+    let _4: T;                           // in scope 0 at $DIR/try_identity_e2e.rs:+4:20: +4:21
+    let _5: E;                           // in scope 0 at $DIR/try_identity_e2e.rs:+5:21: +5:22
     let mut _6: isize;                   // in scope 0 at $DIR/try_identity_e2e.rs:+8:13: +8:37
     let _7: T;                           // in scope 0 at $DIR/try_identity_e2e.rs:+8:35: +8:36
-    let mut _8: E;                       // in scope 0 at $DIR/try_identity_e2e.rs:+9:49: +9:50
+    let _8: E;                           // in scope 0 at $DIR/try_identity_e2e.rs:+9:32: +9:33
     scope 1 {
         debug v => _4;                   // in scope 1 at $DIR/try_identity_e2e.rs:+4:20: +4:21
     }
@@ -30,6 +30,7 @@ fn new(_1: Result<T, E>) -> Result<T, E> {
     }
 
     bb1: {
+        StorageLive(_5);                 // scope 0 at $DIR/try_identity_e2e.rs:+5:21: +5:22
         _5 = move ((_1 as Err).0: E);    // scope 0 at $DIR/try_identity_e2e.rs:+5:21: +5:22
         Deinit(_2);                      // scope 2 at $DIR/try_identity_e2e.rs:+5:27: +5:48
         ((_2 as Break).0: E) = move _5;  // scope 2 at $DIR/try_identity_e2e.rs:+5:27: +5:48
@@ -39,6 +40,7 @@ fn new(_1: Result<T, E>) -> Result<T, E> {
     }
 
     bb2: {
+        StorageLive(_4);                 // scope 0 at $DIR/try_identity_e2e.rs:+4:20: +4:21
         _4 = move ((_1 as Ok).0: T);     // scope 0 at $DIR/try_identity_e2e.rs:+4:20: +4:21
         Deinit(_2);                      // scope 1 at $DIR/try_identity_e2e.rs:+4:26: +4:50
         ((_2 as Continue).0: T) = move _4; // scope 1 at $DIR/try_identity_e2e.rs:+4:26: +4:50
@@ -48,6 +50,7 @@ fn new(_1: Result<T, E>) -> Result<T, E> {
     }
 
     bb3: {
+        StorageLive(_8);                 // scope 0 at $DIR/try_identity_e2e.rs:+9:32: +9:33
         _8 = move ((_2 as Break).0: E);  // scope 0 at $DIR/try_identity_e2e.rs:+9:32: +9:33
         Deinit(_0);                      // scope 4 at $DIR/try_identity_e2e.rs:+9:45: +9:51
         ((_0 as Err).0: E) = move _8;    // scope 4 at $DIR/try_identity_e2e.rs:+9:45: +9:51
@@ -61,6 +64,7 @@ fn new(_1: Result<T, E>) -> Result<T, E> {
     }
 
     bb5: {
+        StorageLive(_7);                 // scope 0 at $DIR/try_identity_e2e.rs:+8:35: +8:36
         _7 = move ((_2 as Continue).0: T); // scope 0 at $DIR/try_identity_e2e.rs:+8:35: +8:36
         Deinit(_0);                      // scope 0 at $DIR/try_identity_e2e.rs:+1:5: +11:6
         ((_0 as Ok).0: T) = move _7;     // scope 0 at $DIR/try_identity_e2e.rs:+1:5: +11:6
index cdbc0681cb8a363ae2acadeeb236c7718ad3c00a..4a838e140262e76e51434fcb2f51f5bf4a743ea1 100644 (file)
@@ -5,7 +5,7 @@ fn old(_1: Result<T, E>) -> Result<T, E> {
     let mut _0: std::result::Result<T, E>; // return place in scope 0 at $DIR/try_identity_e2e.rs:+0:34: +0:46
     let mut _2: isize;                   // in scope 0 at $DIR/try_identity_e2e.rs:+3:13: +3:18
     let _3: T;                           // in scope 0 at $DIR/try_identity_e2e.rs:+3:16: +3:17
-    let mut _4: E;                       // in scope 0 at $DIR/try_identity_e2e.rs:+4:34: +4:35
+    let _4: E;                           // in scope 0 at $DIR/try_identity_e2e.rs:+4:17: +4:18
     scope 1 {
         debug v => _3;                   // in scope 1 at $DIR/try_identity_e2e.rs:+3:16: +3:17
     }
@@ -19,6 +19,7 @@ fn old(_1: Result<T, E>) -> Result<T, E> {
     }
 
     bb1: {
+        StorageLive(_4);                 // scope 0 at $DIR/try_identity_e2e.rs:+4:17: +4:18
         _4 = move ((_1 as Err).0: E);    // scope 0 at $DIR/try_identity_e2e.rs:+4:17: +4:18
         Deinit(_0);                      // scope 2 at $DIR/try_identity_e2e.rs:+4:30: +4:36
         ((_0 as Err).0: E) = move _4;    // scope 2 at $DIR/try_identity_e2e.rs:+4:30: +4:36
@@ -31,6 +32,7 @@ fn old(_1: Result<T, E>) -> Result<T, E> {
     }
 
     bb3: {
+        StorageLive(_3);                 // scope 0 at $DIR/try_identity_e2e.rs:+3:16: +3:17
         _3 = move ((_1 as Ok).0: T);     // scope 0 at $DIR/try_identity_e2e.rs:+3:16: +3:17
         Deinit(_0);                      // scope 0 at $DIR/try_identity_e2e.rs:+1:5: +6:6
         ((_0 as Ok).0: T) = move _3;     // scope 0 at $DIR/try_identity_e2e.rs:+1:5: +6:6
index b95d91b13dd7976c646481fc8425b4754b874095..318119bd477c1572cb3e155597251d5723ffa9b8 100644 (file)
@@ -4,9 +4,7 @@ fn while_loop(_1: bool) -> () {
     debug c => _1;                       // in scope 0 at $DIR/while_storage.rs:+0:15: +0:16
     let mut _0: ();                      // return place in scope 0 at $DIR/while_storage.rs:+0:24: +0:24
     let mut _2: bool;                    // in scope 0 at $DIR/while_storage.rs:+1:11: +1:22
-    let mut _3: bool;                    // in scope 0 at $DIR/while_storage.rs:+1:20: +1:21
-    let mut _4: bool;                    // in scope 0 at $DIR/while_storage.rs:+2:12: +2:23
-    let mut _5: bool;                    // in scope 0 at $DIR/while_storage.rs:+2:21: +2:22
+    let mut _3: bool;                    // in scope 0 at $DIR/while_storage.rs:+2:12: +2:23
 
     bb0: {
         goto -> bb1;                     // scope 0 at $DIR/while_storage.rs:+1:5: +5:6
@@ -14,41 +12,35 @@ fn while_loop(_1: bool) -> () {
 
     bb1: {
         StorageLive(_2);                 // scope 0 at $DIR/while_storage.rs:+1:11: +1:22
-        StorageLive(_3);                 // scope 0 at $DIR/while_storage.rs:+1:20: +1:21
-        _3 = _1;                         // scope 0 at $DIR/while_storage.rs:+1:20: +1:21
-        _2 = get_bool(move _3) -> bb2;   // scope 0 at $DIR/while_storage.rs:+1:11: +1:22
+        _2 = get_bool(_1) -> bb2;        // scope 0 at $DIR/while_storage.rs:+1:11: +1:22
                                          // mir::Constant
                                          // + span: $DIR/while_storage.rs:10:11: 10:19
                                          // + literal: Const { ty: fn(bool) -> bool {get_bool}, val: Value(<ZST>) }
     }
 
     bb2: {
-        StorageDead(_3);                 // scope 0 at $DIR/while_storage.rs:+1:21: +1:22
         switchInt(move _2) -> [0: bb7, otherwise: bb3]; // scope 0 at $DIR/while_storage.rs:+1:11: +1:22
     }
 
     bb3: {
-        StorageLive(_4);                 // scope 0 at $DIR/while_storage.rs:+2:12: +2:23
-        StorageLive(_5);                 // scope 0 at $DIR/while_storage.rs:+2:21: +2:22
-        _5 = _1;                         // scope 0 at $DIR/while_storage.rs:+2:21: +2:22
-        _4 = get_bool(move _5) -> bb4;   // scope 0 at $DIR/while_storage.rs:+2:12: +2:23
+        StorageLive(_3);                 // scope 0 at $DIR/while_storage.rs:+2:12: +2:23
+        _3 = get_bool(_1) -> bb4;        // scope 0 at $DIR/while_storage.rs:+2:12: +2:23
                                          // mir::Constant
                                          // + span: $DIR/while_storage.rs:11:12: 11:20
                                          // + literal: Const { ty: fn(bool) -> bool {get_bool}, val: Value(<ZST>) }
     }
 
     bb4: {
-        StorageDead(_5);                 // scope 0 at $DIR/while_storage.rs:+2:22: +2:23
-        switchInt(move _4) -> [0: bb6, otherwise: bb5]; // scope 0 at $DIR/while_storage.rs:+2:12: +2:23
+        switchInt(move _3) -> [0: bb6, otherwise: bb5]; // scope 0 at $DIR/while_storage.rs:+2:12: +2:23
     }
 
     bb5: {
-        StorageDead(_4);                 // scope 0 at $DIR/while_storage.rs:+4:9: +4:10
+        StorageDead(_3);                 // scope 0 at $DIR/while_storage.rs:+4:9: +4:10
         goto -> bb7;                     // scope 0 at no-location
     }
 
     bb6: {
-        StorageDead(_4);                 // scope 0 at $DIR/while_storage.rs:+4:9: +4:10
+        StorageDead(_3);                 // scope 0 at $DIR/while_storage.rs:+4:9: +4:10
         StorageDead(_2);                 // scope 0 at $DIR/while_storage.rs:+5:5: +5:6
         goto -> bb1;                     // scope 0 at $DIR/while_storage.rs:+1:5: +5:6
     }
index 44d21625a2d108a2e14e966d2e14328215adfa7b..e0fa1fe28246e7be95de552a3642e0666adb8d38 100644 (file)
@@ -34,10 +34,11 @@ fn bar() ({
                     ((::alloc::fmt::format as
                             for<'a> fn(Arguments<'a>) -> String {format})(((<#[lang = "format_arguments"]>::new_v1
                                 as
-                                fn(&[&'static str], &[ArgumentV1<'_>]) -> Arguments<'_> {Arguments::<'_>::new_v1})((&([("test"
+                                fn(&[&'static str], &[core::fmt::ArgumentV1<'_>]) -> Arguments<'_> {Arguments::<'_>::new_v1})((&([("test"
                                             as &str)] as [&str; 1]) as &[&str; 1]),
-                            (&([] as [ArgumentV1<'_>; 0]) as &[ArgumentV1<'_>; 0])) as
-                            Arguments<'_>)) as String);
+                            (&([] as [core::fmt::ArgumentV1<'_>; 0]) as
+                                &[core::fmt::ArgumentV1<'_>; 0])) as Arguments<'_>)) as
+                        String);
                 (res as String)
             } as String);
     } as ())
index 7c78d7783e0b6dbe9e29c95f2c562299c7489c78..e8a1121bfcd975c1023de411450ab6f200e0bc40 100644 (file)
@@ -5,7 +5,12 @@ include ../../run-make-fulldeps/tools.mk
 
 # We're using the llvm-nm instead of the system nm to ensure it is compatible
 # with the LLVM bitcode generated by rustc.
+# Except on Windows where piping/IO redirection under MSYS2 is wonky with llvm-nm.
+ifndef IS_WINDOWS
 NM = "$(LLVM_BIN_DIR)"/llvm-nm
+else
+NM = nm
+endif
 
 all: $(call NATIVE_STATICLIB,native-staticlib)
        # Build a staticlib and a rlib, the `native_func` symbol will be bundled into them
index 9e603f95835986a8a9a9641145e2a56b1ce0acf3..722a49b02cb3bc499d8da6512e3f7a1a7a91babb 100644 (file)
@@ -4,15 +4,19 @@
 
 include ../../run-make-fulldeps/tools.mk
 
+# We'd be using the llvm-objdump instead of the system objdump to ensure compatibility
+# with the LLVM bitcode generated by rustc but on Windows  piping/IO redirection under MSYS2 is wonky with llvm-objdump.
+OBJDUMP = objdump
+
 all:
        $(RUSTC) --crate-type dylib --crate-name raw_dylib_test lib.rs -C prefer-dynamic
        $(RUSTC) --crate-type dylib --crate-name raw_dylib_test_wrapper lib_wrapper.rs -C prefer-dynamic
        $(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)" -C prefer-dynamic
        # Make sure we don't find an import to the functions we expect to be inlined.
-       "$(LLVM_BIN_DIR)"/llvm-objdump -p $(TMPDIR)/driver.exe | $(CGREP) -v -e "inline_library_function"
-       "$(LLVM_BIN_DIR)"/llvm-objdump -p $(TMPDIR)/driver.exe | $(CGREP) -v -e "inline_library_function_calls_inline"
+       $(OBJDUMP) -p $(TMPDIR)/driver.exe | $(CGREP) -v -e "inline_library_function"
+       $(OBJDUMP) -p $(TMPDIR)/driver.exe | $(CGREP) -v -e "inline_library_function_calls_inline"
        # Make sure we do find an import to the functions we expect to be imported.
-       "$(LLVM_BIN_DIR)"/llvm-objdump -p $(TMPDIR)/driver.exe | $(CGREP) -e "library_function"
+       $(OBJDUMP) -p $(TMPDIR)/driver.exe | $(CGREP) -e "library_function"
        $(call COMPILE_OBJ,"$(TMPDIR)"/extern_1.obj,extern_1.c)
        $(call COMPILE_OBJ,"$(TMPDIR)"/extern_2.obj,extern_2.c)
 ifdef IS_MSVC
index 4574cf17f0ef069454b85ead103384503dd7813c..37b8d809a27423d910c25532380894eeb53780d7 100644 (file)
@@ -6,7 +6,12 @@
 
 # We're using the llvm-nm instead of the system nm to ensure it is compatible
 # with the LLVM bitcode generated by rustc.
+# Except on Windows where piping/IO redirection under MSYS2 is wonky with llvm-nm.
+ifndef IS_WINDOWS
 NM = "$(LLVM_BIN_DIR)"/llvm-nm
+else
+NM = nm
+endif
 
 all:
        # Build strange-named dep.
index 0b991ac42e3dc5a634e9848e670adc8be621583b..7fb6ce8d1e4110db9227c636f2e76a1b11a43eb4 100644 (file)
@@ -6,7 +6,12 @@
 
 # We're using the llvm-nm instead of the system nm to ensure it is compatible
 # with the LLVM bitcode generated by rustc.
+# Except on Windows where piping/IO redirection under MSYS2 is wonky with llvm-nm.
+ifndef IS_WINDOWS
 NM = "$(LLVM_BIN_DIR)"/llvm-nm
+else
+NM = nm
+endif
 
 all: $(call NATIVE_STATICLIB,native_dep_1) $(call NATIVE_STATICLIB,native_dep_2) $(call NATIVE_STATICLIB,native_dep_3)
        $(RUSTC) rust_dep_up.rs --crate-type=rlib -Zpacked_bundled_libs
index 9233f37444b6ed9bd2846854b4b64afcc39e32bf..bab66dae70c4f02db9182a6656fdfd7f25881634 100644 (file)
@@ -4,13 +4,13 @@
 goto: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html"
 show-text: true
 // Check the impl headers.
-assert-css: (".impl.has-srclink .srclink", {"font-size": "16px", "font-weight": 400}, ALL)
-assert-css: (".impl.has-srclink .code-header", {"font-size": "18px", "font-weight": 600}, ALL)
+assert-css: (".impl .srclink", {"font-size": "16px", "font-weight": 400}, ALL)
+assert-css: (".impl .code-header", {"font-size": "18px", "font-weight": 600}, ALL)
 // Check the impl items.
-assert-css: (".impl-items .has-srclink .srclink", {"font-size": "16px", "font-weight": 400}, ALL)
-assert-css: (".impl-items .has-srclink .code-header", {"font-size": "16px", "font-weight": 600}, ALL)
+assert-css: (".impl-items .srclink", {"font-size": "16px", "font-weight": 400}, ALL)
+assert-css: (".impl-items .code-header", {"font-size": "16px", "font-weight": 600}, ALL)
 
 // Check that we can click on source link
 store-document-property: (url, "URL")
-click: ".impl-items .has-srclink .srclink"
+click: ".impl-items .srclink"
 assert-document-property-false: {"URL": |url|}
index 546df947c0f910e24daf713f13d986774836b607..4f07fca82d1ebfb860461506cf7ba25986b0d7a2 100644 (file)
     -Z                                 threads=val -- use a thread pool with N threads
     -Z                        time-llvm-passes=val -- measure time of each LLVM pass (default: no)
     -Z                             time-passes=val -- measure time of each rustc pass (default: no)
+    -Z                   tiny-const-eval-limit=val -- sets a tiny, non-configurable limit for const eval; useful for compiler tests
     -Z                               tls-model=val -- choose the TLS model to use (`rustc --print tls-models` for details)
     -Z                            trace-macros=val -- for every macro invocation, print its name and arguments (default: no)
     -Z                       track-diagnostics=val -- tracks where in rustc a diagnostic was emitted
index 75e67330a3ebfe06bfa08bc45a1d64f4766c9bfd..a8587829d3ee7df8877c13ea57f157fbc12e7aff 100644 (file)
@@ -1 +1 @@
-<section id="associatedconstant.YOLO" class="method has-srclink"><a class="srclink rightside" href="../src/foo/anchors.rs.html#16">source</a><h4 class="code-header">const <a href="#associatedconstant.YOLO" class="constant">YOLO</a>: <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a></h4></section>
\ No newline at end of file
+<section id="associatedconstant.YOLO" class="method"><a class="srclink rightside" href="../src/foo/anchors.rs.html#16">source</a><h4 class="code-header">const <a href="#associatedconstant.YOLO" class="constant">YOLO</a>: <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a></h4></section>
\ No newline at end of file
index c002519760242a4ce4d216f3918c1735d8e725cd..4c5e45fea2de599539014cb386bab21b9d4f02a2 100644 (file)
@@ -1 +1 @@
-<section id="associatedconstant.X" class="associatedconstant has-srclink"><a class="srclink rightside" href="../src/foo/anchors.rs.html#42">source</a><h4 class="code-header">pub const <a href="#associatedconstant.X" class="constant">X</a>: <a class="primitive" href="{{channel}}/std/primitive.i32.html">i32</a> = 0i32</h4></section>
\ No newline at end of file
+<section id="associatedconstant.X" class="associatedconstant"><a class="srclink rightside" href="../src/foo/anchors.rs.html#42">source</a><h4 class="code-header">pub const <a href="#associatedconstant.X" class="constant">X</a>: <a class="primitive" href="{{channel}}/std/primitive.i32.html">i32</a> = 0i32</h4></section>
\ No newline at end of file
index b9ec8bf4c09a023c0142f3d3b5fa88cbcf511aa7..44957a5b71a54c333e091d349269feda1099577e 100644 (file)
@@ -1 +1 @@
-<section id="method.new" class="method has-srclink"><a class="srclink rightside" href="../src/foo/anchors.rs.html#48">source</a><h4 class="code-header">pub fn <a href="#method.new" class="fn">new</a>() -&gt; Self</h4></section>
\ No newline at end of file
+<section id="method.new" class="method"><a class="srclink rightside" href="../src/foo/anchors.rs.html#48">source</a><h4 class="code-header">pub fn <a href="#method.new" class="fn">new</a>() -&gt; Self</h4></section>
\ No newline at end of file
index 4308ddad412069e86acea1890b91f62032668536..75c2caf87a89fbf4540b6accb5b7e9a5adec2716 100644 (file)
@@ -1 +1 @@
-<section id="method.bar" class="method has-srclink"><a class="srclink rightside" href="../src/foo/anchors.rs.html#23">source</a><h4 class="code-header">fn <a href="#method.bar" class="fn">bar</a>()</h4></section>
\ No newline at end of file
+<section id="method.bar" class="method"><a class="srclink rightside" href="../src/foo/anchors.rs.html#23">source</a><h4 class="code-header">fn <a href="#method.bar" class="fn">bar</a>()</h4></section>
\ No newline at end of file
index 91eed8a3742926f223e38ebefac3af3160712e9c..38575eadfa9698802e3bd842f56cb163d67b3e01 100644 (file)
@@ -1 +1 @@
-<section id="tymethod.foo" class="method has-srclink"><a class="srclink rightside" href="../src/foo/anchors.rs.html#20">source</a><h4 class="code-header">fn <a href="#tymethod.foo" class="fn">foo</a>()</h4></section>
\ No newline at end of file
+<section id="tymethod.foo" class="method"><a class="srclink rightside" href="../src/foo/anchors.rs.html#20">source</a><h4 class="code-header">fn <a href="#tymethod.foo" class="fn">foo</a>()</h4></section>
\ No newline at end of file
index 2c66d5aa315abab54a6f140ee77f4b861a452531..dd65d98fee69e96102cbd824c8329c232bc57de6 100644 (file)
@@ -1 +1 @@
-<section id="associatedtype.T" class="method has-srclink"><a class="srclink rightside" href="../src/foo/anchors.rs.html#13">source</a><h4 class="code-header">type <a href="#associatedtype.T" class="associatedtype">T</a></h4></section>
\ No newline at end of file
+<section id="associatedtype.T" class="method"><a class="srclink rightside" href="../src/foo/anchors.rs.html#13">source</a><h4 class="code-header">type <a href="#associatedtype.T" class="associatedtype">T</a></h4></section>
\ No newline at end of file
index 72a1186bf7e301853072bcc0ec84267971911fba..f8b59160f15ee07d3a3373a28f7616ccf1ee8dd9 100644 (file)
@@ -1 +1 @@
-<section id="associatedtype.Y" class="associatedtype has-srclink"><h4 class="code-header">type <a href="#associatedtype.Y" class="associatedtype">Y</a> = <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a></h4></section>
+<section id="associatedtype.Y" class="associatedtype"><h4 class="code-header">type <a href="#associatedtype.Y" class="associatedtype">Y</a> = <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a></h4></section>
\ No newline at end of file
index fb7ebb5f82239791039b451f21815eb27a00f443..8cafb5a2497a385acfaa94d5e757bc970b28d443 100644 (file)
@@ -77,12 +77,12 @@ struct AsyncFdReadyGuard<'a, T> { x: &'a T }
 
 impl Foo {
     // @has async_fn/struct.Foo.html
-    // @has - '//*[@class="method has-srclink"]' 'pub async fn complicated_lifetimes( &self, context: &impl Bar) -> impl Iterator<Item = &usize>'
+    // @has - '//*[@class="method"]' 'pub async fn complicated_lifetimes( &self, context: &impl Bar) -> impl Iterator<Item = &usize>'
     pub async fn complicated_lifetimes(&self, context: &impl Bar) -> impl Iterator<Item = &usize> {}
     // taken from `tokio` as an example of a method that was particularly bad before
-    // @has - '//*[@class="method has-srclink"]' "pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()>"
+    // @has - '//*[@class="method"]' "pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()>"
     pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()> {}
-    // @has - '//*[@class="method has-srclink"]' "pub async fn mut_self(&mut self)"
+    // @has - '//*[@class="method"]' "pub async fn mut_self(&mut self)"
     pub async fn mut_self(&mut self) {}
 }
 
index 4366ad4d0adaca435f5cf5ee8df2b307673e8a37..18863abaeaccd3dd70c10c493639126b677f5848 100644 (file)
@@ -8,7 +8,7 @@ pub const fn bar() -> usize {
 }
 
 // @has foo/struct.Foo.html
-// @has - '//*[@class="method has-srclink"]' 'const fn new()'
+// @has - '//*[@class="method"]' 'const fn new()'
 pub struct Foo(usize);
 
 impl Foo {
index 4279de91f56c1420bab481156484d54cdd9fe939..80a9ab3f12e881e708cdb480f5fe6f8ed8c4a0e3 100644 (file)
@@ -5,7 +5,7 @@ pub trait Array {
 }
 
 // @has foo/trait.Array.html
-// @has - '//*[@class="impl has-srclink"]' 'impl<T, const N: usize> Array for [T; N]'
+// @has - '//*[@class="impl"]' 'impl<T, const N: usize> Array for [T; N]'
 impl<T, const N: usize> Array for [T; N] {
     type Item = T;
 }
index 4f15418650c2d69b49ec2f71f1d235b92e50de62..4d5c9f83e1ee0620009f95150bc47b28ccf84538 100644 (file)
@@ -8,7 +8,7 @@ pub trait Bar {
     fn foo(foo: Self::Fuu);
 }
 
-// @has doc_assoc_item/struct.Foo.html '//*[@class="impl has-srclink"]' 'impl<T: Bar<Fuu = u32>> Foo<T>'
+// @has doc_assoc_item/struct.Foo.html '//*[@class="impl"]' 'impl<T: Bar<Fuu = u32>> Foo<T>'
 impl<T: Bar<Fuu = u32>> Foo<T> {
     pub fn new(t: T) -> Foo<T> {
         Foo {
index c1f95ac91c394d7717bda3393d0f97a20d338a7c..4c2071b832266c6fa072bb743d8b8e642778789a 100644 (file)
@@ -3,8 +3,8 @@
 // @has issue_33054/impls/struct.Foo.html
 // @has - '//h3[@class="code-header"]' 'impl Foo'
 // @has - '//h3[@class="code-header"]' 'impl Bar for Foo'
-// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1
-// @count - '//*[@id="main-content"]/div[@id="implementations-list"]/details/summary/*[@class="impl has-srclink"]' 1
+// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1
+// @count - '//*[@id="main-content"]/div[@id="implementations-list"]/details/summary/*[@class="impl"]' 1
 // @has issue_33054/impls/bar/trait.Bar.html
 // @has - '//h3[@class="code-header"]' 'impl Bar for Foo'
 // @count - '//*[@class="struct"]' 1
index 4e901b31c90763e1ef4f965255d609729a389d9c..f32cf310055e0c1da17a3d4ab36fc0c21f08aecb 100644 (file)
@@ -7,7 +7,7 @@
 // blanket implementations.
 
 // @has 'foo/struct.Whatever.html'
-// @count - '//*[@id="blanket-implementations-list"]/section[@class="impl has-srclink"]' 1
+// @count - '//*[@id="blanket-implementations-list"]/section[@class="impl"]' 1
 
 pub trait Something<T> { }
 pub struct Whatever;
index 43971996163022cde80231616b6a78798de5ddb1..e6cff97b184299cfe11db00b9db8f98cd2ba76f9 100644 (file)
@@ -10,7 +10,7 @@
 // There are 3 impl blocks with public item and one that should not be displayed
 // by default because it only contains private items (but not in this case because
 // we used `--document-private-items`).
-// @count - '//*[@class="impl has-srclink"]' 'impl Foo' 4
+// @count - '//*[@class="impl"]' 'impl Foo' 4
 
 // Impl block only containing private items should not be displayed unless the
 // `--document-private-items` flag is used.
index 5caf020658c5f5afaf75ea63535c4aeee62462fa..d44b4a47cee1820590c5b0f3b42d47a82f708392 100644 (file)
@@ -7,7 +7,7 @@
 
 // There are 3 impl blocks with public item and one that should not be displayed
 // because it only contains private items.
-// @count - '//*[@class="impl has-srclink"]' 'impl Foo' 3
+// @count - '//*[@class="impl"]' 'impl Foo' 3
 
 // Impl block only containing private items should not be displayed.
 /// Private
index 95d4db06b3171f7606dbba351238b799682ff2e7..da780580bd087775c41b4caa842bee210aa73656 100644 (file)
@@ -8,7 +8,7 @@
 /// Hello empty impl block!
 impl Foo {}
 // We ensure that this empty impl block without doc isn't rendered.
-// @count - '//*[@class="impl has-srclink"]' 'impl Foo' 1
+// @count - '//*[@class="impl"]' 'impl Foo' 1
 impl Foo {}
 
 // Just to ensure that empty trait impl blocks are rendered.
index 90cbb77cb6b60a013b1b8475bfa9bdde21204227..f7738060e993cced229ee623d27680380959b690 100644 (file)
@@ -5,7 +5,7 @@
 
 pub struct Foo<T> { field: T }
 
-// @has impl_parts/struct.Foo.html '//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has impl_parts/struct.Foo.html '//*[@class="impl"]//h3[@class="code-header"]' \
 //     "impl<T> !AnAutoTrait for Foo<T>where T: Sync + Clone,"
 // @has impl_parts/trait.AnAutoTrait.html '//*[@id="implementors-list"]//h3[@class="code-header"]' \
 //     "impl<T> !AnAutoTrait for Foo<T>where T: Sync + Clone,"
index 6e89167b3a4512fa44ccf57466fbbad4beb855c3..571eaf6be967a45771f682f56d4345148da969f3 100644 (file)
@@ -5,8 +5,8 @@
 extern crate rustdoc_nonreachable_impls;
 
 // @has issue_31948_1/struct.Wobble.html
-// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Bark for'
-// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Woof for'
+// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'Bark for'
+// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'Woof for'
 // @!has - '//*[@class="impl"]//h3[@class="code-header"]' 'Bar for'
 // @!has - '//*[@class="impl"]//h3[@class="code-header"]' 'Qux for'
 pub use rustdoc_nonreachable_impls::hidden::Wobble;
index 141e07656a09c48b2ac298d73ea1308a8175697c..7eae21046ccbc834bb10a16675038dc19d8b4e7e 100644 (file)
@@ -5,9 +5,9 @@
 extern crate rustdoc_nonreachable_impls;
 
 // @has issue_31948_2/struct.Wobble.html
-// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Qux for'
-// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Bark for'
-// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Woof for'
+// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'Qux for'
+// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'Bark for'
+// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'Woof for'
 // @!has - '//*[@class="impl"]//h3[@class="code-header"]' 'Bar for'
 pub use rustdoc_nonreachable_impls::hidden::Wobble;
 
index 96fc6ca47e7f656d95691bffaa164e033dbba5fe..9c271bf4ad43fcbe17689de3ddb0dee9d50dcc6e 100644 (file)
@@ -5,9 +5,9 @@
 extern crate rustdoc_nonreachable_impls;
 
 // @has issue_31948/struct.Foo.html
-// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Bark for'
-// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Woof for'
-// @!has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Bar for'
+// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'Bark for'
+// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'Woof for'
+// @!has - '//*[@class="impl"]//h3[@class="code-header"]' 'Bar for'
 // @!has - '//*[@class="impl"]//h3[@class="code-header"]' 'Qux for'
 pub use rustdoc_nonreachable_impls::Foo;
 
index 43ce13fd9b18524e2033b8e5d6b6d2e76bfdb76b..5de26abace6fab01d1b20f6570358578468f4c88 100644 (file)
@@ -7,5 +7,5 @@ impl super::Blah for super::What { }
 pub trait Blah { }
 
 // @count issue_21474/struct.What.html \
-//        '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1
+//        '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1
 pub struct What;
index b4c52e2f17a6d93fba6a71fba51fa2795939889f..7af00c778361d3042300ba9b8a2ae059aa6fcf07 100644 (file)
@@ -22,7 +22,7 @@ fn ignore(_: &X) {}
         }
 
         // @has issue_33302/struct.S.html \
-        //        '//*[@class="impl has-srclink"]' 'impl T<[i32; 16]> for S'
+        //        '//*[@class="impl"]' 'impl T<[i32; 16]> for S'
         // @has - '//*[@id="associatedconstant.C"]' 'const C: [i32; 16]'
         // @has - '//*[@id="associatedconstant.D"]' 'const D: i32'
         impl T<[i32; ($n * $n)]> for S {
@@ -30,7 +30,7 @@ fn ignore(_: &X) {}
         }
 
         // @has issue_33302/struct.S.html \
-        //        '//*[@class="impl has-srclink"]' 'impl T<[i32; 16]> for S'
+        //        '//*[@class="impl"]' 'impl T<[i32; 16]> for S'
         // @has - '//*[@id="associatedconstant.C-1"]' 'const C: (i32,)'
         // @has - '//*[@id="associatedconstant.D-1"]' 'const D: i32'
         impl T<(i32,)> for S {
@@ -38,7 +38,7 @@ impl T<(i32,)> for S {
         }
 
         // @has issue_33302/struct.S.html \
-        //        '//*[@class="impl has-srclink"]' 'impl T<(i32, i32)> for S'
+        //        '//*[@class="impl"]' 'impl T<(i32, i32)> for S'
         // @has - '//*[@id="associatedconstant.C-2"]' 'const C: (i32, i32)'
         // @has - '//*[@id="associatedconstant.D-2"]' 'const D: i32'
         impl T<(i32, i32)> for S {
index 86479e6fb2e51a67ef6f2143e67dc8930c3822cf..8a5f0413826a910ff7f7ceaa72db9c2438a4ecd7 100644 (file)
@@ -4,12 +4,12 @@ pub trait Bar<T, U> {}
 
 // @has 'foo/struct.Foo1.html'
 pub struct Foo1;
-// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1
-// @has - '//*[@class="impl has-srclink"]' "impl Bar<Foo1, &'static Foo1> for Foo1"
+// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1
+// @has - '//*[@class="impl"]' "impl Bar<Foo1, &'static Foo1> for Foo1"
 impl Bar<Foo1, &'static Foo1> for Foo1 {}
 
 // @has 'foo/struct.Foo2.html'
 pub struct Foo2;
-// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1
-// @has - '//*[@class="impl has-srclink"]' "impl Bar<&'static Foo2, Foo2> for u8"
+// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1
+// @has - '//*[@class="impl"]' "impl Bar<&'static Foo2, Foo2> for u8"
 impl Bar<&'static Foo2, Foo2> for u8 {}
index 04bc4f304d68acc8e72e5021b42a22282bee7231..13bedd5dbb023220adaa5721fd43ac78574c9c4a 100644 (file)
@@ -14,7 +14,7 @@ impl<B, C> Signal2 for B where B: Signal<Item = C> {
 // @has - '//h3[@class="code-header"]' 'impl<B> Send for Switch<B>where <B as Signal>::Item: Send'
 // @has - '//h3[@class="code-header"]' 'impl<B> Sync for Switch<B>where <B as Signal>::Item: Sync'
 // @count - '//*[@id="implementations-list"]//*[@class="impl"]' 0
-// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]' 5
+// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]' 5
 pub struct Switch<B: Signal> {
     pub inner: <B as Signal2>::Item2,
 }
index 1c7aa9c7eefe50c7153bf1b5009a9cc99cc6ca9b..04664805a886f3926abd2e7089eac46958193548 100644 (file)
@@ -7,7 +7,7 @@ pub trait Owned<'a> {
 }
 
 // @has issue_51236/struct.Owned.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
 // "impl<T> Send for Owned<T>where <T as Owned<'static>>::Reader: Send"
 pub struct Owned<T> where T: for<'a> ::traits::Owned<'a> {
     marker: PhantomData<<T as ::traits::Owned<'static>>::Reader>,
index c68ffd52186482da0ffe81389f01305b5522ca09..dc1eb304c3d1da377678f20917c56892bbcd4edb 100644 (file)
@@ -12,9 +12,9 @@ macro_rules! array_impls {
 }
 
 // @has issue_53812/trait.MyIterator.html
-// @has - '//*[@id="implementors-list"]/*[@class="impl has-srclink"][1]' 'MyStruct<[T; 0]>'
-// @has - '//*[@id="implementors-list"]/*[@class="impl has-srclink"][2]' 'MyStruct<[T; 1]>'
-// @has - '//*[@id="implementors-list"]/*[@class="impl has-srclink"][3]' 'MyStruct<[T; 2]>'
-// @has - '//*[@id="implementors-list"]/*[@class="impl has-srclink"][4]' 'MyStruct<[T; 3]>'
-// @has - '//*[@id="implementors-list"]/*[@class="impl has-srclink"][5]' 'MyStruct<[T; 10]>'
+// @has - '//*[@id="implementors-list"]/*[@class="impl"][1]' 'MyStruct<[T; 0]>'
+// @has - '//*[@id="implementors-list"]/*[@class="impl"][2]' 'MyStruct<[T; 1]>'
+// @has - '//*[@id="implementors-list"]/*[@class="impl"][3]' 'MyStruct<[T; 2]>'
+// @has - '//*[@id="implementors-list"]/*[@class="impl"][4]' 'MyStruct<[T; 3]>'
+// @has - '//*[@id="implementors-list"]/*[@class="impl"][5]' 'MyStruct<[T; 10]>'
 array_impls! { 10 3 2 1 0 }
index 7b7290ab4b77c39cf862408852b13a9cd8355832..a886eb0de242c19d57921aaa26747433ad16f65a 100644 (file)
@@ -1,10 +1,10 @@
 pub trait ScopeHandle<'scope> {}
 
 // @has issue_54705/struct.ScopeFutureContents.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
 // "impl<'scope, S> Send for ScopeFutureContents<'scope, S>where S: Sync"
 //
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
 // "impl<'scope, S> Sync for ScopeFutureContents<'scope, S>where S: Sync"
 pub struct ScopeFutureContents<'scope, S>
     where S: ScopeHandle<'scope>,
index 22a18ef90e13ad68b3c57e16f0eda6e45b173c8a..d3c2070d915d67b114961acd04d0e8a0d2fe76b6 100644 (file)
@@ -1,9 +1,9 @@
 #![feature(negative_impls)]
 
 // @has issue_55321/struct.A.html
-// @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="trait-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
 // "impl !Send for A"
-// @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="trait-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
 // "impl !Sync for A"
 pub struct A();
 
@@ -11,8 +11,8 @@ impl !Send for A {}
 impl !Sync for A {}
 
 // @has issue_55321/struct.B.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
 // "impl<T> !Send for B<T>"
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
 // "impl<T> !Sync for B<T>"
 pub struct B<T: ?Sized>(A, Box<T>);
index b4eef344b5f3b6f01abd00cc4bdae13d9934b496..c9a74335702d585a3e02bd0d8c0440dcf8574aeb 100644 (file)
@@ -17,7 +17,7 @@ impl<'a, T> MyTrait for Inner<'a, T> {
 }
 
 // @has issue_56822/struct.Parser.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
 // "impl<'a> Send for Parser<'a>"
 pub struct Parser<'a> {
     field: <Wrapper<Inner<'a, u8>> as MyTrait>::Output
index fbb0f82ae39577701447ddd905e69b7b2723c5f7..e337e4a4f7ad164774044881098725991a45ca57 100644 (file)
@@ -26,9 +26,9 @@ unsafe impl<I> Send for DynTrait<I>
 {}
 
 // @has issue_60726/struct.IntoIter.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
 // "impl<T> !Send for IntoIter<T>"
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
 // "impl<T> !Sync for IntoIter<T>"
 pub struct IntoIter<T>{
     hello:DynTrait<FooInterface<T>>,
index a90e0fea09223064332aa8a094898249a7e9308a..5caea0ec992443b3fdbb469acbbd70ff084b2f11 100644 (file)
@@ -8,7 +8,7 @@ pub const fn bloop() -> i32 {
 pub struct Struct {}
 
 impl Struct {
-    // @has 'issue_76501/struct.Struct.html' '//*[@class="method has-srclink"]' \
+    // @has 'issue_76501/struct.Struct.html' '//*[@class="method"]' \
     // 'pub const fn blurp() -> i32'
     /// A useless function that always returns 1.
     pub const fn blurp() -> i32 {
index 2e4bec2544c9d6fd3a655f8de100293487bc63da..d09141c320473933bef1d05874ca5faff4b0901e 100644 (file)
@@ -7,8 +7,8 @@ pub trait AnAmazingTrait {}
 impl<T: Something> AnAmazingTrait for T {}
 
 // @has 'issue_78673/struct.MyStruct.html'
-// @has  - '//*[@class="impl has-srclink"]' 'AnAmazingTrait for MyStruct'
-// @!has - '//*[@class="impl has-srclink"]' 'AnAmazingTrait for T'
+// @has  - '//*[@class="impl"]' 'AnAmazingTrait for MyStruct'
+// @!has - '//*[@class="impl"]' 'AnAmazingTrait for T'
 pub struct MyStruct;
 
 impl AnAmazingTrait for MyStruct {}
@@ -16,8 +16,8 @@ impl AnAmazingTrait for MyStruct {}
 // generic structs may have _both_ specific and blanket impls that apply
 
 // @has 'issue_78673/struct.AnotherStruct.html'
-// @has - '//*[@class="impl has-srclink"]' 'AnAmazingTrait for AnotherStruct<()>'
-// @has - '//*[@class="impl has-srclink"]' 'AnAmazingTrait for T'
+// @has - '//*[@class="impl"]' 'AnAmazingTrait for AnotherStruct<()>'
+// @has - '//*[@class="impl"]' 'AnAmazingTrait for T'
 pub struct AnotherStruct<T>(T);
 
 impl<T: Something> Something for AnotherStruct<T> {}
index 3b862e651c9098e5989b7208159c8b0f9889fda3..431db51d95f7c3a1fb84db3381df8dee6e5e429b 100644 (file)
@@ -5,7 +5,7 @@
 
 pub struct Foo;
 
-// @count foo/struct.Foo.html '//*[@class="impl-items"]//*[@class="method has-srclink"]' 2
+// @count foo/struct.Foo.html '//*[@class="impl-items"]//*[@class="method"]' 2
 // @!has - '//*[@class="impl-items"]//*[@class="method"]' 'mut'
 impl Foo {
     pub fn foo(mut self) {}
index af19c784d6d0514c85cf4cd8148d94778d5d4090..51223af673732931e7557c79f98084a35b13803b 100644 (file)
@@ -5,10 +5,10 @@
 // @matches negative_impl/struct.Bravo.html '//pre' "pub struct Bravo<B>"
 pub struct Bravo<B>(B);
 
-// @matches negative_impl/struct.Alpha.html '//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @matches negative_impl/struct.Alpha.html '//*[@class="impl"]//h3[@class="code-header"]' \
 // "impl !Send for Alpha"
 impl !Send for Alpha {}
 
-// @matches negative_impl/struct.Bravo.html '//*[@class="impl has-srclink"]//h3[@class="code-header"]' "\
+// @matches negative_impl/struct.Bravo.html '//*[@class="impl"]//h3[@class="code-header"]' "\
 // impl<B> !Send for Bravo<B>"
 impl<B> !Send for Bravo<B> {}
index c3a5eb6d324a475513930b35c91dbff969d7b4d3..10efbefd2b168a6f9df2ad6ce74626a4e074ca47 100644 (file)
@@ -13,7 +13,7 @@
 // @has - '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!'
 
 // There should be only one implementation listed.
-// @count - '//*[@class="impl has-srclink"]' 1
+// @count - '//*[@class="impl"]' 1
 // @has - '//*[@id="impl-Foo%3C%26A%3E-for-%26B"]/*[@class="code-header"]' \
 //        'impl<A, B> Foo<&A> for &B'
 #[doc(primitive = "reference")]
index 0dca3f672cd3c42ca703a80e9112a2298b82084c..7115a01d079ff15b99d7befd2badf45028ffb970 100644 (file)
@@ -10,8 +10,8 @@ pub fn bar() -> usize {
 }
 
 // @has foo/struct.Foo.html
-// @has - '//*[@class="method has-srclink"]' 'pub fn new()'
-// @has - '//*[@class="method has-srclink"]' 'fn not_pub()'
+// @has - '//*[@class="method"]' 'pub fn new()'
+// @has - '//*[@class="method"]' 'fn not_pub()'
 pub struct Foo(usize);
 
 impl Foo {
index 7c6a388653c4987a3c766613afc91ccab65d986a..043ac2414883877a8690a1879f0f74151ae20ff6 100644 (file)
@@ -1,8 +1,8 @@
 // @has basic/struct.Foo.html
 // @has - '//h3[@class="code-header"]' 'impl<T> Send for Foo<T>where T: Send'
 // @has - '//h3[@class="code-header"]' 'impl<T> Sync for Foo<T>where T: Sync'
-// @count - '//*[@id="implementations-list"]//*[@class="impl has-srclink"]' 0
-// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]' 5
+// @count - '//*[@id="implementations-list"]//*[@class="impl"]' 0
+// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]' 5
 pub struct Foo<T> {
     field: T,
 }
index 43393c21fddb41600b4039250f710337f90469d8..4c39f0bf1e07f20b7a95401496eaed7df7ccf083 100644 (file)
@@ -20,7 +20,7 @@ pub struct Foo<T> {
 }
 
 // @has complex/struct.NotOuter.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
 // "impl<'a, T, K: ?Sized> Send for Outer<'a, T, K>where K: for<'b> Fn((&'b bool, &'a u8)) \
 // -> &'b i8, T: MyTrait<'a>, <T as MyTrait<'a>>::MyItem: Copy, 'a: 'static"
 
index 33170a844359b3ca09c2c42a9e7e5963f691f127..71265b3078a06ba91fd3fd4220d6d58ecfa1c1a5 100644 (file)
@@ -9,10 +9,10 @@ unsafe impl<'a, T> Send for Inner<'a, T>
 {}
 
 // @has lifetimes/struct.Foo.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
 // "impl<'c, K> Send for Foo<'c, K>where K: for<'b> Fn(&'b bool) -> &'c u8, 'c: 'static"
 //
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
 // "impl<'c, K> Sync for Foo<'c, K>where K: Sync"
 pub struct Foo<'c, K: 'c> {
     inner_field: Inner<'c, K>,
index 77c04ad2ad942af03c327cf708a075a555d7a75c..7fc8447df3efc7963a4e88ec38d17609913ad8e0 100644 (file)
@@ -1,12 +1,12 @@
 // @has manual/struct.Foo.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
 // 'impl<T> Sync for Foo<T>where T: Sync'
 //
-// @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="trait-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
 // 'impl<T> Send for Foo<T>'
 //
-// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1
-// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]' 4
+// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1
+// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]' 4
 pub struct Foo<T> {
     field: T,
 }
index 2c2c848a5e0fb16db2574bd8015bf3e458b8e39a..97da2d57424cebc94aba9b0b76e6ba42b6e523cf 100644 (file)
@@ -3,10 +3,10 @@ pub struct Inner<T: Copy> {
 }
 
 // @has negative/struct.Outer.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
 // "impl<T> !Send for Outer<T>"
 //
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
 // "impl<T> !Sync for Outer<T>"
 pub struct Outer<T: Copy> {
     inner_field: Inner<T>,
index 423bf115ab165c735a52d857921518db5a7a898d..e4aead71bf2e5a3905689d18c960abd3220bb11a 100644 (file)
@@ -9,10 +9,10 @@ unsafe impl<T> Send for Inner<T>
 }
 
 // @has nested/struct.Foo.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
 // 'impl<T> Send for Foo<T>where T: Copy'
 //
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
 // 'impl<T> Sync for Foo<T>where T: Sync'
 pub struct Foo<T> {
     inner_field: Inner<T>,
index 59f33623322a928d99a56cfeab77f79c6bb75ed6..ea57d7388b85f174c5dc54f5954ea5f40d9b4819 100644 (file)
@@ -9,7 +9,7 @@ unsafe impl<T> Send for Inner<T>
 }
 
 // @has no_redundancy/struct.Outer.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
 // "impl<T> Send for Outer<T>where T: Send + Copy"
 pub struct Outer<T> {
     inner_field: Inner<T>,
index 558ff2add400cae71a218ba9ffcfb11012cd4f3e..7c9412ae9624364a8573dfda8d2b9da52036e53e 100644 (file)
@@ -23,10 +23,10 @@ unsafe impl<'a, T> Sync for Inner<'a, T>
 }
 
 // @has project/struct.Foo.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
 // "impl<'c, K> Send for Foo<'c, K>where K: MyTrait<MyItem = bool>, 'c: 'static"
 //
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
 // "impl<'c, K> Sync for Foo<'c, K>where K: MyTrait, <K as MyTrait>::MyItem: OtherTrait, \
 // 'c: 'static,"
 pub struct Foo<'c, K: 'c> {
index c6ae96de77672381bd308742f21f5a528e3f2c6c..145a2b7e00c0a9d64f60d136c14d3844c74c1722 100644 (file)
@@ -23,7 +23,7 @@ impl<T> Pattern for Wrapper<T> {
 
 
 // @has self_referential/struct.WriteAndThen.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
 // "impl<P1> Send for WriteAndThen<P1>where    <P1 as Pattern>::Value: Send"
 pub struct WriteAndThen<P1>(pub P1::Value,pub <Constrain<P1, Wrapper<P1::Value>> as Pattern>::Value)
     where P1: Pattern;
index 1a76cb919c2989748d476bbbfe3aabdf572ad941..9dc6211ec20b60825c2e8c5ff895c448f5838c55 100644 (file)
@@ -3,7 +3,7 @@ pub trait OwnedTrait<'a> {
 }
 
 // @has static_region/struct.Owned.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
 // "impl<T> Send for Owned<T>where <T as OwnedTrait<'static>>::Reader: Send"
 pub struct Owned<T> where T: OwnedTrait<'static> {
     marker: <T as OwnedTrait<'static>>::Reader,
index d5dfa9484891a66a341c89c723ededde9d2030ee..63e2973c759b6b2b746c81363e16e9858e654f37 100644 (file)
@@ -9,8 +9,8 @@ pub fn method_on_mystruct() {}
 }
 
 // @has typedef/type.MyAlias.html
-// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'impl MyAlias'
-// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'impl MyTrait for MyAlias'
+// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'impl MyAlias'
+// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'impl MyTrait for MyAlias'
 // @hasraw - 'Alias docstring'
 // @has - '//*[@class="sidebar"]//*[@class="location"]' 'MyAlias'
 // @has - '//*[@class="sidebar"]//a[@href="#implementations"]' 'Methods'
index 3ac0c6872a82150c4a621c8919f96a81a7e431ff..644a0058244522a55be5bb50683b51130497927e 100644 (file)
@@ -13,7 +13,7 @@ pub fn charlie<C>() where C: MyTrait {}
 
 pub struct Delta<D>(D);
 
-// @has foo/struct.Delta.html '//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has foo/struct.Delta.html '//*[@class="impl"]//h3[@class="code-header"]' \
 //          "impl<D> Delta<D>where D: MyTrait"
 impl<D> Delta<D> where D: MyTrait {
     pub fn delta() {}
@@ -43,7 +43,7 @@ fn lines(self) -> Lines<Self>
     { todo!() }
 }
 
-// @has foo/struct.Echo.html '//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has foo/struct.Echo.html '//*[@class="impl"]//h3[@class="code-header"]' \
 //          "impl<E> MyTrait for Echo<E>where E: MyTrait"
 // @has foo/trait.MyTrait.html '//*[@id="implementors-list"]//h3[@class="code-header"]' \
 //          "impl<E> MyTrait for Echo<E>where E: MyTrait"
@@ -51,7 +51,7 @@ impl<E> MyTrait for Echo<E>where E: MyTrait {}
 
 pub enum Foxtrot<F> { Foxtrot1(F) }
 
-// @has foo/enum.Foxtrot.html '//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has foo/enum.Foxtrot.html '//*[@class="impl"]//h3[@class="code-header"]' \
 //          "impl<F> MyTrait for Foxtrot<F>where F: MyTrait"
 // @has foo/trait.MyTrait.html '//*[@id="implementors-list"]//h3[@class="code-header"]' \
 //          "impl<F> MyTrait for Foxtrot<F>where F: MyTrait"
index 8b58cb279f376a77ccb005913248ef46027a3144..f30bfaf3f958ce5349428b3185c6a175a28222ea 100644 (file)
@@ -1,8 +1,11 @@
 error[E0080]: evaluation of constant value failed
-  --> $DIR/infinite_loop.rs:6:15
+  --> $DIR/infinite_loop.rs:6:9
    |
-LL |         while n != 0 {
-   |               ^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`)
+LL | /         while n != 0 {
+LL | |
+LL | |             n = if n % 2 == 0 { n/2 } else { 3*n + 1 };
+LL | |         }
+   | |_________^ exceeded interpreter step limit (see `#[const_eval_limit]`)
 
 error: aborting due to previous error
 
index ce65407bbab0b5d928795c8b4fdc82297aac8625..307c1a66834105e316e559ebd2607a5cc75c6f54 100644 (file)
@@ -2,8 +2,8 @@ fn main() {
     let _ = [(); {
         let mut x = &0;
         let mut n = 0;
-        while n < 5 {
-            n = (n + 1) % 5; //~ ERROR evaluation of constant value failed
+        while n < 5 { //~ ERROR evaluation of constant value failed [E0080]
+            n = (n + 1) % 5;
             x = &0; // Materialize a new AllocId
         }
         0
index 8536ff02c6dae89b96403ba90c8fd15b61f58a3b..3aa6bd277ddcbdd3f201f281b512d9604b688cc2 100644 (file)
@@ -1,8 +1,11 @@
 error[E0080]: evaluation of constant value failed
-  --> $DIR/issue-52475.rs:6:17
+  --> $DIR/issue-52475.rs:5:9
    |
-LL |             n = (n + 1) % 5;
-   |                 ^^^^^^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`)
+LL | /         while n < 5 {
+LL | |             n = (n + 1) % 5;
+LL | |             x = &0; // Materialize a new AllocId
+LL | |         }
+   | |_________^ exceeded interpreter step limit (see `#[const_eval_limit]`)
 
 error: aborting due to previous error
 
diff --git a/tests/ui/consts/const-eval/stable-metric/ctfe-fn-call.rs b/tests/ui/consts/const-eval/stable-metric/ctfe-fn-call.rs
new file mode 100644 (file)
index 0000000..c595962
--- /dev/null
@@ -0,0 +1,36 @@
+// check-fail
+// compile-flags: -Z tiny-const-eval-limit
+
+const fn foo() {}
+
+const fn call_foo() -> u32 {
+    foo();
+    foo();
+    foo();
+    foo();
+    foo();
+
+    foo();
+    foo();
+    foo();
+    foo();
+    foo();
+
+    foo();
+    foo();
+    foo();
+    foo();
+    foo();
+
+    foo();
+    foo();
+    foo();
+    foo(); //~ ERROR evaluation of constant value failed [E0080]
+    0
+}
+
+const X: u32 = call_foo();
+
+fn main() {
+    println!("{X}");
+}
diff --git a/tests/ui/consts/const-eval/stable-metric/ctfe-fn-call.stderr b/tests/ui/consts/const-eval/stable-metric/ctfe-fn-call.stderr
new file mode 100644 (file)
index 0000000..ed70975
--- /dev/null
@@ -0,0 +1,20 @@
+error[E0080]: evaluation of constant value failed
+  --> $DIR/ctfe-fn-call.rs:28:5
+   |
+LL |     foo();
+   |     ^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`)
+   |
+note: inside `call_foo`
+  --> $DIR/ctfe-fn-call.rs:28:5
+   |
+LL |     foo();
+   |     ^^^^^
+note: inside `X`
+  --> $DIR/ctfe-fn-call.rs:32:16
+   |
+LL | const X: u32 = call_foo();
+   |                ^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/const-eval/stable-metric/ctfe-labelled-loop.rs b/tests/ui/consts/const-eval/stable-metric/ctfe-labelled-loop.rs
new file mode 100644 (file)
index 0000000..c10b8d8
--- /dev/null
@@ -0,0 +1,19 @@
+// check-fail
+// compile-flags: -Z tiny-const-eval-limit
+
+const fn labelled_loop(n: u32) -> u32 {
+    let mut i = 0;
+    'mylabel: loop { //~ ERROR evaluation of constant value failed [E0080]
+        if i > n {
+            break 'mylabel
+        }
+        i += 1;
+    }
+    0
+}
+
+const X: u32 = labelled_loop(19);
+
+fn main() {
+    println!("{X}");
+}
diff --git a/tests/ui/consts/const-eval/stable-metric/ctfe-labelled-loop.stderr b/tests/ui/consts/const-eval/stable-metric/ctfe-labelled-loop.stderr
new file mode 100644 (file)
index 0000000..d9404ed
--- /dev/null
@@ -0,0 +1,30 @@
+error[E0080]: evaluation of constant value failed
+  --> $DIR/ctfe-labelled-loop.rs:6:5
+   |
+LL | /     'mylabel: loop {
+LL | |         if i > n {
+LL | |             break 'mylabel
+LL | |         }
+LL | |         i += 1;
+LL | |     }
+   | |_____^ exceeded interpreter step limit (see `#[const_eval_limit]`)
+   |
+note: inside `labelled_loop`
+  --> $DIR/ctfe-labelled-loop.rs:6:5
+   |
+LL | /     'mylabel: loop {
+LL | |         if i > n {
+LL | |             break 'mylabel
+LL | |         }
+LL | |         i += 1;
+LL | |     }
+   | |_____^
+note: inside `X`
+  --> $DIR/ctfe-labelled-loop.rs:15:16
+   |
+LL | const X: u32 = labelled_loop(19);
+   |                ^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/const-eval/stable-metric/ctfe-recursion.rs b/tests/ui/consts/const-eval/stable-metric/ctfe-recursion.rs
new file mode 100644 (file)
index 0000000..80ff835
--- /dev/null
@@ -0,0 +1,16 @@
+// check-fail
+// compile-flags: -Z tiny-const-eval-limit
+
+const fn recurse(n: u32) -> u32 {
+    if n == 0 {
+        n
+    } else {
+        recurse(n - 1) //~ ERROR evaluation of constant value failed [E0080]
+    }
+}
+
+const X: u32 = recurse(19);
+
+fn main() {
+    println!("{X}");
+}
diff --git a/tests/ui/consts/const-eval/stable-metric/ctfe-recursion.stderr b/tests/ui/consts/const-eval/stable-metric/ctfe-recursion.stderr
new file mode 100644 (file)
index 0000000..ed9a311
--- /dev/null
@@ -0,0 +1,25 @@
+error[E0080]: evaluation of constant value failed
+  --> $DIR/ctfe-recursion.rs:8:9
+   |
+LL |         recurse(n - 1)
+   |         ^^^^^^^^^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`)
+   |
+note: inside `recurse`
+  --> $DIR/ctfe-recursion.rs:8:9
+   |
+LL |         recurse(n - 1)
+   |         ^^^^^^^^^^^^^^
+note: [... 18 additional calls inside `recurse` ...]
+  --> $DIR/ctfe-recursion.rs:8:9
+   |
+LL |         recurse(n - 1)
+   |         ^^^^^^^^^^^^^^
+note: inside `X`
+  --> $DIR/ctfe-recursion.rs:12:16
+   |
+LL | const X: u32 = recurse(19);
+   |                ^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/const-eval/stable-metric/ctfe-simple-loop.rs b/tests/ui/consts/const-eval/stable-metric/ctfe-simple-loop.rs
new file mode 100644 (file)
index 0000000..ca0eec9
--- /dev/null
@@ -0,0 +1,15 @@
+// check-fail
+// compile-flags: -Z tiny-const-eval-limit
+const fn simple_loop(n: u32) -> u32 {
+    let mut index = 0;
+    while index < n { //~ ERROR evaluation of constant value failed [E0080]
+        index = index + 1;
+    }
+    0
+}
+
+const X: u32 = simple_loop(19);
+
+fn main() {
+    println!("{X}");
+}
diff --git a/tests/ui/consts/const-eval/stable-metric/ctfe-simple-loop.stderr b/tests/ui/consts/const-eval/stable-metric/ctfe-simple-loop.stderr
new file mode 100644 (file)
index 0000000..83ff275
--- /dev/null
@@ -0,0 +1,24 @@
+error[E0080]: evaluation of constant value failed
+  --> $DIR/ctfe-simple-loop.rs:5:5
+   |
+LL | /     while index < n {
+LL | |         index = index + 1;
+LL | |     }
+   | |_____^ exceeded interpreter step limit (see `#[const_eval_limit]`)
+   |
+note: inside `simple_loop`
+  --> $DIR/ctfe-simple-loop.rs:5:5
+   |
+LL | /     while index < n {
+LL | |         index = index + 1;
+LL | |     }
+   | |_____^
+note: inside `X`
+  --> $DIR/ctfe-simple-loop.rs:11:16
+   |
+LL | const X: u32 = simple_loop(19);
+   |                ^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/const-eval/stable-metric/dominators-edge-case.rs b/tests/ui/consts/const-eval/stable-metric/dominators-edge-case.rs
new file mode 100644 (file)
index 0000000..0b0f361
--- /dev/null
@@ -0,0 +1,19 @@
+// check-pass
+//
+// Exercising an edge case which was found during Stage 2 compilation.
+// Compilation would fail for this code when running the `CtfeLimit`
+// MirPass (specifically when looking up the dominators).
+#![crate_type="lib"]
+
+const DUMMY: Expr = Expr::Path(ExprPath {
+    attrs: Vec::new(),
+    path: Vec::new(),
+});
+
+pub enum Expr {
+    Path(ExprPath),
+}
+pub struct ExprPath {
+    pub attrs: Vec<()>,
+    pub path: Vec<()>,
+}
index 850aebdfb2a6df7051bd24946f4e1492f0c4a54d..a8e8ae9bb088a07737324dd98aeaf9a3ad2762df 100644 (file)
@@ -1,8 +1,11 @@
 error[E0080]: evaluation of constant value failed
-  --> $DIR/const_eval_limit_reached.rs:6:11
+  --> $DIR/const_eval_limit_reached.rs:6:5
    |
-LL |     while x != 1000 {
-   |           ^^^^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`)
+LL | /     while x != 1000 {
+LL | |
+LL | |         x += 1;
+LL | |     }
+   | |_____^ exceeded interpreter step limit (see `#[const_eval_limit]`)
 
 error: aborting due to previous error
 
index e6ee11a783b8849acabb006b020b5dad05d4f5ce..2a93a05c627698a2e1eb03e57133fed99215a508 100644 (file)
@@ -889,23 +889,20 @@ impl ::core::cmp::PartialOrd for Mixed {
         -> ::core::option::Option<::core::cmp::Ordering> {
         let __self_tag = ::core::intrinsics::discriminant_value(self);
         let __arg1_tag = ::core::intrinsics::discriminant_value(other);
-        match ::core::cmp::PartialOrd::partial_cmp(&__self_tag, &__arg1_tag) {
-            ::core::option::Option::Some(::core::cmp::Ordering::Equal) =>
-                match (self, other) {
-                    (Mixed::R(__self_0), Mixed::R(__arg1_0)) =>
-                        ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
-                    (Mixed::S { d1: __self_0, d2: __self_1 }, Mixed::S {
-                        d1: __arg1_0, d2: __arg1_1 }) =>
-                        match ::core::cmp::PartialOrd::partial_cmp(__self_0,
-                                __arg1_0) {
-                            ::core::option::Option::Some(::core::cmp::Ordering::Equal)
-                                => ::core::cmp::PartialOrd::partial_cmp(__self_1, __arg1_1),
-                            cmp => cmp,
-                        },
-                    _ =>
-                        ::core::option::Option::Some(::core::cmp::Ordering::Equal),
+        match (self, other) {
+            (Mixed::R(__self_0), Mixed::R(__arg1_0)) =>
+                ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
+            (Mixed::S { d1: __self_0, d2: __self_1 }, Mixed::S {
+                d1: __arg1_0, d2: __arg1_1 }) =>
+                match ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0)
+                    {
+                    ::core::option::Option::Some(::core::cmp::Ordering::Equal)
+                        => ::core::cmp::PartialOrd::partial_cmp(__self_1, __arg1_1),
+                    cmp => cmp,
                 },
-            cmp => cmp,
+            _ =>
+                ::core::cmp::PartialOrd::partial_cmp(&__self_tag,
+                    &__arg1_tag),
         }
     }
 }
@@ -1019,18 +1016,16 @@ impl ::core::cmp::PartialOrd for Fielded {
         -> ::core::option::Option<::core::cmp::Ordering> {
         let __self_tag = ::core::intrinsics::discriminant_value(self);
         let __arg1_tag = ::core::intrinsics::discriminant_value(other);
-        match ::core::cmp::PartialOrd::partial_cmp(&__self_tag, &__arg1_tag) {
-            ::core::option::Option::Some(::core::cmp::Ordering::Equal) =>
-                match (self, other) {
-                    (Fielded::X(__self_0), Fielded::X(__arg1_0)) =>
-                        ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
-                    (Fielded::Y(__self_0), Fielded::Y(__arg1_0)) =>
-                        ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
-                    (Fielded::Z(__self_0), Fielded::Z(__arg1_0)) =>
-                        ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
-                    _ => unsafe { ::core::intrinsics::unreachable() }
-                },
-            cmp => cmp,
+        match (self, other) {
+            (Fielded::X(__self_0), Fielded::X(__arg1_0)) =>
+                ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
+            (Fielded::Y(__self_0), Fielded::Y(__arg1_0)) =>
+                ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
+            (Fielded::Z(__self_0), Fielded::Z(__arg1_0)) =>
+                ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
+            _ =>
+                ::core::cmp::PartialOrd::partial_cmp(&__self_tag,
+                    &__arg1_tag),
         }
     }
 }
diff --git a/tests/ui/feature-gates/feature-gate-multiple_supertrait_upcastable.rs b/tests/ui/feature-gates/feature-gate-multiple_supertrait_upcastable.rs
new file mode 100644 (file)
index 0000000..0467dea
--- /dev/null
@@ -0,0 +1,12 @@
+// check-pass
+
+#![deny(multiple_supertrait_upcastable)]
+//~^ WARNING unknown lint: `multiple_supertrait_upcastable`
+//~| WARNING unknown lint: `multiple_supertrait_upcastable`
+//~| WARNING unknown lint: `multiple_supertrait_upcastable`
+#![warn(multiple_supertrait_upcastable)]
+//~^ WARNING unknown lint: `multiple_supertrait_upcastable`
+//~| WARNING unknown lint: `multiple_supertrait_upcastable`
+//~| WARNING unknown lint: `multiple_supertrait_upcastable`
+
+fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-multiple_supertrait_upcastable.stderr b/tests/ui/feature-gates/feature-gate-multiple_supertrait_upcastable.stderr
new file mode 100644 (file)
index 0000000..1f725f3
--- /dev/null
@@ -0,0 +1,57 @@
+warning: unknown lint: `multiple_supertrait_upcastable`
+  --> $DIR/feature-gate-multiple_supertrait_upcastable.rs:3:1
+   |
+LL | #![deny(multiple_supertrait_upcastable)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `multiple_supertrait_upcastable` lint is unstable
+   = help: add `#![feature(multiple_supertrait_upcastable)]` to the crate attributes to enable
+   = note: `#[warn(unknown_lints)]` on by default
+
+warning: unknown lint: `multiple_supertrait_upcastable`
+  --> $DIR/feature-gate-multiple_supertrait_upcastable.rs:7:1
+   |
+LL | #![warn(multiple_supertrait_upcastable)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `multiple_supertrait_upcastable` lint is unstable
+   = help: add `#![feature(multiple_supertrait_upcastable)]` to the crate attributes to enable
+
+warning: unknown lint: `multiple_supertrait_upcastable`
+  --> $DIR/feature-gate-multiple_supertrait_upcastable.rs:3:1
+   |
+LL | #![deny(multiple_supertrait_upcastable)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `multiple_supertrait_upcastable` lint is unstable
+   = help: add `#![feature(multiple_supertrait_upcastable)]` to the crate attributes to enable
+
+warning: unknown lint: `multiple_supertrait_upcastable`
+  --> $DIR/feature-gate-multiple_supertrait_upcastable.rs:7:1
+   |
+LL | #![warn(multiple_supertrait_upcastable)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `multiple_supertrait_upcastable` lint is unstable
+   = help: add `#![feature(multiple_supertrait_upcastable)]` to the crate attributes to enable
+
+warning: unknown lint: `multiple_supertrait_upcastable`
+  --> $DIR/feature-gate-multiple_supertrait_upcastable.rs:3:1
+   |
+LL | #![deny(multiple_supertrait_upcastable)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `multiple_supertrait_upcastable` lint is unstable
+   = help: add `#![feature(multiple_supertrait_upcastable)]` to the crate attributes to enable
+
+warning: unknown lint: `multiple_supertrait_upcastable`
+  --> $DIR/feature-gate-multiple_supertrait_upcastable.rs:7:1
+   |
+LL | #![warn(multiple_supertrait_upcastable)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `multiple_supertrait_upcastable` lint is unstable
+   = help: add `#![feature(multiple_supertrait_upcastable)]` to the crate attributes to enable
+
+warning: 6 warnings emitted
+
index be321c3c5c08f1279e539132933ba9d391027627..3480a2ec8154806572d6255a4523745a7873f3b0 100644 (file)
@@ -15,7 +15,7 @@ LL |     format!("{:X}", "3");
              NonZeroIsize
            and 21 others
    = note: required for `&str` to implement `UpperHex`
-note: required by a bound in `ArgumentV1::<'a>::new_upper_hex`
+note: required by a bound in `core::fmt::ArgumentV1::<'a>::new_upper_hex`
   --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL
    = note: this error originates in the macro `$crate::__export::format_args` which comes from the expansion of the macro `arg_new` (in Nightly builds, run with -Z macro-backtrace for more info)
 
index 3ed040c3ab35926e91d4d0731b008da25cd2f0e1..d43f4f0d9570b0ce3ffc8c32bd01baf2d887e53a 100644 (file)
@@ -6,11 +6,11 @@ LL |     send(format_args!("{:?}", c));
    |     |
    |     required by a bound introduced by this call
    |
-   = help: within `[ArgumentV1<'_>]`, the trait `Sync` is not implemented for `core::fmt::Opaque`
+   = help: within `[core::fmt::ArgumentV1<'_>]`, the trait `Sync` is not implemented for `core::fmt::Opaque`
    = note: required because it appears within the type `&core::fmt::Opaque`
    = note: required because it appears within the type `ArgumentV1<'_>`
    = note: required because it appears within the type `[ArgumentV1<'_>]`
-   = note: required for `&[ArgumentV1<'_>]` to implement `Send`
+   = note: required for `&[core::fmt::ArgumentV1<'_>]` to implement `Send`
    = note: required because it appears within the type `Arguments<'_>`
 note: required by a bound in `send`
   --> $DIR/send-sync.rs:1:12
diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-match-arrow.rs b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-match-arrow.rs
new file mode 100644 (file)
index 0000000..7ba2b6d
--- /dev/null
@@ -0,0 +1,8 @@
+fn main() {
+    let x = 42;
+    match x {
+        0..=73 => {},
+        74..=> {},   //~ ERROR unexpected `=>` after open range
+                     //~^ ERROR expected one of `=>`, `if`, or `|`, found `>`
+    }
+}
diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-match-arrow.stderr b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-match-arrow.stderr
new file mode 100644 (file)
index 0000000..9ba6d15
--- /dev/null
@@ -0,0 +1,19 @@
+error: unexpected `=>` after open range
+  --> $DIR/half-open-range-pats-inclusive-match-arrow.rs:5:11
+   |
+LL |         74..=> {},
+   |           ^^^
+   |
+help: add a space between the pattern and `=>`
+   |
+LL |         74.. => {},
+   |             +
+
+error: expected one of `=>`, `if`, or `|`, found `>`
+  --> $DIR/half-open-range-pats-inclusive-match-arrow.rs:5:14
+   |
+LL |         74..=> {},
+   |              ^ expected one of `=>`, `if`, or `|`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/mir/mir_codegen_ssa.rs b/tests/ui/mir/mir_codegen_ssa.rs
new file mode 100644 (file)
index 0000000..5e2f10c
--- /dev/null
@@ -0,0 +1,19 @@
+// build-pass
+// compile-flags: --crate-type=lib
+#![feature(custom_mir, core_intrinsics)]
+use std::intrinsics::mir::*;
+
+#[custom_mir(dialect = "runtime", phase = "optimized")]
+pub fn f(a: u32) -> u32 {
+    mir!(
+        let x: u32;
+        {
+            // Previously code generation failed with ICE "use of .. before def ..." because the
+            // definition of x was incorrectly identified as dominating the use of x located in the
+            // same statement:
+            x = x + a;
+            RET = x;
+            Return()
+        }
+    )
+}
diff --git a/tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.fixed b/tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.fixed
new file mode 100644 (file)
index 0000000..0b9a3ba
--- /dev/null
@@ -0,0 +1,11 @@
+// run-rustfix
+use std::pin::Pin;
+
+fn foo(_: &mut ()) {}
+
+fn main() {
+    let mut uwu = ();
+    let mut r = Pin::new(&mut uwu);
+    foo(r.as_mut().get_mut());
+    foo(r.get_mut()); //~ ERROR use of moved value
+}
diff --git a/tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.rs b/tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.rs
new file mode 100644 (file)
index 0000000..0e952b0
--- /dev/null
@@ -0,0 +1,11 @@
+// run-rustfix
+use std::pin::Pin;
+
+fn foo(_: &mut ()) {}
+
+fn main() {
+    let mut uwu = ();
+    let mut r = Pin::new(&mut uwu);
+    foo(r.get_mut());
+    foo(r.get_mut()); //~ ERROR use of moved value
+}
diff --git a/tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.stderr b/tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.stderr
new file mode 100644 (file)
index 0000000..7e513b7
--- /dev/null
@@ -0,0 +1,20 @@
+error[E0382]: use of moved value: `r`
+  --> $DIR/pin-mut-reborrow-infer-var-issue-107419.rs:10:9
+   |
+LL |     let mut r = Pin::new(&mut uwu);
+   |         ----- move occurs because `r` has type `Pin<&mut ()>`, which does not implement the `Copy` trait
+LL |     foo(r.get_mut());
+   |           --------- `r` moved due to this method call
+LL |     foo(r.get_mut());
+   |         ^ value used here after move
+   |
+note: `Pin::<&'a mut T>::get_mut` takes ownership of the receiver `self`, which moves `r`
+  --> $SRC_DIR/core/src/pin.rs:LL:COL
+help: consider reborrowing the `Pin` instead of moving it
+   |
+LL |     foo(r.as_mut().get_mut());
+   |           +++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
index cc04ac052040e30a37be98c8f17be97365dcf820..c41cda18743c81c37c7369a5d315bbf6ce749fae 100644 (file)
@@ -5,6 +5,8 @@ fn foo1(_: &dyn Drop + AsRef<str>) {} //~ ERROR ambiguous `+` in a type
 
 fn foo2(_: &dyn (Drop + AsRef<str>)) {} //~ ERROR incorrect braces around trait bounds
 
+fn foo2_no_space(_: &dyn(Drop + AsRef<str>)) {} //~ ERROR incorrect braces around trait bounds
+
 fn foo3(_: &dyn {Drop + AsRef<str>}) {} //~ ERROR expected parameter name, found `{`
 //~^ ERROR expected one of `!`, `(`, `)`, `*`, `,`, `?`, `for`, `~`, lifetime, or path, found `{`
 //~| ERROR at least one trait is required for an object type
index 99c4515459d2e5166262754634394449e8ad031b..ccce3a8053e703c4e15030c576873eddc0abbb11 100644 (file)
@@ -13,17 +13,29 @@ LL | fn foo2(_: &dyn (Drop + AsRef<str>)) {}
 help: remove the parentheses
    |
 LL - fn foo2(_: &dyn (Drop + AsRef<str>)) {}
-LL + fn foo2(_: &dyn Drop + AsRef<str>) {}
+LL + fn foo2(_: &dyn  Drop + AsRef<str>) {}
+   |
+
+error: incorrect braces around trait bounds
+  --> $DIR/trait-object-delimiters.rs:8:25
+   |
+LL | fn foo2_no_space(_: &dyn(Drop + AsRef<str>)) {}
+   |                         ^                 ^
+   |
+help: remove the parentheses
+   |
+LL - fn foo2_no_space(_: &dyn(Drop + AsRef<str>)) {}
+LL + fn foo2_no_space(_: &dyn Drop + AsRef<str>) {}
    |
 
 error: expected parameter name, found `{`
-  --> $DIR/trait-object-delimiters.rs:8:17
+  --> $DIR/trait-object-delimiters.rs:10:17
    |
 LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {}
    |                 ^ expected parameter name
 
 error: expected one of `!`, `(`, `)`, `*`, `,`, `?`, `for`, `~`, lifetime, or path, found `{`
-  --> $DIR/trait-object-delimiters.rs:8:17
+  --> $DIR/trait-object-delimiters.rs:10:17
    |
 LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {}
    |                -^ expected one of 10 possible tokens
@@ -31,13 +43,13 @@ LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {}
    |                help: missing `,`
 
 error: expected identifier, found `<`
-  --> $DIR/trait-object-delimiters.rs:12:17
+  --> $DIR/trait-object-delimiters.rs:14:17
    |
 LL | fn foo4(_: &dyn <Drop + AsRef<str>>) {}
    |                 ^ expected identifier
 
 error: invalid `dyn` keyword
-  --> $DIR/trait-object-delimiters.rs:14:25
+  --> $DIR/trait-object-delimiters.rs:16:25
    |
 LL | fn foo5(_: &(dyn Drop + dyn AsRef<str>)) {}
    |                         ^^^ help: remove this keyword
@@ -56,13 +68,13 @@ LL | fn foo1(_: &dyn Drop + AsRef<str>) {}
    = 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[E0224]: at least one trait is required for an object type
-  --> $DIR/trait-object-delimiters.rs:8:13
+  --> $DIR/trait-object-delimiters.rs:10:13
    |
 LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {}
    |             ^^^
 
 error[E0225]: only auto traits can be used as additional traits in a trait object
-  --> $DIR/trait-object-delimiters.rs:14:29
+  --> $DIR/trait-object-delimiters.rs:16:29
    |
 LL | fn foo5(_: &(dyn Drop + dyn AsRef<str>)) {}
    |                  ----       ^^^^^^^^^^ additional non-auto trait
@@ -72,7 +84,7 @@ LL | fn foo5(_: &(dyn Drop + dyn AsRef<str>)) {}
    = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Drop + AsRef<str> {}`
    = 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: aborting due to 9 previous errors
+error: aborting due to 10 previous errors
 
 Some errors have detailed explanations: E0224, E0225.
 For more information about an error, try `rustc --explain E0224`.
diff --git a/tests/ui/thir-print/thir-flat.rs b/tests/ui/thir-print/thir-flat.rs
new file mode 100644 (file)
index 0000000..8fa95ce
--- /dev/null
@@ -0,0 +1,4 @@
+// compile-flags: -Z unpretty=thir-flat
+// check-pass
+
+pub fn main() {}
diff --git a/tests/ui/thir-print/thir-flat.stdout b/tests/ui/thir-print/thir-flat.stdout
new file mode 100644 (file)
index 0000000..c399fa6
--- /dev/null
@@ -0,0 +1,56 @@
+DefId(0:3 ~ thir_flat[45a6]::main):
+Thir {
+    arms: [],
+    blocks: [
+        Block {
+            targeted_by_break: false,
+            region_scope: Node(1),
+            opt_destruction_scope: None,
+            span: $DIR/thir-flat.rs:4:15: 4:17 (#0),
+            stmts: [],
+            expr: None,
+            safety_mode: Safe,
+        },
+    ],
+    exprs: [
+        Expr {
+            ty: (),
+            temp_lifetime: Some(
+                Node(2),
+            ),
+            span: $DIR/thir-flat.rs:4:15: 4:17 (#0),
+            kind: Block {
+                block: b0,
+            },
+        },
+        Expr {
+            ty: (),
+            temp_lifetime: Some(
+                Node(2),
+            ),
+            span: $DIR/thir-flat.rs:4:15: 4:17 (#0),
+            kind: Scope {
+                region_scope: Node(2),
+                lint_level: Explicit(
+                    HirId(DefId(0:3 ~ thir_flat[45a6]::main).2),
+                ),
+                value: e0,
+            },
+        },
+        Expr {
+            ty: (),
+            temp_lifetime: Some(
+                Node(2),
+            ),
+            span: $DIR/thir-flat.rs:4:15: 4:17 (#0),
+            kind: Scope {
+                region_scope: Destruction(2),
+                lint_level: Inherited,
+                value: e1,
+            },
+        },
+    ],
+    stmts: [],
+    params: [],
+}
+
diff --git a/tests/ui/thir-print/thir-tree-match.rs b/tests/ui/thir-print/thir-tree-match.rs
new file mode 100644 (file)
index 0000000..a5511ec
--- /dev/null
@@ -0,0 +1,23 @@
+// check-pass
+// compile-flags: -Zunpretty=thir-tree
+
+enum Bar {
+    First,
+    Second,
+    Third,
+}
+
+enum Foo {
+    FooOne(Bar),
+    FooTwo,
+}
+
+fn has_match(foo: Foo) -> bool {
+    match foo {
+        Foo::FooOne(Bar::First) => true,
+        Foo::FooOne(_) => false,
+        Foo::FooTwo => true,
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/thir-print/thir-tree-match.stdout b/tests/ui/thir-print/thir-tree-match.stdout
new file mode 100644 (file)
index 0000000..d6174ec
--- /dev/null
@@ -0,0 +1,342 @@
+DefId(0:16 ~ thir_tree_match[3c9a]::has_match):
+params: [
+    Param {
+        ty: Foo
+        ty_span: Some($DIR/thir-tree-match.rs:15:19: 15:22 (#0))
+        self_kind: None
+        hir_id: Some(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).1))
+        param: Some( 
+            Pat: {
+                ty: Foo
+                span: $DIR/thir-tree-match.rs:15:14: 15:17 (#0)
+                kind: PatKind {
+                    Binding {
+                        mutability: Not
+                        name: "foo"
+                        mode: ByValue
+                        var: LocalVarId(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).2))
+                        ty: Foo
+                        is_primary: true
+                        subpattern: None
+                    }
+                }
+            }
+        )
+    }
+]
+body:
+    Expr {
+        ty: bool
+        temp_lifetime: Some(Node(26))
+        span: $DIR/thir-tree-match.rs:15:32: 21:2 (#0)
+        kind: 
+            Scope {
+                region_scope: Destruction(26)
+                lint_level: Inherited
+                value:
+                    Expr {
+                        ty: bool
+                        temp_lifetime: Some(Node(26))
+                        span: $DIR/thir-tree-match.rs:15:32: 21:2 (#0)
+                        kind: 
+                            Scope {
+                                region_scope: Node(26)
+                                lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).26))
+                                value:
+                                    Expr {
+                                        ty: bool
+                                        temp_lifetime: Some(Node(26))
+                                        span: $DIR/thir-tree-match.rs:15:32: 21:2 (#0)
+                                        kind: 
+                                            Block {
+                                                targeted_by_break: false
+                                                opt_destruction_scope: None
+                                                span: $DIR/thir-tree-match.rs:15:32: 21:2 (#0)
+                                                region_scope: Node(25)
+                                                safety_mode: Safe
+                                                stmts: []
+                                                expr:
+                                                    Expr {
+                                                        ty: bool
+                                                        temp_lifetime: Some(Node(26))
+                                                        span: $DIR/thir-tree-match.rs:16:5: 20:6 (#0)
+                                                        kind: 
+                                                            Scope {
+                                                                region_scope: Node(3)
+                                                                lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).3))
+                                                                value:
+                                                                    Expr {
+                                                                        ty: bool
+                                                                        temp_lifetime: Some(Node(26))
+                                                                        span: $DIR/thir-tree-match.rs:16:5: 20:6 (#0)
+                                                                        kind: 
+                                                                            Match {
+                                                                                scrutinee:
+                                                                                    Expr {
+                                                                                        ty: Foo
+                                                                                        temp_lifetime: Some(Node(26))
+                                                                                        span: $DIR/thir-tree-match.rs:16:11: 16:14 (#0)
+                                                                                        kind: 
+                                                                                            Scope {
+                                                                                                region_scope: Node(4)
+                                                                                                lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).4))
+                                                                                                value:
+                                                                                                    Expr {
+                                                                                                        ty: Foo
+                                                                                                        temp_lifetime: Some(Node(26))
+                                                                                                        span: $DIR/thir-tree-match.rs:16:11: 16:14 (#0)
+                                                                                                        kind: 
+                                                                                                            VarRef {
+                                                                                                                id: LocalVarId(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).2))
+                                                                                                            }
+                                                                                                    }
+                                                                                            }
+                                                                                    }
+                                                                                arms: [
+                                                                                    Arm {
+                                                                                        pattern: 
+                                                                                            Pat: {
+                                                                                                ty: Foo
+                                                                                                span: $DIR/thir-tree-match.rs:17:9: 17:32 (#0)
+                                                                                                kind: PatKind {
+                                                                                                    Variant {
+                                                                                                        adt_def: 
+                                                                                                            AdtDef {
+                                                                                                                did: DefId(0:10 ~ thir_tree_match[3c9a]::Foo)
+                                                                                                                variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[3c9a]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[3c9a]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[3c9a]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[3c9a])) }], flags: NO_VARIANT_FLAGS }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[3c9a]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[3c9a]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], flags: NO_VARIANT_FLAGS }]
+                                                                                                                flags: IS_ENUM
+                                                                                                                repr: ReprOptions { int: None, align: None, pack: None, flags: (empty), field_shuffle_seed: 11573694388057581 }
+                                                                                                        substs: []
+                                                                                                        variant_index: 0
+                                                                                                        subpatterns: [
+                                                                                                            Pat: {
+                                                                                                                ty: Bar
+                                                                                                                span: $DIR/thir-tree-match.rs:17:21: 17:31 (#0)
+                                                                                                                kind: PatKind {
+                                                                                                                    Variant {
+                                                                                                                        adt_def: 
+                                                                                                                            AdtDef {
+                                                                                                                                did: DefId(0:3 ~ thir_tree_match[3c9a]::Bar)
+                                                                                                                                variants: [VariantDef { def_id: DefId(0:4 ~ thir_tree_match[3c9a]::Bar::First), ctor: Some((Const, DefId(0:5 ~ thir_tree_match[3c9a]::Bar::First::{constructor#0}))), name: "First", discr: Relative(0), fields: [], flags: NO_VARIANT_FLAGS }, VariantDef { def_id: DefId(0:6 ~ thir_tree_match[3c9a]::Bar::Second), ctor: Some((Const, DefId(0:7 ~ thir_tree_match[3c9a]::Bar::Second::{constructor#0}))), name: "Second", discr: Relative(1), fields: [], flags: NO_VARIANT_FLAGS }, VariantDef { def_id: DefId(0:8 ~ thir_tree_match[3c9a]::Bar::Third), ctor: Some((Const, DefId(0:9 ~ thir_tree_match[3c9a]::Bar::Third::{constructor#0}))), name: "Third", discr: Relative(2), fields: [], flags: NO_VARIANT_FLAGS }]
+                                                                                                                                flags: IS_ENUM
+                                                                                                                                repr: ReprOptions { int: None, align: None, pack: None, flags: (empty), field_shuffle_seed: 3125160937860410723 }
+                                                                                                                        substs: []
+                                                                                                                        variant_index: 0
+                                                                                                                        subpatterns: []
+                                                                                                                    }
+                                                                                                                }
+                                                                                                            }
+                                                                                                        ]
+                                                                                                    }
+                                                                                                }
+                                                                                            }
+                                                                                        guard: None
+                                                                                        body: 
+                                                                                            Expr {
+                                                                                                ty: bool
+                                                                                                temp_lifetime: Some(Node(13))
+                                                                                                span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0)
+                                                                                                kind: 
+                                                                                                    Scope {
+                                                                                                        region_scope: Destruction(13)
+                                                                                                        lint_level: Inherited
+                                                                                                        value:
+                                                                                                            Expr {
+                                                                                                                ty: bool
+                                                                                                                temp_lifetime: Some(Node(13))
+                                                                                                                span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0)
+                                                                                                                kind: 
+                                                                                                                    Scope {
+                                                                                                                        region_scope: Node(13)
+                                                                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).13))
+                                                                                                                        value:
+                                                                                                                            Expr {
+                                                                                                                                ty: bool
+                                                                                                                                temp_lifetime: Some(Node(13))
+                                                                                                                                span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0)
+                                                                                                                                kind: 
+                                                                                                                                    Literal( lit: Spanned { node: Bool(true), span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0) }, neg: false)
+
+                                                                                                                            }
+                                                                                                                    }
+                                                                                                            }
+                                                                                                    }
+                                                                                            }
+                                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).12))
+                                                                                        scope: Node(12)
+                                                                                        span: $DIR/thir-tree-match.rs:17:9: 17:40 (#0)
+                                                                                    }
+                                                                                    Arm {
+                                                                                        pattern: 
+                                                                                            Pat: {
+                                                                                                ty: Foo
+                                                                                                span: $DIR/thir-tree-match.rs:18:9: 18:23 (#0)
+                                                                                                kind: PatKind {
+                                                                                                    Variant {
+                                                                                                        adt_def: 
+                                                                                                            AdtDef {
+                                                                                                                did: DefId(0:10 ~ thir_tree_match[3c9a]::Foo)
+                                                                                                                variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[3c9a]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[3c9a]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[3c9a]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[3c9a])) }], flags: NO_VARIANT_FLAGS }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[3c9a]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[3c9a]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], flags: NO_VARIANT_FLAGS }]
+                                                                                                                flags: IS_ENUM
+                                                                                                                repr: ReprOptions { int: None, align: None, pack: None, flags: (empty), field_shuffle_seed: 11573694388057581 }
+                                                                                                        substs: []
+                                                                                                        variant_index: 0
+                                                                                                        subpatterns: [
+                                                                                                            Pat: {
+                                                                                                                ty: Bar
+                                                                                                                span: $DIR/thir-tree-match.rs:18:21: 18:22 (#0)
+                                                                                                                kind: PatKind {
+                                                                                                                    Wild
+                                                                                                                }
+                                                                                                            }
+                                                                                                        ]
+                                                                                                    }
+                                                                                                }
+                                                                                            }
+                                                                                        guard: None
+                                                                                        body: 
+                                                                                            Expr {
+                                                                                                ty: bool
+                                                                                                temp_lifetime: Some(Node(19))
+                                                                                                span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0)
+                                                                                                kind: 
+                                                                                                    Scope {
+                                                                                                        region_scope: Destruction(19)
+                                                                                                        lint_level: Inherited
+                                                                                                        value:
+                                                                                                            Expr {
+                                                                                                                ty: bool
+                                                                                                                temp_lifetime: Some(Node(19))
+                                                                                                                span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0)
+                                                                                                                kind: 
+                                                                                                                    Scope {
+                                                                                                                        region_scope: Node(19)
+                                                                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).19))
+                                                                                                                        value:
+                                                                                                                            Expr {
+                                                                                                                                ty: bool
+                                                                                                                                temp_lifetime: Some(Node(19))
+                                                                                                                                span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0)
+                                                                                                                                kind: 
+                                                                                                                                    Literal( lit: Spanned { node: Bool(false), span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0) }, neg: false)
+
+                                                                                                                            }
+                                                                                                                    }
+                                                                                                            }
+                                                                                                    }
+                                                                                            }
+                                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).18))
+                                                                                        scope: Node(18)
+                                                                                        span: $DIR/thir-tree-match.rs:18:9: 18:32 (#0)
+                                                                                    }
+                                                                                    Arm {
+                                                                                        pattern: 
+                                                                                            Pat: {
+                                                                                                ty: Foo
+                                                                                                span: $DIR/thir-tree-match.rs:19:9: 19:20 (#0)
+                                                                                                kind: PatKind {
+                                                                                                    Variant {
+                                                                                                        adt_def: 
+                                                                                                            AdtDef {
+                                                                                                                did: DefId(0:10 ~ thir_tree_match[3c9a]::Foo)
+                                                                                                                variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[3c9a]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[3c9a]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[3c9a]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[3c9a])) }], flags: NO_VARIANT_FLAGS }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[3c9a]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[3c9a]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], flags: NO_VARIANT_FLAGS }]
+                                                                                                                flags: IS_ENUM
+                                                                                                                repr: ReprOptions { int: None, align: None, pack: None, flags: (empty), field_shuffle_seed: 11573694388057581 }
+                                                                                                        substs: []
+                                                                                                        variant_index: 1
+                                                                                                        subpatterns: []
+                                                                                                    }
+                                                                                                }
+                                                                                            }
+                                                                                        guard: None
+                                                                                        body: 
+                                                                                            Expr {
+                                                                                                ty: bool
+                                                                                                temp_lifetime: Some(Node(24))
+                                                                                                span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0)
+                                                                                                kind: 
+                                                                                                    Scope {
+                                                                                                        region_scope: Destruction(24)
+                                                                                                        lint_level: Inherited
+                                                                                                        value:
+                                                                                                            Expr {
+                                                                                                                ty: bool
+                                                                                                                temp_lifetime: Some(Node(24))
+                                                                                                                span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0)
+                                                                                                                kind: 
+                                                                                                                    Scope {
+                                                                                                                        region_scope: Node(24)
+                                                                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).24))
+                                                                                                                        value:
+                                                                                                                            Expr {
+                                                                                                                                ty: bool
+                                                                                                                                temp_lifetime: Some(Node(24))
+                                                                                                                                span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0)
+                                                                                                                                kind: 
+                                                                                                                                    Literal( lit: Spanned { node: Bool(true), span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0) }, neg: false)
+
+                                                                                                                            }
+                                                                                                                    }
+                                                                                                            }
+                                                                                                    }
+                                                                                            }
+                                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).23))
+                                                                                        scope: Node(23)
+                                                                                        span: $DIR/thir-tree-match.rs:19:9: 19:28 (#0)
+                                                                                    }
+                                                                                ]
+                                                                            }
+                                                                    }
+                                                            }
+                                                    }
+                                            }
+                                    }
+                            }
+                    }
+            }
+    }
+
+
+DefId(0:17 ~ thir_tree_match[3c9a]::main):
+params: [
+]
+body:
+    Expr {
+        ty: ()
+        temp_lifetime: Some(Node(2))
+        span: $DIR/thir-tree-match.rs:23:11: 23:13 (#0)
+        kind: 
+            Scope {
+                region_scope: Destruction(2)
+                lint_level: Inherited
+                value:
+                    Expr {
+                        ty: ()
+                        temp_lifetime: Some(Node(2))
+                        span: $DIR/thir-tree-match.rs:23:11: 23:13 (#0)
+                        kind: 
+                            Scope {
+                                region_scope: Node(2)
+                                lint_level: Explicit(HirId(DefId(0:17 ~ thir_tree_match[3c9a]::main).2))
+                                value:
+                                    Expr {
+                                        ty: ()
+                                        temp_lifetime: Some(Node(2))
+                                        span: $DIR/thir-tree-match.rs:23:11: 23:13 (#0)
+                                        kind: 
+                                            Block {
+                                                targeted_by_break: false
+                                                opt_destruction_scope: None
+                                                span: $DIR/thir-tree-match.rs:23:11: 23:13 (#0)
+                                                region_scope: Node(1)
+                                                safety_mode: Safe
+                                                stmts: []
+                                                expr: []
+                                            }
+                                    }
+                            }
+                    }
+            }
+    }
+
+
diff --git a/tests/ui/thir-print/thir-tree.rs b/tests/ui/thir-print/thir-tree.rs
new file mode 100644 (file)
index 0000000..32df790
--- /dev/null
@@ -0,0 +1,4 @@
+// compile-flags: -Z unpretty=thir-tree
+// check-pass
+
+pub fn main() {}
diff --git a/tests/ui/thir-print/thir-tree.stdout b/tests/ui/thir-print/thir-tree.stdout
new file mode 100644 (file)
index 0000000..0a35d9f
--- /dev/null
@@ -0,0 +1,43 @@
+DefId(0:3 ~ thir_tree[8f1d]::main):
+params: [
+]
+body:
+    Expr {
+        ty: ()
+        temp_lifetime: Some(Node(2))
+        span: $DIR/thir-tree.rs:4:15: 4:17 (#0)
+        kind: 
+            Scope {
+                region_scope: Destruction(2)
+                lint_level: Inherited
+                value:
+                    Expr {
+                        ty: ()
+                        temp_lifetime: Some(Node(2))
+                        span: $DIR/thir-tree.rs:4:15: 4:17 (#0)
+                        kind: 
+                            Scope {
+                                region_scope: Node(2)
+                                lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree[8f1d]::main).2))
+                                value:
+                                    Expr {
+                                        ty: ()
+                                        temp_lifetime: Some(Node(2))
+                                        span: $DIR/thir-tree.rs:4:15: 4:17 (#0)
+                                        kind: 
+                                            Block {
+                                                targeted_by_break: false
+                                                opt_destruction_scope: None
+                                                span: $DIR/thir-tree.rs:4:15: 4:17 (#0)
+                                                region_scope: Node(1)
+                                                safety_mode: Safe
+                                                stmts: []
+                                                expr: []
+                                            }
+                                    }
+                            }
+                    }
+            }
+    }
+
+
diff --git a/tests/ui/thir-tree.rs b/tests/ui/thir-tree.rs
deleted file mode 100644 (file)
index 32df790..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-// compile-flags: -Z unpretty=thir-tree
-// check-pass
-
-pub fn main() {}
diff --git a/tests/ui/thir-tree.stdout b/tests/ui/thir-tree.stdout
deleted file mode 100644 (file)
index 4b6915f..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-DefId(0:3 ~ thir_tree[8f1d]::main):
-Thir {
-    arms: [],
-    blocks: [
-        Block {
-            targeted_by_break: false,
-            region_scope: Node(1),
-            opt_destruction_scope: None,
-            span: $DIR/thir-tree.rs:4:15: 4:17 (#0),
-            stmts: [],
-            expr: None,
-            safety_mode: Safe,
-        },
-    ],
-    exprs: [
-        Expr {
-            ty: (),
-            temp_lifetime: Some(
-                Node(2),
-            ),
-            span: $DIR/thir-tree.rs:4:15: 4:17 (#0),
-            kind: Block {
-                block: b0,
-            },
-        },
-        Expr {
-            ty: (),
-            temp_lifetime: Some(
-                Node(2),
-            ),
-            span: $DIR/thir-tree.rs:4:15: 4:17 (#0),
-            kind: Scope {
-                region_scope: Node(2),
-                lint_level: Explicit(
-                    HirId(DefId(0:3 ~ thir_tree[8f1d]::main).2),
-                ),
-                value: e0,
-            },
-        },
-        Expr {
-            ty: (),
-            temp_lifetime: Some(
-                Node(2),
-            ),
-            span: $DIR/thir-tree.rs:4:15: 4:17 (#0),
-            kind: Scope {
-                region_scope: Destruction(2),
-                lint_level: Inherited,
-                value: e1,
-            },
-        },
-    ],
-    stmts: [],
-    params: [],
-}
-
diff --git a/tests/ui/traits/trait-upcasting/multiple_supertrait_upcastable.rs b/tests/ui/traits/trait-upcasting/multiple_supertrait_upcastable.rs
new file mode 100644 (file)
index 0000000..3c6ab86
--- /dev/null
@@ -0,0 +1,10 @@
+#![feature(multiple_supertrait_upcastable)]
+#![deny(multiple_supertrait_upcastable)]
+
+trait A {}
+trait B {}
+
+trait C: A + B {}
+//~^ ERROR `C` is object-safe and has multiple supertraits
+
+fn main() {}
diff --git a/tests/ui/traits/trait-upcasting/multiple_supertrait_upcastable.stderr b/tests/ui/traits/trait-upcasting/multiple_supertrait_upcastable.stderr
new file mode 100644 (file)
index 0000000..ad80a00
--- /dev/null
@@ -0,0 +1,14 @@
+error: `C` is object-safe and has multiple supertraits
+  --> $DIR/multiple_supertrait_upcastable.rs:7:1
+   |
+LL | trait C: A + B {}
+   | ^^^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/multiple_supertrait_upcastable.rs:2:9
+   |
+LL | #![deny(multiple_supertrait_upcastable)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+