]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #104334 - compiler-errors:ufcs-sugg-wrong-def-id, r=estebank
authorbors <bors@rust-lang.org>
Fri, 16 Dec 2022 03:57:10 +0000 (03:57 +0000)
committerbors <bors@rust-lang.org>
Fri, 16 Dec 2022 03:57:10 +0000 (03:57 +0000)
Use impl's def id when calculating type to specify in UFCS

Fixes #104327
Fixes #104328

Also addresses https://github.com/rust-lang/rust/pull/102670#discussion_r987381197

303 files changed:
compiler/rustc_ast/src/ast.rs
compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
compiler/rustc_borrowck/src/diagnostics/region_errors.rs
compiler/rustc_borrowck/src/region_infer/mod.rs
compiler/rustc_codegen_cranelift/.cirrus.yml
compiler/rustc_codegen_cranelift/.github/workflows/main.yml
compiler/rustc_codegen_cranelift/.github/workflows/nightly-cranelift.yml
compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml
compiler/rustc_codegen_cranelift/.gitignore
compiler/rustc_codegen_cranelift/.vscode/settings.json
compiler/rustc_codegen_cranelift/Cargo.lock
compiler/rustc_codegen_cranelift/Cargo.toml
compiler/rustc_codegen_cranelift/Readme.md
compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock
compiler/rustc_codegen_cranelift/build_system/abi_cafe.rs
compiler/rustc_codegen_cranelift/build_system/build_backend.rs
compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs
compiler/rustc_codegen_cranelift/build_system/mod.rs
compiler/rustc_codegen_cranelift/build_system/path.rs [new file with mode: 0644]
compiler/rustc_codegen_cranelift/build_system/prepare.rs
compiler/rustc_codegen_cranelift/build_system/rustc_info.rs
compiler/rustc_codegen_cranelift/build_system/tests.rs
compiler/rustc_codegen_cranelift/build_system/utils.rs
compiler/rustc_codegen_cranelift/clean_all.sh
compiler/rustc_codegen_cranelift/config.txt
compiler/rustc_codegen_cranelift/docs/usage.md
compiler/rustc_codegen_cranelift/example/issue-72793.rs [new file with mode: 0644]
compiler/rustc_codegen_cranelift/example/mini_core.rs
compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
compiler/rustc_codegen_cranelift/example/std_example.rs
compiler/rustc_codegen_cranelift/rust-toolchain
compiler/rustc_codegen_cranelift/rustfmt.toml
compiler/rustc_codegen_cranelift/scripts/filter_profile.rs
compiler/rustc_codegen_cranelift/scripts/rustdoc-clif.rs [new file with mode: 0644]
compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh
compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
compiler/rustc_codegen_cranelift/src/abi/mod.rs
compiler/rustc_codegen_cranelift/src/allocator.rs
compiler/rustc_codegen_cranelift/src/base.rs
compiler/rustc_codegen_cranelift/src/cast.rs
compiler/rustc_codegen_cranelift/src/common.rs
compiler/rustc_codegen_cranelift/src/constant.rs
compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs
compiler/rustc_codegen_cranelift/src/discriminant.rs
compiler/rustc_codegen_cranelift/src/driver/jit.rs
compiler/rustc_codegen_cranelift/src/driver/mod.rs
compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs
compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs [new file with mode: 0644]
compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs [new file with mode: 0644]
compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
compiler/rustc_codegen_cranelift/src/main_shim.rs
compiler/rustc_codegen_cranelift/src/num.rs
compiler/rustc_codegen_cranelift/src/optimize/peephole.rs
compiler/rustc_codegen_cranelift/src/value_and_place.rs
compiler/rustc_codegen_cranelift/test.sh
compiler/rustc_codegen_cranelift/y.rs
compiler/rustc_codegen_ssa/src/mir/block.rs
compiler/rustc_const_eval/src/const_eval/error.rs
compiler/rustc_const_eval/src/const_eval/eval_queries.rs
compiler/rustc_const_eval/src/const_eval/machine.rs
compiler/rustc_const_eval/src/interpret/eval_context.rs
compiler/rustc_const_eval/src/interpret/machine.rs
compiler/rustc_const_eval/src/interpret/memory.rs
compiler/rustc_const_eval/src/interpret/place.rs
compiler/rustc_const_eval/src/transform/validate.rs
compiler/rustc_const_eval/src/util/might_permit_raw_init.rs
compiler/rustc_const_eval/src/util/type_name.rs
compiler/rustc_data_structures/src/sorted_map.rs
compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl
compiler/rustc_error_messages/locales/en-US/monomorphize.ftl
compiler/rustc_errors/src/emitter.rs
compiler/rustc_errors/src/lib.rs
compiler/rustc_hir_analysis/src/astconv/mod.rs
compiler/rustc_hir_analysis/src/check/check.rs
compiler/rustc_hir_analysis/src/check/compare_method.rs
compiler/rustc_hir_analysis/src/errors.rs
compiler/rustc_hir_analysis/src/variance/mod.rs
compiler/rustc_hir_pretty/src/lib.rs
compiler/rustc_hir_typeck/src/_match.rs
compiler/rustc_hir_typeck/src/closure.rs
compiler/rustc_hir_typeck/src/coercion.rs
compiler/rustc_hir_typeck/src/expr.rs
compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
compiler/rustc_hir_typeck/src/generator_interior/mod.rs
compiler/rustc_hir_typeck/src/method/mod.rs
compiler/rustc_hir_typeck/src/method/probe.rs
compiler/rustc_hir_typeck/src/method/suggest.rs
compiler/rustc_hir_typeck/src/writeback.rs
compiler/rustc_infer/src/errors/mod.rs
compiler/rustc_infer/src/infer/combine.rs
compiler/rustc_infer/src/infer/equate.rs
compiler/rustc_infer/src/infer/error_reporting/mod.rs
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs
compiler/rustc_infer/src/infer/error_reporting/suggest.rs
compiler/rustc_infer/src/infer/lattice.rs
compiler/rustc_infer/src/infer/nll_relate/mod.rs
compiler/rustc_infer/src/infer/opaque_types.rs
compiler/rustc_infer/src/infer/outlives/components.rs
compiler/rustc_infer/src/infer/outlives/obligations.rs
compiler/rustc_infer/src/infer/sub.rs
compiler/rustc_lint/src/context.rs
compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
compiler/rustc_lint/src/unused.rs
compiler/rustc_lint_defs/src/builtin.rs
compiler/rustc_macros/src/diagnostics/diagnostic.rs
compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
compiler/rustc_middle/src/mir/mod.rs
compiler/rustc_middle/src/mir/mono.rs
compiler/rustc_middle/src/ty/adjustment.rs
compiler/rustc_middle/src/ty/context.rs
compiler/rustc_middle/src/ty/diagnostics.rs
compiler/rustc_middle/src/ty/error.rs
compiler/rustc_middle/src/ty/fast_reject.rs
compiler/rustc_middle/src/ty/flags.rs
compiler/rustc_middle/src/ty/mod.rs
compiler/rustc_middle/src/ty/parameterized.rs
compiler/rustc_middle/src/ty/print/mod.rs
compiler/rustc_middle/src/ty/print/pretty.rs
compiler/rustc_middle/src/ty/relate.rs
compiler/rustc_middle/src/ty/sty.rs
compiler/rustc_middle/src/ty/typeck_results.rs [new file with mode: 0644]
compiler/rustc_middle/src/ty/util.rs
compiler/rustc_mir_build/src/build/custom/mod.rs
compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
compiler/rustc_mir_build/src/build/matches/test.rs
compiler/rustc_mir_dataflow/src/elaborate_drops.rs
compiler/rustc_mir_transform/src/check_unsafety.rs
compiler/rustc_mir_transform/src/const_prop.rs
compiler/rustc_mir_transform/src/dataflow_const_prop.rs
compiler/rustc_mir_transform/src/dest_prop.rs
compiler/rustc_mir_transform/src/inline.rs
compiler/rustc_mir_transform/src/shim.rs
compiler/rustc_monomorphize/src/errors.rs
compiler/rustc_monomorphize/src/partitioning/mod.rs
compiler/rustc_privacy/src/lib.rs
compiler/rustc_query_system/src/error.rs
compiler/rustc_session/src/config.rs
compiler/rustc_session/src/errors.rs
compiler/rustc_session/src/options.rs
compiler/rustc_span/src/analyze_source_file.rs
compiler/rustc_span/src/lib.rs
compiler/rustc_span/src/source_map.rs
compiler/rustc_symbol_mangling/src/legacy.rs
compiler/rustc_symbol_mangling/src/v0.rs
compiler/rustc_target/src/spec/apple_base.rs
compiler/rustc_target/src/spec/powerpc64_ibm_aix.rs
compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs
compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
compiler/rustc_trait_selection/src/traits/mod.rs
compiler/rustc_trait_selection/src/traits/object_safety.rs
compiler/rustc_trait_selection/src/traits/project.rs
compiler/rustc_trait_selection/src/traits/query/normalize.rs
compiler/rustc_trait_selection/src/traits/relationships.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_trait_selection/src/traits/wf.rs
compiler/rustc_traits/src/chalk/db.rs
compiler/rustc_traits/src/chalk/lowering.rs
compiler/rustc_ty_utils/src/layout.rs
compiler/rustc_type_ir/src/sty.rs
library/core/src/intrinsics/mir.rs
library/std/src/sys/unix/fs.rs
library/std/src/sys/unix/kernel_copy.rs
library/std/src/sys/unix/mod.rs
library/std/src/sys/unix/process/process_unix.rs
library/std/src/sys/unix/stack_overflow.rs
library/std/src/sys/unix/thread.rs
src/bootstrap/cache.rs
src/librustdoc/clean/inline.rs
src/librustdoc/clean/mod.rs
src/librustdoc/clean/types.rs
src/librustdoc/html/markdown.rs
src/librustdoc/html/static/css/rustdoc.css
src/librustdoc/html/static/css/themes/ayu.css
src/librustdoc/html/static/css/themes/dark.css
src/librustdoc/html/static/css/themes/light.css
src/test/codegen/avr/avr-func-addrspace.rs
src/test/mir-opt/building/custom/enums.rs [new file with mode: 0644]
src/test/mir-opt/building/custom/enums.set_discr.built.after.mir [new file with mode: 0644]
src/test/mir-opt/building/custom/enums.set_discr_repr.built.after.mir [new file with mode: 0644]
src/test/mir-opt/building/custom/enums.switch_bool.built.after.mir [new file with mode: 0644]
src/test/mir-opt/building/custom/enums.switch_option.built.after.mir [new file with mode: 0644]
src/test/mir-opt/building/custom/enums.switch_option_repr.built.after.mir [new file with mode: 0644]
src/test/mir-opt/building/custom/projections.rs [new file with mode: 0644]
src/test/mir-opt/building/custom/projections.set.built.after.mir [new file with mode: 0644]
src/test/mir-opt/building/custom/projections.simple_index.built.after.mir [new file with mode: 0644]
src/test/mir-opt/building/custom/projections.tuples.built.after.mir [new file with mode: 0644]
src/test/mir-opt/building/custom/projections.unions.built.after.mir [new file with mode: 0644]
src/test/mir-opt/building/custom/projections.unwrap.built.after.mir [new file with mode: 0644]
src/test/mir-opt/building/custom/projections.unwrap_deref.built.after.mir [new file with mode: 0644]
src/test/mir-opt/building/custom/references.raw_pointer.built.after.mir [new file with mode: 0644]
src/test/mir-opt/building/custom/references.rs
src/test/rustdoc-gui/help-page.goml
src/test/rustdoc-ui/z-help.stdout
src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs
src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
src/test/ui/argument-suggestions/display-is-suggestable.rs [new file with mode: 0644]
src/test/ui/argument-suggestions/display-is-suggestable.stderr [new file with mode: 0644]
src/test/ui/associated-type-bounds/const-projection-err.gce.stderr [new file with mode: 0644]
src/test/ui/associated-type-bounds/const-projection-err.rs [new file with mode: 0644]
src/test/ui/associated-type-bounds/const-projection-err.stock.stderr [new file with mode: 0644]
src/test/ui/associated-types/associated-types-overridden-binding-2.rs
src/test/ui/associated-types/associated-types-overridden-binding-2.stderr
src/test/ui/async-await/in-trait/async-example-desugared-boxed.rs
src/test/ui/async-await/in-trait/async-example-desugared-boxed.stderr [new file with mode: 0644]
src/test/ui/async-await/in-trait/async-example-desugared-extra.rs [new file with mode: 0644]
src/test/ui/async-await/in-trait/async-example-desugared-manual.rs [new file with mode: 0644]
src/test/ui/async-await/in-trait/async-example-desugared-manual.stderr [new file with mode: 0644]
src/test/ui/async-await/in-trait/async-example-desugared.rs
src/test/ui/async-await/in-trait/fn-not-async-err.rs
src/test/ui/async-await/in-trait/fn-not-async-err.stderr
src/test/ui/async-await/in-trait/fn-not-async-err2.rs
src/test/ui/async-await/in-trait/issue-104678.rs [new file with mode: 0644]
src/test/ui/borrowck/issue-104639-lifetime-order.rs [new file with mode: 0644]
src/test/ui/confuse-field-and-method/issue-33784.stderr
src/test/ui/const-generics/generic_const_exprs/issue-72787.min.stderr
src/test/ui/const-generics/issue-105689.rs [new file with mode: 0644]
src/test/ui/const-ptr/forbidden_slices.32bit.stderr
src/test/ui/const-ptr/forbidden_slices.64bit.stderr
src/test/ui/const-ptr/forbidden_slices.rs
src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr
src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr
src/test/ui/consts/const-eval/ub-ref-ptr.rs
src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr
src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr
src/test/ui/consts/const-eval/ub-wide-ptr.rs
src/test/ui/consts/copy-intrinsic.rs
src/test/ui/consts/extra-const-ub/detect-extra-ub.rs
src/test/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr
src/test/ui/empty/empty-struct-braces-expr.stderr
src/test/ui/feature-gates/feature-gate-unsized_fn_params.rs
src/test/ui/feature-gates/feature-gate-unsized_fn_params.stderr
src/test/ui/feature-gates/feature-gate-unsized_locals.stderr
src/test/ui/functions-closures/fn-help-with-err.stderr
src/test/ui/higher-rank-trait-bounds/issue-30786.stderr
src/test/ui/higher-rank-trait-bounds/issue-62203-hrtb-ice.stderr
src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr
src/test/ui/impl-trait/no-method-suggested-traits.stderr
src/test/ui/issues/issue-105330.stderr
src/test/ui/issues/issue-18107.stderr
src/test/ui/issues/issue-21974.stderr
src/test/ui/issues/issue-24424.stderr
src/test/ui/issues/issue-30123.stderr
src/test/ui/issues/issue-31173.stderr
src/test/ui/issues/issue-33941.rs
src/test/ui/issues/issue-33941.stderr
src/test/ui/issues/issue-41880.stderr
src/test/ui/issues/issue-42312.stderr
src/test/ui/issues/issue-5883.stderr
src/test/ui/iterators/invalid-iterator-chain.rs
src/test/ui/iterators/invalid-iterator-chain.stderr
src/test/ui/lifetimes/conflicting-bounds.rs [new file with mode: 0644]
src/test/ui/lifetimes/conflicting-bounds.stderr [new file with mode: 0644]
src/test/ui/lifetimes/issue-34979.stderr
src/test/ui/methods/method-not-found-generic-arg-elision.stderr
src/test/ui/mismatched_types/issue-36053-2.stderr
src/test/ui/never_type/fallback-closure-wrap.fallback.stderr
src/test/ui/print_type_sizes/async.rs
src/test/ui/print_type_sizes/async.stdout
src/test/ui/print_type_sizes/generator.rs
src/test/ui/print_type_sizes/generator_discr_placement.rs [new file with mode: 0644]
src/test/ui/print_type_sizes/generator_discr_placement.stdout [new file with mode: 0644]
src/test/ui/print_type_sizes/generics.rs
src/test/ui/print_type_sizes/multiple_types.rs
src/test/ui/print_type_sizes/niche-filling.rs
src/test/ui/print_type_sizes/no_duplicates.rs
src/test/ui/print_type_sizes/packed.rs
src/test/ui/print_type_sizes/padding.rs
src/test/ui/print_type_sizes/repr-align.rs
src/test/ui/print_type_sizes/repr_int_c.rs
src/test/ui/print_type_sizes/uninhabited.rs
src/test/ui/print_type_sizes/variants.rs
src/test/ui/print_type_sizes/zero-sized-fields.rs
src/test/ui/resolve/issue-5035-2.stderr
src/test/ui/suggestions/clone-on-unconstrained-borrowed-type-param.fixed [new file with mode: 0644]
src/test/ui/suggestions/clone-on-unconstrained-borrowed-type-param.rs [new file with mode: 0644]
src/test/ui/suggestions/clone-on-unconstrained-borrowed-type-param.stderr [new file with mode: 0644]
src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr
src/test/ui/traits/assoc-type-in-superbad.rs
src/test/ui/traits/assoc-type-in-superbad.stderr
src/test/ui/traits/bound/not-on-bare-trait.stderr
src/test/ui/traits/issue-85735.stderr
src/test/ui/type-alias-impl-trait/issue-57961.rs
src/test/ui/type-alias-impl-trait/issue-57961.stderr
src/test/ui/type/type-check/issue-40294.stderr
src/test/ui/typeck/explain_clone_autoref.stderr
src/test/ui/typeck/issue-92481.rs [new file with mode: 0644]
src/test/ui/typeck/issue-92481.stderr [new file with mode: 0644]
src/test/ui/unboxed-closures/unboxed-closures-static-call-wrong-trait.stderr
src/tools/cargo
src/tools/clippy/clippy_lints/src/derive.rs
src/tools/clippy/clippy_lints/src/future_not_send.rs
src/tools/clippy/clippy_utils/src/lib.rs
src/tools/clippy/clippy_utils/src/ty.rs
src/tools/miri/src/machine.rs
src/tools/tidy/src/deps.rs
triagebot.toml

index 2e86970bcfdc7d1ae84ff14adb70cd2bd9a26311..f933b9b161ca91f56bfb0db9e3f39eaae37e4d54 100644 (file)
@@ -2466,7 +2466,7 @@ pub enum ModKind {
     Unloaded,
 }
 
-#[derive(Copy, Clone, Encodable, Decodable, Debug)]
+#[derive(Copy, Clone, Encodable, Decodable, Debug, Default)]
 pub struct ModSpans {
     /// `inner_span` covers the body of the module; for a file module, its the whole file.
     /// For an inline module, its the span inside the `{ ... }`, not including the curly braces.
@@ -2474,12 +2474,6 @@ pub struct ModSpans {
     pub inject_use_span: Span,
 }
 
-impl Default for ModSpans {
-    fn default() -> ModSpans {
-        ModSpans { inner_span: Default::default(), inject_use_span: Default::default() }
-    }
-}
-
 /// Foreign module declaration.
 ///
 /// E.g., `extern { .. }` or `extern "C" { .. }`.
index a92cb6bb38d4766ac9c919e07a732e84aa65d5cd..72c0257756ef2f15d1adfdc8f47a2e143ced6ccc 100644 (file)
@@ -697,7 +697,7 @@ fn suggest_borrow_fn_like(
                     .map_bound(|p| p.predicates),
                 None,
             ),
-            ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs }) => {
+            ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
                 find_fn_kind_from_did(tcx.bound_explicit_item_bounds(*def_id), Some(*substs))
             }
             ty::Closure(_, substs) => match substs.as_closure().kind() {
index e6520301818d82beb2bb99c754fa3b6f7eedf945..f8ec5e5e799149c888e001dd4ddc1b488847c8d2 100644 (file)
@@ -504,7 +504,7 @@ fn report_fnmut_error(
         let ErrorConstraintInfo { outlived_fr, span, .. } = errci;
 
         let mut output_ty = self.regioncx.universal_regions().unnormalized_output_ty;
-        if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs: _ }) = *output_ty.kind() {
+        if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *output_ty.kind() {
             output_ty = self.infcx.tcx.type_of(def_id)
         };
 
index 90e2b6b698cf832ec4a2d45e266e173369a3062f..e9c98bdc514967a63f4f1dc39be0e6be7d1919ed 100644 (file)
@@ -747,27 +747,14 @@ fn apply_member_constraint(
         // Otherwise, we need to find the minimum remaining choice, if
         // any, and take that.
         debug!("choice_regions remaining are {:#?}", choice_regions);
-        let min = |r1: ty::RegionVid, r2: ty::RegionVid| -> Option<ty::RegionVid> {
-            let r1_outlives_r2 = self.universal_region_relations.outlives(r1, r2);
-            let r2_outlives_r1 = self.universal_region_relations.outlives(r2, r1);
-            match (r1_outlives_r2, r2_outlives_r1) {
-                (true, true) => Some(r1.min(r2)),
-                (true, false) => Some(r2),
-                (false, true) => Some(r1),
-                (false, false) => None,
-            }
+        let Some(&min_choice) = choice_regions.iter().find(|&r1| {
+            choice_regions.iter().all(|&r2| {
+                self.universal_region_relations.outlives(r2, *r1)
+            })
+        }) else {
+            debug!("no choice region outlived by all others");
+            return false;
         };
-        let mut min_choice = choice_regions[0];
-        for &other_option in &choice_regions[1..] {
-            debug!(?min_choice, ?other_option,);
-            match min(min_choice, other_option) {
-                Some(m) => min_choice = m,
-                None => {
-                    debug!(?min_choice, ?other_option, "incomparable; no min choice",);
-                    return false;
-                }
-            }
-        }
 
         let min_choice_scc = self.constraint_sccs.scc(min_choice);
         debug!(?min_choice, ?min_choice_scc);
index 732edd66196d7de4c3d8d18e0c944e05d279906c..d627c2ee09c4ef7555f820cc2a239b73c3133269 100644 (file)
@@ -12,8 +12,6 @@ task:
     folder: target
   prepare_script:
     - . $HOME/.cargo/env
-    - git config --global user.email "user@example.com"
-    - git config --global user.name "User"
     - ./y.rs prepare
   test_script:
     - . $HOME/.cargo/env
index 5061010c86cd3451d4b8e7858b05cecf7efc8631..a6bb12a66a247d66441c390105655e9ff0910978 100644 (file)
@@ -19,6 +19,7 @@ jobs:
     - name: Rustfmt
       run: |
         cargo fmt --check
+        rustfmt --check build_system/mod.rs
 
   build:
     runs-on: ${{ matrix.os }}
@@ -28,7 +29,7 @@ jobs:
       fail-fast: false
       matrix:
         include:
-          - os: ubuntu-latest
+          - os: ubuntu-20.04 # FIXME switch to ubuntu-22.04 once #1303 is fixed
             env:
               TARGET_TRIPLE: x86_64-unknown-linux-gnu
           - os: macos-latest
@@ -41,18 +42,22 @@ jobs:
           - os: ubuntu-latest
             env:
               TARGET_TRIPLE: aarch64-unknown-linux-gnu
+          # s390x requires QEMU 6.1 or greater, we could build it from source, but ubuntu 22.04 comes with 6.2 by default
+          - os: ubuntu-latest
+            env:
+              TARGET_TRIPLE: s390x-unknown-linux-gnu
 
     steps:
     - uses: actions/checkout@v3
 
     - name: Cache cargo installed crates
-      uses: actions/cache@v2
+      uses: actions/cache@v3
       with:
         path: ~/.cargo/bin
         key: ${{ runner.os }}-cargo-installed-crates
 
     - name: Cache cargo registry and index
-      uses: actions/cache@v2
+      uses: actions/cache@v3
       with:
         path: |
             ~/.cargo/registry
@@ -60,9 +65,9 @@ jobs:
         key: ${{ runner.os }}-cargo-registry-and-index-${{ hashFiles('**/Cargo.lock') }}
 
     - name: Cache cargo target dir
-      uses: actions/cache@v2
+      uses: actions/cache@v3
       with:
-        path: target
+        path: build/cg_clif
         key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
 
     - name: Install MinGW toolchain and wine
@@ -78,11 +83,14 @@ jobs:
         sudo apt-get update
         sudo apt-get install -y gcc-aarch64-linux-gnu qemu-user
 
-    - name: Prepare dependencies
+    - name: Install s390x toolchain and qemu
+      if: matrix.env.TARGET_TRIPLE == 's390x-unknown-linux-gnu'
       run: |
-        git config --global user.email "user@example.com"
-        git config --global user.name "User"
-        ./y.rs prepare
+        sudo apt-get update
+        sudo apt-get install -y gcc-s390x-linux-gnu qemu-user
+
+    - name: Prepare dependencies
+      run: ./y.rs prepare
 
     - name: Build without unstable features
       env:
@@ -110,7 +118,7 @@ jobs:
         ./y.rs test
 
     - name: Package prebuilt cg_clif
-      run: tar cvfJ cg_clif.tar.xz build
+      run: tar cvfJ cg_clif.tar.xz dist
 
     - name: Upload prebuilt cg_clif
       if: matrix.env.TARGET_TRIPLE != 'x86_64-pc-windows-gnu'
@@ -121,7 +129,7 @@ jobs:
 
     - name: Upload prebuilt cg_clif (cross compile)
       if: matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
-      uses: actions/upload-artifact@v2
+      uses: actions/upload-artifact@v3
       with:
         name: cg_clif-${{ runner.os }}-cross-x86_64-mingw
         path: cg_clif.tar.xz
@@ -147,13 +155,13 @@ jobs:
     - uses: actions/checkout@v3
 
     - name: Cache cargo installed crates
-      uses: actions/cache@v2
+      uses: actions/cache@v3
       with:
         path: ~/.cargo/bin
         key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-installed-crates
 
     - name: Cache cargo registry and index
-      uses: actions/cache@v2
+      uses: actions/cache@v3
       with:
         path: |
             ~/.cargo/registry
@@ -161,9 +169,9 @@ jobs:
         key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-registry-and-index-${{ hashFiles('**/Cargo.lock') }}
 
     - name: Cache cargo target dir
-      uses: actions/cache@v2
+      uses: actions/cache@v3
       with:
-        path: target
+        path: build/cg_clif
         key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
 
     - name: Set MinGW as the default toolchain
@@ -172,8 +180,6 @@ jobs:
 
     - name: Prepare dependencies
       run: |
-        git config --global user.email "user@example.com"
-        git config --global user.name "User"
         git config --global core.autocrlf false
         rustc y.rs -o y.exe -g
         ./y.exe prepare
@@ -198,24 +204,24 @@ jobs:
 
         # Enable extra checks
         $Env:CG_CLIF_ENABLE_VERIFIER=1
-        
+
         # WIP Disable some tests
-        
+
         # This fails due to some weird argument handling by hyperfine, not an actual regression
         # more of a build system issue
         (Get-Content config.txt) -replace '(bench.simple-raytracer)', '# $1' |  Out-File config.txt
-        
-        # This fails with a different output than expected 
+
+        # This fails with a different output than expected
         (Get-Content config.txt) -replace '(test.regex-shootout-regex-dna)', '# $1' |  Out-File config.txt
 
         ./y.exe test
 
     - name: Package prebuilt cg_clif
       # don't use compression as xzip isn't supported by tar on windows and bzip2 hangs
-      run: tar cvf cg_clif.tar build
+      run: tar cvf cg_clif.tar dist
 
     - name: Upload prebuilt cg_clif
-      uses: actions/upload-artifact@v2
+      uses: actions/upload-artifact@v3
       with:
         name: cg_clif-${{ matrix.env.TARGET_TRIPLE }}
         path: cg_clif.tar
index 0a3e7ca073b45debb68785811cf0f727a7e0bde7..d0d58d2a7eacbd19a07442af167bdb0e2926274a 100644 (file)
@@ -14,7 +14,7 @@ jobs:
     - uses: actions/checkout@v3
 
     - name: Cache cargo installed crates
-      uses: actions/cache@v2
+      uses: actions/cache@v3
       with:
         path: ~/.cargo/bin
         key: ubuntu-latest-cargo-installed-crates
index b8a98b83ebe5eb1a5d292f5fa6b2b7df1168a5a9..bef806318efa836aeeb8d6df06d880b77be677fb 100644 (file)
@@ -11,13 +11,13 @@ jobs:
     - uses: actions/checkout@v3
 
     - name: Cache cargo installed crates
-      uses: actions/cache@v2
+      uses: actions/cache@v3
       with:
         path: ~/.cargo/bin
         key: ${{ runner.os }}-cargo-installed-crates
 
     - name: Cache cargo registry and index
-      uses: actions/cache@v2
+      uses: actions/cache@v3
       with:
         path: |
             ~/.cargo/registry
@@ -25,9 +25,9 @@ jobs:
         key: ${{ runner.os }}-cargo-registry-and-index-${{ hashFiles('**/Cargo.lock') }}
 
     - name: Cache cargo target dir
-      uses: actions/cache@v2
+      uses: actions/cache@v3
       with:
-        path: target
+        path: build/cg_clif
         key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
 
     - name: Prepare dependencies
@@ -49,13 +49,13 @@ jobs:
     - uses: actions/checkout@v3
 
     - name: Cache cargo installed crates
-      uses: actions/cache@v2
+      uses: actions/cache@v3
       with:
         path: ~/.cargo/bin
         key: ${{ runner.os }}-cargo-installed-crates
 
     - name: Cache cargo registry and index
-      uses: actions/cache@v2
+      uses: actions/cache@v3
       with:
         path: |
             ~/.cargo/registry
@@ -63,9 +63,9 @@ jobs:
         key: ${{ runner.os }}-cargo-registry-and-index-${{ hashFiles('**/Cargo.lock') }}
 
     - name: Cache cargo target dir
-      uses: actions/cache@v2
+      uses: actions/cache@v3
       with:
-        path: target
+        path: build/cg_clif
         key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
 
     - name: Prepare dependencies
index fae09592c6ac0dc91be2641093896c0adc9559d8..b443fd58a1b98344bec2720e26139b6467907d89 100644 (file)
@@ -14,5 +14,6 @@ perf.data.old
 /build_sysroot/sysroot_src
 /build_sysroot/compiler-builtins
 /build_sysroot/rustc_version
+/dist
 /rust
 /download
index 13301bf20a5ed7d57051c9b45fa4165a98e8b7b5..bc914e37d2b51dda8d3a0e4ef090a4cc1399fc90 100644 (file)
@@ -4,16 +4,10 @@
     "rust-analyzer.imports.granularity.enforce": true,
     "rust-analyzer.imports.granularity.group": "module",
     "rust-analyzer.imports.prefix": "crate",
-    "rust-analyzer.cargo.features": ["unstable-features"],
+    "rust-analyzer.cargo.features": ["unstable-features", "__check_build_system_using_ra"],
     "rust-analyzer.linkedProjects": [
         "./Cargo.toml",
-        //"./build_sysroot/sysroot_src/library/std/Cargo.toml",
         {
-            "roots": [
-                "./example/mini_core.rs",
-                "./example/mini_core_hello_world.rs",
-                "./example/mod_bench.rs"
-            ],
             "crates": [
                 {
                     "root_module": "./example/mini_core.rs",
             ]
         },
         {
-            "roots": ["./example/std_example.rs"],
+            "sysroot_src": "./build_sysroot/sysroot_src/library",
             "crates": [
                 {
                     "root_module": "./example/std_example.rs",
-                    "edition": "2018",
-                    "deps": [{ "crate": 1, "name": "std" }],
-                    "cfg": [],
-                },
-                {
-                    "root_module": "./build_sysroot/sysroot_src/library/std/src/lib.rs",
-                    "edition": "2018",
-                    "deps": [],
-                    "cfg": [],
-                },
-            ]
-        },
-        {
-            "roots": ["./y.rs"],
-            "crates": [
-                {
-                    "root_module": "./y.rs",
-                    "edition": "2018",
-                    "deps": [{ "crate": 1, "name": "std" }],
-                    "cfg": [],
-                },
-                {
-                    "root_module": "./build_sysroot/sysroot_src/library/std/src/lib.rs",
-                    "edition": "2018",
+                    "edition": "2015",
                     "deps": [],
                     "cfg": [],
                 },
index 3b406036c356e9e3023964f049184a2d1f0121f5..e4d3e9ca5ae0a8676863063216c420232248a554 100644 (file)
@@ -15,9 +15,9 @@ dependencies = [
 
 [[package]]
 name = "anyhow"
-version = "1.0.60"
+version = "1.0.66"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c794e162a5eff65c72ef524dfe393eb923c354e350bb78b9c7383df13f3bc142"
+checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6"
 
 [[package]]
 name = "arrayvec"
@@ -39,9 +39,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 
 [[package]]
 name = "bumpalo"
-version = "3.11.0"
+version = "3.11.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d"
+checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba"
 
 [[package]]
 name = "byteorder"
@@ -57,24 +57,25 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "cranelift-bforest"
-version = "0.88.1"
+version = "0.90.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "44409ccf2d0f663920cab563d2b79fcd6b2e9a2bcc6e929fef76c8f82ad6c17a"
+checksum = "b62c772976416112fa4484cbd688cb6fb35fd430005c1c586224fc014018abad"
 dependencies = [
  "cranelift-entity",
 ]
 
 [[package]]
 name = "cranelift-codegen"
-version = "0.88.1"
+version = "0.90.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "98de2018ad96eb97f621f7d6b900a0cc661aec8d02ea4a50e56ecb48e5a2fcaf"
+checksum = "9b40ed2dd13c2ac7e24f88a3090c68ad3414eb1d066a95f8f1f7b3b819cb4e46"
 dependencies = [
  "arrayvec",
  "bumpalo",
  "cranelift-bforest",
  "cranelift-codegen-meta",
  "cranelift-codegen-shared",
+ "cranelift-egraph",
  "cranelift-entity",
  "cranelift-isle",
  "gimli",
@@ -86,30 +87,44 @@ dependencies = [
 
 [[package]]
 name = "cranelift-codegen-meta"
-version = "0.88.1"
+version = "0.90.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5287ce36e6c4758fbaf298bd1a8697ad97a4f2375a3d1b61142ea538db4877e5"
+checksum = "bb927a8f1c27c34ee3759b6b0ffa528d2330405d5cc4511f0cab33fe2279f4b5"
 dependencies = [
  "cranelift-codegen-shared",
 ]
 
 [[package]]
 name = "cranelift-codegen-shared"
-version = "0.88.1"
+version = "0.90.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2855c24219e2f08827f3f4ffb2da92e134ae8d8ecc185b11ec8f9878cf5f588e"
+checksum = "43dfa417b884a9ab488d95fd6b93b25e959321fe7bfd7a0a960ba5d7fb7ab927"
+
+[[package]]
+name = "cranelift-egraph"
+version = "0.90.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e0a66b39785efd8513d2cca967ede56d6cc57c8d7986a595c7c47d0c78de8dce"
+dependencies = [
+ "cranelift-entity",
+ "fxhash",
+ "hashbrown",
+ "indexmap",
+ "log",
+ "smallvec",
+]
 
 [[package]]
 name = "cranelift-entity"
-version = "0.88.1"
+version = "0.90.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b65673279d75d34bf11af9660ae2dbd1c22e6d28f163f5c72f4e1dc56d56103"
+checksum = "0637ffde963cb5d759bc4d454cfa364b6509e6c74cdaa21298add0ed9276f346"
 
 [[package]]
 name = "cranelift-frontend"
-version = "0.88.1"
+version = "0.90.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3ed2b3d7a4751163f6c4a349205ab1b7d9c00eecf19dcea48592ef1f7688eefc"
+checksum = "fb72b8342685e850cb037350418f62cc4fc55d6c2eb9c7ca01b82f9f1a6f3d56"
 dependencies = [
  "cranelift-codegen",
  "log",
@@ -119,15 +134,15 @@ dependencies = [
 
 [[package]]
 name = "cranelift-isle"
-version = "0.88.1"
+version = "0.90.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3be64cecea9d90105fc6a2ba2d003e98c867c1d6c4c86cc878f97ad9fb916293"
+checksum = "850579cb9e4b448f7c301f1e6e6cbad99abe3f1f1d878a4994cb66e33c6db8cd"
 
 [[package]]
 name = "cranelift-jit"
-version = "0.88.1"
+version = "0.90.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f98ed42a70a0c9c388e34ec9477f57fc7300f541b1e5136a0e2ea02b1fac6015"
+checksum = "9add822ad66dcbe152b5ab57de10240a2df4505099f2f6c27159acb711890bd4"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -138,14 +153,15 @@ dependencies = [
  "log",
  "region",
  "target-lexicon",
+ "wasmtime-jit-icache-coherence",
  "windows-sys",
 ]
 
 [[package]]
 name = "cranelift-module"
-version = "0.88.1"
+version = "0.90.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d658ac7f156708bfccb647216cc8b9387469f50d352ba4ad80150541e4ae2d49"
+checksum = "406b772626fc2664864cf947f3895a23b619895c7fff635f3622e2d857f4492f"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -153,9 +169,9 @@ dependencies = [
 
 [[package]]
 name = "cranelift-native"
-version = "0.88.1"
+version = "0.90.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c4a03a6ac1b063e416ca4b93f6247978c991475e8271465340caa6f92f3c16a4"
+checksum = "2d0a279e5bcba3e0466c734d8d8eb6bfc1ad29e95c37f3e4955b492b5616335e"
 dependencies = [
  "cranelift-codegen",
  "libc",
@@ -164,9 +180,9 @@ dependencies = [
 
 [[package]]
 name = "cranelift-object"
-version = "0.88.1"
+version = "0.90.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eef0b4119b645b870a43a036d76c0ada3a076b1f82e8b8487659304c8b09049b"
+checksum = "39793c550f0c1d7db96c2fc1324583670c8143befe6edbfbaf1c68aba53be983"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -185,6 +201,12 @@ dependencies = [
  "cfg-if",
 ]
 
+[[package]]
+name = "fallible-iterator"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
+
 [[package]]
 name = "fxhash"
 version = "0.2.1"
@@ -196,9 +218,9 @@ dependencies = [
 
 [[package]]
 name = "getrandom"
-version = "0.2.7"
+version = "0.2.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6"
+checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
 dependencies = [
  "cfg-if",
  "libc",
@@ -211,7 +233,9 @@ version = "0.26.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d"
 dependencies = [
+ "fallible-iterator",
  "indexmap",
+ "stable_deref_trait",
 ]
 
 [[package]]
@@ -225,9 +249,9 @@ dependencies = [
 
 [[package]]
 name = "indexmap"
-version = "1.9.1"
+version = "1.9.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
+checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
 dependencies = [
  "autocfg",
  "hashbrown",
@@ -235,15 +259,15 @@ dependencies = [
 
 [[package]]
 name = "libc"
-version = "0.2.127"
+version = "0.2.138"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "505e71a4706fa491e9b1b55f51b95d4037d0821ee40131190475f692b35b009b"
+checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8"
 
 [[package]]
 name = "libloading"
-version = "0.7.3"
+version = "0.7.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd"
+checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
 dependencies = [
  "cfg-if",
  "winapi",
@@ -287,15 +311,15 @@ dependencies = [
 
 [[package]]
 name = "once_cell"
-version = "1.13.0"
+version = "1.16.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1"
+checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
 
 [[package]]
 name = "regalloc2"
-version = "0.3.2"
+version = "0.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d43a209257d978ef079f3d446331d0f1794f5e0fc19b306a199983857833a779"
+checksum = "91b2eab54204ea0117fe9a060537e0b07a4e72f7c7d182361ecc346cab2240e5"
 dependencies = [
  "fxhash",
  "log",
@@ -342,15 +366,21 @@ checksum = "03b634d87b960ab1a38c4fe143b508576f075e7c978bfad18217645ebfdfa2ec"
 
 [[package]]
 name = "smallvec"
-version = "1.9.0"
+version = "1.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1"
+checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
+
+[[package]]
+name = "stable_deref_trait"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
 
 [[package]]
 name = "target-lexicon"
-version = "0.12.4"
+version = "0.12.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c02424087780c9b71cc96799eaeddff35af2bc513278cda5c99fc1f5d026d3c1"
+checksum = "9410d0f6853b1d94f0e519fb95df60f29d2c1eff2d921ffdf01a4c8a3b54f12d"
 
 [[package]]
 name = "version_check"
@@ -364,6 +394,17 @@ version = "0.11.0+wasi-snapshot-preview1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
+[[package]]
+name = "wasmtime-jit-icache-coherence"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6bbabb309c06cc238ee91b1455b748c45f0bdcab0dda2c2db85b0a1e69fcb66"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "windows-sys",
+]
+
 [[package]]
 name = "winapi"
 version = "0.3.9"
index 0fdd5de118ccb10cb4db0776c5ca9c69b19cc07f..2b216ca072f0096832412085a0eae3fda4dc79ff 100644 (file)
@@ -3,17 +3,24 @@ name = "rustc_codegen_cranelift"
 version = "0.1.0"
 edition = "2021"
 
+[[bin]]
+# This is used just to teach rust-analyzer how to check the build system. required-features is used
+# to disable it for regular builds.
+name = "y"
+path = "./y.rs"
+required-features = ["__check_build_system_using_ra"]
+
 [lib]
 crate-type = ["dylib"]
 
 [dependencies]
 # These have to be in sync with each other
-cranelift-codegen = { version = "0.88.1", features = ["unwind", "all-arch"] }
-cranelift-frontend = "0.88.1"
-cranelift-module = "0.88.1"
-cranelift-native = "0.88.1"
-cranelift-jit = { version = "0.88.1", optional = true }
-cranelift-object = "0.88.1"
+cranelift-codegen = { version = "0.90.1", features = ["unwind", "all-arch"] }
+cranelift-frontend = "0.90.1"
+cranelift-module = "0.90.1"
+cranelift-native = "0.90.1"
+cranelift-jit = { version = "0.90.1", optional = true }
+cranelift-object = "0.90.1"
 target-lexicon = "0.12.0"
 gimli = { version = "0.26.0", default-features = false, features = ["write"]}
 object = { version = "0.29.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
@@ -39,6 +46,7 @@ smallvec = "1.8.1"
 unstable-features = ["jit", "inline_asm"]
 jit = ["cranelift-jit", "libloading"]
 inline_asm = []
+__check_build_system_using_ra = []
 
 [package.metadata.rust-analyzer]
 rustc_private = true
index 1e84c7fa3657b37afeb26614a49896fab8846b40..0e9c77244d4cc85d765371e97370db5c0adebf11 100644 (file)
@@ -37,7 +37,7 @@ Assuming `$cg_clif_dir` is the directory you cloned this repo into and you follo
 In the directory with your project (where you can do the usual `cargo build`), run:
 
 ```bash
-$ $cg_clif_dir/build/cargo-clif build
+$ $cg_clif_dir/dist/cargo-clif build
 ```
 
 This will build your project with rustc_codegen_cranelift instead of the usual LLVM backend.
index f6a9cb67290c7d88d591a72b2abfafaa2df67c28..bba3210536ef7832e44ba9dbb5e46c3ee036baf6 100644 (file)
@@ -4,9 +4,9 @@ version = 3
 
 [[package]]
 name = "addr2line"
-version = "0.16.0"
+version = "0.17.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3e61f2b7f93d2c7d2b08263acaa4a363b3e276806c68af6134c44f523bf1aacd"
+checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b"
 dependencies = [
  "compiler_builtins",
  "gimli",
@@ -32,27 +32,11 @@ dependencies = [
  "core",
 ]
 
-[[package]]
-name = "autocfg"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
-
 [[package]]
 name = "cc"
-version = "1.0.73"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
-
-[[package]]
-name = "cfg-if"
-version = "0.1.10"
+version = "1.0.77"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
-dependencies = [
- "compiler_builtins",
- "rustc-std-workspace-core",
-]
+checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4"
 
 [[package]]
 name = "cfg-if"
@@ -66,9 +50,9 @@ dependencies = [
 
 [[package]]
 name = "compiler_builtins"
-version = "0.1.82"
+version = "0.1.85"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "18cd7635fea7bb481ea543b392789844c1ad581299da70184c7175ce3af76603"
+checksum = "13e81c6cd7ab79f51a0c927d22858d61ad12bd0b3865f0b13ece02a4486aeabb"
 dependencies = [
  "rustc-std-workspace-core",
 ]
@@ -111,9 +95,9 @@ dependencies = [
 
 [[package]]
 name = "gimli"
-version = "0.25.0"
+version = "0.26.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f0a01e0497841a3b2db4f8afa483cce65f7e96a3498bd6c541734792aeac8fe7"
+checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d"
 dependencies = [
  "compiler_builtins",
  "rustc-std-workspace-alloc",
@@ -145,9 +129,9 @@ dependencies = [
 
 [[package]]
 name = "libc"
-version = "0.2.135"
+version = "0.2.138"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68783febc7782c6c5cb401fbda4de5a9898be1762314da0bb2c10ced61f18b0c"
+checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8"
 dependencies = [
  "rustc-std-workspace-core",
 ]
@@ -164,12 +148,11 @@ dependencies = [
 
 [[package]]
 name = "miniz_oxide"
-version = "0.4.4"
+version = "0.5.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b"
+checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34"
 dependencies = [
  "adler",
- "autocfg",
  "compiler_builtins",
  "rustc-std-workspace-alloc",
  "rustc-std-workspace-core",
@@ -177,9 +160,9 @@ dependencies = [
 
 [[package]]
 name = "object"
-version = "0.26.2"
+version = "0.29.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "39f37e50073ccad23b6d09bcb5b263f4e76d3bb6038e4a3c08e52162ffa8abc2"
+checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53"
 dependencies = [
  "compiler_builtins",
  "memchr",
@@ -192,7 +175,7 @@ name = "panic_abort"
 version = "0.0.0"
 dependencies = [
  "alloc",
- "cfg-if 0.1.10",
+ "cfg-if",
  "compiler_builtins",
  "core",
  "libc",
@@ -203,7 +186,7 @@ name = "panic_unwind"
 version = "0.0.0"
 dependencies = [
  "alloc",
- "cfg-if 0.1.10",
+ "cfg-if",
  "compiler_builtins",
  "core",
  "libc",
@@ -255,7 +238,7 @@ version = "0.0.0"
 dependencies = [
  "addr2line",
  "alloc",
- "cfg-if 1.0.0",
+ "cfg-if",
  "compiler_builtins",
  "core",
  "dlmalloc",
@@ -277,7 +260,7 @@ dependencies = [
 name = "std_detect"
 version = "0.1.5"
 dependencies = [
- "cfg-if 1.0.0",
+ "cfg-if",
  "compiler_builtins",
  "libc",
  "rustc-std-workspace-alloc",
@@ -299,7 +282,7 @@ dependencies = [
 name = "test"
 version = "0.0.0"
 dependencies = [
- "cfg-if 0.1.10",
+ "cfg-if",
  "core",
  "getopts",
  "libc",
@@ -325,7 +308,7 @@ name = "unwind"
 version = "0.0.0"
 dependencies = [
  "cc",
- "cfg-if 0.1.10",
+ "cfg-if",
  "compiler_builtins",
  "core",
  "libc",
index fae5b27163680badc511023892f92fe462ddfbaf..a081fdaa1c7e6475a727f764c033f07090b2b87e 100644 (file)
@@ -1,16 +1,21 @@
-use std::env;
 use std::path::Path;
 
 use super::build_sysroot;
 use super::config;
-use super::prepare;
-use super::utils::{cargo_command, spawn_and_wait};
+use super::path::Dirs;
+use super::prepare::GitRepo;
+use super::utils::{spawn_and_wait, CargoProject, Compiler};
 use super::SysrootKind;
 
+pub(crate) static ABI_CAFE_REPO: GitRepo =
+    GitRepo::github("Gankra", "abi-cafe", "4c6dc8c9c687e2b3a760ff2176ce236872b37212", "abi-cafe");
+
+static ABI_CAFE: CargoProject = CargoProject::new(&ABI_CAFE_REPO.source_dir(), "abi_cafe");
+
 pub(crate) fn run(
     channel: &str,
     sysroot_kind: SysrootKind,
-    target_dir: &Path,
+    dirs: &Dirs,
     cg_clif_dylib: &Path,
     host_triple: &str,
     target_triple: &str,
@@ -27,26 +32,25 @@ pub(crate) fn run(
 
     eprintln!("Building sysroot for abi-cafe");
     build_sysroot::build_sysroot(
+        dirs,
         channel,
         sysroot_kind,
-        target_dir,
         cg_clif_dylib,
         host_triple,
         target_triple,
     );
 
     eprintln!("Running abi-cafe");
-    let abi_cafe_path = prepare::ABI_CAFE.source_dir();
-    env::set_current_dir(abi_cafe_path.clone()).unwrap();
 
     let pairs = ["rustc_calls_cgclif", "cgclif_calls_rustc", "cgclif_calls_cc", "cc_calls_cgclif"];
 
-    let mut cmd = cargo_command("cargo", "run", Some(target_triple), &abi_cafe_path);
+    let mut cmd = ABI_CAFE.run(&Compiler::host(), dirs);
     cmd.arg("--");
     cmd.arg("--pairs");
     cmd.args(pairs);
     cmd.arg("--add-rustc-codegen-backend");
     cmd.arg(format!("cgclif:{}", cg_clif_dylib.display()));
+    cmd.current_dir(ABI_CAFE.source_dir(dirs));
 
     spawn_and_wait(cmd);
 }
index cda468bcfa2dfc2e0bfe494bd5a1a9414a97eed6..fde8ef424ccc5441e0198ef7b33b23c39dbe37bc 100644 (file)
@@ -1,16 +1,19 @@
 use std::env;
 use std::path::PathBuf;
 
+use super::path::{Dirs, RelPath};
 use super::rustc_info::get_file_name;
-use super::utils::{cargo_command, is_ci};
+use super::utils::{is_ci, CargoProject, Compiler};
+
+static CG_CLIF: CargoProject = CargoProject::new(&RelPath::SOURCE, "cg_clif");
 
 pub(crate) fn build_backend(
+    dirs: &Dirs,
     channel: &str,
     host_triple: &str,
     use_unstable_features: bool,
 ) -> PathBuf {
-    let source_dir = std::env::current_dir().unwrap();
-    let mut cmd = cargo_command("cargo", "build", Some(host_triple), &source_dir);
+    let mut cmd = CG_CLIF.build(&Compiler::host(), dirs);
 
     cmd.env("CARGO_BUILD_INCREMENTAL", "true"); // Force incr comp even in release mode
 
@@ -41,8 +44,8 @@ pub(crate) fn build_backend(
     eprintln!("[BUILD] rustc_codegen_cranelift");
     super::utils::spawn_and_wait(cmd);
 
-    source_dir
-        .join("target")
+    CG_CLIF
+        .target_dir(dirs)
         .join(host_triple)
         .join(channel)
         .join(get_file_name("rustc_codegen_cranelift", "dylib"))
index 856aecc49fd1c05f476c91232c9bb0b429c4c907..cbbf09b9b97b8422ab06caff3b59b34c6352dfd4 100644 (file)
@@ -1,57 +1,60 @@
 use std::fs;
-use std::path::{Path, PathBuf};
+use std::path::Path;
 use std::process::{self, Command};
 
+use super::path::{Dirs, RelPath};
 use super::rustc_info::{get_file_name, get_rustc_version, get_wrapper_file_name};
-use super::utils::{cargo_command, spawn_and_wait, try_hard_link};
+use super::utils::{spawn_and_wait, try_hard_link, CargoProject, Compiler};
 use super::SysrootKind;
 
+static DIST_DIR: RelPath = RelPath::DIST;
+static BIN_DIR: RelPath = RelPath::DIST.join("bin");
+static LIB_DIR: RelPath = RelPath::DIST.join("lib");
+static RUSTLIB_DIR: RelPath = LIB_DIR.join("rustlib");
+
 pub(crate) fn build_sysroot(
+    dirs: &Dirs,
     channel: &str,
     sysroot_kind: SysrootKind,
-    target_dir: &Path,
     cg_clif_dylib_src: &Path,
     host_triple: &str,
     target_triple: &str,
 ) {
     eprintln!("[BUILD] sysroot {:?}", sysroot_kind);
 
-    if target_dir.exists() {
-        fs::remove_dir_all(target_dir).unwrap();
-    }
-    fs::create_dir_all(target_dir.join("bin")).unwrap();
-    fs::create_dir_all(target_dir.join("lib")).unwrap();
+    DIST_DIR.ensure_fresh(dirs);
+    BIN_DIR.ensure_exists(dirs);
+    LIB_DIR.ensure_exists(dirs);
 
     // Copy the backend
-    let cg_clif_dylib_path = target_dir
-        .join(if cfg!(windows) {
-            // Windows doesn't have rpath support, so the cg_clif dylib needs to be next to the
-            // binaries.
-            "bin"
-        } else {
-            "lib"
-        })
-        .join(get_file_name("rustc_codegen_cranelift", "dylib"));
+    let cg_clif_dylib_path = if cfg!(windows) {
+        // Windows doesn't have rpath support, so the cg_clif dylib needs to be next to the
+        // binaries.
+        BIN_DIR
+    } else {
+        LIB_DIR
+    }
+    .to_path(dirs)
+    .join(get_file_name("rustc_codegen_cranelift", "dylib"));
     try_hard_link(cg_clif_dylib_src, &cg_clif_dylib_path);
 
     // Build and copy rustc and cargo wrappers
-    for wrapper in ["rustc-clif", "cargo-clif"] {
+    for wrapper in ["rustc-clif", "rustdoc-clif", "cargo-clif"] {
         let wrapper_name = get_wrapper_file_name(wrapper, "bin");
 
         let mut build_cargo_wrapper_cmd = Command::new("rustc");
         build_cargo_wrapper_cmd
-            .arg(PathBuf::from("scripts").join(format!("{wrapper}.rs")))
+            .arg(RelPath::SCRIPTS.to_path(dirs).join(&format!("{wrapper}.rs")))
             .arg("-o")
-            .arg(target_dir.join(wrapper_name))
+            .arg(DIST_DIR.to_path(dirs).join(wrapper_name))
             .arg("-g");
         spawn_and_wait(build_cargo_wrapper_cmd);
     }
 
     let default_sysroot = super::rustc_info::get_default_sysroot();
 
-    let rustlib = target_dir.join("lib").join("rustlib");
-    let host_rustlib_lib = rustlib.join(host_triple).join("lib");
-    let target_rustlib_lib = rustlib.join(target_triple).join("lib");
+    let host_rustlib_lib = RUSTLIB_DIR.to_path(dirs).join(host_triple).join("lib");
+    let target_rustlib_lib = RUSTLIB_DIR.to_path(dirs).join(target_triple).join("lib");
     fs::create_dir_all(&host_rustlib_lib).unwrap();
     fs::create_dir_all(&target_rustlib_lib).unwrap();
 
@@ -112,24 +115,18 @@ pub(crate) fn build_sysroot(
             }
         }
         SysrootKind::Clif => {
-            build_clif_sysroot_for_triple(
-                channel,
-                target_dir,
-                host_triple,
-                &cg_clif_dylib_path,
-                None,
-            );
+            build_clif_sysroot_for_triple(dirs, channel, host_triple, &cg_clif_dylib_path, None);
 
             if host_triple != target_triple {
                 // When cross-compiling it is often necessary to manually pick the right linker
-                let linker = if target_triple == "aarch64-unknown-linux-gnu" {
-                    Some("aarch64-linux-gnu-gcc")
-                } else {
-                    None
+                let linker = match target_triple {
+                    "aarch64-unknown-linux-gnu" => Some("aarch64-linux-gnu-gcc"),
+                    "s390x-unknown-linux-gnu" => Some("s390x-linux-gnu-gcc"),
+                    _ => None,
                 };
                 build_clif_sysroot_for_triple(
+                    dirs,
                     channel,
-                    target_dir,
                     target_triple,
                     &cg_clif_dylib_path,
                     linker,
@@ -142,21 +139,26 @@ pub(crate) fn build_sysroot(
                 let file = file.unwrap().path();
                 let filename = file.file_name().unwrap().to_str().unwrap();
                 if filename.contains("std-") && !filename.contains(".rlib") {
-                    try_hard_link(&file, target_dir.join("lib").join(file.file_name().unwrap()));
+                    try_hard_link(&file, LIB_DIR.to_path(dirs).join(file.file_name().unwrap()));
                 }
             }
         }
     }
 }
 
+// FIXME move to download/ or dist/
+pub(crate) static SYSROOT_RUSTC_VERSION: RelPath = RelPath::BUILD_SYSROOT.join("rustc_version");
+pub(crate) static SYSROOT_SRC: RelPath = RelPath::BUILD_SYSROOT.join("sysroot_src");
+static STANDARD_LIBRARY: CargoProject = CargoProject::new(&RelPath::BUILD_SYSROOT, "build_sysroot");
+
 fn build_clif_sysroot_for_triple(
+    dirs: &Dirs,
     channel: &str,
-    target_dir: &Path,
     triple: &str,
     cg_clif_dylib_path: &Path,
     linker: Option<&str>,
 ) {
-    match fs::read_to_string(Path::new("build_sysroot").join("rustc_version")) {
+    match fs::read_to_string(SYSROOT_RUSTC_VERSION.to_path(dirs)) {
         Err(e) => {
             eprintln!("Failed to get rustc version for patched sysroot source: {}", e);
             eprintln!("Hint: Try `./y.rs prepare` to patch the sysroot source");
@@ -174,7 +176,7 @@ fn build_clif_sysroot_for_triple(
         }
     }
 
-    let build_dir = Path::new("build_sysroot").join("target").join(triple).join(channel);
+    let build_dir = STANDARD_LIBRARY.target_dir(dirs).join(triple).join(channel);
 
     if !super::config::get_bool("keep_sysroot") {
         // Cleanup the deps dir, but keep build scripts and the incremental cache for faster
@@ -185,27 +187,27 @@ fn build_clif_sysroot_for_triple(
     }
 
     // Build sysroot
-    let mut build_cmd = cargo_command("cargo", "build", Some(triple), Path::new("build_sysroot"));
     let mut rustflags = "-Zforce-unstable-if-unmarked -Cpanic=abort".to_string();
     rustflags.push_str(&format!(" -Zcodegen-backend={}", cg_clif_dylib_path.to_str().unwrap()));
-    rustflags.push_str(&format!(" --sysroot={}", target_dir.to_str().unwrap()));
+    rustflags.push_str(&format!(" --sysroot={}", DIST_DIR.to_path(dirs).to_str().unwrap()));
     if channel == "release" {
-        build_cmd.arg("--release");
         rustflags.push_str(" -Zmir-opt-level=3");
     }
     if let Some(linker) = linker {
         use std::fmt::Write;
         write!(rustflags, " -Clinker={}", linker).unwrap();
     }
-    build_cmd.env("RUSTFLAGS", rustflags);
+    let mut compiler = Compiler::with_triple(triple.to_owned());
+    compiler.rustflags = rustflags;
+    let mut build_cmd = STANDARD_LIBRARY.build(&compiler, dirs);
+    if channel == "release" {
+        build_cmd.arg("--release");
+    }
     build_cmd.env("__CARGO_DEFAULT_LIB_METADATA", "cg_clif");
     spawn_and_wait(build_cmd);
 
     // Copy all relevant files to the sysroot
-    for entry in
-        fs::read_dir(Path::new("build_sysroot/target").join(triple).join(channel).join("deps"))
-            .unwrap()
-    {
+    for entry in fs::read_dir(build_dir.join("deps")).unwrap() {
         let entry = entry.unwrap();
         if let Some(ext) = entry.path().extension() {
             if ext == "rmeta" || ext == "d" || ext == "dSYM" || ext == "clif" {
@@ -216,7 +218,7 @@ fn build_clif_sysroot_for_triple(
         };
         try_hard_link(
             entry.path(),
-            target_dir.join("lib").join("rustlib").join(triple).join("lib").join(entry.file_name()),
+            RUSTLIB_DIR.to_path(dirs).join(triple).join("lib").join(entry.file_name()),
         );
     }
 }
index b25270d832ceb4fd483cfdbad2b6b712a4ee1a50..1afc9a55c73b5318bbc9ed006899c4f5ab3647c3 100644 (file)
@@ -8,20 +8,37 @@
 mod build_backend;
 mod build_sysroot;
 mod config;
+mod path;
 mod prepare;
 mod rustc_info;
 mod tests;
 mod utils;
 
+const USAGE: &str = r#"The build system of cg_clif.
+
+USAGE:
+    ./y.rs prepare [--out-dir DIR]
+    ./y.rs build [--debug] [--sysroot none|clif|llvm] [--out-dir DIR] [--no-unstable-features]
+    ./y.rs test [--debug] [--sysroot none|clif|llvm] [--out-dir DIR] [--no-unstable-features]
+
+OPTIONS:
+    --sysroot none|clif|llvm
+            Which sysroot libraries to use:
+            `none` will not include any standard library in the sysroot.
+            `clif` will build the standard library using Cranelift.
+            `llvm` will use the pre-compiled standard library of rustc which is compiled with LLVM.
+
+    --out-dir DIR
+            Specify the directory in which the download, build and dist directories are stored.
+            By default this is the working directory.
+
+    --no-unstable-features
+            fSome features are not yet ready for production usage. This option will disable these
+            features. This includes the JIT mode and inline assembly support.
+"#;
+
 fn usage() {
-    eprintln!("Usage:");
-    eprintln!("  ./y.rs prepare");
-    eprintln!(
-        "  ./y.rs build [--debug] [--sysroot none|clif|llvm] [--target-dir DIR] [--no-unstable-features]"
-    );
-    eprintln!(
-        "  ./y.rs test [--debug] [--sysroot none|clif|llvm] [--target-dir DIR] [--no-unstable-features]"
-    );
+    eprintln!("{USAGE}");
 }
 
 macro_rules! arg_error {
@@ -34,6 +51,7 @@ macro_rules! arg_error {
 
 #[derive(PartialEq, Debug)]
 enum Command {
+    Prepare,
     Build,
     Test,
 }
@@ -48,8 +66,6 @@ pub(crate) enum SysrootKind {
 pub fn main() {
     env::set_var("CG_CLIF_DISPLAY_CG_TIME", "1");
     env::set_var("CG_CLIF_DISABLE_INCR_CACHE", "1");
-    // The target dir is expected in the default location. Guard against the user changing it.
-    env::set_var("CARGO_TARGET_DIR", "target");
 
     if is_ci() {
         // Disabling incr comp reduces cache size and incr comp doesn't save as much on CI anyway
@@ -58,13 +74,7 @@ pub fn main() {
 
     let mut args = env::args().skip(1);
     let command = match args.next().as_deref() {
-        Some("prepare") => {
-            if args.next().is_some() {
-                arg_error!("./y.rs prepare doesn't expect arguments");
-            }
-            prepare::prepare();
-            process::exit(0);
-        }
+        Some("prepare") => Command::Prepare,
         Some("build") => Command::Build,
         Some("test") => Command::Test,
         Some(flag) if flag.starts_with('-') => arg_error!("Expected command found flag {}", flag),
@@ -75,15 +85,15 @@ pub fn main() {
         }
     };
 
-    let mut target_dir = PathBuf::from("build");
+    let mut out_dir = PathBuf::from(".");
     let mut channel = "release";
     let mut sysroot_kind = SysrootKind::Clif;
     let mut use_unstable_features = true;
     while let Some(arg) = args.next().as_deref() {
         match arg {
-            "--target-dir" => {
-                target_dir = PathBuf::from(args.next().unwrap_or_else(|| {
-                    arg_error!("--target-dir requires argument");
+            "--out-dir" => {
+                out_dir = PathBuf::from(args.next().unwrap_or_else(|| {
+                    arg_error!("--out-dir requires argument");
                 }))
             }
             "--debug" => channel = "debug",
@@ -101,7 +111,6 @@ pub fn main() {
             arg => arg_error!("Unexpected argument {}", arg),
         }
     }
-    target_dir = std::env::current_dir().unwrap().join(target_dir);
 
     let host_triple = if let Ok(host_triple) = std::env::var("HOST_TRIPLE") {
         host_triple
@@ -122,13 +131,43 @@ pub fn main() {
         host_triple.clone()
     };
 
-    let cg_clif_dylib = build_backend::build_backend(channel, &host_triple, use_unstable_features);
+    // FIXME allow changing the location of these dirs using cli arguments
+    let current_dir = std::env::current_dir().unwrap();
+    out_dir = current_dir.join(out_dir);
+    let dirs = path::Dirs {
+        source_dir: current_dir.clone(),
+        download_dir: out_dir.join("download"),
+        build_dir: out_dir.join("build"),
+        dist_dir: out_dir.join("dist"),
+    };
+
+    path::RelPath::BUILD.ensure_exists(&dirs);
+
+    {
+        // Make sure we always explicitly specify the target dir
+        let target =
+            path::RelPath::BUILD.join("target_dir_should_be_set_explicitly").to_path(&dirs);
+        env::set_var("CARGO_TARGET_DIR", &target);
+        let _ = std::fs::remove_file(&target);
+        std::fs::File::create(target).unwrap();
+    }
+
+    if command == Command::Prepare {
+        prepare::prepare(&dirs);
+        process::exit(0);
+    }
+
+    let cg_clif_dylib =
+        build_backend::build_backend(&dirs, channel, &host_triple, use_unstable_features);
     match command {
+        Command::Prepare => {
+            // Handled above
+        }
         Command::Test => {
             tests::run_tests(
+                &dirs,
                 channel,
                 sysroot_kind,
-                &target_dir,
                 &cg_clif_dylib,
                 &host_triple,
                 &target_triple,
@@ -137,7 +176,7 @@ pub fn main() {
             abi_cafe::run(
                 channel,
                 sysroot_kind,
-                &target_dir,
+                &dirs,
                 &cg_clif_dylib,
                 &host_triple,
                 &target_triple,
@@ -145,9 +184,9 @@ pub fn main() {
         }
         Command::Build => {
             build_sysroot::build_sysroot(
+                &dirs,
                 channel,
                 sysroot_kind,
-                &target_dir,
                 &cg_clif_dylib,
                 &host_triple,
                 &target_triple,
diff --git a/compiler/rustc_codegen_cranelift/build_system/path.rs b/compiler/rustc_codegen_cranelift/build_system/path.rs
new file mode 100644 (file)
index 0000000..e93981f
--- /dev/null
@@ -0,0 +1,70 @@
+use std::fs;
+use std::path::PathBuf;
+
+#[derive(Debug, Clone)]
+pub(crate) struct Dirs {
+    pub(crate) source_dir: PathBuf,
+    pub(crate) download_dir: PathBuf,
+    pub(crate) build_dir: PathBuf,
+    pub(crate) dist_dir: PathBuf,
+}
+
+#[doc(hidden)]
+#[derive(Debug, Copy, Clone)]
+pub(crate) enum PathBase {
+    Source,
+    Download,
+    Build,
+    Dist,
+}
+
+impl PathBase {
+    fn to_path(self, dirs: &Dirs) -> PathBuf {
+        match self {
+            PathBase::Source => dirs.source_dir.clone(),
+            PathBase::Download => dirs.download_dir.clone(),
+            PathBase::Build => dirs.build_dir.clone(),
+            PathBase::Dist => dirs.dist_dir.clone(),
+        }
+    }
+}
+
+#[derive(Debug, Copy, Clone)]
+pub(crate) enum RelPath {
+    Base(PathBase),
+    Join(&'static RelPath, &'static str),
+}
+
+impl RelPath {
+    pub(crate) const SOURCE: RelPath = RelPath::Base(PathBase::Source);
+    pub(crate) const DOWNLOAD: RelPath = RelPath::Base(PathBase::Download);
+    pub(crate) const BUILD: RelPath = RelPath::Base(PathBase::Build);
+    pub(crate) const DIST: RelPath = RelPath::Base(PathBase::Dist);
+
+    pub(crate) const SCRIPTS: RelPath = RelPath::SOURCE.join("scripts");
+    pub(crate) const BUILD_SYSROOT: RelPath = RelPath::SOURCE.join("build_sysroot");
+    pub(crate) const PATCHES: RelPath = RelPath::SOURCE.join("patches");
+
+    pub(crate) const fn join(&'static self, suffix: &'static str) -> RelPath {
+        RelPath::Join(self, suffix)
+    }
+
+    pub(crate) fn to_path(&self, dirs: &Dirs) -> PathBuf {
+        match self {
+            RelPath::Base(base) => base.to_path(dirs),
+            RelPath::Join(base, suffix) => base.to_path(dirs).join(suffix),
+        }
+    }
+
+    pub(crate) fn ensure_exists(&self, dirs: &Dirs) {
+        fs::create_dir_all(self.to_path(dirs)).unwrap();
+    }
+
+    pub(crate) fn ensure_fresh(&self, dirs: &Dirs) {
+        let path = self.to_path(dirs);
+        if path.exists() {
+            fs::remove_dir_all(&path).unwrap();
+        }
+        fs::create_dir_all(path).unwrap();
+    }
+}
index 3111f62f6c2156eaec0ef00a9a7213acf8950f88..8ac67e8f9422823090a97ffab654c0da5a848e12 100644 (file)
@@ -1,92 +1,75 @@
-use std::env;
 use std::ffi::OsStr;
 use std::fs;
 use std::path::{Path, PathBuf};
 use std::process::Command;
 
+use super::build_sysroot::{SYSROOT_RUSTC_VERSION, SYSROOT_SRC};
+use super::path::{Dirs, RelPath};
 use super::rustc_info::{get_file_name, get_rustc_path, get_rustc_version};
-use super::utils::{cargo_command, copy_dir_recursively, spawn_and_wait};
-
-pub(crate) const ABI_CAFE: GitRepo =
-    GitRepo::github("Gankra", "abi-cafe", "4c6dc8c9c687e2b3a760ff2176ce236872b37212", "abi-cafe");
-
-pub(crate) const RAND: GitRepo =
-    GitRepo::github("rust-random", "rand", "0f933f9c7176e53b2a3c7952ded484e1783f0bf1", "rand");
-
-pub(crate) const REGEX: GitRepo =
-    GitRepo::github("rust-lang", "regex", "341f207c1071f7290e3f228c710817c280c8dca1", "regex");
-
-pub(crate) const PORTABLE_SIMD: GitRepo = GitRepo::github(
-    "rust-lang",
-    "portable-simd",
-    "d5cd4a8112d958bd3a252327e0d069a6363249bd",
-    "portable-simd",
-);
-
-pub(crate) const SIMPLE_RAYTRACER: GitRepo = GitRepo::github(
-    "ebobby",
-    "simple-raytracer",
-    "804a7a21b9e673a482797aa289a18ed480e4d813",
-    "<none>",
-);
-
-pub(crate) fn prepare() {
-    if Path::new("download").exists() {
-        std::fs::remove_dir_all(Path::new("download")).unwrap();
+use super::utils::{copy_dir_recursively, spawn_and_wait, Compiler};
+
+pub(crate) fn prepare(dirs: &Dirs) {
+    if RelPath::DOWNLOAD.to_path(dirs).exists() {
+        std::fs::remove_dir_all(RelPath::DOWNLOAD.to_path(dirs)).unwrap();
     }
-    std::fs::create_dir_all(Path::new("download")).unwrap();
+    std::fs::create_dir_all(RelPath::DOWNLOAD.to_path(dirs)).unwrap();
 
-    prepare_sysroot();
+    prepare_sysroot(dirs);
 
     // FIXME maybe install this only locally?
     eprintln!("[INSTALL] hyperfine");
-    Command::new("cargo").arg("install").arg("hyperfine").spawn().unwrap().wait().unwrap();
+    Command::new("cargo")
+        .arg("install")
+        .arg("hyperfine")
+        .env_remove("CARGO_TARGET_DIR")
+        .spawn()
+        .unwrap()
+        .wait()
+        .unwrap();
 
-    ABI_CAFE.fetch();
-    RAND.fetch();
-    REGEX.fetch();
-    PORTABLE_SIMD.fetch();
-    SIMPLE_RAYTRACER.fetch();
+    super::abi_cafe::ABI_CAFE_REPO.fetch(dirs);
+    super::tests::RAND_REPO.fetch(dirs);
+    super::tests::REGEX_REPO.fetch(dirs);
+    super::tests::PORTABLE_SIMD_REPO.fetch(dirs);
+    super::tests::SIMPLE_RAYTRACER_REPO.fetch(dirs);
 
     eprintln!("[LLVM BUILD] simple-raytracer");
-    let build_cmd = cargo_command("cargo", "build", None, &SIMPLE_RAYTRACER.source_dir());
+    let host_compiler = Compiler::host();
+    let build_cmd = super::tests::SIMPLE_RAYTRACER.build(&host_compiler, dirs);
     spawn_and_wait(build_cmd);
     fs::copy(
-        SIMPLE_RAYTRACER
-            .source_dir()
-            .join("target")
+        super::tests::SIMPLE_RAYTRACER
+            .target_dir(dirs)
+            .join(&host_compiler.triple)
             .join("debug")
             .join(get_file_name("main", "bin")),
-        SIMPLE_RAYTRACER.source_dir().join(get_file_name("raytracer_cg_llvm", "bin")),
+        RelPath::BUILD.to_path(dirs).join(get_file_name("raytracer_cg_llvm", "bin")),
     )
     .unwrap();
 }
 
-fn prepare_sysroot() {
+fn prepare_sysroot(dirs: &Dirs) {
     let rustc_path = get_rustc_path();
     let sysroot_src_orig = rustc_path.parent().unwrap().join("../lib/rustlib/src/rust");
-    let sysroot_src = env::current_dir().unwrap().join("build_sysroot").join("sysroot_src");
+    let sysroot_src = SYSROOT_SRC;
 
     assert!(sysroot_src_orig.exists());
 
-    if sysroot_src.exists() {
-        fs::remove_dir_all(&sysroot_src).unwrap();
-    }
-    fs::create_dir_all(sysroot_src.join("library")).unwrap();
+    sysroot_src.ensure_fresh(dirs);
+    fs::create_dir_all(sysroot_src.to_path(dirs).join("library")).unwrap();
     eprintln!("[COPY] sysroot src");
-    copy_dir_recursively(&sysroot_src_orig.join("library"), &sysroot_src.join("library"));
+    copy_dir_recursively(
+        &sysroot_src_orig.join("library"),
+        &sysroot_src.to_path(dirs).join("library"),
+    );
 
     let rustc_version = get_rustc_version();
-    fs::write(Path::new("build_sysroot").join("rustc_version"), &rustc_version).unwrap();
+    fs::write(SYSROOT_RUSTC_VERSION.to_path(dirs), &rustc_version).unwrap();
 
     eprintln!("[GIT] init");
-    let mut git_init_cmd = Command::new("git");
-    git_init_cmd.arg("init").arg("-q").current_dir(&sysroot_src);
-    spawn_and_wait(git_init_cmd);
-
-    init_git_repo(&sysroot_src);
+    init_git_repo(&sysroot_src.to_path(dirs));
 
-    apply_patches("sysroot", &sysroot_src);
+    apply_patches(dirs, "sysroot", &sysroot_src.to_path(dirs));
 }
 
 pub(crate) struct GitRepo {
@@ -100,7 +83,7 @@ enum GitRepoUrl {
 }
 
 impl GitRepo {
-    const fn github(
+    pub(crate) const fn github(
         user: &'static str,
         repo: &'static str,
         rev: &'static str,
@@ -109,21 +92,25 @@ const fn github(
         GitRepo { url: GitRepoUrl::Github { user, repo }, rev, patch_name }
     }
 
-    pub(crate) fn source_dir(&self) -> PathBuf {
+    pub(crate) const fn source_dir(&self) -> RelPath {
         match self.url {
-            GitRepoUrl::Github { user: _, repo } => {
-                std::env::current_dir().unwrap().join("download").join(repo)
-            }
+            GitRepoUrl::Github { user: _, repo } => RelPath::DOWNLOAD.join(repo),
         }
     }
 
-    fn fetch(&self) {
+    fn fetch(&self, dirs: &Dirs) {
         match self.url {
             GitRepoUrl::Github { user, repo } => {
-                clone_repo_shallow_github(&self.source_dir(), user, repo, self.rev);
+                clone_repo_shallow_github(
+                    dirs,
+                    &self.source_dir().to_path(dirs),
+                    user,
+                    repo,
+                    self.rev,
+                );
             }
         }
-        apply_patches(self.patch_name, &self.source_dir());
+        apply_patches(dirs, self.patch_name, &self.source_dir().to_path(dirs));
     }
 }
 
@@ -142,18 +129,16 @@ fn clone_repo(download_dir: &Path, repo: &str, rev: &str) {
     spawn_and_wait(checkout_cmd);
 }
 
-fn clone_repo_shallow_github(download_dir: &Path, user: &str, repo: &str, rev: &str) {
+fn clone_repo_shallow_github(dirs: &Dirs, download_dir: &Path, user: &str, repo: &str, rev: &str) {
     if cfg!(windows) {
         // Older windows doesn't have tar or curl by default. Fall back to using git.
         clone_repo(download_dir, &format!("https://github.com/{}/{}.git", user, repo), rev);
         return;
     }
 
-    let downloads_dir = std::env::current_dir().unwrap().join("download");
-
     let archive_url = format!("https://github.com/{}/{}/archive/{}.tar.gz", user, repo, rev);
-    let archive_file = downloads_dir.join(format!("{}.tar.gz", rev));
-    let archive_dir = downloads_dir.join(format!("{}-{}", repo, rev));
+    let archive_file = RelPath::DOWNLOAD.to_path(dirs).join(format!("{}.tar.gz", rev));
+    let archive_dir = RelPath::DOWNLOAD.to_path(dirs).join(format!("{}-{}", repo, rev));
 
     eprintln!("[DOWNLOAD] {}/{} from {}", user, repo, archive_url);
 
@@ -169,7 +154,7 @@ fn clone_repo_shallow_github(download_dir: &Path, user: &str, repo: &str, rev: &
 
     // Unpack tar archive
     let mut unpack_cmd = Command::new("tar");
-    unpack_cmd.arg("xf").arg(&archive_file).current_dir(downloads_dir);
+    unpack_cmd.arg("xf").arg(&archive_file).current_dir(RelPath::DOWNLOAD.to_path(dirs));
     spawn_and_wait(unpack_cmd);
 
     // Rename unpacked dir to the expected name
@@ -191,12 +176,21 @@ fn init_git_repo(repo_dir: &Path) {
     spawn_and_wait(git_add_cmd);
 
     let mut git_commit_cmd = Command::new("git");
-    git_commit_cmd.arg("commit").arg("-m").arg("Initial commit").arg("-q").current_dir(repo_dir);
+    git_commit_cmd
+        .arg("-c")
+        .arg("user.name=Dummy")
+        .arg("-c")
+        .arg("user.email=dummy@example.com")
+        .arg("commit")
+        .arg("-m")
+        .arg("Initial commit")
+        .arg("-q")
+        .current_dir(repo_dir);
     spawn_and_wait(git_commit_cmd);
 }
 
-fn get_patches(source_dir: &Path, crate_name: &str) -> Vec<PathBuf> {
-    let mut patches: Vec<_> = fs::read_dir(source_dir.join("patches"))
+fn get_patches(dirs: &Dirs, crate_name: &str) -> Vec<PathBuf> {
+    let mut patches: Vec<_> = fs::read_dir(RelPath::PATCHES.to_path(dirs))
         .unwrap()
         .map(|entry| entry.unwrap().path())
         .filter(|path| path.extension() == Some(OsStr::new("patch")))
@@ -215,19 +209,27 @@ fn get_patches(source_dir: &Path, crate_name: &str) -> Vec<PathBuf> {
     patches
 }
 
-fn apply_patches(crate_name: &str, target_dir: &Path) {
+fn apply_patches(dirs: &Dirs, crate_name: &str, target_dir: &Path) {
     if crate_name == "<none>" {
         return;
     }
 
-    for patch in get_patches(&std::env::current_dir().unwrap(), crate_name) {
+    for patch in get_patches(dirs, crate_name) {
         eprintln!(
             "[PATCH] {:?} <- {:?}",
             target_dir.file_name().unwrap(),
             patch.file_name().unwrap()
         );
         let mut apply_patch_cmd = Command::new("git");
-        apply_patch_cmd.arg("am").arg(patch).arg("-q").current_dir(target_dir);
+        apply_patch_cmd
+            .arg("-c")
+            .arg("user.name=Dummy")
+            .arg("-c")
+            .arg("user.email=dummy@example.com")
+            .arg("am")
+            .arg(patch)
+            .arg("-q")
+            .current_dir(target_dir);
         spawn_and_wait(apply_patch_cmd);
     }
 }
index 3c08b6fa3894d61277a0c0b6499e23ddcdc544a9..8e5ab688e131b35325af4fb83a3387b8c6228449 100644 (file)
@@ -23,6 +23,16 @@ pub(crate) fn get_host_triple() -> String {
         .to_owned()
 }
 
+pub(crate) fn get_cargo_path() -> PathBuf {
+    let cargo_path = Command::new("rustup")
+        .stderr(Stdio::inherit())
+        .args(&["which", "cargo"])
+        .output()
+        .unwrap()
+        .stdout;
+    Path::new(String::from_utf8(cargo_path).unwrap().trim()).to_owned()
+}
+
 pub(crate) fn get_rustc_path() -> PathBuf {
     let rustc_path = Command::new("rustup")
         .stderr(Stdio::inherit())
@@ -33,6 +43,16 @@ pub(crate) fn get_rustc_path() -> PathBuf {
     Path::new(String::from_utf8(rustc_path).unwrap().trim()).to_owned()
 }
 
+pub(crate) fn get_rustdoc_path() -> PathBuf {
+    let rustc_path = Command::new("rustup")
+        .stderr(Stdio::inherit())
+        .args(&["which", "rustdoc"])
+        .output()
+        .unwrap()
+        .stdout;
+    Path::new(String::from_utf8(rustc_path).unwrap().trim()).to_owned()
+}
+
 pub(crate) fn get_default_sysroot() -> PathBuf {
     let default_sysroot = Command::new("rustc")
         .stderr(Stdio::inherit())
index a414b60f4e06b2b79dccc1ee64bc233f32ae6ba1..1c372736ed65d9121dccf04ae5bcf504d45127bc 100644 (file)
@@ -1,15 +1,20 @@
 use super::build_sysroot;
 use super::config;
-use super::prepare;
-use super::rustc_info::get_wrapper_file_name;
-use super::utils::{cargo_command, hyperfine_command, spawn_and_wait, spawn_and_wait_with_input};
-use build_system::SysrootKind;
+use super::path::{Dirs, RelPath};
+use super::prepare::GitRepo;
+use super::rustc_info::{get_cargo_path, get_wrapper_file_name};
+use super::utils::{
+    hyperfine_command, spawn_and_wait, spawn_and_wait_with_input, CargoProject, Compiler,
+};
+use super::SysrootKind;
 use std::env;
 use std::ffi::OsStr;
 use std::fs;
-use std::path::{Path, PathBuf};
+use std::path::Path;
 use std::process::Command;
 
+static BUILD_EXAMPLE_OUT_DIR: RelPath = RelPath::BUILD.join("example");
+
 struct TestCase {
     config: &'static str,
     func: &'static dyn Fn(&TestRunner),
@@ -30,7 +35,7 @@ const fn new(config: &'static str, func: &'static dyn Fn(&TestRunner)) -> Self {
             "--crate-type",
             "lib,dylib",
             "--target",
-            &runner.target_triple,
+            &runner.target_compiler.triple,
         ]);
     }),
     TestCase::new("build.example", &|runner| {
@@ -39,7 +44,7 @@ const fn new(config: &'static str, func: &'static dyn Fn(&TestRunner)) -> Self {
             "--crate-type",
             "lib",
             "--target",
-            &runner.target_triple,
+            &runner.target_compiler.triple,
         ]);
     }),
     TestCase::new("jit.mini_core_hello_world", &|runner| {
@@ -51,7 +56,7 @@ const fn new(config: &'static str, func: &'static dyn Fn(&TestRunner)) -> Self {
             "--cfg",
             "jit",
             "--target",
-            &runner.host_triple,
+            &runner.target_compiler.triple,
         ]);
         jit_cmd.env("CG_CLIF_JIT_ARGS", "abc bcd");
         spawn_and_wait(jit_cmd);
@@ -65,7 +70,7 @@ const fn new(config: &'static str, func: &'static dyn Fn(&TestRunner)) -> Self {
             "--cfg",
             "jit",
             "--target",
-            &runner.host_triple,
+            &runner.target_compiler.triple,
         ]);
         jit_cmd.env("CG_CLIF_JIT_ARGS", "abc bcd");
         spawn_and_wait(jit_cmd);
@@ -79,7 +84,7 @@ const fn new(config: &'static str, func: &'static dyn Fn(&TestRunner)) -> Self {
             "bin",
             "-g",
             "--target",
-            &runner.target_triple,
+            &runner.target_compiler.triple,
         ]);
         runner.run_out_command("mini_core_hello_world", ["abc", "bcd"]);
     }),
@@ -94,7 +99,7 @@ const fn new(config: &'static str, func: &'static dyn Fn(&TestRunner)) -> Self {
             "--crate-type",
             "bin",
             "--target",
-            &runner.target_triple,
+            &runner.target_compiler.triple,
         ]);
         runner.run_out_command("arbitrary_self_types_pointers_and_wrappers", []);
     }),
@@ -106,7 +111,7 @@ const fn new(config: &'static str, func: &'static dyn Fn(&TestRunner)) -> Self {
             "--crate-type",
             "bin",
             "--target",
-            &runner.target_triple,
+            &runner.target_compiler.triple,
         ]);
         runner.run_out_command("issue_91827_extern_types", []);
     }),
@@ -116,7 +121,7 @@ const fn new(config: &'static str, func: &'static dyn Fn(&TestRunner)) -> Self {
             "--crate-type",
             "lib",
             "--target",
-            &runner.target_triple,
+            &runner.target_compiler.triple,
         ]);
     }),
     TestCase::new("aot.alloc_example", &|runner| {
@@ -125,7 +130,7 @@ const fn new(config: &'static str, func: &'static dyn Fn(&TestRunner)) -> Self {
             "--crate-type",
             "bin",
             "--target",
-            &runner.target_triple,
+            &runner.target_compiler.triple,
         ]);
         runner.run_out_command("alloc_example", []);
     }),
@@ -136,7 +141,7 @@ const fn new(config: &'static str, func: &'static dyn Fn(&TestRunner)) -> Self {
             "-Cprefer-dynamic",
             "example/std_example.rs",
             "--target",
-            &runner.host_triple,
+            &runner.target_compiler.triple,
         ]);
 
         eprintln!("[JIT-lazy] std_example");
@@ -146,7 +151,7 @@ const fn new(config: &'static str, func: &'static dyn Fn(&TestRunner)) -> Self {
             "-Cprefer-dynamic",
             "example/std_example.rs",
             "--target",
-            &runner.host_triple,
+            &runner.target_compiler.triple,
         ]);
     }),
     TestCase::new("aot.std_example", &|runner| {
@@ -155,7 +160,7 @@ const fn new(config: &'static str, func: &'static dyn Fn(&TestRunner)) -> Self {
             "--crate-type",
             "bin",
             "--target",
-            &runner.target_triple,
+            &runner.target_compiler.triple,
         ]);
         runner.run_out_command("std_example", ["arg"]);
     }),
@@ -167,7 +172,7 @@ const fn new(config: &'static str, func: &'static dyn Fn(&TestRunner)) -> Self {
             "--crate-type",
             "bin",
             "--target",
-            &runner.target_triple,
+            &runner.target_compiler.triple,
         ]);
         runner.run_out_command("dst_field_align", []);
     }),
@@ -178,7 +183,7 @@ const fn new(config: &'static str, func: &'static dyn Fn(&TestRunner)) -> Self {
             "bin",
             "-Cpanic=abort",
             "--target",
-            &runner.target_triple,
+            &runner.target_compiler.triple,
         ]);
         runner.run_out_command("subslice-patterns-const-eval", []);
     }),
@@ -189,7 +194,7 @@ const fn new(config: &'static str, func: &'static dyn Fn(&TestRunner)) -> Self {
             "bin",
             "-Cpanic=abort",
             "--target",
-            &runner.target_triple,
+            &runner.target_compiler.triple,
         ]);
         runner.run_out_command("track-caller-attribute", []);
     }),
@@ -200,7 +205,7 @@ const fn new(config: &'static str, func: &'static dyn Fn(&TestRunner)) -> Self {
             "bin",
             "-Cpanic=abort",
             "--target",
-            &runner.target_triple,
+            &runner.target_compiler.triple,
         ]);
         runner.run_out_command("float-minmax-pass", []);
     }),
@@ -210,205 +215,252 @@ const fn new(config: &'static str, func: &'static dyn Fn(&TestRunner)) -> Self {
             "--crate-type",
             "bin",
             "--target",
-            &runner.target_triple,
+            &runner.target_compiler.triple,
         ]);
         runner.run_out_command("mod_bench", []);
     }),
+    TestCase::new("aot.issue-72793", &|runner| {
+        runner.run_rustc([
+            "example/issue-72793.rs",
+            "--crate-type",
+            "bin",
+            "--target",
+            &runner.target_compiler.triple,
+        ]);
+        runner.run_out_command("issue-72793", []);
+    }),
 ];
 
+pub(crate) static RAND_REPO: GitRepo =
+    GitRepo::github("rust-random", "rand", "0f933f9c7176e53b2a3c7952ded484e1783f0bf1", "rand");
+
+static RAND: CargoProject = CargoProject::new(&RAND_REPO.source_dir(), "rand");
+
+pub(crate) static REGEX_REPO: GitRepo =
+    GitRepo::github("rust-lang", "regex", "341f207c1071f7290e3f228c710817c280c8dca1", "regex");
+
+static REGEX: CargoProject = CargoProject::new(&REGEX_REPO.source_dir(), "regex");
+
+pub(crate) static PORTABLE_SIMD_REPO: GitRepo = GitRepo::github(
+    "rust-lang",
+    "portable-simd",
+    "d5cd4a8112d958bd3a252327e0d069a6363249bd",
+    "portable-simd",
+);
+
+static PORTABLE_SIMD: CargoProject =
+    CargoProject::new(&PORTABLE_SIMD_REPO.source_dir(), "portable_simd");
+
+pub(crate) static SIMPLE_RAYTRACER_REPO: GitRepo = GitRepo::github(
+    "ebobby",
+    "simple-raytracer",
+    "804a7a21b9e673a482797aa289a18ed480e4d813",
+    "<none>",
+);
+
+pub(crate) static SIMPLE_RAYTRACER: CargoProject =
+    CargoProject::new(&SIMPLE_RAYTRACER_REPO.source_dir(), "simple_raytracer");
+
+static LIBCORE_TESTS: CargoProject =
+    CargoProject::new(&RelPath::BUILD_SYSROOT.join("sysroot_src/library/core/tests"), "core_tests");
+
 const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[
     TestCase::new("test.rust-random/rand", &|runner| {
-        runner.in_dir(prepare::RAND.source_dir(), |runner| {
-            runner.run_cargo("clean", []);
-
-            if runner.host_triple == runner.target_triple {
-                eprintln!("[TEST] rust-random/rand");
-                runner.run_cargo("test", ["--workspace"]);
-            } else {
-                eprintln!("[AOT] rust-random/rand");
-                runner.run_cargo("build", ["--workspace", "--tests"]);
-            }
-        });
+        spawn_and_wait(RAND.clean(&runner.target_compiler.cargo, &runner.dirs));
+
+        if runner.is_native {
+            eprintln!("[TEST] rust-random/rand");
+            let mut test_cmd = RAND.test(&runner.target_compiler, &runner.dirs);
+            test_cmd.arg("--workspace");
+            spawn_and_wait(test_cmd);
+        } else {
+            eprintln!("[AOT] rust-random/rand");
+            let mut build_cmd = RAND.build(&runner.target_compiler, &runner.dirs);
+            build_cmd.arg("--workspace").arg("--tests");
+            spawn_and_wait(build_cmd);
+        }
     }),
     TestCase::new("bench.simple-raytracer", &|runner| {
-        runner.in_dir(prepare::SIMPLE_RAYTRACER.source_dir(), |runner| {
-            let run_runs = env::var("RUN_RUNS").unwrap_or("10".to_string()).parse().unwrap();
-
-            if runner.host_triple == runner.target_triple {
-                eprintln!("[BENCH COMPILE] ebobby/simple-raytracer");
-                let prepare = runner.cargo_command("clean", []);
-
-                let llvm_build_cmd = cargo_command("cargo", "build", None, Path::new("."));
-
-                let cargo_clif = runner
-                    .root_dir
-                    .clone()
-                    .join("build")
-                    .join(get_wrapper_file_name("cargo-clif", "bin"));
-                let clif_build_cmd = cargo_command(cargo_clif, "build", None, Path::new("."));
-
-                let bench_compile =
-                    hyperfine_command(1, run_runs, Some(prepare), llvm_build_cmd, clif_build_cmd);
-
-                spawn_and_wait(bench_compile);
-
-                eprintln!("[BENCH RUN] ebobby/simple-raytracer");
-                fs::copy(PathBuf::from("./target/debug/main"), PathBuf::from("raytracer_cg_clif"))
-                    .unwrap();
-
-                let bench_run = hyperfine_command(
-                    0,
-                    run_runs,
-                    None,
-                    Command::new("./raytracer_cg_llvm"),
-                    Command::new("./raytracer_cg_clif"),
-                );
-                spawn_and_wait(bench_run);
-            } else {
-                runner.run_cargo("clean", []);
-                eprintln!("[BENCH COMPILE] ebobby/simple-raytracer (skipped)");
-                eprintln!("[COMPILE] ebobby/simple-raytracer");
-                runner.run_cargo("build", []);
-                eprintln!("[BENCH RUN] ebobby/simple-raytracer (skipped)");
-            }
-        });
+        let run_runs = env::var("RUN_RUNS").unwrap_or("10".to_string()).parse().unwrap();
+
+        if runner.is_native {
+            eprintln!("[BENCH COMPILE] ebobby/simple-raytracer");
+            let cargo_clif = RelPath::DIST
+                .to_path(&runner.dirs)
+                .join(get_wrapper_file_name("cargo-clif", "bin"));
+            let manifest_path = SIMPLE_RAYTRACER.manifest_path(&runner.dirs);
+            let target_dir = SIMPLE_RAYTRACER.target_dir(&runner.dirs);
+
+            let clean_cmd = format!(
+                "cargo clean --manifest-path {manifest_path} --target-dir {target_dir}",
+                manifest_path = manifest_path.display(),
+                target_dir = target_dir.display(),
+            );
+            let llvm_build_cmd = format!(
+                "cargo build --manifest-path {manifest_path} --target-dir {target_dir}",
+                manifest_path = manifest_path.display(),
+                target_dir = target_dir.display(),
+            );
+            let clif_build_cmd = format!(
+                "{cargo_clif} build --manifest-path {manifest_path} --target-dir {target_dir}",
+                cargo_clif = cargo_clif.display(),
+                manifest_path = manifest_path.display(),
+                target_dir = target_dir.display(),
+            );
+
+            let bench_compile =
+                hyperfine_command(1, run_runs, Some(&clean_cmd), &llvm_build_cmd, &clif_build_cmd);
+
+            spawn_and_wait(bench_compile);
+
+            eprintln!("[BENCH RUN] ebobby/simple-raytracer");
+            fs::copy(
+                target_dir.join("debug").join("main"),
+                RelPath::BUILD.to_path(&runner.dirs).join("raytracer_cg_clif"),
+            )
+            .unwrap();
+
+            let mut bench_run =
+                hyperfine_command(0, run_runs, None, "./raytracer_cg_llvm", "./raytracer_cg_clif");
+            bench_run.current_dir(RelPath::BUILD.to_path(&runner.dirs));
+            spawn_and_wait(bench_run);
+        } else {
+            spawn_and_wait(SIMPLE_RAYTRACER.clean(&runner.target_compiler.cargo, &runner.dirs));
+            eprintln!("[BENCH COMPILE] ebobby/simple-raytracer (skipped)");
+            eprintln!("[COMPILE] ebobby/simple-raytracer");
+            spawn_and_wait(SIMPLE_RAYTRACER.build(&runner.target_compiler, &runner.dirs));
+            eprintln!("[BENCH RUN] ebobby/simple-raytracer (skipped)");
+        }
     }),
     TestCase::new("test.libcore", &|runner| {
-        runner.in_dir(
-            std::env::current_dir()
-                .unwrap()
-                .join("build_sysroot")
-                .join("sysroot_src")
-                .join("library")
-                .join("core")
-                .join("tests"),
-            |runner| {
-                runner.run_cargo("clean", []);
-
-                if runner.host_triple == runner.target_triple {
-                    runner.run_cargo("test", []);
-                } else {
-                    eprintln!("Cross-Compiling: Not running tests");
-                    runner.run_cargo("build", ["--tests"]);
-                }
-            },
-        );
+        spawn_and_wait(LIBCORE_TESTS.clean(&runner.host_compiler.cargo, &runner.dirs));
+
+        if runner.is_native {
+            spawn_and_wait(LIBCORE_TESTS.test(&runner.target_compiler, &runner.dirs));
+        } else {
+            eprintln!("Cross-Compiling: Not running tests");
+            let mut build_cmd = LIBCORE_TESTS.build(&runner.target_compiler, &runner.dirs);
+            build_cmd.arg("--tests");
+            spawn_and_wait(build_cmd);
+        }
     }),
     TestCase::new("test.regex-shootout-regex-dna", &|runner| {
-        runner.in_dir(prepare::REGEX.source_dir(), |runner| {
-            runner.run_cargo("clean", []);
-
-            // newer aho_corasick versions throw a deprecation warning
-            let lint_rust_flags = format!("{} --cap-lints warn", runner.rust_flags);
-
-            let mut build_cmd = runner.cargo_command("build", ["--example", "shootout-regex-dna"]);
-            build_cmd.env("RUSTFLAGS", lint_rust_flags.clone());
-            spawn_and_wait(build_cmd);
-
-            if runner.host_triple == runner.target_triple {
-                let mut run_cmd = runner.cargo_command("run", ["--example", "shootout-regex-dna"]);
-                run_cmd.env("RUSTFLAGS", lint_rust_flags);
-
-                let input =
-                    fs::read_to_string(PathBuf::from("examples/regexdna-input.txt")).unwrap();
-                let expected_path = PathBuf::from("examples/regexdna-output.txt");
-                let expected = fs::read_to_string(&expected_path).unwrap();
-
-                let output = spawn_and_wait_with_input(run_cmd, input);
-                // Make sure `[codegen mono items] start` doesn't poison the diff
-                let output = output
-                    .lines()
-                    .filter(|line| !line.contains("codegen mono items"))
-                    .chain(Some("")) // This just adds the trailing newline
-                    .collect::<Vec<&str>>()
-                    .join("\r\n");
-
-                let output_matches = expected.lines().eq(output.lines());
-                if !output_matches {
-                    let res_path = PathBuf::from("res.txt");
-                    fs::write(&res_path, &output).unwrap();
-
-                    if cfg!(windows) {
-                        println!("Output files don't match!");
-                        println!("Expected Output:\n{}", expected);
-                        println!("Actual Output:\n{}", output);
-                    } else {
-                        let mut diff = Command::new("diff");
-                        diff.arg("-u");
-                        diff.arg(res_path);
-                        diff.arg(expected_path);
-                        spawn_and_wait(diff);
-                    }
-
-                    std::process::exit(1);
+        spawn_and_wait(REGEX.clean(&runner.target_compiler.cargo, &runner.dirs));
+
+        // newer aho_corasick versions throw a deprecation warning
+        let lint_rust_flags = format!("{} --cap-lints warn", runner.target_compiler.rustflags);
+
+        let mut build_cmd = REGEX.build(&runner.target_compiler, &runner.dirs);
+        build_cmd.arg("--example").arg("shootout-regex-dna");
+        build_cmd.env("RUSTFLAGS", lint_rust_flags.clone());
+        spawn_and_wait(build_cmd);
+
+        if runner.is_native {
+            let mut run_cmd = REGEX.run(&runner.target_compiler, &runner.dirs);
+            run_cmd.arg("--example").arg("shootout-regex-dna");
+            run_cmd.env("RUSTFLAGS", lint_rust_flags);
+
+            let input = fs::read_to_string(
+                REGEX.source_dir(&runner.dirs).join("examples").join("regexdna-input.txt"),
+            )
+            .unwrap();
+            let expected_path =
+                REGEX.source_dir(&runner.dirs).join("examples").join("regexdna-output.txt");
+            let expected = fs::read_to_string(&expected_path).unwrap();
+
+            let output = spawn_and_wait_with_input(run_cmd, input);
+            // Make sure `[codegen mono items] start` doesn't poison the diff
+            let output = output
+                .lines()
+                .filter(|line| !line.contains("codegen mono items"))
+                .chain(Some("")) // This just adds the trailing newline
+                .collect::<Vec<&str>>()
+                .join("\r\n");
+
+            let output_matches = expected.lines().eq(output.lines());
+            if !output_matches {
+                let res_path = REGEX.source_dir(&runner.dirs).join("res.txt");
+                fs::write(&res_path, &output).unwrap();
+
+                if cfg!(windows) {
+                    println!("Output files don't match!");
+                    println!("Expected Output:\n{}", expected);
+                    println!("Actual Output:\n{}", output);
+                } else {
+                    let mut diff = Command::new("diff");
+                    diff.arg("-u");
+                    diff.arg(res_path);
+                    diff.arg(expected_path);
+                    spawn_and_wait(diff);
                 }
+
+                std::process::exit(1);
             }
-        });
+        }
     }),
     TestCase::new("test.regex", &|runner| {
-        runner.in_dir(prepare::REGEX.source_dir(), |runner| {
-            runner.run_cargo("clean", []);
-
-            // newer aho_corasick versions throw a deprecation warning
-            let lint_rust_flags = format!("{} --cap-lints warn", runner.rust_flags);
-
-            if runner.host_triple == runner.target_triple {
-                let mut run_cmd = runner.cargo_command(
-                    "test",
-                    [
-                        "--tests",
-                        "--",
-                        "--exclude-should-panic",
-                        "--test-threads",
-                        "1",
-                        "-Zunstable-options",
-                        "-q",
-                    ],
-                );
-                run_cmd.env("RUSTFLAGS", lint_rust_flags);
-                spawn_and_wait(run_cmd);
-            } else {
-                eprintln!("Cross-Compiling: Not running tests");
-                let mut build_cmd =
-                    runner.cargo_command("build", ["--tests", "--target", &runner.target_triple]);
-                build_cmd.env("RUSTFLAGS", lint_rust_flags.clone());
-                spawn_and_wait(build_cmd);
-            }
-        });
+        spawn_and_wait(REGEX.clean(&runner.host_compiler.cargo, &runner.dirs));
+
+        // newer aho_corasick versions throw a deprecation warning
+        let lint_rust_flags = format!("{} --cap-lints warn", runner.target_compiler.rustflags);
+
+        if runner.is_native {
+            let mut run_cmd = REGEX.test(&runner.target_compiler, &runner.dirs);
+            run_cmd.args([
+                "--tests",
+                "--",
+                "--exclude-should-panic",
+                "--test-threads",
+                "1",
+                "-Zunstable-options",
+                "-q",
+            ]);
+            run_cmd.env("RUSTFLAGS", lint_rust_flags);
+            spawn_and_wait(run_cmd);
+        } else {
+            eprintln!("Cross-Compiling: Not running tests");
+            let mut build_cmd = REGEX.build(&runner.target_compiler, &runner.dirs);
+            build_cmd.arg("--tests");
+            build_cmd.env("RUSTFLAGS", lint_rust_flags.clone());
+            spawn_and_wait(build_cmd);
+        }
     }),
     TestCase::new("test.portable-simd", &|runner| {
-        runner.in_dir(prepare::PORTABLE_SIMD.source_dir(), |runner| {
-            runner.run_cargo("clean", []);
-            runner.run_cargo("build", ["--all-targets", "--target", &runner.target_triple]);
+        spawn_and_wait(PORTABLE_SIMD.clean(&runner.host_compiler.cargo, &runner.dirs));
 
-            if runner.host_triple == runner.target_triple {
-                runner.run_cargo("test", ["-q"]);
-            }
-        });
+        let mut build_cmd = PORTABLE_SIMD.build(&runner.target_compiler, &runner.dirs);
+        build_cmd.arg("--all-targets");
+        spawn_and_wait(build_cmd);
+
+        if runner.is_native {
+            let mut test_cmd = PORTABLE_SIMD.test(&runner.target_compiler, &runner.dirs);
+            test_cmd.arg("-q");
+            spawn_and_wait(test_cmd);
+        }
     }),
 ];
 
 pub(crate) fn run_tests(
+    dirs: &Dirs,
     channel: &str,
     sysroot_kind: SysrootKind,
-    target_dir: &Path,
     cg_clif_dylib: &Path,
     host_triple: &str,
     target_triple: &str,
 ) {
-    let runner = TestRunner::new(host_triple.to_string(), target_triple.to_string());
+    let runner = TestRunner::new(dirs.clone(), host_triple.to_string(), target_triple.to_string());
 
     if config::get_bool("testsuite.no_sysroot") {
         build_sysroot::build_sysroot(
+            dirs,
             channel,
             SysrootKind::None,
-            &target_dir,
             cg_clif_dylib,
             &host_triple,
             &target_triple,
         );
 
-        let _ = fs::remove_dir_all(Path::new("target").join("out"));
+        BUILD_EXAMPLE_OUT_DIR.ensure_fresh(dirs);
         runner.run_testsuite(NO_SYSROOT_SUITE);
     } else {
         eprintln!("[SKIP] no_sysroot tests");
@@ -419,9 +471,9 @@ pub(crate) fn run_tests(
 
     if run_base_sysroot || run_extended_sysroot {
         build_sysroot::build_sysroot(
+            dirs,
             channel,
             sysroot_kind,
-            &target_dir,
             cg_clif_dylib,
             &host_triple,
             &target_triple,
@@ -442,40 +494,50 @@ pub(crate) fn run_tests(
 }
 
 struct TestRunner {
-    root_dir: PathBuf,
-    out_dir: PathBuf,
+    is_native: bool,
     jit_supported: bool,
-    rust_flags: String,
-    run_wrapper: Vec<String>,
-    host_triple: String,
-    target_triple: String,
+    dirs: Dirs,
+    host_compiler: Compiler,
+    target_compiler: Compiler,
 }
 
 impl TestRunner {
-    pub fn new(host_triple: String, target_triple: String) -> Self {
-        let root_dir = env::current_dir().unwrap();
-
-        let mut out_dir = root_dir.clone();
-        out_dir.push("target");
-        out_dir.push("out");
-
+    pub fn new(dirs: Dirs, host_triple: String, target_triple: String) -> Self {
         let is_native = host_triple == target_triple;
         let jit_supported =
             target_triple.contains("x86_64") && is_native && !host_triple.contains("windows");
 
-        let mut rust_flags = env::var("RUSTFLAGS").ok().unwrap_or("".to_string());
-        let mut run_wrapper = Vec::new();
+        let rustc_clif =
+            RelPath::DIST.to_path(&dirs).join(get_wrapper_file_name("rustc-clif", "bin"));
+        let rustdoc_clif =
+            RelPath::DIST.to_path(&dirs).join(get_wrapper_file_name("rustdoc-clif", "bin"));
+
+        let mut rustflags = env::var("RUSTFLAGS").ok().unwrap_or("".to_string());
+        let mut runner = vec![];
 
         if !is_native {
             match target_triple.as_str() {
                 "aarch64-unknown-linux-gnu" => {
                     // We are cross-compiling for aarch64. Use the correct linker and run tests in qemu.
-                    rust_flags = format!("-Clinker=aarch64-linux-gnu-gcc{}", rust_flags);
-                    run_wrapper = vec!["qemu-aarch64", "-L", "/usr/aarch64-linux-gnu"];
+                    rustflags = format!("-Clinker=aarch64-linux-gnu-gcc{}", rustflags);
+                    runner = vec![
+                        "qemu-aarch64".to_owned(),
+                        "-L".to_owned(),
+                        "/usr/aarch64-linux-gnu".to_owned(),
+                    ];
+                }
+                "s390x-unknown-linux-gnu" => {
+                    // We are cross-compiling for s390x. Use the correct linker and run tests in qemu.
+                    rustflags = format!("-Clinker=s390x-linux-gnu-gcc{}", rustflags);
+                    runner = vec![
+                        "qemu-s390x".to_owned(),
+                        "-L".to_owned(),
+                        "/usr/s390x-linux-gnu".to_owned(),
+                    ];
                 }
                 "x86_64-pc-windows-gnu" => {
                     // We are cross-compiling for Windows. Run tests in wine.
-                    run_wrapper = vec!["wine"];
+                    runner = vec!["wine".to_owned()];
                 }
                 _ => {
                     println!("Unknown non-native platform");
@@ -484,19 +546,31 @@ pub fn new(host_triple: String, target_triple: String) -> Self {
         }
 
         // FIXME fix `#[linkage = "extern_weak"]` without this
-        if host_triple.contains("darwin") {
-            rust_flags = format!("{} -Clink-arg=-undefined -Clink-arg=dynamic_lookup", rust_flags);
+        if target_triple.contains("darwin") {
+            rustflags = format!("{} -Clink-arg=-undefined -Clink-arg=dynamic_lookup", rustflags);
         }
 
-        Self {
-            root_dir,
-            out_dir,
-            jit_supported,
-            rust_flags,
-            run_wrapper: run_wrapper.iter().map(|s| s.to_string()).collect(),
-            host_triple,
-            target_triple,
-        }
+        let host_compiler = Compiler {
+            cargo: get_cargo_path(),
+            rustc: rustc_clif.clone(),
+            rustdoc: rustdoc_clif.clone(),
+            rustflags: String::new(),
+            rustdocflags: String::new(),
+            triple: host_triple,
+            runner: vec![],
+        };
+
+        let target_compiler = Compiler {
+            cargo: get_cargo_path(),
+            rustc: rustc_clif,
+            rustdoc: rustdoc_clif,
+            rustflags: rustflags.clone(),
+            rustdocflags: rustflags,
+            triple: target_triple,
+            runner,
+        };
+
+        Self { is_native, jit_supported, dirs, host_compiler, target_compiler }
     }
 
     pub fn run_testsuite(&self, tests: &[TestCase]) {
@@ -516,29 +590,18 @@ pub fn run_testsuite(&self, tests: &[TestCase]) {
         }
     }
 
-    fn in_dir(&self, new: impl AsRef<Path>, callback: impl FnOnce(&TestRunner)) {
-        let current = env::current_dir().unwrap();
-
-        env::set_current_dir(new).unwrap();
-        callback(self);
-        env::set_current_dir(current).unwrap();
-    }
-
+    #[must_use]
     fn rustc_command<I, S>(&self, args: I) -> Command
     where
         I: IntoIterator<Item = S>,
         S: AsRef<OsStr>,
     {
-        let mut rustc_clif = self.root_dir.clone();
-        rustc_clif.push("build");
-        rustc_clif.push(get_wrapper_file_name("rustc-clif", "bin"));
-
-        let mut cmd = Command::new(rustc_clif);
-        cmd.args(self.rust_flags.split_whitespace());
+        let mut cmd = Command::new(&self.target_compiler.rustc);
+        cmd.args(self.target_compiler.rustflags.split_whitespace());
         cmd.arg("-L");
-        cmd.arg(format!("crate={}", self.out_dir.display()));
+        cmd.arg(format!("crate={}", BUILD_EXAMPLE_OUT_DIR.to_path(&self.dirs).display()));
         cmd.arg("--out-dir");
-        cmd.arg(format!("{}", self.out_dir.display()));
+        cmd.arg(format!("{}", BUILD_EXAMPLE_OUT_DIR.to_path(&self.dirs).display()));
         cmd.arg("-Cdebuginfo=2");
         cmd.args(args);
         cmd
@@ -559,15 +622,13 @@ fn run_out_command<'a, I>(&self, name: &str, args: I)
         let mut full_cmd = vec![];
 
         // Prepend the RUN_WRAPPER's
-        if !self.run_wrapper.is_empty() {
-            full_cmd.extend(self.run_wrapper.iter().cloned());
+        if !self.target_compiler.runner.is_empty() {
+            full_cmd.extend(self.target_compiler.runner.iter().cloned());
         }
 
-        full_cmd.push({
-            let mut out_path = self.out_dir.clone();
-            out_path.push(name);
-            out_path.to_str().unwrap().to_string()
-        });
+        full_cmd.push(
+            BUILD_EXAMPLE_OUT_DIR.to_path(&self.dirs).join(name).to_str().unwrap().to_string(),
+        );
 
         for arg in args.into_iter() {
             full_cmd.push(arg.to_string());
@@ -581,30 +642,4 @@ fn run_out_command<'a, I>(&self, name: &str, args: I)
 
         spawn_and_wait(cmd);
     }
-
-    fn cargo_command<'a, I>(&self, subcommand: &str, args: I) -> Command
-    where
-        I: IntoIterator<Item = &'a str>,
-    {
-        let mut cargo_clif = self.root_dir.clone();
-        cargo_clif.push("build");
-        cargo_clif.push(get_wrapper_file_name("cargo-clif", "bin"));
-
-        let mut cmd = cargo_command(
-            cargo_clif,
-            subcommand,
-            if subcommand == "clean" { None } else { Some(&self.target_triple) },
-            Path::new("."),
-        );
-        cmd.args(args);
-        cmd.env("RUSTFLAGS", &self.rust_flags);
-        cmd
-    }
-
-    fn run_cargo<'a, I>(&self, subcommand: &str, args: I)
-    where
-        I: IntoIterator<Item = &'a str>,
-    {
-        spawn_and_wait(self.cargo_command(subcommand, args));
-    }
 }
index c627af4e62fe14073bc539d195cb5623afd7dabe..2be70e8e421b2961e97b53c99f38c83256940365 100644 (file)
 use std::env;
 use std::fs;
 use std::io::Write;
-use std::path::Path;
+use std::path::{Path, PathBuf};
 use std::process::{self, Command, Stdio};
 
-pub(crate) fn cargo_command(
-    cargo: impl AsRef<Path>,
-    subcommand: &str,
-    triple: Option<&str>,
-    source_dir: &Path,
-) -> Command {
-    let mut cmd = Command::new(cargo.as_ref());
-    cmd.arg(subcommand)
-        .arg("--manifest-path")
-        .arg(source_dir.join("Cargo.toml"))
-        .arg("--target-dir")
-        .arg(source_dir.join("target"));
+use super::path::{Dirs, RelPath};
+use super::rustc_info::{get_cargo_path, get_host_triple, get_rustc_path, get_rustdoc_path};
+
+pub(crate) struct Compiler {
+    pub(crate) cargo: PathBuf,
+    pub(crate) rustc: PathBuf,
+    pub(crate) rustdoc: PathBuf,
+    pub(crate) rustflags: String,
+    pub(crate) rustdocflags: String,
+    pub(crate) triple: String,
+    pub(crate) runner: Vec<String>,
+}
+
+impl Compiler {
+    pub(crate) fn host() -> Compiler {
+        Compiler {
+            cargo: get_cargo_path(),
+            rustc: get_rustc_path(),
+            rustdoc: get_rustdoc_path(),
+            rustflags: String::new(),
+            rustdocflags: String::new(),
+            triple: get_host_triple(),
+            runner: vec![],
+        }
+    }
+
+    pub(crate) fn with_triple(triple: String) -> Compiler {
+        Compiler {
+            cargo: get_cargo_path(),
+            rustc: get_rustc_path(),
+            rustdoc: get_rustdoc_path(),
+            rustflags: String::new(),
+            rustdocflags: String::new(),
+            triple,
+            runner: vec![],
+        }
+    }
+}
+
+pub(crate) struct CargoProject {
+    source: &'static RelPath,
+    target: &'static str,
+}
+
+impl CargoProject {
+    pub(crate) const fn new(path: &'static RelPath, target: &'static str) -> CargoProject {
+        CargoProject { source: path, target }
+    }
+
+    pub(crate) fn source_dir(&self, dirs: &Dirs) -> PathBuf {
+        self.source.to_path(dirs)
+    }
+
+    pub(crate) fn manifest_path(&self, dirs: &Dirs) -> PathBuf {
+        self.source_dir(dirs).join("Cargo.toml")
+    }
+
+    pub(crate) fn target_dir(&self, dirs: &Dirs) -> PathBuf {
+        RelPath::BUILD.join(self.target).to_path(dirs)
+    }
 
-    if let Some(triple) = triple {
-        cmd.arg("--target").arg(triple);
+    fn base_cmd(&self, command: &str, cargo: &Path, dirs: &Dirs) -> Command {
+        let mut cmd = Command::new(cargo);
+
+        cmd.arg(command)
+            .arg("--manifest-path")
+            .arg(self.manifest_path(dirs))
+            .arg("--target-dir")
+            .arg(self.target_dir(dirs));
+
+        cmd
+    }
+
+    fn build_cmd(&self, command: &str, compiler: &Compiler, dirs: &Dirs) -> Command {
+        let mut cmd = self.base_cmd(command, &compiler.cargo, dirs);
+
+        cmd.arg("--target").arg(&compiler.triple);
+
+        cmd.env("RUSTC", &compiler.rustc);
+        cmd.env("RUSTDOC", &compiler.rustdoc);
+        cmd.env("RUSTFLAGS", &compiler.rustflags);
+        cmd.env("RUSTDOCFLAGS", &compiler.rustdocflags);
+        if !compiler.runner.is_empty() {
+            cmd.env(
+                format!("CARGO_TARGET_{}_RUNNER", compiler.triple.to_uppercase().replace('-', "_")),
+                compiler.runner.join(" "),
+            );
+        }
+
+        cmd
     }
 
-    cmd
+    #[must_use]
+    pub(crate) fn fetch(&self, cargo: impl AsRef<Path>, dirs: &Dirs) -> Command {
+        let mut cmd = Command::new(cargo.as_ref());
+
+        cmd.arg("fetch").arg("--manifest-path").arg(self.manifest_path(dirs));
+
+        cmd
+    }
+
+    #[must_use]
+    pub(crate) fn clean(&self, cargo: &Path, dirs: &Dirs) -> Command {
+        self.base_cmd("clean", cargo, dirs)
+    }
+
+    #[must_use]
+    pub(crate) fn build(&self, compiler: &Compiler, dirs: &Dirs) -> Command {
+        self.build_cmd("build", compiler, dirs)
+    }
+
+    #[must_use]
+    pub(crate) fn test(&self, compiler: &Compiler, dirs: &Dirs) -> Command {
+        self.build_cmd("test", compiler, dirs)
+    }
+
+    #[must_use]
+    pub(crate) fn run(&self, compiler: &Compiler, dirs: &Dirs) -> Command {
+        self.build_cmd("run", compiler, dirs)
+    }
 }
 
+#[must_use]
 pub(crate) fn hyperfine_command(
     warmup: u64,
     runs: u64,
-    prepare: Option<Command>,
-    a: Command,
-    b: Command,
+    prepare: Option<&str>,
+    a: &str,
+    b: &str,
 ) -> Command {
     let mut bench = Command::new("hyperfine");
 
@@ -42,10 +145,10 @@ pub(crate) fn hyperfine_command(
     }
 
     if let Some(prepare) = prepare {
-        bench.arg("--prepare").arg(format!("{:?}", prepare));
+        bench.arg("--prepare").arg(prepare);
     }
 
-    bench.arg(format!("{:?}", a)).arg(format!("{:?}", b));
+    bench.arg(a).arg(b);
 
     bench
 }
index fedab2433aa05f66f33949f35ea62cd88ec3f4ed..1760e5836ecce00a48f7a0236748dfb94329fce0 100755 (executable)
@@ -2,7 +2,7 @@
 set -e
 
 rm -rf build_sysroot/{sysroot_src/,target/,compiler-builtins/,rustc_version}
-rm -rf target/ build/ perf.data{,.old} y.bin
+rm -rf target/ build/ dist/ perf.data{,.old} y.bin
 rm -rf download/
 
 # Kept for now in case someone updates their checkout of cg_clif before running clean_all.sh
index 0d539191b12f95936b65e6d134d460b31d96c3e6..258b67e931476850a25cab17bbc2c3300a243821 100644 (file)
@@ -40,6 +40,7 @@ aot.subslice-patterns-const-eval
 aot.track-caller-attribute
 aot.float-minmax-pass
 aot.mod_bench
+aot.issue-72793
 
 testsuite.extended_sysroot
 test.rust-random/rand
index 33f146e7ba27aec13e57e55d40ebb79e3f28e359..4c2b0fa170498812b976b67041cc62ab73ff3f81 100644 (file)
@@ -9,7 +9,7 @@ Assuming `$cg_clif_dir` is the directory you cloned this repo into and you follo
 In the directory with your project (where you can do the usual `cargo build`), run:
 
 ```bash
-$ $cg_clif_dir/build/cargo-clif build
+$ $cg_clif_dir/dist/cargo-clif build
 ```
 
 This will build your project with rustc_codegen_cranelift instead of the usual LLVM backend.
@@ -19,7 +19,7 @@ This will build your project with rustc_codegen_cranelift instead of the usual L
 > You should prefer using the Cargo method.
 
 ```bash
-$ $cg_clif_dir/build/rustc-clif my_crate.rs
+$ $cg_clif_dir/dist/rustc-clif my_crate.rs
 ```
 
 ## Jit mode
@@ -32,20 +32,20 @@ In jit mode cg_clif will immediately execute your code without creating an execu
 > The jit mode will probably need cargo integration to make this possible.
 
 ```bash
-$ $cg_clif_dir/build/cargo-clif jit
+$ $cg_clif_dir/dist/cargo-clif jit
 ```
 
 or
 
 ```bash
-$ $cg_clif_dir/build/rustc-clif -Zunstable-features -Cllvm-args=mode=jit -Cprefer-dynamic my_crate.rs
+$ $cg_clif_dir/dist/rustc-clif -Zunstable-features -Cllvm-args=mode=jit -Cprefer-dynamic my_crate.rs
 ```
 
 There is also an experimental lazy jit mode. In this mode functions are only compiled once they are
 first called.
 
 ```bash
-$ $cg_clif_dir/build/cargo-clif lazy-jit
+$ $cg_clif_dir/dist/cargo-clif lazy-jit
 ```
 
 ## Shell
@@ -54,7 +54,7 @@ These are a few functions that allow you to easily run rust code from the shell
 
 ```bash
 function jit_naked() {
-    echo "$@" | $cg_clif_dir/build/rustc-clif - -Zunstable-features -Cllvm-args=mode=jit -Cprefer-dynamic
+    echo "$@" | $cg_clif_dir/dist/rustc-clif - -Zunstable-features -Cllvm-args=mode=jit -Cprefer-dynamic
 }
 
 function jit() {
diff --git a/compiler/rustc_codegen_cranelift/example/issue-72793.rs b/compiler/rustc_codegen_cranelift/example/issue-72793.rs
new file mode 100644 (file)
index 0000000..b1bb9b8
--- /dev/null
@@ -0,0 +1,24 @@
+// Adapted from rustc ui test suite (ui/type-alias-impl-trait/issue-72793.rs)
+
+#![feature(type_alias_impl_trait)]
+
+trait T { type Item; }
+
+type Alias<'a> = impl T<Item = &'a ()>;
+
+struct S;
+impl<'a> T for &'a S {
+    type Item = &'a ();
+}
+
+fn filter_positive<'a>() -> Alias<'a> {
+    &S
+}
+
+fn with_positive(fun: impl Fn(Alias<'_>)) {
+    fun(filter_positive());
+}
+
+fn main() {
+    with_positive(|_| ());
+}
index 7f85b52f083a7c2a8de18913a937a65e711474b7..1f9db1eb2a97affce42fe9395435a0b5cd0b8341 100644 (file)
@@ -19,6 +19,9 @@ pub trait Sized {}
 #[lang = "destruct"]
 pub trait Destruct {}
 
+#[lang = "tuple_trait"]
+pub trait Tuple {}
+
 #[lang = "unsize"]
 pub trait Unsize<T: ?Sized> {}
 
@@ -443,7 +446,7 @@ pub enum Option<T> {
 
 #[lang = "fn_once"]
 #[rustc_paren_sugar]
-pub trait FnOnce<Args> {
+pub trait FnOnce<Args: Tuple> {
     #[lang = "fn_once_output"]
     type Output;
 
@@ -452,7 +455,7 @@ pub trait FnOnce<Args> {
 
 #[lang = "fn_mut"]
 #[rustc_paren_sugar]
-pub trait FnMut<Args>: FnOnce<Args> {
+pub trait FnMut<Args: Tuple>: FnOnce<Args> {
     extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
 }
 
index 215d3556a17ca8cf2b5eb7a7673b5a090612da70..c00f8a2e0cdad3229ad1362047bffeb8a4be2ad9 100644 (file)
@@ -171,8 +171,6 @@ fn main() {
 
     assert_eq!(slice_ptr as usize % 4, 0);
 
-    //return;
-
     unsafe {
         printf("Hello %s\n\0" as *const str as *const i8, "printf\0" as *const str as *const i8);
 
index ad108c34992e30efa101dc5d71fa5f832e45788f..8481d9c39a3cf672e83f85b03220fabdacf61817 100644 (file)
@@ -164,6 +164,8 @@ unsafe fn test_simd() {
     let cmp_eq = _mm_cmpeq_epi8(y, y);
     let cmp_lt = _mm_cmplt_epi8(y, y);
 
+    let (zero0, zero1) = std::mem::transmute::<_, (u64, u64)>(x);
+    assert_eq!((zero0, zero1), (0, 0));
     assert_eq!(std::mem::transmute::<_, [u16; 8]>(or), [7, 7, 7, 7, 7, 7, 7, 7]);
     assert_eq!(std::mem::transmute::<_, [u16; 8]>(cmp_eq), [0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff]);
     assert_eq!(std::mem::transmute::<_, [u16; 8]>(cmp_lt), [0, 0, 0, 0, 0, 0, 0, 0]);
index c0a2e7a7883fcb14031a9ea5a38289d564d30d4a..d8f28dbcc15c8c43d9631834b087f34ed547cebb 100644 (file)
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2022-10-23"
+channel = "nightly-2022-12-13"
 components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
index 2bd8f7d1bc15d7a6690a34aad18f968f7af9bd3c..ebeca8662a5195c6408e8707a06248c189ffab99 100644 (file)
@@ -1,3 +1,5 @@
+ignore = ["y.rs"]
+
 # Matches rustfmt.toml of rustc
 version = "Two"
 use_small_heuristics = "Max"
index e6f60d1c0cb230985bf85311076b15199291a807..f782671fe36f9b45fab05a5c6f335d9880211c23 100755 (executable)
@@ -2,7 +2,7 @@
 #![forbid(unsafe_code)]/* This line is ignored by bash
 # This block is ignored by rustc
 pushd $(dirname "$0")/../
-RUSTC="$(pwd)/build/rustc-clif"
+RUSTC="$(pwd)/dist/rustc-clif"
 popd
 PROFILE=$1 OUTPUT=$2 exec $RUSTC -Zunstable-options -Cllvm-args=mode=jit -Cprefer-dynamic $0
 #*/
diff --git a/compiler/rustc_codegen_cranelift/scripts/rustdoc-clif.rs b/compiler/rustc_codegen_cranelift/scripts/rustdoc-clif.rs
new file mode 100644 (file)
index 0000000..a19d72a
--- /dev/null
@@ -0,0 +1,36 @@
+use std::env;
+use std::ffi::OsString;
+#[cfg(unix)]
+use std::os::unix::process::CommandExt;
+use std::path::PathBuf;
+use std::process::Command;
+
+fn main() {
+    let sysroot = PathBuf::from(env::current_exe().unwrap().parent().unwrap());
+
+    let cg_clif_dylib_path = sysroot.join(if cfg!(windows) { "bin" } else { "lib" }).join(
+        env::consts::DLL_PREFIX.to_string() + "rustc_codegen_cranelift" + env::consts::DLL_SUFFIX,
+    );
+
+    let mut args = std::env::args_os().skip(1).collect::<Vec<_>>();
+    args.push(OsString::from("-Cpanic=abort"));
+    args.push(OsString::from("-Zpanic-abort-tests"));
+    let mut codegen_backend_arg = OsString::from("-Zcodegen-backend=");
+    codegen_backend_arg.push(cg_clif_dylib_path);
+    args.push(codegen_backend_arg);
+    if !args.contains(&OsString::from("--sysroot")) {
+        args.push(OsString::from("--sysroot"));
+        args.push(OsString::from(sysroot.to_str().unwrap()));
+    }
+
+    // Ensure that the right toolchain is used
+    env::set_var("RUSTUP_TOOLCHAIN", env!("RUSTUP_TOOLCHAIN"));
+
+    #[cfg(unix)]
+    Command::new("rustdoc").args(args).exec();
+
+    #[cfg(not(unix))]
+    std::process::exit(
+        Command::new("rustdoc").args(args).spawn().unwrap().wait().unwrap().code().unwrap_or(1),
+    );
+}
index d6a37789599fe8d0621de8a2577fc77aa45b1be3..6c64b7de7daa10d863a903a186e0ee9c4846aeed 100644 (file)
@@ -27,24 +27,6 @@ index d95b5b7f17f..00b6f0e3635 100644
  [dev-dependencies]
  rand = "0.7"
  rand_xorshift = "0.2"
-diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
-index 8431aa7b818..a3ff7e68ce5 100644
---- a/src/tools/compiletest/src/runtest.rs
-+++ b/src/tools/compiletest/src/runtest.rs
-@@ -3489,12 +3489,7 @@ fn normalize_output(&self, output: &str, custom_rules: &[(String, String)]) -> S
-         let compiler_src_dir = base_dir.join("compiler");
-         normalize_path(&compiler_src_dir, "$(echo '$COMPILER_DIR')");
-
--        if let Some(virtual_rust_source_base_dir) =
--            option_env!("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR").map(PathBuf::from)
--        {
--            normalize_path(&virtual_rust_source_base_dir.join("library"), "$(echo '$SRC_DIR')");
--            normalize_path(&virtual_rust_source_base_dir.join("compiler"), "$(echo '$COMPILER_DIR')");
--        }
-+        normalize_path(&Path::new("$(cd ../build_sysroot/sysroot_src/library; pwd)"), "$(echo '$SRC_DIR')");
-
-         // Paths into the build directory
-         let test_build_dir = &self.config.build_base;
 EOF
 
 cat > config.toml <<EOF
@@ -54,7 +36,7 @@ changelog-seen = 2
 ninja = false
 
 [build]
-rustc = "$(pwd)/../build/rustc-clif"
+rustc = "$(pwd)/../dist/rustc-clif"
 cargo = "$(rustup which cargo)"
 full-bootstrap = true
 local-rebuild = true
@@ -69,6 +51,8 @@ popd
 # FIXME remove once inline asm is fully supported
 export RUSTFLAGS="$RUSTFLAGS --cfg=rustix_use_libc"
 
+export CFG_VIRTUAL_RUST_SOURCE_BASE_DIR="$(cd build_sysroot/sysroot_src; pwd)"
+
 # Allow the testsuite to use llvm tools
 host_triple=$(rustc -vV | grep host | cut -d: -f2 | tr -d " ")
 export LLVM_BIN_DIR="$(rustc --print sysroot)/lib/rustlib/$host_triple/bin"
index 9b5db3cf81f0e3341f553398f6354c9320cf0640..04ad77ec97eac3a76d01166d875cf18bc073f76f 100755 (executable)
@@ -20,6 +20,7 @@ for test in $(rg -i --files-with-matches "//(\[\w+\])?~[^\|]*\s*ERR|// error-pat
 done
 
 git checkout -- src/test/ui/issues/auxiliary/issue-3136-a.rs # contains //~ERROR, but shouldn't be removed
+git checkout -- src/test/ui/proc-macro/pretty-print-hack/
 
 # missing features
 # ================
@@ -30,6 +31,7 @@ rm src/test/incremental/issue-80691-bad-eval-cache.rs # -Cpanic=abort causes abo
 
 # requires compiling with -Cpanic=unwind
 rm -r src/test/ui/macros/rfc-2011-nicer-assert-messages/
+rm -r src/test/run-make/test-benches
 
 # vendor intrinsics
 rm src/test/ui/sse2.rs # cpuid not supported, so sse2 not detected
@@ -64,6 +66,8 @@ rm src/test/ui/fn/dyn-fn-alignment.rs # wants a 256 byte alignment
 rm -r src/test/run-make/emit-named-files # requires full --emit support
 rm src/test/ui/abi/stack-probes.rs # stack probes not yet implemented
 rm src/test/ui/simd/intrinsic/ptr-cast.rs # simd_expose_addr intrinsic unimplemented
+rm -r src/test/run-make/repr128-dwarf # debuginfo test
+rm src/test/codegen-units/item-collection/asm-sym.rs # requires support for sym in asm!()
 
 # optimization tests
 # ==================
@@ -82,20 +86,20 @@ rm src/test/ui/abi/stack-protector.rs # requires stack protector support
 rm src/test/ui/mir/mir_misc_casts.rs # depends on deduplication of constants
 rm src/test/ui/mir/mir_raw_fat_ptr.rs # same
 rm src/test/ui/consts/issue-33537.rs # same
+rm src/test/ui/layout/valid_range_oob.rs # different ICE message
 
 # doesn't work due to the way the rustc test suite is invoked.
 # should work when using ./x.py test the way it is intended
 # ============================================================
-rm -r src/test/run-make/emit-shared-files # requires the rustdoc executable in build/bin/
+rm -r src/test/run-make/emit-shared-files # requires the rustdoc executable in dist/bin/
 rm -r src/test/run-make/unstable-flag-required # same
 rm -r src/test/run-make/rustdoc-* # same
 rm -r src/test/run-make/issue-88756-default-output # same
 rm -r src/test/run-make/remap-path-prefix-dwarf # requires llvm-dwarfdump
+rm -r src/test/ui/consts/missing_span_in_backtrace.rs # expects sysroot source to be elsewhere
 
 # genuine bugs
 # ============
-rm src/test/ui/allocator/no_std-alloc-error-handler-default.rs # missing rust_oom definition
-
 rm src/test/incremental/spike-neg1.rs # errors out for some reason
 rm src/test/incremental/spike-neg2.rs # same
 rm src/test/ui/issues/issue-74564-if-expr-stack-overflow.rs # gives a stackoverflow before the backend runs
@@ -104,6 +108,8 @@ rm src/test/ui/type-alias-impl-trait/assoc-projection-ice.rs # produces ICE
 
 rm src/test/ui/simd/intrinsic/generic-reduction-pass.rs # simd_reduce_add_unordered doesn't accept an accumulator for integer vectors
 
+rm src/test/ui/runtime/out-of-stack.rs # SIGSEGV instead of SIGABRT for some reason (#1301)
+
 # bugs in the test suite
 # ======================
 rm src/test/ui/backtrace.rs # TODO warning
@@ -111,6 +117,8 @@ rm src/test/ui/simple_global_asm.rs # TODO add needs-asm-support
 rm src/test/ui/test-attrs/test-type.rs # TODO panic message on stderr. correct stdout
 # not sure if this is actually a bug in the test suite, but the symbol list shows the function without leading _ for some reason
 rm -r src/test/run-make/native-link-modifier-bundle
+rm src/test/ui/process/nofile-limit.rs # TODO some AArch64 linking issue
+rm src/test/ui/dyn-star/dispatch-on-pin-mut.rs # TODO failed assertion in vtable::get_ptr_and_method_ref
 
 rm src/test/ui/stdio-is-blocking.rs # really slow with unoptimized libstd
 
index 98b5fb1cce28531eb856e758cde8061b8ae15426..65cc6b4376713d8c7e855c2fca1f833894a3cd09 100644 (file)
@@ -56,13 +56,13 @@ pub(crate) fn conv_to_call_conv(c: Conv, default_call_conv: CallConv) -> CallCon
 
 pub(crate) fn get_function_sig<'tcx>(
     tcx: TyCtxt<'tcx>,
-    triple: &target_lexicon::Triple,
+    default_call_conv: CallConv,
     inst: Instance<'tcx>,
 ) -> Signature {
     assert!(!inst.substs.needs_infer());
     clif_sig_from_fn_abi(
         tcx,
-        CallConv::triple_default(triple),
+        default_call_conv,
         &RevealAllLayoutCx(tcx).fn_abi_of_instance(inst, ty::List::empty()),
     )
 }
@@ -74,7 +74,7 @@ pub(crate) fn import_function<'tcx>(
     inst: Instance<'tcx>,
 ) -> FuncId {
     let name = tcx.symbol_name(inst).name;
-    let sig = get_function_sig(tcx, module.isa().triple(), inst);
+    let sig = get_function_sig(tcx, module.target_config().default_call_conv, inst);
     match module.declare_function(name, Linkage::Import, &sig) {
         Ok(func_id) => func_id,
         Err(ModuleError::IncompatibleDeclaration(_)) => tcx.sess.fatal(&format!(
@@ -341,14 +341,13 @@ pub(crate) fn codegen_terminator_call<'tcx>(
     destination: Place<'tcx>,
     target: Option<BasicBlock>,
 ) {
-    let fn_ty = fx.monomorphize(func.ty(fx.mir, fx.tcx));
-    let fn_sig =
-        fx.tcx.normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), fn_ty.fn_sig(fx.tcx));
+    let func = codegen_operand(fx, func);
+    let fn_sig = func.layout().ty.fn_sig(fx.tcx);
 
     let ret_place = codegen_place(fx, destination);
 
     // Handle special calls like intrinsics and empty drop glue.
-    let instance = if let ty::FnDef(def_id, substs) = *fn_ty.kind() {
+    let instance = if let ty::FnDef(def_id, substs) = *func.layout().ty.kind() {
         let instance =
             ty::Instance::expect_resolve(fx.tcx, ty::ParamEnv::reveal_all(), def_id, substs)
                 .polymorphize(fx.tcx);
@@ -390,17 +389,17 @@ pub(crate) fn codegen_terminator_call<'tcx>(
         None
     };
 
-    let extra_args = &args[fn_sig.inputs().len()..];
+    let extra_args = &args[fn_sig.inputs().skip_binder().len()..];
     let extra_args = fx
         .tcx
         .mk_type_list(extra_args.iter().map(|op_arg| fx.monomorphize(op_arg.ty(fx.mir, fx.tcx))));
     let fn_abi = if let Some(instance) = instance {
         RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(instance, extra_args)
     } else {
-        RevealAllLayoutCx(fx.tcx).fn_abi_of_fn_ptr(fn_ty.fn_sig(fx.tcx), extra_args)
+        RevealAllLayoutCx(fx.tcx).fn_abi_of_fn_ptr(fn_sig, extra_args)
     };
 
-    let is_cold = if fn_sig.abi == Abi::RustCold {
+    let is_cold = if fn_sig.abi() == Abi::RustCold {
         true
     } else {
         instance
@@ -417,7 +416,7 @@ pub(crate) fn codegen_terminator_call<'tcx>(
     }
 
     // Unpack arguments tuple for closures
-    let mut args = if fn_sig.abi == Abi::RustCall {
+    let mut args = if fn_sig.abi() == Abi::RustCall {
         assert_eq!(args.len(), 2, "rust-call abi requires two arguments");
         let self_arg = codegen_call_argument_operand(fx, &args[0]);
         let pack_arg = codegen_call_argument_operand(fx, &args[1]);
@@ -485,7 +484,7 @@ enum CallTarget {
                 fx.add_comment(nop_inst, "indirect call");
             }
 
-            let func = codegen_operand(fx, func).load_scalar(fx);
+            let func = func.load_scalar(fx);
             let sig = clif_sig_from_fn_abi(fx.tcx, fx.target_config.default_call_conv, &fn_abi);
             let sig = fx.bcx.import_signature(sig);
 
@@ -516,11 +515,11 @@ enum CallTarget {
         };
 
         // FIXME find a cleaner way to support varargs
-        if fn_sig.c_variadic {
-            if !matches!(fn_sig.abi, Abi::C { .. }) {
+        if fn_sig.c_variadic() {
+            if !matches!(fn_sig.abi(), Abi::C { .. }) {
                 fx.tcx.sess.span_fatal(
                     source_info.span,
-                    &format!("Variadic call for non-C abi {:?}", fn_sig.abi),
+                    &format!("Variadic call for non-C abi {:?}", fn_sig.abi()),
                 );
             }
             let sig_ref = fx.bcx.func.dfg.call_signature(call_inst).unwrap();
index 12bb00d346db42c42c88adfad2d5939df371c1f6..8508227179ac611fb77c350c541e5835e0313936 100644 (file)
@@ -66,7 +66,7 @@ fn codegen_inner(
         };
 
         let sig = Signature {
-            call_conv: CallConv::triple_default(module.isa().triple()),
+            call_conv: module.target_config().default_call_conv,
             params: arg_tys.iter().cloned().map(AbiParam::new).collect(),
             returns: output.into_iter().map(AbiParam::new).collect(),
         };
@@ -104,7 +104,7 @@ fn codegen_inner(
     }
 
     let sig = Signature {
-        call_conv: CallConv::triple_default(module.isa().triple()),
+        call_conv: module.target_config().default_call_conv,
         params: vec![AbiParam::new(usize_ty), AbiParam::new(usize_ty)],
         returns: vec![],
     };
index 06813d7ec953f558a44eec3eb059723167e45131..89d955e8bf2e1d84c1a40045d0b063140d325525 100644 (file)
@@ -59,7 +59,7 @@ pub(crate) fn codegen_fn<'tcx>(
 
     // Declare function
     let symbol_name = tcx.symbol_name(instance).name.to_string();
-    let sig = get_function_sig(tcx, module.isa().triple(), instance);
+    let sig = get_function_sig(tcx, module.target_config().default_call_conv, instance);
     let func_id = module.declare_function(&symbol_name, Linkage::Local, &sig).unwrap();
 
     // Make the FunctionBuilder
@@ -390,11 +390,9 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
                         _ => unreachable!("{:?}", targets),
                     };
 
-                    let discr = crate::optimize::peephole::maybe_unwrap_bint(&mut fx.bcx, discr);
                     let (discr, is_inverted) =
                         crate::optimize::peephole::maybe_unwrap_bool_not(&mut fx.bcx, discr);
                     let test_zero = if is_inverted { !test_zero } else { test_zero };
-                    let discr = crate::optimize::peephole::maybe_unwrap_bint(&mut fx.bcx, discr);
                     if let Some(taken) = crate::optimize::peephole::maybe_known_branch_taken(
                         &fx.bcx, discr, test_zero,
                     ) {
@@ -571,7 +569,7 @@ fn codegen_stmt<'tcx>(
                         UnOp::Not => match layout.ty.kind() {
                             ty::Bool => {
                                 let res = fx.bcx.ins().icmp_imm(IntCC::Equal, val, 0);
-                                CValue::by_val(fx.bcx.ins().bint(types::I8, res), layout)
+                                CValue::by_val(res, layout)
                             }
                             ty::Uint(_) | ty::Int(_) => {
                                 CValue::by_val(fx.bcx.ins().bnot(val), layout)
@@ -579,12 +577,6 @@ fn codegen_stmt<'tcx>(
                             _ => unreachable!("un op Not for {:?}", layout.ty),
                         },
                         UnOp::Neg => match layout.ty.kind() {
-                            ty::Int(IntTy::I128) => {
-                                // FIXME remove this case once ineg.i128 works
-                                let zero =
-                                    CValue::const_val(fx, layout, ty::ScalarInt::null(layout.size));
-                                crate::num::codegen_int_binop(fx, BinOp::Sub, zero, operand)
-                            }
                             ty::Int(_) => CValue::by_val(fx.bcx.ins().ineg(val), layout),
                             ty::Float(_) => CValue::by_val(fx.bcx.ins().fneg(val), layout),
                             _ => unreachable!("un op Neg for {:?}", layout.ty),
index bad5d1f08a9cf5454766b36de3f2614e5a6020a4..5091c5a9fedacbb7f4dda7b4d5ab7f086f17d1d7 100644 (file)
@@ -149,7 +149,7 @@ pub(crate) fn clif_int_or_float_cast(
         }
 
         let is_not_nan = fx.bcx.ins().fcmp(FloatCC::Equal, from, from);
-        let zero = fx.bcx.ins().iconst(to_ty, 0);
+        let zero = type_zero_value(&mut fx.bcx, to_ty);
         fx.bcx.ins().select(is_not_nan, val, zero)
     } else if from_ty.is_float() && to_ty.is_float() {
         // float -> float
index 589594465783e1611c688cd17f5c82325ae9576f..2dcd42fbd8f431833ac46b414c539e40c828f0e8 100644 (file)
@@ -162,11 +162,20 @@ pub(crate) fn codegen_icmp_imm(
             }
         }
     } else {
-        let rhs = i64::try_from(rhs).expect("codegen_icmp_imm rhs out of range for <128bit int");
+        let rhs = rhs as i64; // Truncates on purpose in case rhs is actually an unsigned value
         fx.bcx.ins().icmp_imm(intcc, lhs, rhs)
     }
 }
 
+pub(crate) fn type_zero_value(bcx: &mut FunctionBuilder<'_>, ty: Type) -> Value {
+    if ty == types::I128 {
+        let zero = bcx.ins().iconst(types::I64, 0);
+        bcx.ins().iconcat(zero, zero)
+    } else {
+        bcx.ins().iconst(ty, 0)
+    }
+}
+
 pub(crate) fn type_min_max_value(
     bcx: &mut FunctionBuilder<'_>,
     ty: Type,
index a6bde88408497ed9d12a7cd28a82966d7fc52439..dee6fb5b5130d1f27abaf1fda1581605a82973b5 100644 (file)
@@ -28,9 +28,7 @@ pub(crate) fn new() -> Self {
     }
 
     pub(crate) fn finalize(mut self, tcx: TyCtxt<'_>, module: &mut dyn Module) {
-        //println!("todo {:?}", self.todo);
         define_all_allocs(tcx, module, &mut self);
-        //println!("done {:?}", self.done);
         self.done.clear();
     }
 }
@@ -268,16 +266,7 @@ fn data_id_for_static(
     def_id: DefId,
     definition: bool,
 ) -> DataId {
-    let rlinkage = tcx.codegen_fn_attrs(def_id).linkage;
-    let linkage = if definition {
-        crate::linkage::get_static_linkage(tcx, def_id)
-    } else if rlinkage == Some(rustc_middle::mir::mono::Linkage::ExternalWeak)
-        || rlinkage == Some(rustc_middle::mir::mono::Linkage::WeakAny)
-    {
-        Linkage::Preemptible
-    } else {
-        Linkage::Import
-    };
+    let attrs = tcx.codegen_fn_attrs(def_id);
 
     let instance = Instance::mono(tcx, def_id).polymorphize(tcx);
     let symbol_name = tcx.symbol_name(instance).name;
@@ -289,22 +278,30 @@ fn data_id_for_static(
     };
     let align = tcx.layout_of(ParamEnv::reveal_all().and(ty)).unwrap().align.pref.bytes();
 
-    let attrs = tcx.codegen_fn_attrs(def_id);
+    if let Some(import_linkage) = attrs.import_linkage {
+        assert!(!definition);
 
-    let data_id = match module.declare_data(
-        &*symbol_name,
-        linkage,
-        is_mutable,
-        attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL),
-    ) {
-        Ok(data_id) => data_id,
-        Err(ModuleError::IncompatibleDeclaration(_)) => tcx.sess.fatal(&format!(
-            "attempt to declare `{symbol_name}` as static, but it was already declared as function"
-        )),
-        Err(err) => Err::<_, _>(err).unwrap(),
-    };
+        let linkage = if import_linkage == rustc_middle::mir::mono::Linkage::ExternalWeak
+            || import_linkage == rustc_middle::mir::mono::Linkage::WeakAny
+        {
+            Linkage::Preemptible
+        } else {
+            Linkage::Import
+        };
+
+        let data_id = match module.declare_data(
+            &*symbol_name,
+            linkage,
+            is_mutable,
+            attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL),
+        ) {
+            Ok(data_id) => data_id,
+            Err(ModuleError::IncompatibleDeclaration(_)) => tcx.sess.fatal(&format!(
+                "attempt to declare `{symbol_name}` as static, but it was already declared as function"
+            )),
+            Err(err) => Err::<_, _>(err).unwrap(),
+        };
 
-    if rlinkage.is_some() {
         // Comment copied from https://github.com/rust-lang/rust/blob/45060c2a66dfd667f88bd8b94261b28a58d85bd5/src/librustc_codegen_llvm/consts.rs#L141
         // Declare an internal global `extern_with_linkage_foo` which
         // is initialized with the address of `foo`.  If `foo` is
@@ -326,10 +323,34 @@ fn data_id_for_static(
             Err(ModuleError::DuplicateDefinition(_)) => {}
             res => res.unwrap(),
         }
-        ref_data_id
-    } else {
-        data_id
+
+        return ref_data_id;
     }
+
+    let linkage = if definition {
+        crate::linkage::get_static_linkage(tcx, def_id)
+    } else if attrs.linkage == Some(rustc_middle::mir::mono::Linkage::ExternalWeak)
+        || attrs.linkage == Some(rustc_middle::mir::mono::Linkage::WeakAny)
+    {
+        Linkage::Preemptible
+    } else {
+        Linkage::Import
+    };
+
+    let data_id = match module.declare_data(
+        &*symbol_name,
+        linkage,
+        is_mutable,
+        attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL),
+    ) {
+        Ok(data_id) => data_id,
+        Err(ModuleError::IncompatibleDeclaration(_)) => tcx.sess.fatal(&format!(
+            "attempt to declare `{symbol_name}` as static, but it was already declared as function"
+        )),
+        Err(err) => Err::<_, _>(err).unwrap(),
+    };
+
+    data_id
 }
 
 fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut ConstantCx) {
@@ -348,8 +369,6 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant
                 (data_id, alloc, None)
             }
             TodoItem::Static(def_id) => {
-                //println!("static {:?}", def_id);
-
                 let section_name = tcx.codegen_fn_attrs(def_id).link_section;
 
                 let alloc = tcx.eval_static_initializer(def_id).unwrap();
@@ -359,7 +378,6 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant
             }
         };
 
-        //("data_id {}", data_id);
         if cx.done.contains(&data_id) {
             continue;
         }
index d26392c4913b508a3ab68335d2ea771243c6b42d..493359c743f119d6bcee87920e595c943a009642 100644 (file)
@@ -39,7 +39,9 @@ pub(crate) fn new(isa: &dyn TargetIsa, pic_eh_frame: bool) -> Self {
     }
 
     pub(crate) fn add_function(&mut self, func_id: FuncId, context: &Context, isa: &dyn TargetIsa) {
-        let unwind_info = if let Some(unwind_info) = context.create_unwind_info(isa).unwrap() {
+        let unwind_info = if let Some(unwind_info) =
+            context.compiled_code().unwrap().create_unwind_info(isa).unwrap()
+        {
             unwind_info
         } else {
             return;
index 97b395bcd05186b199e59026ddec9fda4472dc77..3cbf313adf0df5a69887cdb1f0516245f2b23232 100644 (file)
@@ -1,6 +1,7 @@
 //! Handling of enum discriminants
 //!
-//! Adapted from <https://github.com/rust-lang/rust/blob/d760df5aea483aae041c9a241e7acacf48f75035/src/librustc_codegen_ssa/mir/place.rs>
+//! Adapted from <https://github.com/rust-lang/rust/blob/31c0645b9d2539f47eecb096142474b29dc542f7/compiler/rustc_codegen_ssa/src/mir/place.rs>
+//! (<https://github.com/rust-lang/rust/pull/104535>)
 
 use rustc_target::abi::{Int, TagEncoding, Variants};
 
@@ -47,13 +48,19 @@ pub(crate) fn codegen_set_discriminant<'tcx>(
         } => {
             if variant_index != untagged_variant {
                 let niche = place.place_field(fx, mir::Field::new(tag_field));
+                let niche_type = fx.clif_type(niche.layout().ty).unwrap();
                 let niche_value = variant_index.as_u32() - niche_variants.start().as_u32();
-                let niche_value = ty::ScalarInt::try_from_uint(
-                    u128::from(niche_value).wrapping_add(niche_start),
-                    niche.layout().size,
-                )
-                .unwrap();
-                let niche_llval = CValue::const_val(fx, niche.layout(), niche_value);
+                let niche_value = (niche_value as u128).wrapping_add(niche_start);
+                let niche_value = match niche_type {
+                    types::I128 => {
+                        let lsb = fx.bcx.ins().iconst(types::I64, niche_value as u64 as i64);
+                        let msb =
+                            fx.bcx.ins().iconst(types::I64, (niche_value >> 64) as u64 as i64);
+                        fx.bcx.ins().iconcat(lsb, msb)
+                    }
+                    ty => fx.bcx.ins().iconst(ty, niche_value as i64),
+                };
+                let niche_llval = CValue::by_val(niche_value, niche.layout());
                 niche.write_cvalue(fx, niche_llval);
             }
         }
@@ -96,6 +103,7 @@ pub(crate) fn codegen_get_discriminant<'tcx>(
         }
     };
 
+    let cast_to_size = dest_layout.layout.size();
     let cast_to = fx.clif_type(dest_layout.ty).unwrap();
 
     // Read the tag/niche-encoded discriminant from memory.
@@ -114,21 +122,128 @@ pub(crate) fn codegen_get_discriminant<'tcx>(
             dest.write_cvalue(fx, res);
         }
         TagEncoding::Niche { untagged_variant, ref niche_variants, niche_start } => {
-            // Rebase from niche values to discriminants, and check
-            // whether the result is in range for the niche variants.
-
-            // We first compute the "relative discriminant" (wrt `niche_variants`),
-            // that is, if `n = niche_variants.end() - niche_variants.start()`,
-            // we remap `niche_start..=niche_start + n` (which may wrap around)
-            // to (non-wrap-around) `0..=n`, to be able to check whether the
-            // discriminant corresponds to a niche variant with one comparison.
-            // We also can't go directly to the (variant index) discriminant
-            // and check that it is in the range `niche_variants`, because
-            // that might not fit in the same type, on top of needing an extra
-            // comparison (see also the comment on `let niche_discr`).
-            let relative_discr = if niche_start == 0 {
-                tag
+            let tag_size = tag_scalar.size(fx);
+            let max_unsigned = tag_size.unsigned_int_max();
+            let max_signed = tag_size.signed_int_max() as u128;
+            let min_signed = max_signed + 1;
+            let relative_max = niche_variants.end().as_u32() - niche_variants.start().as_u32();
+            let niche_end = niche_start.wrapping_add(relative_max as u128) & max_unsigned;
+            let range = tag_scalar.valid_range(fx);
+
+            let sle = |lhs: u128, rhs: u128| -> bool {
+                // Signed and unsigned comparisons give the same results,
+                // except that in signed comparisons an integer with the
+                // sign bit set is less than one with the sign bit clear.
+                // Toggle the sign bit to do a signed comparison.
+                (lhs ^ min_signed) <= (rhs ^ min_signed)
+            };
+
+            // We have a subrange `niche_start..=niche_end` inside `range`.
+            // If the value of the tag is inside this subrange, it's a
+            // "niche value", an increment of the discriminant. Otherwise it
+            // indicates the untagged variant.
+            // A general algorithm to extract the discriminant from the tag
+            // is:
+            // relative_tag = tag - niche_start
+            // is_niche = relative_tag <= (ule) relative_max
+            // discr = if is_niche {
+            //     cast(relative_tag) + niche_variants.start()
+            // } else {
+            //     untagged_variant
+            // }
+            // However, we will likely be able to emit simpler code.
+
+            // Find the least and greatest values in `range`, considered
+            // both as signed and unsigned.
+            let (low_unsigned, high_unsigned) =
+                if range.start <= range.end { (range.start, range.end) } else { (0, max_unsigned) };
+            let (low_signed, high_signed) = if sle(range.start, range.end) {
+                (range.start, range.end)
             } else {
+                (min_signed, max_signed)
+            };
+
+            let niches_ule = niche_start <= niche_end;
+            let niches_sle = sle(niche_start, niche_end);
+            let cast_smaller = cast_to_size <= tag_size;
+
+            // In the algorithm above, we can change
+            // cast(relative_tag) + niche_variants.start()
+            // into
+            // cast(tag + (niche_variants.start() - niche_start))
+            // if either the casted type is no larger than the original
+            // type, or if the niche values are contiguous (in either the
+            // signed or unsigned sense).
+            let can_incr = cast_smaller || niches_ule || niches_sle;
+
+            let data_for_boundary_niche = || -> Option<(IntCC, u128)> {
+                if !can_incr {
+                    None
+                } else if niche_start == low_unsigned {
+                    Some((IntCC::UnsignedLessThanOrEqual, niche_end))
+                } else if niche_end == high_unsigned {
+                    Some((IntCC::UnsignedGreaterThanOrEqual, niche_start))
+                } else if niche_start == low_signed {
+                    Some((IntCC::SignedLessThanOrEqual, niche_end))
+                } else if niche_end == high_signed {
+                    Some((IntCC::SignedGreaterThanOrEqual, niche_start))
+                } else {
+                    None
+                }
+            };
+
+            let (is_niche, tagged_discr, delta) = if relative_max == 0 {
+                // Best case scenario: only one tagged variant. This will
+                // likely become just a comparison and a jump.
+                // The algorithm is:
+                // is_niche = tag == niche_start
+                // discr = if is_niche {
+                //     niche_start
+                // } else {
+                //     untagged_variant
+                // }
+                let is_niche = codegen_icmp_imm(fx, IntCC::Equal, tag, niche_start as i128);
+                let tagged_discr =
+                    fx.bcx.ins().iconst(cast_to, niche_variants.start().as_u32() as i64);
+                (is_niche, tagged_discr, 0)
+            } else if let Some((predicate, constant)) = data_for_boundary_niche() {
+                // The niche values are either the lowest or the highest in
+                // `range`. We can avoid the first subtraction in the
+                // algorithm.
+                // The algorithm is now this:
+                // is_niche = tag <= niche_end
+                // discr = if is_niche {
+                //     cast(tag + (niche_variants.start() - niche_start))
+                // } else {
+                //     untagged_variant
+                // }
+                // (the first line may instead be tag >= niche_start,
+                // and may be a signed or unsigned comparison)
+                // The arithmetic must be done before the cast, so we can
+                // have the correct wrapping behavior. See issue #104519 for
+                // the consequences of getting this wrong.
+                let is_niche = codegen_icmp_imm(fx, predicate, tag, constant as i128);
+                let delta = (niche_variants.start().as_u32() as u128).wrapping_sub(niche_start);
+                let incr_tag = if delta == 0 {
+                    tag
+                } else {
+                    let delta = match fx.bcx.func.dfg.value_type(tag) {
+                        types::I128 => {
+                            let lsb = fx.bcx.ins().iconst(types::I64, delta as u64 as i64);
+                            let msb = fx.bcx.ins().iconst(types::I64, (delta >> 64) as u64 as i64);
+                            fx.bcx.ins().iconcat(lsb, msb)
+                        }
+                        ty => fx.bcx.ins().iconst(ty, delta as i64),
+                    };
+                    fx.bcx.ins().iadd(tag, delta)
+                };
+
+                let cast_tag = clif_intcast(fx, incr_tag, cast_to, !niches_ule);
+
+                (is_niche, cast_tag, 0)
+            } else {
+                // The special cases don't apply, so we'll have to go with
+                // the general algorithm.
                 let niche_start = match fx.bcx.func.dfg.value_type(tag) {
                     types::I128 => {
                         let lsb = fx.bcx.ins().iconst(types::I64, niche_start as u64 as i64);
@@ -138,40 +253,40 @@ pub(crate) fn codegen_get_discriminant<'tcx>(
                     }
                     ty => fx.bcx.ins().iconst(ty, niche_start as i64),
                 };
-                fx.bcx.ins().isub(tag, niche_start)
-            };
-            let relative_max = niche_variants.end().as_u32() - niche_variants.start().as_u32();
-            let is_niche = {
-                codegen_icmp_imm(
+                let relative_discr = fx.bcx.ins().isub(tag, niche_start);
+                let cast_tag = clif_intcast(fx, relative_discr, cast_to, false);
+                let is_niche = crate::common::codegen_icmp_imm(
                     fx,
                     IntCC::UnsignedLessThanOrEqual,
                     relative_discr,
                     i128::from(relative_max),
-                )
+                );
+                (is_niche, cast_tag, niche_variants.start().as_u32() as u128)
             };
 
-            // NOTE(eddyb) this addition needs to be performed on the final
-            // type, in case the niche itself can't represent all variant
-            // indices (e.g. `u8` niche with more than `256` variants,
-            // but enough uninhabited variants so that the remaining variants
-            // fit in the niche).
-            // In other words, `niche_variants.end - niche_variants.start`
-            // is representable in the niche, but `niche_variants.end`
-            // might not be, in extreme cases.
-            let niche_discr = {
-                let relative_discr = if relative_max == 0 {
-                    // HACK(eddyb) since we have only one niche, we know which
-                    // one it is, and we can avoid having a dynamic value here.
-                    fx.bcx.ins().iconst(cast_to, 0)
-                } else {
-                    clif_intcast(fx, relative_discr, cast_to, false)
+            let tagged_discr = if delta == 0 {
+                tagged_discr
+            } else {
+                let delta = match cast_to {
+                    types::I128 => {
+                        let lsb = fx.bcx.ins().iconst(types::I64, delta as u64 as i64);
+                        let msb = fx.bcx.ins().iconst(types::I64, (delta >> 64) as u64 as i64);
+                        fx.bcx.ins().iconcat(lsb, msb)
+                    }
+                    ty => fx.bcx.ins().iconst(ty, delta as i64),
                 };
-                fx.bcx.ins().iadd_imm(relative_discr, i64::from(niche_variants.start().as_u32()))
+                fx.bcx.ins().iadd(tagged_discr, delta)
             };
 
-            let untagged_variant =
-                fx.bcx.ins().iconst(cast_to, i64::from(untagged_variant.as_u32()));
-            let discr = fx.bcx.ins().select(is_niche, niche_discr, untagged_variant);
+            let untagged_variant = if cast_to == types::I128 {
+                let zero = fx.bcx.ins().iconst(types::I64, 0);
+                let untagged_variant =
+                    fx.bcx.ins().iconst(types::I64, i64::from(untagged_variant.as_u32()));
+                fx.bcx.ins().iconcat(untagged_variant, zero)
+            } else {
+                fx.bcx.ins().iconst(cast_to, i64::from(untagged_variant.as_u32()))
+            };
+            let discr = fx.bcx.ins().select(is_niche, tagged_discr, untagged_variant);
             let res = CValue::by_val(discr, dest_layout);
             dest.write_cvalue(fx, res);
         }
index 6a430b5215e36d11b483213b5bb7e74c75425727..be1b8c9ead3bf2e133d326818df523e19f201fda 100644 (file)
@@ -159,7 +159,7 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! {
 
     tcx.sess.abort_if_errors();
 
-    jit_module.finalize_definitions();
+    jit_module.finalize_definitions().unwrap();
     unsafe { cx.unwind_context.register_jit(&jit_module) };
 
     println!(
@@ -245,7 +245,11 @@ fn jit_fn(instance_ptr: *const Instance<'static>, trampoline_ptr: *const u8) ->
             let backend_config = lazy_jit_state.backend_config.clone();
 
             let name = tcx.symbol_name(instance).name;
-            let sig = crate::abi::get_function_sig(tcx, jit_module.isa().triple(), instance);
+            let sig = crate::abi::get_function_sig(
+                tcx,
+                jit_module.target_config().default_call_conv,
+                instance,
+            );
             let func_id = jit_module.declare_function(name, Linkage::Export, &sig).unwrap();
 
             let current_ptr = jit_module.read_got_entry(func_id);
@@ -278,7 +282,7 @@ fn jit_fn(instance_ptr: *const Instance<'static>, trampoline_ptr: *const u8) ->
             });
 
             assert!(cx.global_asm.is_empty());
-            jit_module.finalize_definitions();
+            jit_module.finalize_definitions().unwrap();
             unsafe { cx.unwind_context.register_jit(&jit_module) };
             jit_module.get_finalized_function(func_id)
         })
@@ -344,7 +348,7 @@ fn codegen_shim<'tcx>(
     let pointer_type = module.target_config().pointer_type();
 
     let name = tcx.symbol_name(inst).name;
-    let sig = crate::abi::get_function_sig(tcx, module.isa().triple(), inst);
+    let sig = crate::abi::get_function_sig(tcx, module.target_config().default_call_conv, inst);
     let func_id = module.declare_function(name, Linkage::Export, &sig).unwrap();
 
     let instance_ptr = Box::into_raw(Box::new(inst));
index 8f5714ecb417704e446edda114f65b4966facb66..6e925cea277078b68ac5d03de3cc18fae0e91e71 100644 (file)
@@ -24,7 +24,8 @@ fn predefine_mono_items<'tcx>(
                 MonoItem::Fn(instance) => {
                     let name = tcx.symbol_name(instance).name;
                     let _inst_guard = crate::PrintOnPanic(|| format!("{:?} {}", instance, name));
-                    let sig = get_function_sig(tcx, module.isa().triple(), instance);
+                    let sig =
+                        get_function_sig(tcx, module.target_config().default_call_conv, instance);
                     let linkage = crate::linkage::get_clif_linkage(
                         mono_item,
                         linkage,
index 783d426c30bcc0d14cf94bb658b854e1e4b337fb..f722e52284fe8205f269103a620fec33015ef9a4 100644 (file)
 pub(crate) fn codegen_llvm_intrinsic_call<'tcx>(
     fx: &mut FunctionCx<'_, '_, 'tcx>,
     intrinsic: &str,
-    _substs: SubstsRef<'tcx>,
+    substs: SubstsRef<'tcx>,
     args: &[mir::Operand<'tcx>],
     ret: CPlace<'tcx>,
     target: Option<BasicBlock>,
 ) {
-    match intrinsic {
-        "llvm.x86.sse2.pause" | "llvm.aarch64.isb" => {
-            // Spin loop hint
-        }
+    if intrinsic.starts_with("llvm.aarch64") {
+        return llvm_aarch64::codegen_aarch64_llvm_intrinsic_call(
+            fx, intrinsic, substs, args, ret, target,
+        );
+    }
+    if intrinsic.starts_with("llvm.x86") {
+        return llvm_x86::codegen_x86_llvm_intrinsic_call(fx, intrinsic, substs, args, ret, target);
+    }
 
-        // Used by `_mm_movemask_epi8` and `_mm256_movemask_epi8`
-        "llvm.x86.sse2.pmovmskb.128" | "llvm.x86.avx2.pmovmskb" | "llvm.x86.sse2.movmsk.pd" => {
+    match intrinsic {
+        _ if intrinsic.starts_with("llvm.ctlz.v") => {
             intrinsic_args!(fx, args => (a); intrinsic);
 
-            let (lane_count, lane_ty) = a.layout().ty.simd_size_and_type(fx.tcx);
-            let lane_ty = fx.clif_type(lane_ty).unwrap();
-            assert!(lane_count <= 32);
-
-            let mut res = fx.bcx.ins().iconst(types::I32, 0);
-
-            for lane in (0..lane_count).rev() {
-                let a_lane = a.value_lane(fx, lane).load_scalar(fx);
-
-                // cast float to int
-                let a_lane = match lane_ty {
-                    types::F32 => fx.bcx.ins().bitcast(types::I32, a_lane),
-                    types::F64 => fx.bcx.ins().bitcast(types::I64, a_lane),
-                    _ => a_lane,
-                };
-
-                // extract sign bit of an int
-                let a_lane_sign = fx.bcx.ins().ushr_imm(a_lane, i64::from(lane_ty.bits() - 1));
-
-                // shift sign bit into result
-                let a_lane_sign = clif_intcast(fx, a_lane_sign, types::I32, false);
-                res = fx.bcx.ins().ishl_imm(res, 1);
-                res = fx.bcx.ins().bor(res, a_lane_sign);
-            }
-
-            let res = CValue::by_val(res, fx.layout_of(fx.tcx.types.i32));
-            ret.write_cvalue(fx, res);
-        }
-        "llvm.x86.sse2.cmp.ps" | "llvm.x86.sse2.cmp.pd" => {
-            let (x, y, kind) = match args {
-                [x, y, kind] => (x, y, kind),
-                _ => bug!("wrong number of args for intrinsic {intrinsic}"),
-            };
-            let x = codegen_operand(fx, x);
-            let y = codegen_operand(fx, y);
-            let kind = crate::constant::mir_operand_get_const_val(fx, kind)
-                .expect("llvm.x86.sse2.cmp.* kind not const");
-
-            let flt_cc = match kind
-                .try_to_bits(Size::from_bytes(1))
-                .unwrap_or_else(|| panic!("kind not scalar: {:?}", kind))
-            {
-                0 => FloatCC::Equal,
-                1 => FloatCC::LessThan,
-                2 => FloatCC::LessThanOrEqual,
-                7 => FloatCC::Ordered,
-                3 => FloatCC::Unordered,
-                4 => FloatCC::NotEqual,
-                5 => FloatCC::UnorderedOrGreaterThanOrEqual,
-                6 => FloatCC::UnorderedOrGreaterThan,
-                kind => unreachable!("kind {:?}", kind),
-            };
-
-            simd_pair_for_each_lane(fx, x, y, ret, &|fx, lane_ty, res_lane_ty, x_lane, y_lane| {
-                let res_lane = match lane_ty.kind() {
-                    ty::Float(_) => fx.bcx.ins().fcmp(flt_cc, x_lane, y_lane),
-                    _ => unreachable!("{:?}", lane_ty),
-                };
-                bool_to_zero_or_max_uint(fx, res_lane_ty, res_lane)
+            simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| {
+                fx.bcx.ins().clz(lane)
             });
         }
-        "llvm.x86.sse2.psrli.d" => {
-            let (a, imm8) = match args {
-                [a, imm8] => (a, imm8),
-                _ => bug!("wrong number of args for intrinsic {intrinsic}"),
-            };
-            let a = codegen_operand(fx, a);
-            let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8)
-                .expect("llvm.x86.sse2.psrli.d imm8 not const");
 
-            simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8
-                .try_to_bits(Size::from_bytes(4))
-                .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8))
-            {
-                imm8 if imm8 < 32 => fx.bcx.ins().ushr_imm(lane, i64::from(imm8 as u8)),
-                _ => fx.bcx.ins().iconst(types::I32, 0),
-            });
-        }
-        "llvm.x86.sse2.pslli.d" => {
-            let (a, imm8) = match args {
-                [a, imm8] => (a, imm8),
-                _ => bug!("wrong number of args for intrinsic {intrinsic}"),
-            };
-            let a = codegen_operand(fx, a);
-            let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8)
-                .expect("llvm.x86.sse2.psrli.d imm8 not const");
+        _ if intrinsic.starts_with("llvm.ctpop.v") => {
+            intrinsic_args!(fx, args => (a); intrinsic);
 
-            simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8
-                .try_to_bits(Size::from_bytes(4))
-                .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8))
-            {
-                imm8 if imm8 < 32 => fx.bcx.ins().ishl_imm(lane, i64::from(imm8 as u8)),
-                _ => fx.bcx.ins().iconst(types::I32, 0),
+            simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| {
+                fx.bcx.ins().popcnt(lane)
             });
         }
-        "llvm.x86.sse2.storeu.dq" => {
-            intrinsic_args!(fx, args => (mem_addr, a); intrinsic);
-            let mem_addr = mem_addr.load_scalar(fx);
-
-            // FIXME correctly handle the unalignment
-            let dest = CPlace::for_ptr(Pointer::new(mem_addr), a.layout());
-            dest.write_cvalue(fx, a);
-        }
-        "llvm.x86.addcarry.64" => {
-            intrinsic_args!(fx, args => (c_in, a, b); intrinsic);
-            let c_in = c_in.load_scalar(fx);
-
-            llvm_add_sub(fx, BinOp::Add, ret, c_in, a, b);
-        }
-        "llvm.x86.subborrow.64" => {
-            intrinsic_args!(fx, args => (b_in, a, b); intrinsic);
-            let b_in = b_in.load_scalar(fx);
 
-            llvm_add_sub(fx, BinOp::Sub, ret, b_in, a, b);
-        }
         _ => {
             fx.tcx
                 .sess
@@ -150,47 +52,3 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>(
     let ret_block = fx.get_block(dest);
     fx.bcx.ins().jump(ret_block, &[]);
 }
-
-// llvm.x86.avx2.vperm2i128
-// llvm.x86.ssse3.pshuf.b.128
-// llvm.x86.avx2.pshuf.b
-// llvm.x86.avx2.psrli.w
-// llvm.x86.sse2.psrli.w
-
-fn llvm_add_sub<'tcx>(
-    fx: &mut FunctionCx<'_, '_, 'tcx>,
-    bin_op: BinOp,
-    ret: CPlace<'tcx>,
-    cb_in: Value,
-    a: CValue<'tcx>,
-    b: CValue<'tcx>,
-) {
-    assert_eq!(
-        a.layout().ty,
-        fx.tcx.types.u64,
-        "llvm.x86.addcarry.64/llvm.x86.subborrow.64 second operand must be u64"
-    );
-    assert_eq!(
-        b.layout().ty,
-        fx.tcx.types.u64,
-        "llvm.x86.addcarry.64/llvm.x86.subborrow.64 third operand must be u64"
-    );
-
-    // c + carry -> c + first intermediate carry or borrow respectively
-    let int0 = crate::num::codegen_checked_int_binop(fx, bin_op, a, b);
-    let c = int0.value_field(fx, mir::Field::new(0));
-    let cb0 = int0.value_field(fx, mir::Field::new(1)).load_scalar(fx);
-
-    // c + carry -> c + second intermediate carry or borrow respectively
-    let cb_in_as_u64 = fx.bcx.ins().uextend(types::I64, cb_in);
-    let cb_in_as_u64 = CValue::by_val(cb_in_as_u64, fx.layout_of(fx.tcx.types.u64));
-    let int1 = crate::num::codegen_checked_int_binop(fx, bin_op, c, cb_in_as_u64);
-    let (c, cb1) = int1.load_scalar_pair(fx);
-
-    // carry0 | carry1 -> carry or borrow respectively
-    let cb_out = fx.bcx.ins().bor(cb0, cb1);
-
-    let layout = fx.layout_of(fx.tcx.mk_tup([fx.tcx.types.u8, fx.tcx.types.u64].iter()));
-    let val = CValue::by_val_pair(cb_out, c, layout);
-    ret.write_cvalue(fx, val);
-}
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs
new file mode 100644 (file)
index 0000000..b431158
--- /dev/null
@@ -0,0 +1,222 @@
+//! Emulate AArch64 LLVM intrinsics
+
+use crate::intrinsics::*;
+use crate::prelude::*;
+
+use rustc_middle::ty::subst::SubstsRef;
+
+pub(crate) fn codegen_aarch64_llvm_intrinsic_call<'tcx>(
+    fx: &mut FunctionCx<'_, '_, 'tcx>,
+    intrinsic: &str,
+    _substs: SubstsRef<'tcx>,
+    args: &[mir::Operand<'tcx>],
+    ret: CPlace<'tcx>,
+    target: Option<BasicBlock>,
+) {
+    // llvm.aarch64.neon.sqshl.v*i*
+
+    match intrinsic {
+        "llvm.aarch64.isb" => {
+            fx.bcx.ins().fence();
+        }
+
+        _ if intrinsic.starts_with("llvm.aarch64.neon.abs.v") => {
+            intrinsic_args!(fx, args => (a); intrinsic);
+
+            simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| {
+                fx.bcx.ins().iabs(lane)
+            });
+        }
+
+        _ if intrinsic.starts_with("llvm.aarch64.neon.cls.v") => {
+            intrinsic_args!(fx, args => (a); intrinsic);
+
+            simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| {
+                fx.bcx.ins().cls(lane)
+            });
+        }
+
+        _ if intrinsic.starts_with("llvm.aarch64.neon.rbit.v") => {
+            intrinsic_args!(fx, args => (a); intrinsic);
+
+            simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| {
+                fx.bcx.ins().bitrev(lane)
+            });
+        }
+
+        _ if intrinsic.starts_with("llvm.aarch64.neon.sqadd.v") => {
+            intrinsic_args!(fx, args => (x, y); intrinsic);
+
+            simd_pair_for_each_lane_typed(fx, x, y, ret, &|fx, x_lane, y_lane| {
+                crate::num::codegen_saturating_int_binop(fx, BinOp::Add, x_lane, y_lane)
+            });
+        }
+
+        _ if intrinsic.starts_with("llvm.aarch64.neon.sqsub.v") => {
+            intrinsic_args!(fx, args => (x, y); intrinsic);
+
+            simd_pair_for_each_lane_typed(fx, x, y, ret, &|fx, x_lane, y_lane| {
+                crate::num::codegen_saturating_int_binop(fx, BinOp::Sub, x_lane, y_lane)
+            });
+        }
+
+        _ if intrinsic.starts_with("llvm.aarch64.neon.smax.v") => {
+            intrinsic_args!(fx, args => (x, y); intrinsic);
+
+            simd_pair_for_each_lane(
+                fx,
+                x,
+                y,
+                ret,
+                &|fx, _lane_ty, _res_lane_ty, x_lane, y_lane| {
+                    let gt = fx.bcx.ins().icmp(IntCC::SignedGreaterThan, x_lane, y_lane);
+                    fx.bcx.ins().select(gt, x_lane, y_lane)
+                },
+            );
+        }
+
+        _ if intrinsic.starts_with("llvm.aarch64.neon.umax.v") => {
+            intrinsic_args!(fx, args => (x, y); intrinsic);
+
+            simd_pair_for_each_lane(
+                fx,
+                x,
+                y,
+                ret,
+                &|fx, _lane_ty, _res_lane_ty, x_lane, y_lane| {
+                    let gt = fx.bcx.ins().icmp(IntCC::UnsignedGreaterThan, x_lane, y_lane);
+                    fx.bcx.ins().select(gt, x_lane, y_lane)
+                },
+            );
+        }
+
+        _ if intrinsic.starts_with("llvm.aarch64.neon.smaxv.i") => {
+            intrinsic_args!(fx, args => (v); intrinsic);
+
+            simd_reduce(fx, v, None, ret, &|fx, _ty, a, b| {
+                let gt = fx.bcx.ins().icmp(IntCC::SignedGreaterThan, a, b);
+                fx.bcx.ins().select(gt, a, b)
+            });
+        }
+
+        _ if intrinsic.starts_with("llvm.aarch64.neon.umaxv.i") => {
+            intrinsic_args!(fx, args => (v); intrinsic);
+
+            simd_reduce(fx, v, None, ret, &|fx, _ty, a, b| {
+                let gt = fx.bcx.ins().icmp(IntCC::UnsignedGreaterThan, a, b);
+                fx.bcx.ins().select(gt, a, b)
+            });
+        }
+
+        _ if intrinsic.starts_with("llvm.aarch64.neon.smin.v") => {
+            intrinsic_args!(fx, args => (x, y); intrinsic);
+
+            simd_pair_for_each_lane(
+                fx,
+                x,
+                y,
+                ret,
+                &|fx, _lane_ty, _res_lane_ty, x_lane, y_lane| {
+                    let gt = fx.bcx.ins().icmp(IntCC::SignedLessThan, x_lane, y_lane);
+                    fx.bcx.ins().select(gt, x_lane, y_lane)
+                },
+            );
+        }
+
+        _ if intrinsic.starts_with("llvm.aarch64.neon.umin.v") => {
+            intrinsic_args!(fx, args => (x, y); intrinsic);
+
+            simd_pair_for_each_lane(
+                fx,
+                x,
+                y,
+                ret,
+                &|fx, _lane_ty, _res_lane_ty, x_lane, y_lane| {
+                    let gt = fx.bcx.ins().icmp(IntCC::UnsignedLessThan, x_lane, y_lane);
+                    fx.bcx.ins().select(gt, x_lane, y_lane)
+                },
+            );
+        }
+
+        _ if intrinsic.starts_with("llvm.aarch64.neon.sminv.i") => {
+            intrinsic_args!(fx, args => (v); intrinsic);
+
+            simd_reduce(fx, v, None, ret, &|fx, _ty, a, b| {
+                let gt = fx.bcx.ins().icmp(IntCC::SignedLessThan, a, b);
+                fx.bcx.ins().select(gt, a, b)
+            });
+        }
+
+        _ if intrinsic.starts_with("llvm.aarch64.neon.uminv.i") => {
+            intrinsic_args!(fx, args => (v); intrinsic);
+
+            simd_reduce(fx, v, None, ret, &|fx, _ty, a, b| {
+                let gt = fx.bcx.ins().icmp(IntCC::UnsignedLessThan, a, b);
+                fx.bcx.ins().select(gt, a, b)
+            });
+        }
+
+        /*
+        _ if intrinsic.starts_with("llvm.aarch64.neon.sshl.v")
+            || intrinsic.starts_with("llvm.aarch64.neon.sqshl.v")
+            // FIXME split this one out once saturating is implemented
+            || intrinsic.starts_with("llvm.aarch64.neon.sqshlu.v") =>
+        {
+            intrinsic_args!(fx, args => (a, b); intrinsic);
+
+            simd_pair_for_each_lane(fx, a, b, ret, &|fx, _lane_ty, _res_lane_ty, a, b| {
+                // FIXME saturate?
+                fx.bcx.ins().ishl(a, b)
+            });
+        }
+
+        _ if intrinsic.starts_with("llvm.aarch64.neon.sqshrn.v") => {
+            let (a, imm32) = match args {
+                [a, imm32] => (a, imm32),
+                _ => bug!("wrong number of args for intrinsic {intrinsic}"),
+            };
+            let a = codegen_operand(fx, a);
+            let imm32 = crate::constant::mir_operand_get_const_val(fx, imm32)
+                .expect("llvm.aarch64.neon.sqshrn.v* imm32 not const");
+
+            simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm32
+                .try_to_bits(Size::from_bytes(4))
+                .unwrap_or_else(|| panic!("imm32 not scalar: {:?}", imm32))
+            {
+                imm32 if imm32 < 32 => fx.bcx.ins().sshr_imm(lane, i64::from(imm32 as u8)),
+                _ => fx.bcx.ins().iconst(types::I32, 0),
+            });
+        }
+
+        _ if intrinsic.starts_with("llvm.aarch64.neon.sqshrun.v") => {
+            let (a, imm32) = match args {
+                [a, imm32] => (a, imm32),
+                _ => bug!("wrong number of args for intrinsic {intrinsic}"),
+            };
+            let a = codegen_operand(fx, a);
+            let imm32 = crate::constant::mir_operand_get_const_val(fx, imm32)
+                .expect("llvm.aarch64.neon.sqshrn.v* imm32 not const");
+
+            simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm32
+                .try_to_bits(Size::from_bytes(4))
+                .unwrap_or_else(|| panic!("imm32 not scalar: {:?}", imm32))
+            {
+                imm32 if imm32 < 32 => fx.bcx.ins().ushr_imm(lane, i64::from(imm32 as u8)),
+                _ => fx.bcx.ins().iconst(types::I32, 0),
+            });
+        }
+        */
+        _ => {
+            fx.tcx.sess.warn(&format!(
+                "unsupported AArch64 llvm intrinsic {}; replacing with trap",
+                intrinsic
+            ));
+            crate::trap::trap_unimplemented(fx, intrinsic);
+            return;
+        }
+    }
+
+    let dest = target.expect("all llvm intrinsics used by stdlib should return");
+    let ret_block = fx.get_block(dest);
+    fx.bcx.ins().jump(ret_block, &[]);
+}
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
new file mode 100644 (file)
index 0000000..7bc161f
--- /dev/null
@@ -0,0 +1,197 @@
+//! Emulate x86 LLVM intrinsics
+
+use crate::intrinsics::*;
+use crate::prelude::*;
+
+use rustc_middle::ty::subst::SubstsRef;
+
+pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
+    fx: &mut FunctionCx<'_, '_, 'tcx>,
+    intrinsic: &str,
+    _substs: SubstsRef<'tcx>,
+    args: &[mir::Operand<'tcx>],
+    ret: CPlace<'tcx>,
+    target: Option<BasicBlock>,
+) {
+    match intrinsic {
+        "llvm.x86.sse2.pause" | "llvm.aarch64.isb" => {
+            // Spin loop hint
+        }
+
+        // Used by `_mm_movemask_epi8` and `_mm256_movemask_epi8`
+        "llvm.x86.sse2.pmovmskb.128" | "llvm.x86.avx2.pmovmskb" | "llvm.x86.sse2.movmsk.pd" => {
+            intrinsic_args!(fx, args => (a); intrinsic);
+
+            let (lane_count, lane_ty) = a.layout().ty.simd_size_and_type(fx.tcx);
+            let lane_ty = fx.clif_type(lane_ty).unwrap();
+            assert!(lane_count <= 32);
+
+            let mut res = fx.bcx.ins().iconst(types::I32, 0);
+
+            for lane in (0..lane_count).rev() {
+                let a_lane = a.value_lane(fx, lane).load_scalar(fx);
+
+                // cast float to int
+                let a_lane = match lane_ty {
+                    types::F32 => fx.bcx.ins().bitcast(types::I32, a_lane),
+                    types::F64 => fx.bcx.ins().bitcast(types::I64, a_lane),
+                    _ => a_lane,
+                };
+
+                // extract sign bit of an int
+                let a_lane_sign = fx.bcx.ins().ushr_imm(a_lane, i64::from(lane_ty.bits() - 1));
+
+                // shift sign bit into result
+                let a_lane_sign = clif_intcast(fx, a_lane_sign, types::I32, false);
+                res = fx.bcx.ins().ishl_imm(res, 1);
+                res = fx.bcx.ins().bor(res, a_lane_sign);
+            }
+
+            let res = CValue::by_val(res, fx.layout_of(fx.tcx.types.i32));
+            ret.write_cvalue(fx, res);
+        }
+        "llvm.x86.sse2.cmp.ps" | "llvm.x86.sse2.cmp.pd" => {
+            let (x, y, kind) = match args {
+                [x, y, kind] => (x, y, kind),
+                _ => bug!("wrong number of args for intrinsic {intrinsic}"),
+            };
+            let x = codegen_operand(fx, x);
+            let y = codegen_operand(fx, y);
+            let kind = crate::constant::mir_operand_get_const_val(fx, kind)
+                .expect("llvm.x86.sse2.cmp.* kind not const");
+
+            let flt_cc = match kind
+                .try_to_bits(Size::from_bytes(1))
+                .unwrap_or_else(|| panic!("kind not scalar: {:?}", kind))
+            {
+                0 => FloatCC::Equal,
+                1 => FloatCC::LessThan,
+                2 => FloatCC::LessThanOrEqual,
+                7 => FloatCC::Ordered,
+                3 => FloatCC::Unordered,
+                4 => FloatCC::NotEqual,
+                5 => FloatCC::UnorderedOrGreaterThanOrEqual,
+                6 => FloatCC::UnorderedOrGreaterThan,
+                kind => unreachable!("kind {:?}", kind),
+            };
+
+            simd_pair_for_each_lane(fx, x, y, ret, &|fx, lane_ty, res_lane_ty, x_lane, y_lane| {
+                let res_lane = match lane_ty.kind() {
+                    ty::Float(_) => fx.bcx.ins().fcmp(flt_cc, x_lane, y_lane),
+                    _ => unreachable!("{:?}", lane_ty),
+                };
+                bool_to_zero_or_max_uint(fx, res_lane_ty, res_lane)
+            });
+        }
+        "llvm.x86.sse2.psrli.d" => {
+            let (a, imm8) = match args {
+                [a, imm8] => (a, imm8),
+                _ => bug!("wrong number of args for intrinsic {intrinsic}"),
+            };
+            let a = codegen_operand(fx, a);
+            let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8)
+                .expect("llvm.x86.sse2.psrli.d imm8 not const");
+
+            simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8
+                .try_to_bits(Size::from_bytes(4))
+                .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8))
+            {
+                imm8 if imm8 < 32 => fx.bcx.ins().ushr_imm(lane, i64::from(imm8 as u8)),
+                _ => fx.bcx.ins().iconst(types::I32, 0),
+            });
+        }
+        "llvm.x86.sse2.pslli.d" => {
+            let (a, imm8) = match args {
+                [a, imm8] => (a, imm8),
+                _ => bug!("wrong number of args for intrinsic {intrinsic}"),
+            };
+            let a = codegen_operand(fx, a);
+            let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8)
+                .expect("llvm.x86.sse2.psrli.d imm8 not const");
+
+            simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8
+                .try_to_bits(Size::from_bytes(4))
+                .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8))
+            {
+                imm8 if imm8 < 32 => fx.bcx.ins().ishl_imm(lane, i64::from(imm8 as u8)),
+                _ => fx.bcx.ins().iconst(types::I32, 0),
+            });
+        }
+        "llvm.x86.sse2.storeu.dq" => {
+            intrinsic_args!(fx, args => (mem_addr, a); intrinsic);
+            let mem_addr = mem_addr.load_scalar(fx);
+
+            // FIXME correctly handle the unalignment
+            let dest = CPlace::for_ptr(Pointer::new(mem_addr), a.layout());
+            dest.write_cvalue(fx, a);
+        }
+        "llvm.x86.addcarry.64" => {
+            intrinsic_args!(fx, args => (c_in, a, b); intrinsic);
+            let c_in = c_in.load_scalar(fx);
+
+            llvm_add_sub(fx, BinOp::Add, ret, c_in, a, b);
+        }
+        "llvm.x86.subborrow.64" => {
+            intrinsic_args!(fx, args => (b_in, a, b); intrinsic);
+            let b_in = b_in.load_scalar(fx);
+
+            llvm_add_sub(fx, BinOp::Sub, ret, b_in, a, b);
+        }
+        _ => {
+            fx.tcx.sess.warn(&format!(
+                "unsupported x86 llvm intrinsic {}; replacing with trap",
+                intrinsic
+            ));
+            crate::trap::trap_unimplemented(fx, intrinsic);
+            return;
+        }
+    }
+
+    let dest = target.expect("all llvm intrinsics used by stdlib should return");
+    let ret_block = fx.get_block(dest);
+    fx.bcx.ins().jump(ret_block, &[]);
+}
+
+// llvm.x86.avx2.vperm2i128
+// llvm.x86.ssse3.pshuf.b.128
+// llvm.x86.avx2.pshuf.b
+// llvm.x86.avx2.psrli.w
+// llvm.x86.sse2.psrli.w
+
+fn llvm_add_sub<'tcx>(
+    fx: &mut FunctionCx<'_, '_, 'tcx>,
+    bin_op: BinOp,
+    ret: CPlace<'tcx>,
+    cb_in: Value,
+    a: CValue<'tcx>,
+    b: CValue<'tcx>,
+) {
+    assert_eq!(
+        a.layout().ty,
+        fx.tcx.types.u64,
+        "llvm.x86.addcarry.64/llvm.x86.subborrow.64 second operand must be u64"
+    );
+    assert_eq!(
+        b.layout().ty,
+        fx.tcx.types.u64,
+        "llvm.x86.addcarry.64/llvm.x86.subborrow.64 third operand must be u64"
+    );
+
+    // c + carry -> c + first intermediate carry or borrow respectively
+    let int0 = crate::num::codegen_checked_int_binop(fx, bin_op, a, b);
+    let c = int0.value_field(fx, mir::Field::new(0));
+    let cb0 = int0.value_field(fx, mir::Field::new(1)).load_scalar(fx);
+
+    // c + carry -> c + second intermediate carry or borrow respectively
+    let cb_in_as_u64 = fx.bcx.ins().uextend(types::I64, cb_in);
+    let cb_in_as_u64 = CValue::by_val(cb_in_as_u64, fx.layout_of(fx.tcx.types.u64));
+    let int1 = crate::num::codegen_checked_int_binop(fx, bin_op, c, cb_in_as_u64);
+    let (c, cb1) = int1.load_scalar_pair(fx);
+
+    // carry0 | carry1 -> carry or borrow respectively
+    let cb_out = fx.bcx.ins().bor(cb0, cb1);
+
+    let layout = fx.layout_of(fx.tcx.mk_tup([fx.tcx.types.u8, fx.tcx.types.u64].iter()));
+    let val = CValue::by_val_pair(cb_out, c, layout);
+    ret.write_cvalue(fx, val);
+}
index 0302b843aa226345328a278674026baa33fda632..7a380acf798572a7606130959a7517cfecb2462b 100644 (file)
@@ -14,6 +14,8 @@ macro_rules! intrinsic_args {
 
 mod cpuid;
 mod llvm;
+mod llvm_aarch64;
+mod llvm_x86;
 mod simd;
 
 pub(crate) use cpuid::codegen_cpuid_call;
@@ -195,8 +197,7 @@ fn bool_to_zero_or_max_uint<'tcx>(
         ty => ty,
     };
 
-    let val = fx.bcx.ins().bint(int_ty, val);
-    let mut res = fx.bcx.ins().ineg(val);
+    let mut res = fx.bcx.ins().bmask(int_ty, val);
 
     if ty.is_float() {
         res = fx.bcx.ins().bitcast(ty, res);
@@ -632,85 +633,15 @@ fn codegen_regular_intrinsic_call<'tcx>(
             ret.write_cvalue(fx, res);
         }
         sym::bswap => {
-            // FIXME(CraneStation/cranelift#794) add bswap instruction to cranelift
-            fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
-                match bcx.func.dfg.value_type(v) {
-                    types::I8 => v,
-
-                    // https://code.woboq.org/gcc/include/bits/byteswap.h.html
-                    types::I16 => {
-                        let tmp1 = bcx.ins().ishl_imm(v, 8);
-                        let n1 = bcx.ins().band_imm(tmp1, 0xFF00);
-
-                        let tmp2 = bcx.ins().ushr_imm(v, 8);
-                        let n2 = bcx.ins().band_imm(tmp2, 0x00FF);
-
-                        bcx.ins().bor(n1, n2)
-                    }
-                    types::I32 => {
-                        let tmp1 = bcx.ins().ishl_imm(v, 24);
-                        let n1 = bcx.ins().band_imm(tmp1, 0xFF00_0000);
-
-                        let tmp2 = bcx.ins().ishl_imm(v, 8);
-                        let n2 = bcx.ins().band_imm(tmp2, 0x00FF_0000);
-
-                        let tmp3 = bcx.ins().ushr_imm(v, 8);
-                        let n3 = bcx.ins().band_imm(tmp3, 0x0000_FF00);
-
-                        let tmp4 = bcx.ins().ushr_imm(v, 24);
-                        let n4 = bcx.ins().band_imm(tmp4, 0x0000_00FF);
-
-                        let or_tmp1 = bcx.ins().bor(n1, n2);
-                        let or_tmp2 = bcx.ins().bor(n3, n4);
-                        bcx.ins().bor(or_tmp1, or_tmp2)
-                    }
-                    types::I64 => {
-                        let tmp1 = bcx.ins().ishl_imm(v, 56);
-                        let n1 = bcx.ins().band_imm(tmp1, 0xFF00_0000_0000_0000u64 as i64);
-
-                        let tmp2 = bcx.ins().ishl_imm(v, 40);
-                        let n2 = bcx.ins().band_imm(tmp2, 0x00FF_0000_0000_0000u64 as i64);
-
-                        let tmp3 = bcx.ins().ishl_imm(v, 24);
-                        let n3 = bcx.ins().band_imm(tmp3, 0x0000_FF00_0000_0000u64 as i64);
-
-                        let tmp4 = bcx.ins().ishl_imm(v, 8);
-                        let n4 = bcx.ins().band_imm(tmp4, 0x0000_00FF_0000_0000u64 as i64);
-
-                        let tmp5 = bcx.ins().ushr_imm(v, 8);
-                        let n5 = bcx.ins().band_imm(tmp5, 0x0000_0000_FF00_0000u64 as i64);
-
-                        let tmp6 = bcx.ins().ushr_imm(v, 24);
-                        let n6 = bcx.ins().band_imm(tmp6, 0x0000_0000_00FF_0000u64 as i64);
-
-                        let tmp7 = bcx.ins().ushr_imm(v, 40);
-                        let n7 = bcx.ins().band_imm(tmp7, 0x0000_0000_0000_FF00u64 as i64);
-
-                        let tmp8 = bcx.ins().ushr_imm(v, 56);
-                        let n8 = bcx.ins().band_imm(tmp8, 0x0000_0000_0000_00FFu64 as i64);
-
-                        let or_tmp1 = bcx.ins().bor(n1, n2);
-                        let or_tmp2 = bcx.ins().bor(n3, n4);
-                        let or_tmp3 = bcx.ins().bor(n5, n6);
-                        let or_tmp4 = bcx.ins().bor(n7, n8);
-
-                        let or_tmp5 = bcx.ins().bor(or_tmp1, or_tmp2);
-                        let or_tmp6 = bcx.ins().bor(or_tmp3, or_tmp4);
-                        bcx.ins().bor(or_tmp5, or_tmp6)
-                    }
-                    types::I128 => {
-                        let (lo, hi) = bcx.ins().isplit(v);
-                        let lo = swap(bcx, lo);
-                        let hi = swap(bcx, hi);
-                        bcx.ins().iconcat(hi, lo)
-                    }
-                    ty => unreachable!("bswap {}", ty),
-                }
-            }
             intrinsic_args!(fx, args => (arg); intrinsic);
             let val = arg.load_scalar(fx);
 
-            let res = CValue::by_val(swap(&mut fx.bcx, val), arg.layout());
+            let res = if fx.bcx.func.dfg.value_type(val) == types::I8 {
+                val
+            } else {
+                fx.bcx.ins().bswap(val)
+            };
+            let res = CValue::by_val(res, arg.layout());
             ret.write_cvalue(fx, res);
         }
         sym::assert_inhabited | sym::assert_zero_valid | sym::assert_uninit_valid => {
@@ -936,8 +867,7 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
             let old = fx.bcx.ins().atomic_cas(MemFlags::trusted(), ptr, test_old, new);
             let is_eq = fx.bcx.ins().icmp(IntCC::Equal, old, test_old);
 
-            let ret_val =
-                CValue::by_val_pair(old, fx.bcx.ins().bint(types::I8, is_eq), ret.layout());
+            let ret_val = CValue::by_val_pair(old, is_eq, ret.layout());
             ret.write_cvalue(fx, ret_val)
         }
 
@@ -1259,8 +1189,7 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
                 flags.set_notrap();
                 let lhs_val = fx.bcx.ins().load(clty, flags, lhs_ref, 0);
                 let rhs_val = fx.bcx.ins().load(clty, flags, rhs_ref, 0);
-                let eq = fx.bcx.ins().icmp(IntCC::Equal, lhs_val, rhs_val);
-                fx.bcx.ins().bint(types::I8, eq)
+                fx.bcx.ins().icmp(IntCC::Equal, lhs_val, rhs_val)
             } else {
                 // Just call `memcmp` (like slices do in core) when the
                 // size is too large or it's not a power-of-two.
@@ -1270,8 +1199,7 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
                 let returns = vec![AbiParam::new(types::I32)];
                 let args = &[lhs_ref, rhs_ref, bytes_val];
                 let cmp = fx.lib_call("memcmp", params, returns, args)[0];
-                let eq = fx.bcx.ins().icmp_imm(IntCC::Equal, cmp, 0);
-                fx.bcx.ins().bint(types::I8, eq)
+                fx.bcx.ins().icmp_imm(IntCC::Equal, cmp, 0)
             };
             ret.write_cvalue(fx, CValue::by_val(is_eq_value, ret.layout()));
         }
index 51fce8c854bdb5307149680f288fa590ed8a8b53..14f5e9187399fac76f2a64d0147f2f647a904929 100644 (file)
@@ -112,10 +112,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
                     _ => unreachable!(),
                 };
 
-                let ty = fx.clif_type(res_lane_ty).unwrap();
-
-                let res_lane = fx.bcx.ins().bint(ty, res_lane);
-                fx.bcx.ins().ineg(res_lane)
+                bool_to_zero_or_max_uint(fx, res_lane_ty, res_lane)
             });
         }
 
@@ -716,7 +713,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
 
             let res_type =
                 Type::int_with_byte_size(u16::try_from(expected_bytes).unwrap()).unwrap();
-            let mut res = fx.bcx.ins().iconst(res_type, 0);
+            let mut res = type_zero_value(&mut fx.bcx, res_type);
 
             let lanes = match fx.tcx.sess.target.endian {
                 Endian::Big => Box::new(0..lane_count) as Box<dyn Iterator<Item = u64>>,
index f7434633ea442b40fa30f4a85370135e8c134017..c10054e7f0d2c971711364aafdfe563558e3fd5d 100644 (file)
@@ -65,7 +65,7 @@ fn create_entry_fn(
             returns: vec![AbiParam::new(m.target_config().pointer_type() /*isize*/)],
             call_conv: crate::conv_to_call_conv(
                 tcx.sess.target.options.entry_abi,
-                CallConv::triple_default(m.isa().triple()),
+                m.target_config().default_call_conv,
             ),
         };
 
@@ -75,7 +75,7 @@ fn create_entry_fn(
         let instance = Instance::mono(tcx, rust_main_def_id).polymorphize(tcx);
 
         let main_name = tcx.symbol_name(instance).name;
-        let main_sig = get_function_sig(tcx, m.isa().triple(), instance);
+        let main_sig = get_function_sig(tcx, m.target_config().default_call_conv, instance);
         let main_func_id = m.declare_function(main_name, Linkage::Import, &main_sig).unwrap();
 
         let mut ctx = Context::new();
@@ -119,7 +119,7 @@ fn create_entry_fn(
                 .polymorphize(tcx);
 
                 let report_name = tcx.symbol_name(report).name;
-                let report_sig = get_function_sig(tcx, m.isa().triple(), report);
+                let report_sig = get_function_sig(tcx, m.target_config().default_call_conv, report);
                 let report_func_id =
                     m.declare_function(report_name, Linkage::Import, &report_sig).unwrap();
                 let report_func_ref = m.declare_func_in_func(report_func_id, &mut bcx.func);
index ecbab408ded972889b6cbca8840daee8c2e837f4..afacbec644582195440bcb8e3e9c58d6d99b3c74 100644 (file)
@@ -49,7 +49,6 @@ fn codegen_compare_bin_op<'tcx>(
 ) -> CValue<'tcx> {
     let intcc = crate::num::bin_op_to_intcc(bin_op, signed).unwrap();
     let val = fx.bcx.ins().icmp(intcc, lhs, rhs);
-    let val = fx.bcx.ins().bint(types::I8, val);
     CValue::by_val(val, fx.layout_of(fx.tcx.types.bool))
 }
 
@@ -290,8 +289,6 @@ pub(crate) fn codegen_checked_int_binop<'tcx>(
         _ => bug!("binop {:?} on checked int/uint lhs: {:?} rhs: {:?}", bin_op, in_lhs, in_rhs),
     };
 
-    let has_overflow = fx.bcx.ins().bint(types::I8, has_overflow);
-
     let out_layout = fx.layout_of(fx.tcx.mk_tup([in_lhs.layout().ty, fx.tcx.types.bool].iter()));
     CValue::by_val_pair(res, has_overflow, out_layout)
 }
@@ -368,7 +365,6 @@ pub(crate) fn codegen_float_binop<'tcx>(
                 _ => unreachable!(),
             };
             let val = fx.bcx.ins().fcmp(fltcc, lhs, rhs);
-            let val = fx.bcx.ins().bint(types::I8, val);
             return CValue::by_val(val, fx.layout_of(fx.tcx.types.bool));
         }
         _ => unreachable!("{:?}({:?}, {:?})", bin_op, in_lhs, in_rhs),
@@ -440,7 +436,7 @@ pub(crate) fn codegen_ptr_binop<'tcx>(
             _ => panic!("bin_op {:?} on ptr", bin_op),
         };
 
-        CValue::by_val(fx.bcx.ins().bint(types::I8, res), fx.layout_of(fx.tcx.types.bool))
+        CValue::by_val(res, fx.layout_of(fx.tcx.types.bool))
     }
 }
 
index d637b4d89293cea0a0a855ebb97378b111c3789b..7f45bbd8f28136a43b8271ba5f3e2755d19d522d 100644 (file)
@@ -3,19 +3,6 @@
 use cranelift_codegen::ir::{condcodes::IntCC, InstructionData, Opcode, Value, ValueDef};
 use cranelift_frontend::FunctionBuilder;
 
-/// If the given value was produced by a `bint` instruction, return it's input, otherwise return the
-/// given value.
-pub(crate) fn maybe_unwrap_bint(bcx: &mut FunctionBuilder<'_>, arg: Value) -> Value {
-    if let ValueDef::Result(arg_inst, 0) = bcx.func.dfg.value_def(arg) {
-        match bcx.func.dfg[arg_inst] {
-            InstructionData::Unary { opcode: Opcode::Bint, arg } => arg,
-            _ => arg,
-        }
-    } else {
-        arg
-    }
-}
-
 /// If the given value was produced by the lowering of `Rvalue::Not` return the input and true,
 /// otherwise return the given value and false.
 pub(crate) fn maybe_unwrap_bool_not(bcx: &mut FunctionBuilder<'_>, arg: Value) -> (Value, bool) {
@@ -48,13 +35,6 @@ pub(crate) fn maybe_known_branch_taken(
     };
 
     match bcx.func.dfg[arg_inst] {
-        InstructionData::UnaryBool { opcode: Opcode::Bconst, imm } => {
-            if test_zero {
-                Some(!imm)
-            } else {
-                Some(imm)
-            }
-        }
         InstructionData::UnaryImm { opcode: Opcode::Iconst, imm } => {
             if test_zero {
                 Some(imm.bits() == 0)
index 34746ff6b6645c11bdda409d0af1f627908e65a0..fe8af21ac6de567cff94a34ec13e625f8876fe4a 100644 (file)
@@ -392,7 +392,7 @@ pub(crate) fn new_var(
         local: Local,
         layout: TyAndLayout<'tcx>,
     ) -> CPlace<'tcx> {
-        let var = Variable::with_u32(fx.next_ssa_var);
+        let var = Variable::from_u32(fx.next_ssa_var);
         fx.next_ssa_var += 1;
         fx.bcx.declare_var(var, fx.clif_type(layout.ty).unwrap());
         CPlace { inner: CPlaceInner::Var(local, var), layout }
@@ -403,9 +403,9 @@ pub(crate) fn new_var_pair(
         local: Local,
         layout: TyAndLayout<'tcx>,
     ) -> CPlace<'tcx> {
-        let var1 = Variable::with_u32(fx.next_ssa_var);
+        let var1 = Variable::from_u32(fx.next_ssa_var);
         fx.next_ssa_var += 1;
-        let var2 = Variable::with_u32(fx.next_ssa_var);
+        let var2 = Variable::from_u32(fx.next_ssa_var);
         fx.next_ssa_var += 1;
 
         let (ty1, ty2) = fx.clif_pair_type(layout.ty).unwrap();
@@ -515,9 +515,7 @@ fn transmute_value<'tcx>(
                 | (types::F32, types::I32)
                 | (types::I64, types::F64)
                 | (types::F64, types::I64) => fx.bcx.ins().bitcast(dst_ty, data),
-                _ if src_ty.is_vector() && dst_ty.is_vector() => {
-                    fx.bcx.ins().raw_bitcast(dst_ty, data)
-                }
+                _ if src_ty.is_vector() && dst_ty.is_vector() => fx.bcx.ins().bitcast(dst_ty, data),
                 _ if src_ty.is_vector() || dst_ty.is_vector() => {
                     // FIXME do something more efficient for transmutes between vectors and integers.
                     let stack_slot = fx.bcx.create_sized_stack_slot(StackSlotData {
@@ -590,7 +588,10 @@ fn transmute_value<'tcx>(
                 return;
             }
             CPlaceInner::VarPair(_local, var1, var2) => {
-                let (data1, data2) = CValue(from.0, dst_layout).load_scalar_pair(fx);
+                let (ptr, meta) = from.force_stack(fx);
+                assert!(meta.is_none());
+                let (data1, data2) =
+                    CValue(CValueInner::ByRef(ptr, None), dst_layout).load_scalar_pair(fx);
                 let (dst_ty1, dst_ty2) = fx.clif_pair_type(self.layout().ty).unwrap();
                 transmute_value(fx, var1, data1, dst_ty1);
                 transmute_value(fx, var2, data2, dst_ty2);
index 3d929a1d50ce2435307a7834c1fe04c1c73b94bd..13e7784539d5a9b9cdb3c81dd7f548afcb0c418b 100755 (executable)
@@ -1,2 +1,2 @@
 #!/usr/bin/env bash
-exec ./y.rs test
+exec ./y.rs test "$@"
index f177b91c2c4876a4ac7b62dd653a3e4ea0857453..02e1e21ade1de98f4d72256adbe70755a3997a55 100755 (executable)
@@ -3,7 +3,7 @@
 # This block is ignored by rustc
 set -e
 echo "[BUILD] y.rs" 1>&2
-rustc $0 -o ${0/.rs/.bin} -Cdebuginfo=1
+rustc $0 -o ${0/.rs/.bin} -Cdebuginfo=1 --edition 2021
 exec ${0/.rs/.bin} $@
 */
 
index 58dfd17fb363546dfcd17a386e653a1165e52bea..3860138018bb14c2a69bdfe4a5cfc37bfc1e6da3 100644 (file)
@@ -1802,15 +1802,20 @@ fn codegen_transmute_into(
         match (src.layout.abi, dst.layout.abi) {
             (abi::Abi::Scalar(src_scalar), abi::Abi::Scalar(dst_scalar)) => {
                 // HACK(eddyb) LLVM doesn't like `bitcast`s between pointers and non-pointers.
-                if (src_scalar.primitive() == abi::Pointer)
-                    == (dst_scalar.primitive() == abi::Pointer)
-                {
+                let src_is_ptr = src_scalar.primitive() == abi::Pointer;
+                let dst_is_ptr = dst_scalar.primitive() == abi::Pointer;
+                if src_is_ptr == dst_is_ptr {
                     assert_eq!(src.layout.size, dst.layout.size);
 
                     // NOTE(eddyb) the `from_immediate` and `to_immediate_scalar`
                     // conversions allow handling `bool`s the same as `u8`s.
                     let src = bx.from_immediate(src.immediate());
-                    let src_as_dst = bx.bitcast(src, bx.backend_type(dst.layout));
+                    // LLVM also doesn't like `bitcast`s between pointers in different address spaces.
+                    let src_as_dst = if src_is_ptr {
+                        bx.pointercast(src, bx.backend_type(dst.layout))
+                    } else {
+                        bx.bitcast(src, bx.backend_type(dst.layout))
+                    };
                     Immediate(bx.to_immediate_scalar(src_as_dst, dst_scalar)).store(bx, dst);
                     return;
                 }
index c60d6e4fed9f55277ba8640f9fb8ed81d4612dfc..13472cc2bfa0a5c4b8ed7ba81baa6eb3114ac9f9 100644 (file)
@@ -86,6 +86,59 @@ pub(super) fn report(&self, tcx: TyCtxtAt<'tcx>, message: &str) -> ErrorHandled
         self.report_decorated(tcx, message, |_| {})
     }
 
+    #[instrument(level = "trace", skip(self, decorate))]
+    pub(super) fn decorate(&self, err: &mut Diagnostic, decorate: impl FnOnce(&mut Diagnostic)) {
+        trace!("reporting const eval failure at {:?}", self.span);
+        // Add some more context for select error types.
+        match self.error {
+            InterpError::Unsupported(
+                UnsupportedOpInfo::ReadPointerAsBytes
+                | UnsupportedOpInfo::PartialPointerOverwrite(_)
+                | UnsupportedOpInfo::PartialPointerCopy(_),
+            ) => {
+                err.help("this code performed an operation that depends on the underlying bytes representing a pointer");
+                err.help("the absolute address of a pointer is not known at compile-time, so such operations are not supported");
+            }
+            _ => {}
+        }
+        // Add spans for the stacktrace. Don't print a single-line backtrace though.
+        if self.stacktrace.len() > 1 {
+            // Helper closure to print duplicated lines.
+            let mut flush_last_line = |last_frame, times| {
+                if let Some((line, span)) = last_frame {
+                    err.span_note(span, &line);
+                    // Don't print [... additional calls ...] if the number of lines is small
+                    if times < 3 {
+                        for _ in 0..times {
+                            err.span_note(span, &line);
+                        }
+                    } else {
+                        err.span_note(
+                            span,
+                            format!("[... {} additional calls {} ...]", times, &line),
+                        );
+                    }
+                }
+            };
+
+            let mut last_frame = None;
+            let mut times = 0;
+            for frame_info in &self.stacktrace {
+                let frame = (frame_info.to_string(), frame_info.span);
+                if last_frame.as_ref() == Some(&frame) {
+                    times += 1;
+                } else {
+                    flush_last_line(last_frame, times);
+                    last_frame = Some(frame);
+                    times = 0;
+                }
+            }
+            flush_last_line(last_frame, times);
+        }
+        // Let the caller attach any additional information it wants.
+        decorate(err);
+    }
+
     /// Create a diagnostic for this const eval error.
     ///
     /// Sets the message passed in via `message` and adds span labels with detailed error
@@ -101,88 +154,30 @@ pub(super) fn report_decorated(
         message: &str,
         decorate: impl FnOnce(&mut Diagnostic),
     ) -> ErrorHandled {
-        let finish = |err: &mut Diagnostic, span_msg: Option<String>| {
-            trace!("reporting const eval failure at {:?}", self.span);
-            if let Some(span_msg) = span_msg {
-                err.span_label(self.span, span_msg);
-            }
-            // Add some more context for select error types.
-            match self.error {
-                InterpError::Unsupported(
-                    UnsupportedOpInfo::ReadPointerAsBytes
-                    | UnsupportedOpInfo::PartialPointerOverwrite(_)
-                    | UnsupportedOpInfo::PartialPointerCopy(_),
-                ) => {
-                    err.help("this code performed an operation that depends on the underlying bytes representing a pointer");
-                    err.help("the absolute address of a pointer is not known at compile-time, so such operations are not supported");
-                }
-                _ => {}
-            }
-            // Add spans for the stacktrace. Don't print a single-line backtrace though.
-            if self.stacktrace.len() > 1 {
-                // Helper closure to print duplicated lines.
-                let mut flush_last_line = |last_frame, times| {
-                    if let Some((line, span)) = last_frame {
-                        err.span_note(span, &line);
-                        // Don't print [... additional calls ...] if the number of lines is small
-                        if times < 3 {
-                            for _ in 0..times {
-                                err.span_note(span, &line);
-                            }
-                        } else {
-                            err.span_note(
-                                span,
-                                format!("[... {} additional calls {} ...]", times, &line),
-                            );
-                        }
-                    }
-                };
-
-                let mut last_frame = None;
-                let mut times = 0;
-                for frame_info in &self.stacktrace {
-                    let frame = (frame_info.to_string(), frame_info.span);
-                    if last_frame.as_ref() == Some(&frame) {
-                        times += 1;
-                    } else {
-                        flush_last_line(last_frame, times);
-                        last_frame = Some(frame);
-                        times = 0;
-                    }
-                }
-                flush_last_line(last_frame, times);
-            }
-            // Let the caller attach any additional information it wants.
-            decorate(err);
-        };
-
         debug!("self.error: {:?}", self.error);
         // Special handling for certain errors
         match &self.error {
             // Don't emit a new diagnostic for these errors
             err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => {
-                return ErrorHandled::TooGeneric;
-            }
-            err_inval!(AlreadyReported(error_reported)) => {
-                return ErrorHandled::Reported(*error_reported);
+                ErrorHandled::TooGeneric
             }
+            err_inval!(AlreadyReported(error_reported)) => ErrorHandled::Reported(*error_reported),
             err_inval!(Layout(LayoutError::SizeOverflow(_))) => {
                 // We must *always* hard error on these, even if the caller wants just a lint.
                 // The `message` makes little sense here, this is a more serious error than the
                 // caller thinks anyway.
                 // See <https://github.com/rust-lang/rust/pull/63152>.
                 let mut err = struct_error(tcx, &self.error.to_string());
-                finish(&mut err, None);
-                return ErrorHandled::Reported(err.emit());
+                self.decorate(&mut err, decorate);
+                ErrorHandled::Reported(err.emit())
             }
-            _ => {}
-        };
-
-        let err_msg = self.error.to_string();
-
-        // Report as hard error.
-        let mut err = struct_error(tcx, message);
-        finish(&mut err, Some(err_msg));
-        ErrorHandled::Reported(err.emit())
+            _ => {
+                // Report as hard error.
+                let mut err = struct_error(tcx, message);
+                err.span_label(self.span, self.error.to_string());
+                self.decorate(&mut err, decorate);
+                ErrorHandled::Reported(err.emit())
+            }
+        }
     }
 }
index 319f2b2c25ebf320f71c6d0fe83bca042fe3f191..18e01567ca35e44888e52e19abd6bb07edca0d0e 100644 (file)
@@ -1,3 +1,4 @@
+use crate::const_eval::CheckAlignment;
 use std::borrow::Cow;
 
 use either::{Left, Right};
@@ -76,7 +77,7 @@ fn eval_body_using_ecx<'mir, 'tcx>(
             None => InternKind::Constant,
         }
     };
-    ecx.machine.check_alignment = false; // interning doesn't need to respect alignment
+    ecx.machine.check_alignment = CheckAlignment::No; // interning doesn't need to respect alignment
     intern_const_alloc_recursive(ecx, intern_kind, &ret)?;
     // we leave alignment checks off, since this `ecx` will not be used for further evaluation anyway
 
@@ -102,11 +103,7 @@ pub(super) fn mk_eval_cx<'mir, 'tcx>(
         tcx,
         root_span,
         param_env,
-        CompileTimeInterpreter::new(
-            tcx.const_eval_limit(),
-            can_access_statics,
-            /*check_alignment:*/ false,
-        ),
+        CompileTimeInterpreter::new(tcx.const_eval_limit(), can_access_statics, CheckAlignment::No),
     )
 }
 
@@ -311,7 +308,11 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
         CompileTimeInterpreter::new(
             tcx.const_eval_limit(),
             /*can_access_statics:*/ is_static,
-            /*check_alignment:*/ tcx.sess.opts.unstable_opts.extra_const_ub_checks,
+            if tcx.sess.opts.unstable_opts.extra_const_ub_checks {
+                CheckAlignment::Error
+            } else {
+                CheckAlignment::FutureIncompat
+            },
         ),
     );
 
index 3dfded2d930a052c305859ed257536285303eda8..e006a62feeabd12bc568da7c5c42e76bdde1cc2f 100644 (file)
@@ -1,9 +1,10 @@
 use rustc_hir::def::DefKind;
-use rustc_hir::LangItem;
+use rustc_hir::{LangItem, CRATE_HIR_ID};
 use rustc_middle::mir;
 use rustc_middle::mir::interpret::PointerArithmetic;
 use rustc_middle::ty::layout::FnAbiOf;
 use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_session::lint::builtin::INVALID_ALIGNMENT;
 use std::borrow::Borrow;
 use std::hash::Hash;
 use std::ops::ControlFlow;
@@ -47,14 +48,34 @@ pub struct CompileTimeInterpreter<'mir, 'tcx> {
     pub(super) can_access_statics: bool,
 
     /// Whether to check alignment during evaluation.
-    pub(super) check_alignment: bool,
+    pub(super) check_alignment: CheckAlignment,
+}
+
+#[derive(Copy, Clone)]
+pub enum CheckAlignment {
+    /// Ignore alignment when following relocations.
+    /// This is mainly used in interning.
+    No,
+    /// Hard error when dereferencing a misaligned pointer.
+    Error,
+    /// Emit a future incompat lint when dereferencing a misaligned pointer.
+    FutureIncompat,
+}
+
+impl CheckAlignment {
+    pub fn should_check(&self) -> bool {
+        match self {
+            CheckAlignment::No => false,
+            CheckAlignment::Error | CheckAlignment::FutureIncompat => true,
+        }
+    }
 }
 
 impl<'mir, 'tcx> CompileTimeInterpreter<'mir, 'tcx> {
     pub(crate) fn new(
         const_eval_limit: Limit,
         can_access_statics: bool,
-        check_alignment: bool,
+        check_alignment: CheckAlignment,
     ) -> Self {
         CompileTimeInterpreter {
             steps_remaining: const_eval_limit.0,
@@ -309,7 +330,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
     const PANIC_ON_ALLOC_FAIL: bool = false; // will be raised as a proper error
 
     #[inline(always)]
-    fn enforce_alignment(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
+    fn enforce_alignment(ecx: &InterpCx<'mir, 'tcx, Self>) -> CheckAlignment {
         ecx.machine.check_alignment
     }
 
@@ -318,6 +339,36 @@ fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
         ecx.tcx.sess.opts.unstable_opts.extra_const_ub_checks
     }
 
+    fn alignment_check_failed(
+        ecx: &InterpCx<'mir, 'tcx, Self>,
+        has: Align,
+        required: Align,
+        check: CheckAlignment,
+    ) -> InterpResult<'tcx, ()> {
+        let err = err_ub!(AlignmentCheckFailed { has, required }).into();
+        match check {
+            CheckAlignment::Error => Err(err),
+            CheckAlignment::No => span_bug!(
+                ecx.cur_span(),
+                "`alignment_check_failed` called when no alignment check requested"
+            ),
+            CheckAlignment::FutureIncompat => {
+                let err = ConstEvalErr::new(ecx, err, None);
+                ecx.tcx.struct_span_lint_hir(
+                    INVALID_ALIGNMENT,
+                    ecx.stack().iter().find_map(|frame| frame.lint_root()).unwrap_or(CRATE_HIR_ID),
+                    err.span,
+                    err.error.to_string(),
+                    |db| {
+                        err.decorate(db, |_| {});
+                        db
+                    },
+                );
+                Ok(())
+            }
+        }
+    }
+
     fn load_mir(
         ecx: &InterpCx<'mir, 'tcx, Self>,
         instance: ty::InstanceDef<'tcx>,
index 0b2809f1d2c285238c1a93a8bb65fc314483de87..f551b5c29114d9984fcf108ceb1b9e12628db580 100644 (file)
@@ -248,6 +248,15 @@ pub fn current_span(&self) -> Span {
             Right(span) => span,
         }
     }
+
+    pub fn lint_root(&self) -> Option<hir::HirId> {
+        self.current_source_info().and_then(|source_info| {
+            match &self.body.source_scopes[source_info.scope].local_data {
+                mir::ClearCrossCrate::Set(data) => Some(data.lint_root),
+                mir::ClearCrossCrate::Clear => None,
+            }
+        })
+    }
 }
 
 impl<'tcx> fmt::Display for FrameInfo<'tcx> {
@@ -954,12 +963,7 @@ pub fn generate_stacktrace_from_stack(
         // This deliberately does *not* honor `requires_caller_location` since it is used for much
         // more than just panics.
         for frame in stack.iter().rev() {
-            let lint_root = frame.current_source_info().and_then(|source_info| {
-                match &frame.body.source_scopes[source_info.scope].local_data {
-                    mir::ClearCrossCrate::Set(data) => Some(data.lint_root),
-                    mir::ClearCrossCrate::Clear => None,
-                }
-            });
+            let lint_root = frame.lint_root();
             let span = frame.current_span();
 
             frames.push(FrameInfo { span, instance: frame.instance, lint_root });
index 0604d5ee6fa4c93e94211111da45abd2e4715f15..1d4ef20d0651f7bd11d7cb466f0290d375ff27d8 100644 (file)
 use rustc_middle::mir;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::def_id::DefId;
-use rustc_target::abi::Size;
+use rustc_target::abi::{Align, Size};
 use rustc_target::spec::abi::Abi as CallAbi;
 
+use crate::const_eval::CheckAlignment;
+
 use super::{
     AllocId, AllocRange, Allocation, ConstAllocation, Frame, ImmTy, InterpCx, InterpResult,
     MemoryKind, OpTy, Operand, PlaceTy, Pointer, Provenance, Scalar, StackPopUnwind,
@@ -122,7 +124,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
     const PANIC_ON_ALLOC_FAIL: bool;
 
     /// Whether memory accesses should be alignment-checked.
-    fn enforce_alignment(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
+    fn enforce_alignment(ecx: &InterpCx<'mir, 'tcx, Self>) -> CheckAlignment;
 
     /// Whether, when checking alignment, we should look at the actual address and thus support
     /// custom alignment logic based on whatever the integer address happens to be.
@@ -130,6 +132,13 @@ pub trait Machine<'mir, 'tcx>: Sized {
     /// If this returns true, Provenance::OFFSET_IS_ADDR must be true.
     fn use_addr_for_alignment_check(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
 
+    fn alignment_check_failed(
+        ecx: &InterpCx<'mir, 'tcx, Self>,
+        has: Align,
+        required: Align,
+        check: CheckAlignment,
+    ) -> InterpResult<'tcx, ()>;
+
     /// Whether to enforce the validity invariant
     fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
 
index 528c1cb06c0ebadf1e2ca0cb324cc51bd8c0e794..5b1ac6b2f65e29f7bc7a726d3044a6fd5cb95654 100644 (file)
@@ -18,6 +18,8 @@
 use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TyCtxt};
 use rustc_target::abi::{Align, HasDataLayout, Size};
 
+use crate::const_eval::CheckAlignment;
+
 use super::{
     alloc_range, AllocId, AllocMap, AllocRange, Allocation, CheckInAllocMsg, GlobalAlloc, InterpCx,
     InterpResult, Machine, MayLeak, Pointer, PointerArithmetic, Provenance, Scalar,
@@ -349,11 +351,11 @@ fn get_ptr_access(
         size: Size,
         align: Align,
     ) -> InterpResult<'tcx, Option<(AllocId, Size, M::ProvenanceExtra)>> {
-        let align = M::enforce_alignment(&self).then_some(align);
         self.check_and_deref_ptr(
             ptr,
             size,
             align,
+            M::enforce_alignment(self),
             CheckInAllocMsg::MemoryAccessTest,
             |alloc_id, offset, prov| {
                 let (size, align) = self.get_live_alloc_size_and_align(alloc_id)?;
@@ -373,10 +375,17 @@ pub fn check_ptr_access_align(
         align: Align,
         msg: CheckInAllocMsg,
     ) -> InterpResult<'tcx> {
-        self.check_and_deref_ptr(ptr, size, Some(align), msg, |alloc_id, _, _| {
-            let (size, align) = self.get_live_alloc_size_and_align(alloc_id)?;
-            Ok((size, align, ()))
-        })?;
+        self.check_and_deref_ptr(
+            ptr,
+            size,
+            align,
+            CheckAlignment::Error,
+            msg,
+            |alloc_id, _, _| {
+                let (size, align) = self.get_live_alloc_size_and_align(alloc_id)?;
+                Ok((size, align, ()))
+            },
+        )?;
         Ok(())
     }
 
@@ -388,7 +397,8 @@ fn check_and_deref_ptr<T>(
         &self,
         ptr: Pointer<Option<M::Provenance>>,
         size: Size,
-        align: Option<Align>,
+        align: Align,
+        check: CheckAlignment,
         msg: CheckInAllocMsg,
         alloc_size: impl FnOnce(
             AllocId,
@@ -396,19 +406,6 @@ fn check_and_deref_ptr<T>(
             M::ProvenanceExtra,
         ) -> InterpResult<'tcx, (Size, Align, T)>,
     ) -> InterpResult<'tcx, Option<T>> {
-        fn check_offset_align<'tcx>(offset: u64, align: Align) -> InterpResult<'tcx> {
-            if offset % align.bytes() == 0 {
-                Ok(())
-            } else {
-                // The biggest power of two through which `offset` is divisible.
-                let offset_pow2 = 1 << offset.trailing_zeros();
-                throw_ub!(AlignmentCheckFailed {
-                    has: Align::from_bytes(offset_pow2).unwrap(),
-                    required: align,
-                })
-            }
-        }
-
         Ok(match self.ptr_try_get_alloc_id(ptr) {
             Err(addr) => {
                 // We couldn't get a proper allocation. This is only okay if the access size is 0,
@@ -417,8 +414,8 @@ fn check_offset_align<'tcx>(offset: u64, align: Align) -> InterpResult<'tcx> {
                     throw_ub!(DanglingIntPointer(addr, msg));
                 }
                 // Must be aligned.
-                if let Some(align) = align {
-                    check_offset_align(addr, align)?;
+                if check.should_check() {
+                    self.check_offset_align(addr, align, check)?;
                 }
                 None
             }
@@ -441,16 +438,16 @@ fn check_offset_align<'tcx>(offset: u64, align: Align) -> InterpResult<'tcx> {
                 }
                 // Test align. Check this last; if both bounds and alignment are violated
                 // we want the error to be about the bounds.
-                if let Some(align) = align {
+                if check.should_check() {
                     if M::use_addr_for_alignment_check(self) {
                         // `use_addr_for_alignment_check` can only be true if `OFFSET_IS_ADDR` is true.
-                        check_offset_align(ptr.addr().bytes(), align)?;
+                        self.check_offset_align(ptr.addr().bytes(), align, check)?;
                     } else {
                         // Check allocation alignment and offset alignment.
                         if alloc_align.bytes() < align.bytes() {
-                            throw_ub!(AlignmentCheckFailed { has: alloc_align, required: align });
+                            M::alignment_check_failed(self, alloc_align, align, check)?;
                         }
-                        check_offset_align(offset.bytes(), align)?;
+                        self.check_offset_align(offset.bytes(), align, check)?;
                     }
                 }
 
@@ -460,6 +457,21 @@ fn check_offset_align<'tcx>(offset: u64, align: Align) -> InterpResult<'tcx> {
             }
         })
     }
+
+    fn check_offset_align(
+        &self,
+        offset: u64,
+        align: Align,
+        check: CheckAlignment,
+    ) -> InterpResult<'tcx> {
+        if offset % align.bytes() == 0 {
+            Ok(())
+        } else {
+            // The biggest power of two through which `offset` is divisible.
+            let offset_pow2 = 1 << offset.trailing_zeros();
+            M::alignment_check_failed(self, Align::from_bytes(offset_pow2).unwrap(), align, check)
+        }
+    }
 }
 
 /// Allocation accessors
@@ -560,11 +572,11 @@ pub fn get_ptr_alloc<'a>(
         size: Size,
         align: Align,
     ) -> InterpResult<'tcx, Option<AllocRef<'a, 'tcx, M::Provenance, M::AllocExtra>>> {
-        let align = M::enforce_alignment(self).then_some(align);
         let ptr_and_alloc = self.check_and_deref_ptr(
             ptr,
             size,
             align,
+            M::enforce_alignment(self),
             CheckInAllocMsg::MemoryAccessTest,
             |alloc_id, offset, prov| {
                 let alloc = self.get_alloc_raw(alloc_id)?;
index c47cfe8bb69fd05831734e1f42cf16e3781d7049..905eb71bb18edde28b2eeb30f7d406defedcf4ce 100644 (file)
@@ -364,13 +364,8 @@ pub fn check_mplace(&self, mplace: MPlaceTy<'tcx, M::Provenance>) -> InterpResul
             .size_and_align_of_mplace(&mplace)?
             .unwrap_or((mplace.layout.size, mplace.layout.align.abi));
         assert!(mplace.align <= align, "dynamic alignment less strict than static one?");
-        let align = M::enforce_alignment(self).then_some(align);
-        self.check_ptr_access_align(
-            mplace.ptr,
-            size,
-            align.unwrap_or(Align::ONE),
-            CheckInAllocMsg::DerefTest,
-        )?;
+        let align = if M::enforce_alignment(self).should_check() { align } else { Align::ONE };
+        self.check_ptr_access_align(mplace.ptr, size, align, CheckInAllocMsg::DerefTest)?;
         Ok(())
     }
 
index decddf47b715d7a9f4aff4df1f52ee0a7f48c6a3..bb897b95b2c53cd1122663b41945764ccd354960 100644 (file)
@@ -241,7 +241,7 @@ fn visit_projection_elem(
                 };
 
                 let kind = match parent_ty.ty.kind() {
-                    &ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs }) => {
+                    &ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
                         self.tcx.bound_type_of(def_id).subst(self.tcx, substs).kind()
                     }
                     kind => kind,
index 6ca71223391d2a5828b39b655cb113473cd0e46f..4ce107ea68d4f0f3869cebe3cce00c706a42f58d 100644 (file)
@@ -3,7 +3,7 @@
 use rustc_session::Limit;
 use rustc_target::abi::{Abi, FieldsShape, InitKind, Scalar, Variants};
 
-use crate::const_eval::CompileTimeInterpreter;
+use crate::const_eval::{CheckAlignment, CompileTimeInterpreter};
 use crate::interpret::{InterpCx, MemoryKind, OpTy};
 
 /// Determines if this type permits "raw" initialization by just transmuting some memory into an
@@ -41,7 +41,7 @@ fn might_permit_raw_init_strict<'tcx>(
     let machine = CompileTimeInterpreter::new(
         Limit::new(0),
         /*can_access_statics:*/ false,
-        /*check_alignment:*/ true,
+        CheckAlignment::Error,
     );
 
     let mut cx = InterpCx::new(tcx, rustc_span::DUMMY_SP, ParamEnv::reveal_all(), machine);
index dd65d4fd591e547a93089cff9fa0e0ac27690ece..c4122f66498143a70950219d6afb696c91d58f40 100644 (file)
@@ -58,7 +58,7 @@ fn print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> {
             // Types with identity (print the module path).
             ty::Adt(ty::AdtDef(Interned(&ty::AdtDefData { did: def_id, .. }, _)), substs)
             | ty::FnDef(def_id, substs)
-            | ty::Alias(_, ty::AliasTy { def_id, substs })
+            | ty::Alias(_, ty::AliasTy { def_id, substs, .. })
             | ty::Closure(def_id, substs)
             | ty::Generator(def_id, substs, _) => self.print_def_path(def_id, substs),
             ty::Foreign(def_id) => self.print_def_path(def_id, &[]),
index 03ff5e5b3751fe502d5c1c3c0265dc9c07c74aa8..05f059c89d5cd0fea01ea73e00e8d8419b4b3c9e 100644 (file)
@@ -126,13 +126,13 @@ pub fn iter(&self) -> std::slice::Iter<'_, (K, V)> {
     /// Iterate over the keys, sorted
     #[inline]
     pub fn keys(&self) -> impl Iterator<Item = &K> + ExactSizeIterator + DoubleEndedIterator {
-        self.data.iter().map(|&(ref k, _)| k)
+        self.data.iter().map(|(k, _)| k)
     }
 
     /// Iterate over values, sorted by key
     #[inline]
     pub fn values(&self) -> impl Iterator<Item = &V> + ExactSizeIterator + DoubleEndedIterator {
-        self.data.iter().map(|&(_, ref v)| v)
+        self.data.iter().map(|(_, v)| v)
     }
 
     #[inline]
@@ -222,7 +222,7 @@ fn lookup_index_for<Q>(&self, key: &Q) -> Result<usize, usize>
         K: Borrow<Q>,
         Q: Ord + ?Sized,
     {
-        self.data.binary_search_by(|&(ref x, _)| x.borrow().cmp(key))
+        self.data.binary_search_by(|(x, _)| x.borrow().cmp(key))
     }
 
     #[inline]
@@ -300,7 +300,7 @@ impl<K: Ord, V> FromIterator<(K, V)> for SortedMap<K, V> {
     fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
         let mut data: Vec<(K, V)> = iter.into_iter().collect();
 
-        data.sort_unstable_by(|&(ref k1, _), &(ref k2, _)| k1.cmp(k2));
+        data.sort_unstable_by(|(k1, _), (k2, _)| k1.cmp(k2));
         data.dedup_by(|&mut (ref k1, _), &mut (ref k2, _)| k1.cmp(k2) == Ordering::Equal);
 
         SortedMap { data }
index e33323a7795369bf6ccf2b77c0299b0e9b7600d2..26cdf8a58f3fb5e975342ef93f2237c095a2932d 100644 (file)
@@ -20,6 +20,10 @@ hir_analysis_lifetimes_or_bounds_mismatch_on_trait =
     .where_label = this `where` clause might not match the one in the trait
     .bounds_label = this bound might be missing in the impl
 
+hir_analysis_async_trait_impl_should_be_async =
+    method `{$method_name}` should be async because the method from the trait is async
+    .trait_item_label = required because the trait method is async
+
 hir_analysis_drop_impl_on_wrong_item =
     the `Drop` trait may only be implemented for local structs, enums, and unions
     .label = must be a struct, enum, or union in the current crate
index 48ddb54b79e795eb3c67f96b69bb5dda24e32f01..243d10bfa062150bf9bda530541b8f235d35ceae 100644 (file)
@@ -21,3 +21,6 @@ monomorphize_large_assignments =
     moving {$size} bytes
     .label = value moved from here
     .note = The current maximum size is {$limit}, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
+
+monomorphize_couldnt_dump_mono_stats =
+    unexpected error occurred while dumping monomorphization stats: {$error}
index c62e358e804cade724910bb8f95020b3853dfc84..e2a0e436fd5e2677a9524066380a034907ef59b0 100644 (file)
@@ -2313,7 +2313,7 @@ fn add_annotation_to_file(
         }
 
         // Find overlapping multiline annotations, put them at different depths
-        multiline_annotations.sort_by_key(|&(_, ref ml)| (ml.line_start, usize::MAX - ml.line_end));
+        multiline_annotations.sort_by_key(|(_, ml)| (ml.line_start, usize::MAX - ml.line_end));
         for (_, ann) in multiline_annotations.clone() {
             for (_, a) in multiline_annotations.iter_mut() {
                 // Move all other multiline annotations overlapping with this one
index eb0506c459afa732b0bf07918bf8adfde11659af..518b5ec10f8906122c4ab9fb26cc19e80231bf8a 100644 (file)
@@ -324,7 +324,7 @@ fn push_trailing(
                         // Account for the difference between the width of the current code and the
                         // snippet being suggested, so that the *later* suggestions are correctly
                         // aligned on the screen.
-                        acc += len as isize - (cur_hi.col.0 - cur_lo.col.0) as isize;
+                        acc += len - (cur_hi.col.0 - cur_lo.col.0) as isize;
                     }
                     prev_hi = cur_hi;
                     prev_line = sf.get_line(prev_hi.line - 1);
index c8c10385f0cd60c4d035985c1931e1277e6f8f1a..71f26eb60c9628e880f5f5b71ca4274e4fed5598 100644 (file)
@@ -680,7 +680,7 @@ fn instantiate_poly_trait_ref_inner(
         let assoc_bindings = self.create_assoc_bindings_for_generic_args(args);
 
         let poly_trait_ref =
-            ty::Binder::bind_with_vars(ty::TraitRef::new(trait_def_id, substs), bound_vars);
+            ty::Binder::bind_with_vars(tcx.mk_trait_ref(trait_def_id, substs), bound_vars);
 
         debug!(?poly_trait_ref, ?assoc_bindings);
         bounds.trait_bounds.push((poly_trait_ref, span, constness));
@@ -813,7 +813,7 @@ fn ast_path_to_mono_trait_ref(
         if let Some(b) = trait_segment.args().bindings.first() {
             Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
         }
-        ty::TraitRef::new(trait_def_id, substs)
+        self.tcx().mk_trait_ref(trait_def_id, substs)
     }
 
     #[instrument(level = "debug", skip(self, span))]
@@ -1146,7 +1146,7 @@ fn add_predicates_for_ast_type_binding(
 
             debug!(?substs_trait_ref_and_assoc_item);
 
-            ty::AliasTy { def_id: assoc_item.def_id, substs: substs_trait_ref_and_assoc_item }
+            self.tcx().mk_alias_ty(assoc_item.def_id, substs_trait_ref_and_assoc_item)
         });
 
         if !speculative {
index dd841707b29069e3510d38db347891b553afa1c5..aa01feb3a1ea4d686e5b84401d4100913088ae76 100644 (file)
@@ -570,7 +570,7 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
                             assoc_item,
                             assoc_item,
                             default.span,
-                            ty::TraitRef { def_id: it.owner_id.to_def_id(), substs: trait_substs },
+                            tcx.mk_trait_ref(it.owner_id.to_def_id(), trait_substs),
                         );
                     }
                     _ => {}
@@ -1440,7 +1440,7 @@ fn opaque_type_cycle_error(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) -> E
                 impl<'tcx> ty::visit::TypeVisitor<'tcx> for OpaqueTypeCollector {
                     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                         match *t.kind() {
-                            ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, substs: _ }) => {
+                            ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => {
                                 self.0.push(def);
                                 ControlFlow::CONTINUE
                             }
index ba7d31cea2e2f3e778702c331738ca93ab9dffc7..6b9ce9a4599e2ce45ddd8e8479ec41f32d73d6b7 100644 (file)
@@ -67,6 +67,10 @@ pub(crate) fn compare_impl_method<'tcx>(
         return;
     }
 
+    if let Err(_) = compare_asyncness(tcx, impl_m, impl_m_span, trait_m, trait_item_span) {
+        return;
+    }
+
     if let Err(_) = compare_predicate_entailment(tcx, impl_m, impl_m_span, trait_m, impl_trait_ref)
     {
         return;
@@ -323,6 +327,34 @@ fn compare_predicate_entailment<'tcx>(
     Ok(())
 }
 
+fn compare_asyncness<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    impl_m: &ty::AssocItem,
+    impl_m_span: Span,
+    trait_m: &ty::AssocItem,
+    trait_item_span: Option<Span>,
+) -> Result<(), ErrorGuaranteed> {
+    if tcx.asyncness(trait_m.def_id) == hir::IsAsync::Async {
+        match tcx.fn_sig(impl_m.def_id).skip_binder().output().kind() {
+            ty::Alias(ty::Opaque, ..) => {
+                // allow both `async fn foo()` and `fn foo() -> impl Future`
+            }
+            ty::Error(rustc_errors::ErrorGuaranteed { .. }) => {
+                // We don't know if it's ok, but at least it's already an error.
+            }
+            _ => {
+                return Err(tcx.sess.emit_err(crate::errors::AsyncTraitImplShouldBeAsync {
+                    span: impl_m_span,
+                    method_name: trait_m.name,
+                    trait_item_span,
+                }));
+            }
+        };
+    }
+
+    Ok(())
+}
+
 #[instrument(skip(tcx), level = "debug", ret)]
 pub fn collect_trait_impl_trait_tys<'tcx>(
     tcx: TyCtxt<'tcx>,
@@ -1746,10 +1778,7 @@ pub fn check_type_bounds<'tcx>(
             _ => predicates.push(
                 ty::Binder::bind_with_vars(
                     ty::ProjectionPredicate {
-                        projection_ty: ty::AliasTy {
-                            def_id: trait_ty.def_id,
-                            substs: rebased_substs,
-                        },
+                        projection_ty: tcx.mk_alias_ty(trait_ty.def_id, rebased_substs),
                         term: impl_ty_value.into(),
                     },
                     bound_vars,
index d9697c63c56e1e8df9d2cfa2ceb5542b92a04ad8..d383fcacb3a9c914ce0b862daf1386e8b52c453e 100644 (file)
@@ -51,6 +51,17 @@ pub struct LifetimesOrBoundsMismatchOnTrait {
     pub ident: Ident,
 }
 
+#[derive(Diagnostic)]
+#[diag(hir_analysis_async_trait_impl_should_be_async)]
+pub struct AsyncTraitImplShouldBeAsync {
+    #[primary_span]
+    // #[label]
+    pub span: Span,
+    #[label(trait_item_label)]
+    pub trait_item_span: Option<Span>,
+    pub method_name: Symbol,
+}
+
 #[derive(Diagnostic)]
 #[diag(hir_analysis_drop_impl_on_wrong_item, code = "E0120")]
 pub struct DropImplOnWrongItem {
index 3c29c72841e44579ce491c1e28ba2cac9283e6ed..24008f88814339d1f343fe38c0cf368165afe994 100644 (file)
@@ -111,7 +111,7 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
         #[instrument(level = "trace", skip(self), ret)]
         fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
             match t.kind() {
-                ty::Alias(_, ty::AliasTy { def_id, substs })
+                ty::Alias(_, ty::AliasTy { def_id, substs, .. })
                     if matches!(
                         self.tcx.def_kind(*def_id),
                         DefKind::OpaqueTy | DefKind::ImplTraitPlaceholder
@@ -160,7 +160,7 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         // instead of requiring an additional `+ 'a`.
         match pred.kind().skip_binder() {
             ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate {
-                trait_ref: ty::TraitRef { def_id: _, substs },
+                trait_ref: ty::TraitRef { def_id: _, substs, .. },
                 constness: _,
                 polarity: _,
             })) => {
@@ -169,7 +169,7 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                 }
             }
             ty::PredicateKind::Clause(ty::Clause::Projection(ty::ProjectionPredicate {
-                projection_ty: ty::AliasTy { substs, def_id: _ },
+                projection_ty: ty::AliasTy { substs, .. },
                 term,
             })) => {
                 for subst in &substs[1..] {
index ef98c4ba54cbdfd1e3a6c1a0b0401beb5ab2a5e8..29a6902ccb0772591f896c431ec61e9d45ce37e1 100644 (file)
@@ -1757,7 +1757,6 @@ pub fn print_pat(&mut self, pat: &hir::Pat<'_>) {
                 self.print_qpath(qpath, true);
                 self.popen();
                 if let Some(ddpos) = ddpos.as_opt_usize() {
-                    let ddpos = ddpos as usize;
                     self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(p));
                     if ddpos != 0 {
                         self.word_space(",");
index a86bd80a668b03d74aed8daed979d3679f264765..ab12cae4e2b08a0b48fc57e8b687f841b7b59509 100644 (file)
@@ -518,7 +518,7 @@ pub(crate) fn opt_suggest_box_span(
 
                 let substs = sig.output().walk().find_map(|arg| {
                     if let ty::GenericArgKind::Type(ty) = arg.unpack()
-                        && let ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs }) = *ty.kind()
+                        && let ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) = *ty.kind()
                         && def_id == rpit_def_id
                     {
                         Some(substs)
@@ -542,15 +542,12 @@ pub(crate) fn opt_suggest_box_span(
                             ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) => {
                                 assert_eq!(trait_pred.trait_ref.self_ty(), opaque_ty);
                                 ty::PredicateKind::Clause(ty::Clause::Trait(
-                                    trait_pred.with_self_type(self.tcx, ty),
+                                    trait_pred.with_self_ty(self.tcx, ty),
                                 ))
                             }
                             ty::PredicateKind::Clause(ty::Clause::Projection(mut proj_pred)) => {
                                 assert_eq!(proj_pred.projection_ty.self_ty(), opaque_ty);
-                                proj_pred.projection_ty.substs = self.tcx.mk_substs_trait(
-                                    ty,
-                                    proj_pred.projection_ty.substs.iter().skip(1),
-                                );
+                                proj_pred = proj_pred.with_self_ty(self.tcx, ty);
                                 ty::PredicateKind::Clause(ty::Clause::Projection(proj_pred))
                             }
                             _ => continue,
index a96d27868a6d50d128ec8f1230c5a0825c7b91fa..72d8a936ab39db2adcc5b8f4970fcdc705b638ba 100644 (file)
@@ -167,7 +167,7 @@ fn deduce_expectations_from_expected_type(
         expected_ty: Ty<'tcx>,
     ) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) {
         match *expected_ty.kind() {
-            ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs }) => self
+            ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => self
                 .deduce_signature_from_predicates(
                     self.tcx.bound_explicit_item_bounds(def_id).subst_iter_copied(self.tcx, substs),
                 ),
@@ -678,7 +678,7 @@ fn deduce_future_output_from_obligations(
                     get_future_output(obligation.predicate, obligation.cause.span)
                 })?
             }
-            ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs }) => self
+            ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => self
                 .tcx
                 .bound_explicit_item_bounds(def_id)
                 .subst_iter_copied(self.tcx, substs)
index a4ca7571142b6b1ea2c165521d834c01c3fa8377..36cf4791492dd1c8c8b36d1125289dc008cb3fed 100644 (file)
@@ -1805,7 +1805,7 @@ fn add_impl_trait_explanation<'a>(
         {
             let ty = <dyn AstConv<'_>>::ast_ty_to_ty(fcx, ty);
             // Get the `impl Trait`'s `DefId`.
-            if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs: _ }) = ty.kind()
+            if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = ty.kind()
                 // Get the `impl Trait`'s `Item` so that we can get its trait bounds and
                 // get the `Trait`'s `DefId`.
                 && let hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds, .. }) =
index 4e2a78562240710741f64a61f99c76a75550fb4b..866090260b2723dad6ef078f500805ab69b7d46c 100644 (file)
@@ -2391,7 +2391,7 @@ fn ban_nonexisting_field(
             ty::Param(param_ty) => {
                 self.point_at_param_definition(&mut err, param_ty);
             }
-            ty::Alias(ty::Opaque, ty::AliasTy { def_id: _, substs: _ }) => {
+            ty::Alias(ty::Opaque, _) => {
                 self.suggest_await_on_field_access(&mut err, ident, base, base_ty.peel_refs());
             }
             _ => {}
index c8ea8ba5ab0655837ce7c16617890516e8c25e01..1a4e6bf763821b05ee33737dc392ef35d145eb8a 100644 (file)
@@ -716,7 +716,7 @@ pub(in super::super) fn expected_inputs_for_expected_output(
         if formal_ret.has_infer_types() {
             for ty in ret_ty.walk() {
                 if let ty::subst::GenericArgKind::Type(ty) = ty.unpack()
-                    && let ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs: _ }) = *ty.kind()
+                    && let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *ty.kind()
                     && let Some(def_id) = def_id.as_local()
                     && self.opaque_type_origin(def_id, DUMMY_SP).is_some() {
                     return None;
index 615f374b2ec0b8e3f2c34d63247424d4a4f9dd12..8e520e563ff630ecdeb62b0e4a1b046feb7dbe14 100644 (file)
@@ -2124,7 +2124,7 @@ fn label_fn_like(
                         }
                     }
                 }
-                ty::Alias(ty::Opaque, ty::AliasTy { def_id: new_def_id, substs: _ })
+                ty::Alias(ty::Opaque, ty::AliasTy { def_id: new_def_id, .. })
                 | ty::Closure(new_def_id, _)
                 | ty::FnDef(new_def_id, _) => {
                     def_id = new_def_id;
@@ -2132,19 +2132,15 @@ fn label_fn_like(
                 _ => {
                     // Look for a user-provided impl of a `Fn` trait, and point to it.
                     let new_def_id = self.probe(|_| {
-                        let trait_ref = ty::TraitRef::new(
+                        let trait_ref = self.tcx.mk_trait_ref(
                             call_kind.to_def_id(self.tcx),
-                            self.tcx.mk_substs(
-                                [
-                                    ty::GenericArg::from(callee_ty),
-                                    self.next_ty_var(TypeVariableOrigin {
-                                        kind: TypeVariableOriginKind::MiscVariable,
-                                        span: rustc_span::DUMMY_SP,
-                                    })
-                                    .into(),
-                                ]
-                                .into_iter(),
-                            ),
+                            [
+                                callee_ty,
+                                self.next_ty_var(TypeVariableOrigin {
+                                    kind: TypeVariableOriginKind::MiscVariable,
+                                    span: rustc_span::DUMMY_SP,
+                                }),
+                            ],
                         );
                         let obligation = traits::Obligation::new(
                             self.tcx,
index e6e1098e33d74057a0615355aaacc1f7a497c3a8..407d6ac8544c211a8cce00fa74b0cfb983bddbea 100644 (file)
@@ -13,7 +13,9 @@
 use rustc_infer::infer;
 use rustc_infer::traits::{self, StatementAsExpression};
 use rustc_middle::lint::in_external_macro;
-use rustc_middle::ty::{self, Binder, DefIdTree, IsSuggestable, ToPredicate, Ty};
+use rustc_middle::ty::{
+    self, suggest_constraining_type_params, Binder, DefIdTree, IsSuggestable, ToPredicate, Ty,
+};
 use rustc_session::errors::ExprParenthesesNeeded;
 use rustc_span::symbol::sym;
 use rustc_span::Span;
@@ -174,7 +176,7 @@ pub(in super::super) fn extract_callable_info(
                     let fn_sig = substs.as_closure().sig();
                     Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs().map_bound(|inputs| &inputs[1..])))
                 }
-                ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs }) => {
+                ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
                     self.tcx.bound_item_bounds(def_id).subst(self.tcx, substs).iter().find_map(|pred| {
                         if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = pred.kind().skip_binder()
                         && Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output()
@@ -1276,18 +1278,14 @@ pub(crate) fn note_type_is_not_clone(
             && !results.expr_adjustments(callee_expr).iter().any(|adj| matches!(adj.kind, ty::adjustment::Adjust::Deref(..)))
             // Check that we're in fact trying to clone into the expected type
             && self.can_coerce(*pointee_ty, expected_ty)
+            && let trait_ref = ty::Binder::dummy(self.tcx.mk_trait_ref(clone_trait_did, [expected_ty]))
             // And the expected type doesn't implement `Clone`
-            && !self.predicate_must_hold_considering_regions(&traits::Obligation {
-                cause: traits::ObligationCause::dummy(),
-                param_env: self.param_env,
-                recursion_depth: 0,
-                predicate: ty::Binder::dummy(ty::TraitRef {
-                    def_id: clone_trait_did,
-                    substs: self.tcx.mk_substs([expected_ty.into()].iter()),
-                })
-                .without_const()
-                .to_predicate(self.tcx),
-            })
+            && !self.predicate_must_hold_considering_regions(&traits::Obligation::new(
+                self.tcx,
+                traits::ObligationCause::dummy(),
+                self.param_env,
+                trait_ref,
+            ))
         {
             diag.span_note(
                 callee_expr.span,
@@ -1295,6 +1293,19 @@ pub(crate) fn note_type_is_not_clone(
                     "`{expected_ty}` does not implement `Clone`, so `{found_ty}` was cloned instead"
                 ),
             );
+            let owner = self.tcx.hir().enclosing_body_owner(expr.hir_id);
+            if let ty::Param(param) = expected_ty.kind()
+                && let Some(generics) = self.tcx.hir().get_generics(owner)
+            {
+                suggest_constraining_type_params(
+                    self.tcx,
+                    generics,
+                    diag,
+                    vec![(param.name.as_str(), "Clone", Some(clone_trait_did))].into_iter(),
+                );
+            } else {
+                self.suggest_derive(diag, &[(trait_ref.to_predicate(self.tcx), None, None)]);
+            }
         }
     }
 
index d83b9eb995d2b687e2502191122f00e4e91ffd8c..93f2ceed777b5be20bda25798be7d198ef998950 100644 (file)
@@ -563,7 +563,7 @@ fn check_must_not_suspend_ty<'tcx>(
         }
         ty::Adt(def, _) => check_must_not_suspend_def(fcx.tcx, def.did(), hir_id, data),
         // FIXME: support adding the attribute to TAITs
-        ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, substs: _ }) => {
+        ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => {
             let mut has_emitted = false;
             for &(predicate, _) in fcx.tcx.explicit_item_bounds(def) {
                 // We only look at the `DefId`, so it is safe to skip the binder here.
index a7eae392de1dd1fccefb6d46a0b3ecd1c27795ec..3f3af53d199b12918512a1597a9f7b1eb34532a5 100644 (file)
@@ -285,7 +285,7 @@ pub(super) fn obligation_for_method(
             self.var_for_def(span, param)
         });
 
-        let trait_ref = ty::TraitRef::new(trait_def_id, substs);
+        let trait_ref = self.tcx.mk_trait_ref(trait_def_id, substs);
 
         // Construct an obligation
         let poly_trait_ref = ty::Binder::dummy(trait_ref);
@@ -326,7 +326,7 @@ pub(super) fn obligation_for_op_method(
             self.var_for_def(span, param)
         });
 
-        let trait_ref = ty::TraitRef::new(trait_def_id, substs);
+        let trait_ref = self.tcx.mk_trait_ref(trait_def_id, substs);
 
         // Construct an obligation
         let poly_trait_ref = ty::Binder::dummy(trait_ref);
index 070359e71becc13381d15e12fb510b336a58c28e..b9e7830bf079214af2a29491fff1ab458fbee011 100644 (file)
@@ -920,7 +920,7 @@ fn assemble_extension_candidates_for_trait(
     ) {
         debug!("assemble_extension_candidates_for_trait(trait_def_id={:?})", trait_def_id);
         let trait_substs = self.fresh_item_substs(trait_def_id);
-        let trait_ref = ty::TraitRef::new(trait_def_id, trait_substs);
+        let trait_ref = self.tcx.mk_trait_ref(trait_def_id, trait_substs);
 
         if self.tcx.is_trait_alias(trait_def_id) {
             // For trait aliases, assume all supertraits are relevant.
index 41cd6bf314ebf557527bde7bf783f163ee9ef29a..63cec9216eb89fa70f262db6c73cb57b4eee1d6b 100644 (file)
@@ -25,7 +25,7 @@
 use rustc_middle::traits::util::supertraits;
 use rustc_middle::ty::fast_reject::DeepRejectCtxt;
 use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
-use rustc_middle::ty::print::with_crate_prefix;
+use rustc_middle::ty::print::{with_crate_prefix, with_forced_trimmed_paths};
 use rustc_middle::ty::{self, DefIdTree, GenericArgKind, Ty, TyCtxt, TypeVisitable};
 use rustc_middle::ty::{IsSuggestable, ToPolyTraitRef};
 use rustc_span::symbol::{kw, sym, Ident};
@@ -270,7 +270,7 @@ pub fn report_method_error(
                 let tcx = self.tcx;
 
                 let rcvr_ty = self.resolve_vars_if_possible(rcvr_ty);
-                let ty_str = self.ty_to_string(rcvr_ty);
+                let ty_str = with_forced_trimmed_paths!(self.ty_to_string(rcvr_ty));
                 let is_method = mode == Mode::MethodCall;
                 let item_kind = if is_method {
                     "method"
@@ -557,15 +557,16 @@ pub fn report_method_error(
                                         .chain(projection_ty.substs.iter().skip(1)),
                                 );
 
-                                let quiet_projection_ty = ty::AliasTy {
-                                    substs: substs_with_infer_self,
-                                    def_id: projection_ty.def_id,
-                                };
+                                let quiet_projection_ty =
+                                    tcx.mk_alias_ty(projection_ty.def_id, substs_with_infer_self);
 
                                 let term = pred.skip_binder().term;
 
                                 let obligation = format!("{} = {}", projection_ty, term);
-                                let quiet = format!("{} = {}", quiet_projection_ty, term);
+                                let quiet = with_forced_trimmed_paths!(format!(
+                                    "{} = {}",
+                                    quiet_projection_ty, term
+                                ));
 
                                 bound_span_label(projection_ty.self_ty(), &obligation, &quiet);
                                 Some((obligation, projection_ty.self_ty()))
@@ -575,7 +576,7 @@ pub fn report_method_error(
                                 let self_ty = p.self_ty();
                                 let path = p.print_only_trait_path();
                                 let obligation = format!("{}: {}", self_ty, path);
-                                let quiet = format!("_: {}", path);
+                                let quiet = with_forced_trimmed_paths!(format!("_: {}", path));
                                 bound_span_label(self_ty, &obligation, &quiet);
                                 Some((obligation, self_ty))
                             }
@@ -798,7 +799,8 @@ trait bound{s}",
                                 (None, None)
                             };
                         let primary_message = primary_message.unwrap_or_else(|| format!(
-                            "the {item_kind} `{item_name}` exists for {actual_prefix} `{ty_str}`, but its trait bounds were not satisfied"
+                            "the {item_kind} `{item_name}` exists for {actual_prefix} `{ty_str}`, \
+                             but its trait bounds were not satisfied"
                         ));
                         err.set_primary_message(&primary_message);
                         if let Some(label) = label {
@@ -895,7 +897,14 @@ trait bound{s}",
                             }
                         }
                     } else {
-                        err.span_label(span, format!("{item_kind} cannot be called on `{ty_str}` due to unsatisfied trait bounds"));
+                        let ty_str = if ty_str.len() > 50 {
+                            String::new()
+                        } else {
+                            format!("on `{ty_str}` ")
+                        };
+                        err.span_label(span, format!(
+                            "{item_kind} cannot be called {ty_str}due to unsatisfied trait bounds"
+                        ));
                     }
                 };
 
@@ -1843,7 +1852,7 @@ pub(crate) fn note_unmet_impls_on_type(
         self.suggest_derive(err, &preds);
     }
 
-    fn suggest_derive(
+    pub fn suggest_derive(
         &self,
         err: &mut Diagnostic,
         unsatisfied_predicates: &[(
index d25d9672c36d05ef7e638be2860812a0cfe671a3..bb956ddc780423876eca53ec2fc209aaed365aa8 100644 (file)
@@ -546,7 +546,7 @@ struct RecursionChecker {
             impl<'tcx> ty::TypeVisitor<'tcx> for RecursionChecker {
                 type BreakTy = ();
                 fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
-                    if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs: _ }) = *t.kind() {
+                    if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *t.kind() {
                         if def_id == self.def_id.to_def_id() {
                             return ControlFlow::Break(());
                         }
index 74c4c65cc1729a981db0c42c44e4c57d355cf6cd..c4f11472d55482e979acfdb41894115a7a6a4923 100644 (file)
@@ -517,6 +517,6 @@ pub struct MismatchedStaticLifetime<'a> {
     pub expl: Option<note_and_explain::RegionExplanation<'a>>,
     #[subdiagnostic]
     pub does_not_outlive_static_from_impl: DoesNotOutliveStaticFromImpl,
-    #[subdiagnostic(eager)]
+    #[subdiagnostic]
     pub implicit_static_lifetimes: Vec<ImplicitStaticLifetimeSubdiag>,
 }
index 316077f69d99b65ffc8fb15c4bd43c1853b60c34..9a1c49c1aa6af24feb4625f718fc2a29acbdc2aa 100644 (file)
@@ -675,7 +675,7 @@ fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
                 // relatable.
                 Ok(t)
             }
-            ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs }) => {
+            ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
                 let s = self.relate(substs, substs)?;
                 Ok(if s == substs { t } else { self.infcx.tcx.mk_opaque(def_id, s) })
             }
index 9fd4bdee096ac81dc36862ab93218da4d7019b07..46e7813d99e562cd1cff9b39b0224eaa75048fb1 100644 (file)
@@ -101,13 +101,13 @@ fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
             }
 
             (
-                &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, substs: _ }),
-                &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, substs: _ }),
+                &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }),
+                &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }),
             ) if a_def_id == b_def_id => {
                 self.fields.infcx.super_combine_tys(self, a, b)?;
             }
-            (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs: _ }), _)
-            | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs: _ }))
+            (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
+            | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
                 if self.fields.define_opaque_types && def_id.is_local() =>
             {
                 self.fields.obligations.extend(
index 3d2b2c6ff2dad9a56cc8ab22144158d0ffb03c93..397fa43175f732b3d87e566678388b0fbcd342d8 100644 (file)
@@ -339,7 +339,7 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>(
 impl<'tcx> InferCtxt<'tcx> {
     pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
         let (def_id, substs) = match *ty.kind() {
-            ty::Alias(_, ty::AliasTy { def_id, substs })
+            ty::Alias(_, ty::AliasTy { def_id, substs, .. })
                 if matches!(
                     self.tcx.def_kind(def_id),
                     DefKind::OpaqueTy | DefKind::ImplTraitPlaceholder
@@ -2767,9 +2767,7 @@ fn descr(&self) -> &'static str {
     pub fn from_ty(tcx: TyCtxt<'_>, ty: Ty<'_>) -> Option<(Self, DefId)> {
         match *ty.kind() {
             ty::Closure(def_id, _) => Some((Self::Closure, def_id)),
-            ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs: _ }) => {
-                Some((Self::Opaque, def_id))
-            }
+            ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => Some((Self::Opaque, def_id)),
             ty::Generator(def_id, ..) => {
                 Some((Self::Generator(tcx.generator_kind(def_id).unwrap()), def_id))
             }
index 1f554c81eff8e1941453d2f0a544ec245cd16d51..fed9fda74bfb33ec462dfadf8200f54432691762 100644 (file)
@@ -226,13 +226,11 @@ fn report_trait_placeholder_mismatch(
             false
         };
 
-        let expected_trait_ref = self.cx.resolve_vars_if_possible(ty::TraitRef {
-            def_id: trait_def_id,
-            substs: expected_substs,
-        });
-        let actual_trait_ref = self
+        let expected_trait_ref = self
             .cx
-            .resolve_vars_if_possible(ty::TraitRef { def_id: trait_def_id, substs: actual_substs });
+            .resolve_vars_if_possible(self.cx.tcx.mk_trait_ref(trait_def_id, expected_substs));
+        let actual_trait_ref =
+            self.cx.resolve_vars_if_possible(self.cx.tcx.mk_trait_ref(trait_def_id, actual_substs));
 
         // Search the expected and actual trait references to see (a)
         // whether the sub/sup placeholders appear in them (sometimes
index 62655d11ca309fd448cd44c8c7dfc4c85e4585fd..30ca9f41d6e6f8d73830b5c2b98150ee61e5dd05 100644 (file)
@@ -487,12 +487,12 @@ pub fn could_remove_semicolon(
                 StatementAsExpression::CorrectType
             }
             (
-                ty::Alias(ty::Opaque, ty::AliasTy { def_id: last_def_id, substs: _ }),
-                ty::Alias(ty::Opaque, ty::AliasTy { def_id: exp_def_id, substs: _ }),
+                ty::Alias(ty::Opaque, ty::AliasTy { def_id: last_def_id, .. }),
+                ty::Alias(ty::Opaque, ty::AliasTy { def_id: exp_def_id, .. }),
             ) if last_def_id == exp_def_id => StatementAsExpression::CorrectType,
             (
-                ty::Alias(ty::Opaque, ty::AliasTy { def_id: last_def_id, substs: last_bounds }),
-                ty::Alias(ty::Opaque, ty::AliasTy { def_id: exp_def_id, substs: exp_bounds }),
+                ty::Alias(ty::Opaque, ty::AliasTy { def_id: last_def_id, substs: last_bounds, .. }),
+                ty::Alias(ty::Opaque, ty::AliasTy { def_id: exp_def_id, substs: exp_bounds, .. }),
             ) => {
                 debug!(
                     "both opaque, likely future {:?} {:?} {:?} {:?}",
index 47d76dc5bdf02904cebcff63dd042038284cd0d4..0ebc6d55bcba952678c86e6ff3c1dba91d8a11bd 100644 (file)
@@ -106,11 +106,11 @@ pub fn super_lattice_tys<'a, 'tcx: 'a, L>(
         }
 
         (
-            &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, substs: _ }),
-            &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, substs: _ }),
+            &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }),
+            &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }),
         ) if a_def_id == b_def_id => infcx.super_combine_tys(this, a, b),
-        (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs: _ }), _)
-        | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs: _ }))
+        (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
+        | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
             if this.define_opaque_types() && def_id.is_local() =>
         {
             this.add_obligations(
index 3b9683e5b59333542f09347aaeaf123bd9b7295a..1f9d86a78d6e50912f7cc3dba6e0b006391a33aa 100644 (file)
@@ -611,8 +611,8 @@ fn tys(&mut self, a: Ty<'tcx>, mut b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>>
             (&ty::Infer(ty::TyVar(vid)), _) => self.relate_ty_var((vid, b)),
 
             (
-                &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, substs: _ }),
-                &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, substs: _ }),
+                &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }),
+                &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }),
             ) if a_def_id == b_def_id => infcx.super_combine_tys(self, a, b).or_else(|err| {
                 self.tcx().sess.delay_span_bug(
                     self.delegate.span(),
@@ -620,8 +620,8 @@ fn tys(&mut self, a: Ty<'tcx>, mut b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>>
                 );
                 if a_def_id.is_local() { self.relate_opaques(a, b) } else { Err(err) }
             }),
-            (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs: _ }), _)
-            | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs: _ }))
+            (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
+            | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
                 if def_id.is_local() =>
             {
                 self.relate_opaques(a, b)
index 67e4554c4c7074b7ba400ecb080eddc381b58e93..a130fde47ed5c4d7c0ccdae1536387b649f7cc1b 100644 (file)
@@ -66,7 +66,7 @@ pub fn replace_opaque_types_with_inference_vars<T: TypeFoldable<'tcx>>(
             lt_op: |lt| lt,
             ct_op: |ct| ct,
             ty_op: |ty| match *ty.kind() {
-                ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs: _ })
+                ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })
                     if replace_opaque_type(def_id) =>
                 {
                     let def_span = self.tcx.def_span(def_id);
@@ -106,7 +106,7 @@ pub fn handle_opaque_type(
         }
         let (a, b) = if a_is_expected { (a, b) } else { (b, a) };
         let process = |a: Ty<'tcx>, b: Ty<'tcx>, a_is_expected| match *a.kind() {
-            ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs }) if def_id.is_local() => {
+            ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) if def_id.is_local() => {
                 let def_id = def_id.expect_local();
                 let origin = match self.defining_use_anchor {
                     DefiningAnchor::Bind(_) => {
@@ -149,9 +149,7 @@ pub fn handle_opaque_type(
                     DefiningAnchor::Bubble => self.opaque_ty_origin_unchecked(def_id, cause.span),
                     DefiningAnchor::Error => return None,
                 };
-                if let ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, substs: _ }) =
-                    *b.kind()
-                {
+                if let ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }) = *b.kind() {
                     // We could accept this, but there are various ways to handle this situation, and we don't
                     // want to make a decision on it right now. Likely this case is so super rare anyway, that
                     // no one encounters it in practice.
@@ -480,7 +478,7 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                 substs.as_generator().resume_ty().visit_with(self);
             }
 
-            ty::Alias(ty::Opaque, ty::AliasTy { def_id, ref substs }) => {
+            ty::Alias(ty::Opaque, ty::AliasTy { def_id, ref substs, .. }) => {
                 // Skip lifetime paramters that are not captures.
                 let variances = self.tcx.variances_of(*def_id);
 
@@ -583,17 +581,16 @@ fn register_hidden_type(
                     }
                     // Replace all other mentions of the same opaque type with the hidden type,
                     // as the bounds must hold on the hidden type after all.
-                    ty::Alias(ty::Opaque, ty::AliasTy { def_id: def_id2, substs: substs2 })
+                    ty::Alias(ty::Opaque, ty::AliasTy { def_id: def_id2, substs: substs2, .. })
                         if def_id.to_def_id() == def_id2 && substs == substs2 =>
                     {
                         hidden_ty
                     }
                     // FIXME(RPITIT): This can go away when we move to associated types
-                    ty::Alias(ty::Projection, ty::AliasTy { def_id: def_id2, substs: substs2 })
-                        if def_id.to_def_id() == def_id2 && substs == substs2 =>
-                    {
-                        hidden_ty
-                    }
+                    ty::Alias(
+                        ty::Projection,
+                        ty::AliasTy { def_id: def_id2, substs: substs2, .. },
+                    ) if def_id.to_def_id() == def_id2 && substs == substs2 => hidden_ty,
                     _ => ty,
                 },
                 lt_op: |lt| lt,
index 984bbe169e6cf7ae110549236f2c6145de2dc3d4..aa2b5d067d266d8742c322ea147ffe5bc4905442 100644 (file)
@@ -130,7 +130,7 @@ fn compute_components<'tcx>(
             // outlives any other lifetime, which is unsound.
             // See https://github.com/rust-lang/rust/issues/84305 for
             // more details.
-            ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs }) => {
+            ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
                 out.push(Component::Opaque(def_id, substs));
             },
 
index da85de60199324b2d236e386699b3f235324b657..ccae7165d80d2fac9d859c26b64031742bcbd244 100644 (file)
@@ -338,7 +338,7 @@ fn opaque_must_outlive(
             substs,
             true,
             |ty| match *ty.kind() {
-                ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs }) => (def_id, substs),
+                ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => (def_id, substs),
                 _ => bug!("expected only projection types from env, not {:?}", ty),
             },
         );
index 58e27f8b21d6366337fe89ecb46c8b5eb255f467..bd38b52ba34a7eab0fbcbae019d94d58dd0d2c40 100644 (file)
@@ -131,14 +131,14 @@ fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
             }
 
             (
-                &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, substs: _ }),
-                &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, substs: _ }),
+                &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }),
+                &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }),
             ) if a_def_id == b_def_id => {
                 self.fields.infcx.super_combine_tys(self, a, b)?;
                 Ok(a)
             }
-            (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs: _ }), _)
-            | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs: _ }))
+            (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
+            | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
                 if self.fields.define_opaque_types && def_id.is_local() =>
             {
                 self.fields.obligations.extend(
index e6a0d7e60ca772b10cd67b0630dbdc50724a4907..40b2588388d66886353297cc50a5070b0bdd6069 100644 (file)
@@ -1258,7 +1258,7 @@ pub fn get_associated_type(
         tcx.associated_items(trait_id)
             .find_by_name_and_kind(tcx, Ident::from_str(name), ty::AssocKind::Type, trait_id)
             .and_then(|assoc| {
-                let proj = tcx.mk_projection(assoc.def_id, tcx.mk_substs_trait(self_ty, []));
+                let proj = tcx.mk_projection(assoc.def_id, [self_ty]);
                 tcx.try_normalize_erasing_regions(self.param_env, proj).ok()
             })
     }
index 3808d308186c0ee104b8f6a41d4fbd17f621bb17..42442cfb1904d4ddfdd621d53b156e62ec1186f2 100644 (file)
@@ -117,7 +117,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
                     // then we can emit a suggestion to add the bound.
                     let add_bound = match (proj_term.kind(), assoc_pred.kind().skip_binder()) {
                         (
-                            ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs: _ }),
+                            ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }),
                             ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)),
                         ) => Some(AddBound {
                             suggest_span: cx.tcx.def_span(*def_id).shrink_to_hi(),
index fb2c8b1ef647c85d3e9a4679b393703be441bd9f..d628a18dd01c5875c36e5ad8bebb8940b8f89cc6 100644 (file)
@@ -96,7 +96,7 @@ fn check_stmt(&mut self, cx: &LateContext<'_>, s: &hir::Stmt<'_>) {
 
         if let hir::ExprKind::Match(await_expr, _arms, hir::MatchSource::AwaitDesugar) = expr.kind
             && let ty = cx.typeck_results().expr_ty(&await_expr)
-            && let ty::Alias(ty::Opaque, ty::AliasTy { def_id: future_def_id, substs: _ }) = ty.kind()
+            && let ty::Alias(ty::Opaque, ty::AliasTy { def_id: future_def_id, .. }) = ty.kind()
             && cx.tcx.ty_is_opaque_future(ty)
             // FIXME: This also includes non-async fns that return `impl Future`.
             && let async_fn_def_id = cx.tcx.parent(*future_def_id)
@@ -251,7 +251,7 @@ fn is_ty_must_use<'tcx>(
                         .map(|inner| MustUsePath::Boxed(Box::new(inner)))
                 }
                 ty::Adt(def, _) => is_def_must_use(cx, def.did(), span),
-                ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, substs: _ }) => {
+                ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => {
                     elaborate_predicates_with_span(
                         cx.tcx,
                         cx.tcx.explicit_item_bounds(def).iter().cloned(),
index a3008e9e321c8b00736aa4a9636bae292dce5ba3..33cb35e60ebb6cfc1edf37d68a4262b57956e19b 100644 (file)
     };
 }
 
+declare_lint! {
+    /// The `invalid_alignment` lint detects dereferences of misaligned pointers during
+    /// constant evluation.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![feature(const_ptr_read)]
+    /// const FOO: () = unsafe {
+    ///     let x = &[0_u8; 4];
+    ///     let y = x.as_ptr().cast::<u32>();
+    ///     y.read(); // the address of a `u8` array is unknown and thus we don't know if
+    ///     // it is aligned enough for reading a `u32`.
+    /// };
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// The compiler allowed dereferencing raw pointers irrespective of alignment
+    /// during const eval due to the const evaluator at the time not making it easy
+    /// or cheap to check. Now that it is both, this is not accepted anymore.
+    ///
+    /// Since it was undefined behaviour to begin with, this breakage does not violate
+    /// Rust's stability guarantees. Using undefined behaviour can cause arbitrary
+    /// behaviour, including failure to build.
+    ///
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
+    pub INVALID_ALIGNMENT,
+    Deny,
+    "raw pointers must be aligned before dereferencing",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #68585 <https://github.com/rust-lang/rust/issues/104616>",
+        reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow,
+    };
+}
+
 declare_lint! {
     /// The `exported_private_dependencies` lint detects private dependencies
     /// that are exposed in a public interface.
index 684835d8c5c86b88e60713d8639ab1962a4eb0da..13f06fe747349d8084b9b53d1a303c75f9b0278b 100644 (file)
@@ -192,7 +192,7 @@ fn check(slug: &syn::Path) -> Option<Mismatch> {
         let crate_name = std::env::var("CARGO_CRATE_NAME").ok()?;
 
         // If we're not in a "rustc_" crate, bail.
-        let Some(("rustc", slug_prefix)) = crate_name.split_once("_") else { return None };
+        let Some(("rustc", slug_prefix)) = crate_name.split_once('_') else { return None };
 
         let slug_name = slug.segments.first()?.ident.to_string();
         if !slug_name.starts_with(slug_prefix) {
index 9f2ac5112f1cd9d3aa4b78a9cf1deeda1c0ae799..82f6812026a7d73a185a526b7390173f4602f996 100644 (file)
@@ -372,46 +372,21 @@ fn generate_inner_field_code(
                 }
             }
             (Meta::Path(_), "subdiagnostic") => {
-                return Ok(quote! { #diag.subdiagnostic(#binding); });
+                if FieldInnerTy::from_type(&info.binding.ast().ty).will_iterate() {
+                    let DiagnosticDeriveKind::Diagnostic { handler } = &self.parent.kind else {
+                        // No eager translation for lints.
+                        return Ok(quote! { #diag.subdiagnostic(#binding); });
+                    };
+                    return Ok(quote! { #diag.eager_subdiagnostic(#handler, #binding); });
+                } else {
+                    return Ok(quote! { #diag.subdiagnostic(#binding); });
+                }
             }
-            (Meta::NameValue(_), "subdiagnostic") => {
+            (Meta::List(_), "subdiagnostic") => {
                 throw_invalid_attr!(attr, &meta, |diag| {
-                    diag.help("`eager` is the only supported nested attribute for `subdiagnostic`")
+                    diag.help("`subdiagnostic` does not support nested attributes")
                 })
             }
-            (Meta::List(MetaList { ref nested, .. }), "subdiagnostic") => {
-                if nested.len() != 1 {
-                    throw_invalid_attr!(attr, &meta, |diag| {
-                        diag.help(
-                            "`eager` is the only supported nested attribute for `subdiagnostic`",
-                        )
-                    })
-                }
-
-                let handler = match &self.parent.kind {
-                    DiagnosticDeriveKind::Diagnostic { handler } => handler,
-                    DiagnosticDeriveKind::LintDiagnostic => {
-                        throw_invalid_attr!(attr, &meta, |diag| {
-                            diag.help("eager subdiagnostics are not supported on lints")
-                        })
-                    }
-                };
-
-                let nested_attr = nested.first().expect("pop failed for single element list");
-                match nested_attr {
-                    NestedMeta::Meta(meta @ Meta::Path(_))
-                        if meta.path().segments.last().unwrap().ident.to_string().as_str()
-                            == "eager" =>
-                    {
-                        return Ok(quote! { #diag.eager_subdiagnostic(#handler, #binding); });
-                    }
-                    _ => {
-                        throw_invalid_nested_attr!(attr, nested_attr, |diag| {
-                            diag.help("`eager` is the only supported nested attribute for `subdiagnostic`")
-                        })
-                    }
-                }
-            }
             _ => (),
         }
 
index db4fe6f886b2549044777dd6f0e7b399fc0c3bfc..bdaa586c69879ca53ddea0eb5d308436341f00d5 100644 (file)
@@ -533,6 +533,11 @@ pub fn should_skip(&self) -> bool {
         };
         injection_phase > self.phase
     }
+
+    #[inline]
+    pub fn is_custom_mir(&self) -> bool {
+        self.injection_phase.is_some()
+    }
 }
 
 #[derive(Copy, Clone, PartialEq, Eq, Debug, TyEncodable, TyDecodable, HashStable)]
@@ -1847,7 +1852,7 @@ impl<'tcx> Operand<'tcx> {
     pub fn function_handle(
         tcx: TyCtxt<'tcx>,
         def_id: DefId,
-        substs: SubstsRef<'tcx>,
+        substs: impl IntoIterator<Item = GenericArg<'tcx>>,
         span: Span,
     ) -> Self {
         let ty = tcx.mk_fn_def(def_id, substs);
index 15a24aa4ace512f1b453902ddca2e34d2033abab..1e8d5f7eae87a8881edadb729794f43e43fc9a9e 100644 (file)
@@ -200,6 +200,15 @@ pub fn krate(&self) -> CrateNum {
             MonoItem::GlobalAsm(..) => LOCAL_CRATE,
         }
     }
+
+    /// Returns the item's `DefId`
+    pub fn def_id(&self) -> DefId {
+        match *self {
+            MonoItem::Fn(Instance { def, .. }) => def.def_id(),
+            MonoItem::Static(def_id) => def_id,
+            MonoItem::GlobalAsm(item_id) => item_id.owner_id.to_def_id(),
+        }
+    }
 }
 
 impl<'tcx> fmt::Display for MonoItem<'tcx> {
index 7036c4a7b27d60b8da7772a1e575c33297736d4d..8ce06404de0811d64a177271ba6d4679278e007f 100644 (file)
@@ -131,7 +131,7 @@ pub fn method_call(&self, tcx: TyCtxt<'tcx>, source: Ty<'tcx>) -> Ty<'tcx> {
             .find(|m| m.kind == ty::AssocKind::Fn)
             .unwrap()
             .def_id;
-        tcx.mk_fn_def(method_def_id, tcx.mk_substs_trait(source, []))
+        tcx.mk_fn_def(method_def_id, [source])
     }
 }
 
index dc333b4702f39e1a2a658c88f8ddce14966db3b6..173c5ed4feef0f9de96add81d3ddf7094fdacc5d 100644 (file)
@@ -4,8 +4,7 @@
 
 use crate::arena::Arena;
 use crate::dep_graph::{DepGraph, DepKindStruct};
-use crate::hir::place::Place as HirPlace;
-use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos};
+use crate::infer::canonical::{CanonicalVarInfo, CanonicalVarInfos};
 use crate::lint::struct_lint_level;
 use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
 use crate::middle::resolve_lifetime;
 use crate::traits;
 use crate::ty::query::{self, TyCtxtAt};
 use crate::ty::{
-    self, AdtDef, AdtDefData, AdtKind, AliasTy, Binder, BindingMode, BoundVar, CanonicalPolyFnSig,
-    ClosureSizeProfileData, Const, ConstS, DefIdTree, FloatTy, FloatVar, FloatVid,
-    GenericParamDefKind, InferTy, IntTy, IntVar, IntVid, List, ParamConst, ParamTy,
-    PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, Region, RegionKind, ReprOptions,
-    TraitObjectVisitor, Ty, TyKind, TyVar, TyVid, TypeAndMut, UintTy, Visibility,
+    self, AdtDef, AdtDefData, AdtKind, Binder, Const, ConstS, DefIdTree, FloatTy, FloatVar,
+    FloatVid, GenericParamDefKind, ImplPolarity, InferTy, IntTy, IntVar, IntVid, List, ParamConst,
+    ParamTy, PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, Region, RegionKind,
+    ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVar, TyVid, TypeAndMut, TypeckResults, UintTy,
+    Visibility,
 };
-use crate::ty::{GenericArg, GenericArgKind, InternalSubsts, SubstsRef, UserSubsts};
+use crate::ty::{GenericArg, InternalSubsts, SubstsRef};
 use rustc_ast as ast;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::steal::Steal;
 use rustc_data_structures::sync::{self, Lock, Lrc, ReadGuard, WorkerLocal};
-use rustc_data_structures::unord::UnordSet;
-use rustc_data_structures::vec_map::VecMap;
 use rustc_errors::{
     DecorateLint, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, MultiSpan,
 };
 use rustc_hir as hir;
-use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalDefIdMap, LOCAL_CRATE};
+use rustc_hir::def::DefKind;
+use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
 use rustc_hir::definitions::Definitions;
-use rustc_hir::hir_id::OwnerId;
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{
-    Constness, ExprKind, HirId, ImplItemKind, ItemKind, ItemLocalId, ItemLocalMap, ItemLocalSet,
-    Node, TraitCandidate, TraitItemKind,
+    Constness, ExprKind, HirId, ImplItemKind, ItemKind, Node, TraitCandidate, TraitItemKind,
 };
-use rustc_index::vec::{Idx, IndexVec};
+use rustc_index::vec::IndexVec;
 use rustc_macros::HashStable;
-use rustc_middle::mir::FakeReadCause;
 use rustc_query_system::dep_graph::DepNodeIndex;
 use rustc_query_system::ich::StableHashingContext;
 use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
@@ -75,7 +69,6 @@
 use std::any::Any;
 use std::borrow::Borrow;
 use std::cmp::Ordering;
-use std::collections::hash_map::{self, Entry};
 use std::fmt;
 use std::hash::{Hash, Hasher};
 use std::iter;
@@ -83,8 +76,6 @@
 use std::ops::{Bound, Deref};
 use std::sync::Arc;
 
-use super::{ImplPolarity, RvalueScopes};
-
 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
@@ -284,666 +275,6 @@ pub struct CommonConsts<'tcx> {
     pub unit: Const<'tcx>,
 }
 
-pub struct LocalTableInContext<'a, V> {
-    hir_owner: OwnerId,
-    data: &'a ItemLocalMap<V>,
-}
-
-/// Validate that the given HirId (respectively its `local_id` part) can be
-/// safely used as a key in the maps of a TypeckResults. For that to be
-/// the case, the HirId must have the same `owner` as all the other IDs in
-/// this table (signified by `hir_owner`). Otherwise the HirId
-/// would be in a different frame of reference and using its `local_id`
-/// would result in lookup errors, or worse, in silently wrong data being
-/// stored/returned.
-#[inline]
-fn validate_hir_id_for_typeck_results(hir_owner: OwnerId, hir_id: hir::HirId) {
-    if hir_id.owner != hir_owner {
-        invalid_hir_id_for_typeck_results(hir_owner, hir_id);
-    }
-}
-
-#[cold]
-#[inline(never)]
-fn invalid_hir_id_for_typeck_results(hir_owner: OwnerId, hir_id: hir::HirId) {
-    ty::tls::with(|tcx| {
-        bug!(
-            "node {} with HirId::owner {:?} cannot be placed in TypeckResults with hir_owner {:?}",
-            tcx.hir().node_to_string(hir_id),
-            hir_id.owner,
-            hir_owner
-        )
-    });
-}
-
-impl<'a, V> LocalTableInContext<'a, V> {
-    pub fn contains_key(&self, id: hir::HirId) -> bool {
-        validate_hir_id_for_typeck_results(self.hir_owner, id);
-        self.data.contains_key(&id.local_id)
-    }
-
-    pub fn get(&self, id: hir::HirId) -> Option<&V> {
-        validate_hir_id_for_typeck_results(self.hir_owner, id);
-        self.data.get(&id.local_id)
-    }
-
-    pub fn iter(&self) -> hash_map::Iter<'_, hir::ItemLocalId, V> {
-        self.data.iter()
-    }
-}
-
-impl<'a, V> ::std::ops::Index<hir::HirId> for LocalTableInContext<'a, V> {
-    type Output = V;
-
-    fn index(&self, key: hir::HirId) -> &V {
-        self.get(key).expect("LocalTableInContext: key not found")
-    }
-}
-
-pub struct LocalTableInContextMut<'a, V> {
-    hir_owner: OwnerId,
-    data: &'a mut ItemLocalMap<V>,
-}
-
-impl<'a, V> LocalTableInContextMut<'a, V> {
-    pub fn get_mut(&mut self, id: hir::HirId) -> Option<&mut V> {
-        validate_hir_id_for_typeck_results(self.hir_owner, id);
-        self.data.get_mut(&id.local_id)
-    }
-
-    pub fn entry(&mut self, id: hir::HirId) -> Entry<'_, hir::ItemLocalId, V> {
-        validate_hir_id_for_typeck_results(self.hir_owner, id);
-        self.data.entry(id.local_id)
-    }
-
-    pub fn insert(&mut self, id: hir::HirId, val: V) -> Option<V> {
-        validate_hir_id_for_typeck_results(self.hir_owner, id);
-        self.data.insert(id.local_id, val)
-    }
-
-    pub fn remove(&mut self, id: hir::HirId) -> Option<V> {
-        validate_hir_id_for_typeck_results(self.hir_owner, id);
-        self.data.remove(&id.local_id)
-    }
-}
-
-/// Whenever a value may be live across a generator yield, the type of that value winds up in the
-/// `GeneratorInteriorTypeCause` struct. This struct adds additional information about such
-/// captured types that can be useful for diagnostics. In particular, it stores the span that
-/// caused a given type to be recorded, along with the scope that enclosed the value (which can
-/// be used to find the await that the value is live across).
-///
-/// For example:
-///
-/// ```ignore (pseudo-Rust)
-/// async move {
-///     let x: T = expr;
-///     foo.await
-///     ...
-/// }
-/// ```
-///
-/// Here, we would store the type `T`, the span of the value `x`, the "scope-span" for
-/// the scope that contains `x`, the expr `T` evaluated from, and the span of `foo.await`.
-#[derive(TyEncodable, TyDecodable, Clone, Debug, Eq, Hash, PartialEq, HashStable)]
-#[derive(TypeFoldable, TypeVisitable)]
-pub struct GeneratorInteriorTypeCause<'tcx> {
-    /// Type of the captured binding.
-    pub ty: Ty<'tcx>,
-    /// Span of the binding that was captured.
-    pub span: Span,
-    /// Span of the scope of the captured binding.
-    pub scope_span: Option<Span>,
-    /// Span of `.await` or `yield` expression.
-    pub yield_span: Span,
-    /// Expr which the type evaluated from.
-    pub expr: Option<hir::HirId>,
-}
-
-// This type holds diagnostic information on generators and async functions across crate boundaries
-// and is used to provide better error messages
-#[derive(TyEncodable, TyDecodable, Clone, Debug, HashStable)]
-pub struct GeneratorDiagnosticData<'tcx> {
-    pub generator_interior_types: ty::Binder<'tcx, Vec<GeneratorInteriorTypeCause<'tcx>>>,
-    pub hir_owner: DefId,
-    pub nodes_types: ItemLocalMap<Ty<'tcx>>,
-    pub adjustments: ItemLocalMap<Vec<ty::adjustment::Adjustment<'tcx>>>,
-}
-
-#[derive(TyEncodable, TyDecodable, Debug, HashStable)]
-pub struct TypeckResults<'tcx> {
-    /// The `HirId::owner` all `ItemLocalId`s in this table are relative to.
-    pub hir_owner: OwnerId,
-
-    /// Resolved definitions for `<T>::X` associated paths and
-    /// method calls, including those of overloaded operators.
-    type_dependent_defs: ItemLocalMap<Result<(DefKind, DefId), ErrorGuaranteed>>,
-
-    /// Resolved field indices for field accesses in expressions (`S { field }`, `obj.field`)
-    /// or patterns (`S { field }`). The index is often useful by itself, but to learn more
-    /// about the field you also need definition of the variant to which the field
-    /// belongs, but it may not exist if it's a tuple field (`tuple.0`).
-    field_indices: ItemLocalMap<usize>,
-
-    /// Stores the types for various nodes in the AST. Note that this table
-    /// is not guaranteed to be populated outside inference. See
-    /// typeck::check::fn_ctxt for details.
-    node_types: ItemLocalMap<Ty<'tcx>>,
-
-    /// Stores the type parameters which were substituted to obtain the type
-    /// of this node. This only applies to nodes that refer to entities
-    /// parameterized by type parameters, such as generic fns, types, or
-    /// other items.
-    node_substs: ItemLocalMap<SubstsRef<'tcx>>,
-
-    /// This will either store the canonicalized types provided by the user
-    /// or the substitutions that the user explicitly gave (if any) attached
-    /// to `id`. These will not include any inferred values. The canonical form
-    /// is used to capture things like `_` or other unspecified values.
-    ///
-    /// For example, if the user wrote `foo.collect::<Vec<_>>()`, then the
-    /// canonical substitutions would include only `for<X> { Vec<X> }`.
-    ///
-    /// See also `AscribeUserType` statement in MIR.
-    user_provided_types: ItemLocalMap<CanonicalUserType<'tcx>>,
-
-    /// Stores the canonicalized types provided by the user. See also
-    /// `AscribeUserType` statement in MIR.
-    pub user_provided_sigs: LocalDefIdMap<CanonicalPolyFnSig<'tcx>>,
-
-    adjustments: ItemLocalMap<Vec<ty::adjustment::Adjustment<'tcx>>>,
-
-    /// Stores the actual binding mode for all instances of hir::BindingAnnotation.
-    pat_binding_modes: ItemLocalMap<BindingMode>,
-
-    /// Stores the types which were implicitly dereferenced in pattern binding modes
-    /// for later usage in THIR lowering. For example,
-    ///
-    /// ```
-    /// match &&Some(5i32) {
-    ///     Some(n) => {},
-    ///     _ => {},
-    /// }
-    /// ```
-    /// leads to a `vec![&&Option<i32>, &Option<i32>]`. Empty vectors are not stored.
-    ///
-    /// See:
-    /// <https://github.com/rust-lang/rfcs/blob/master/text/2005-match-ergonomics.md#definitions>
-    pat_adjustments: ItemLocalMap<Vec<Ty<'tcx>>>,
-
-    /// Records the reasons that we picked the kind of each closure;
-    /// not all closures are present in the map.
-    closure_kind_origins: ItemLocalMap<(Span, HirPlace<'tcx>)>,
-
-    /// For each fn, records the "liberated" types of its arguments
-    /// and return type. Liberated means that all bound regions
-    /// (including late-bound regions) are replaced with free
-    /// equivalents. This table is not used in codegen (since regions
-    /// are erased there) and hence is not serialized to metadata.
-    ///
-    /// This table also contains the "revealed" values for any `impl Trait`
-    /// that appear in the signature and whose values are being inferred
-    /// by this function.
-    ///
-    /// # Example
-    ///
-    /// ```rust
-    /// # use std::fmt::Debug;
-    /// fn foo(x: &u32) -> impl Debug { *x }
-    /// ```
-    ///
-    /// The function signature here would be:
-    ///
-    /// ```ignore (illustrative)
-    /// for<'a> fn(&'a u32) -> Foo
-    /// ```
-    ///
-    /// where `Foo` is an opaque type created for this function.
-    ///
-    ///
-    /// The *liberated* form of this would be
-    ///
-    /// ```ignore (illustrative)
-    /// fn(&'a u32) -> u32
-    /// ```
-    ///
-    /// Note that `'a` is not bound (it would be an `ReFree`) and
-    /// that the `Foo` opaque type is replaced by its hidden type.
-    liberated_fn_sigs: ItemLocalMap<ty::FnSig<'tcx>>,
-
-    /// For each FRU expression, record the normalized types of the fields
-    /// of the struct - this is needed because it is non-trivial to
-    /// normalize while preserving regions. This table is used only in
-    /// MIR construction and hence is not serialized to metadata.
-    fru_field_types: ItemLocalMap<Vec<Ty<'tcx>>>,
-
-    /// For every coercion cast we add the HIR node ID of the cast
-    /// expression to this set.
-    coercion_casts: ItemLocalSet,
-
-    /// Set of trait imports actually used in the method resolution.
-    /// This is used for warning unused imports. During type
-    /// checking, this `Lrc` should not be cloned: it must have a ref-count
-    /// of 1 so that we can insert things into the set mutably.
-    pub used_trait_imports: Lrc<UnordSet<LocalDefId>>,
-
-    /// If any errors occurred while type-checking this body,
-    /// this field will be set to `Some(ErrorGuaranteed)`.
-    pub tainted_by_errors: Option<ErrorGuaranteed>,
-
-    /// All the opaque types that have hidden types set
-    /// by this function. We also store the
-    /// type here, so that mir-borrowck can use it as a hint for figuring out hidden types,
-    /// even if they are only set in dead code (which doesn't show up in MIR).
-    pub concrete_opaque_types: VecMap<LocalDefId, ty::OpaqueHiddenType<'tcx>>,
-
-    /// Tracks the minimum captures required for a closure;
-    /// see `MinCaptureInformationMap` for more details.
-    pub closure_min_captures: ty::MinCaptureInformationMap<'tcx>,
-
-    /// Tracks the fake reads required for a closure and the reason for the fake read.
-    /// When performing pattern matching for closures, there are times we don't end up
-    /// reading places that are mentioned in a closure (because of _ patterns). However,
-    /// to ensure the places are initialized, we introduce fake reads.
-    /// Consider these two examples:
-    /// ``` (discriminant matching with only wildcard arm)
-    /// let x: u8;
-    /// let c = || match x { _ => () };
-    /// ```
-    /// In this example, we don't need to actually read/borrow `x` in `c`, and so we don't
-    /// want to capture it. However, we do still want an error here, because `x` should have
-    /// to be initialized at the point where c is created. Therefore, we add a "fake read"
-    /// instead.
-    /// ``` (destructured assignments)
-    /// let c = || {
-    ///     let (t1, t2) = t;
-    /// }
-    /// ```
-    /// In the second example, we capture the disjoint fields of `t` (`t.0` & `t.1`), but
-    /// we never capture `t`. This becomes an issue when we build MIR as we require
-    /// information on `t` in order to create place `t.0` and `t.1`. We can solve this
-    /// issue by fake reading `t`.
-    pub closure_fake_reads: FxHashMap<LocalDefId, Vec<(HirPlace<'tcx>, FakeReadCause, hir::HirId)>>,
-
-    /// Tracks the rvalue scoping rules which defines finer scoping for rvalue expressions
-    /// by applying extended parameter rules.
-    /// Details may be find in `rustc_hir_analysis::check::rvalue_scopes`.
-    pub rvalue_scopes: RvalueScopes,
-
-    /// Stores the type, expression, span and optional scope span of all types
-    /// that are live across the yield of this generator (if a generator).
-    pub generator_interior_types: ty::Binder<'tcx, Vec<GeneratorInteriorTypeCause<'tcx>>>,
-
-    /// We sometimes treat byte string literals (which are of type `&[u8; N]`)
-    /// as `&[u8]`, depending on the pattern  in which they are used.
-    /// This hashset records all instances where we behave
-    /// like this to allow `const_to_pat` to reliably handle this situation.
-    pub treat_byte_string_as_slice: ItemLocalSet,
-
-    /// Contains the data for evaluating the effect of feature `capture_disjoint_fields`
-    /// on closure size.
-    pub closure_size_eval: FxHashMap<LocalDefId, ClosureSizeProfileData<'tcx>>,
-}
-
-impl<'tcx> TypeckResults<'tcx> {
-    pub fn new(hir_owner: OwnerId) -> TypeckResults<'tcx> {
-        TypeckResults {
-            hir_owner,
-            type_dependent_defs: Default::default(),
-            field_indices: Default::default(),
-            user_provided_types: Default::default(),
-            user_provided_sigs: Default::default(),
-            node_types: Default::default(),
-            node_substs: Default::default(),
-            adjustments: Default::default(),
-            pat_binding_modes: Default::default(),
-            pat_adjustments: Default::default(),
-            closure_kind_origins: Default::default(),
-            liberated_fn_sigs: Default::default(),
-            fru_field_types: Default::default(),
-            coercion_casts: Default::default(),
-            used_trait_imports: Lrc::new(Default::default()),
-            tainted_by_errors: None,
-            concrete_opaque_types: Default::default(),
-            closure_min_captures: Default::default(),
-            closure_fake_reads: Default::default(),
-            rvalue_scopes: Default::default(),
-            generator_interior_types: ty::Binder::dummy(Default::default()),
-            treat_byte_string_as_slice: Default::default(),
-            closure_size_eval: Default::default(),
-        }
-    }
-
-    /// Returns the final resolution of a `QPath` in an `Expr` or `Pat` node.
-    pub fn qpath_res(&self, qpath: &hir::QPath<'_>, id: hir::HirId) -> Res {
-        match *qpath {
-            hir::QPath::Resolved(_, ref path) => path.res,
-            hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => self
-                .type_dependent_def(id)
-                .map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)),
-        }
-    }
-
-    pub fn type_dependent_defs(
-        &self,
-    ) -> LocalTableInContext<'_, Result<(DefKind, DefId), ErrorGuaranteed>> {
-        LocalTableInContext { hir_owner: self.hir_owner, data: &self.type_dependent_defs }
-    }
-
-    pub fn type_dependent_def(&self, id: HirId) -> Option<(DefKind, DefId)> {
-        validate_hir_id_for_typeck_results(self.hir_owner, id);
-        self.type_dependent_defs.get(&id.local_id).cloned().and_then(|r| r.ok())
-    }
-
-    pub fn type_dependent_def_id(&self, id: HirId) -> Option<DefId> {
-        self.type_dependent_def(id).map(|(_, def_id)| def_id)
-    }
-
-    pub fn type_dependent_defs_mut(
-        &mut self,
-    ) -> LocalTableInContextMut<'_, Result<(DefKind, DefId), ErrorGuaranteed>> {
-        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.type_dependent_defs }
-    }
-
-    pub fn field_indices(&self) -> LocalTableInContext<'_, usize> {
-        LocalTableInContext { hir_owner: self.hir_owner, data: &self.field_indices }
-    }
-
-    pub fn field_indices_mut(&mut self) -> LocalTableInContextMut<'_, usize> {
-        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.field_indices }
-    }
-
-    pub fn field_index(&self, id: hir::HirId) -> usize {
-        self.field_indices().get(id).cloned().expect("no index for a field")
-    }
-
-    pub fn opt_field_index(&self, id: hir::HirId) -> Option<usize> {
-        self.field_indices().get(id).cloned()
-    }
-
-    pub fn user_provided_types(&self) -> LocalTableInContext<'_, CanonicalUserType<'tcx>> {
-        LocalTableInContext { hir_owner: self.hir_owner, data: &self.user_provided_types }
-    }
-
-    pub fn user_provided_types_mut(
-        &mut self,
-    ) -> LocalTableInContextMut<'_, CanonicalUserType<'tcx>> {
-        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.user_provided_types }
-    }
-
-    pub fn node_types(&self) -> LocalTableInContext<'_, Ty<'tcx>> {
-        LocalTableInContext { hir_owner: self.hir_owner, data: &self.node_types }
-    }
-
-    pub fn node_types_mut(&mut self) -> LocalTableInContextMut<'_, Ty<'tcx>> {
-        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.node_types }
-    }
-
-    pub fn get_generator_diagnostic_data(&self) -> GeneratorDiagnosticData<'tcx> {
-        let generator_interior_type = self.generator_interior_types.map_bound_ref(|vec| {
-            vec.iter()
-                .map(|item| {
-                    GeneratorInteriorTypeCause {
-                        ty: item.ty,
-                        span: item.span,
-                        scope_span: item.scope_span,
-                        yield_span: item.yield_span,
-                        expr: None, //FIXME: Passing expression over crate boundaries is impossible at the moment
-                    }
-                })
-                .collect::<Vec<_>>()
-        });
-        GeneratorDiagnosticData {
-            generator_interior_types: generator_interior_type,
-            hir_owner: self.hir_owner.to_def_id(),
-            nodes_types: self.node_types.clone(),
-            adjustments: self.adjustments.clone(),
-        }
-    }
-
-    pub fn node_type(&self, id: hir::HirId) -> Ty<'tcx> {
-        self.node_type_opt(id).unwrap_or_else(|| {
-            bug!("node_type: no type for node `{}`", tls::with(|tcx| tcx.hir().node_to_string(id)))
-        })
-    }
-
-    pub fn node_type_opt(&self, id: hir::HirId) -> Option<Ty<'tcx>> {
-        validate_hir_id_for_typeck_results(self.hir_owner, id);
-        self.node_types.get(&id.local_id).cloned()
-    }
-
-    pub fn node_substs_mut(&mut self) -> LocalTableInContextMut<'_, SubstsRef<'tcx>> {
-        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.node_substs }
-    }
-
-    pub fn node_substs(&self, id: hir::HirId) -> SubstsRef<'tcx> {
-        validate_hir_id_for_typeck_results(self.hir_owner, id);
-        self.node_substs.get(&id.local_id).cloned().unwrap_or_else(|| InternalSubsts::empty())
-    }
-
-    pub fn node_substs_opt(&self, id: hir::HirId) -> Option<SubstsRef<'tcx>> {
-        validate_hir_id_for_typeck_results(self.hir_owner, id);
-        self.node_substs.get(&id.local_id).cloned()
-    }
-
-    /// Returns the type of a pattern as a monotype. Like [`expr_ty`], this function
-    /// doesn't provide type parameter substitutions.
-    ///
-    /// [`expr_ty`]: TypeckResults::expr_ty
-    pub fn pat_ty(&self, pat: &hir::Pat<'_>) -> Ty<'tcx> {
-        self.node_type(pat.hir_id)
-    }
-
-    /// Returns the type of an expression as a monotype.
-    ///
-    /// NB (1): This is the PRE-ADJUSTMENT TYPE for the expression.  That is, in
-    /// some cases, we insert `Adjustment` annotations such as auto-deref or
-    /// auto-ref.  The type returned by this function does not consider such
-    /// adjustments.  See `expr_ty_adjusted()` instead.
-    ///
-    /// NB (2): This type doesn't provide type parameter substitutions; e.g., if you
-    /// ask for the type of `id` in `id(3)`, it will return `fn(&isize) -> isize`
-    /// instead of `fn(ty) -> T with T = isize`.
-    pub fn expr_ty(&self, expr: &hir::Expr<'_>) -> Ty<'tcx> {
-        self.node_type(expr.hir_id)
-    }
-
-    pub fn expr_ty_opt(&self, expr: &hir::Expr<'_>) -> Option<Ty<'tcx>> {
-        self.node_type_opt(expr.hir_id)
-    }
-
-    pub fn adjustments(&self) -> LocalTableInContext<'_, Vec<ty::adjustment::Adjustment<'tcx>>> {
-        LocalTableInContext { hir_owner: self.hir_owner, data: &self.adjustments }
-    }
-
-    pub fn adjustments_mut(
-        &mut self,
-    ) -> LocalTableInContextMut<'_, Vec<ty::adjustment::Adjustment<'tcx>>> {
-        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.adjustments }
-    }
-
-    pub fn expr_adjustments(&self, expr: &hir::Expr<'_>) -> &[ty::adjustment::Adjustment<'tcx>] {
-        validate_hir_id_for_typeck_results(self.hir_owner, expr.hir_id);
-        self.adjustments.get(&expr.hir_id.local_id).map_or(&[], |a| &a[..])
-    }
-
-    /// Returns the type of `expr`, considering any `Adjustment`
-    /// entry recorded for that expression.
-    pub fn expr_ty_adjusted(&self, expr: &hir::Expr<'_>) -> Ty<'tcx> {
-        self.expr_adjustments(expr).last().map_or_else(|| self.expr_ty(expr), |adj| adj.target)
-    }
-
-    pub fn expr_ty_adjusted_opt(&self, expr: &hir::Expr<'_>) -> Option<Ty<'tcx>> {
-        self.expr_adjustments(expr).last().map(|adj| adj.target).or_else(|| self.expr_ty_opt(expr))
-    }
-
-    pub fn is_method_call(&self, expr: &hir::Expr<'_>) -> bool {
-        // Only paths and method calls/overloaded operators have
-        // entries in type_dependent_defs, ignore the former here.
-        if let hir::ExprKind::Path(_) = expr.kind {
-            return false;
-        }
-
-        matches!(self.type_dependent_defs().get(expr.hir_id), Some(Ok((DefKind::AssocFn, _))))
-    }
-
-    pub fn extract_binding_mode(&self, s: &Session, id: HirId, sp: Span) -> Option<BindingMode> {
-        self.pat_binding_modes().get(id).copied().or_else(|| {
-            s.delay_span_bug(sp, "missing binding mode");
-            None
-        })
-    }
-
-    pub fn pat_binding_modes(&self) -> LocalTableInContext<'_, BindingMode> {
-        LocalTableInContext { hir_owner: self.hir_owner, data: &self.pat_binding_modes }
-    }
-
-    pub fn pat_binding_modes_mut(&mut self) -> LocalTableInContextMut<'_, BindingMode> {
-        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_binding_modes }
-    }
-
-    pub fn pat_adjustments(&self) -> LocalTableInContext<'_, Vec<Ty<'tcx>>> {
-        LocalTableInContext { hir_owner: self.hir_owner, data: &self.pat_adjustments }
-    }
-
-    pub fn pat_adjustments_mut(&mut self) -> LocalTableInContextMut<'_, Vec<Ty<'tcx>>> {
-        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_adjustments }
-    }
-
-    /// For a given closure, returns the iterator of `ty::CapturedPlace`s that are captured
-    /// by the closure.
-    pub fn closure_min_captures_flattened(
-        &self,
-        closure_def_id: LocalDefId,
-    ) -> impl Iterator<Item = &ty::CapturedPlace<'tcx>> {
-        self.closure_min_captures
-            .get(&closure_def_id)
-            .map(|closure_min_captures| closure_min_captures.values().flat_map(|v| v.iter()))
-            .into_iter()
-            .flatten()
-    }
-
-    pub fn closure_kind_origins(&self) -> LocalTableInContext<'_, (Span, HirPlace<'tcx>)> {
-        LocalTableInContext { hir_owner: self.hir_owner, data: &self.closure_kind_origins }
-    }
-
-    pub fn closure_kind_origins_mut(
-        &mut self,
-    ) -> LocalTableInContextMut<'_, (Span, HirPlace<'tcx>)> {
-        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.closure_kind_origins }
-    }
-
-    pub fn liberated_fn_sigs(&self) -> LocalTableInContext<'_, ty::FnSig<'tcx>> {
-        LocalTableInContext { hir_owner: self.hir_owner, data: &self.liberated_fn_sigs }
-    }
-
-    pub fn liberated_fn_sigs_mut(&mut self) -> LocalTableInContextMut<'_, ty::FnSig<'tcx>> {
-        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.liberated_fn_sigs }
-    }
-
-    pub fn fru_field_types(&self) -> LocalTableInContext<'_, Vec<Ty<'tcx>>> {
-        LocalTableInContext { hir_owner: self.hir_owner, data: &self.fru_field_types }
-    }
-
-    pub fn fru_field_types_mut(&mut self) -> LocalTableInContextMut<'_, Vec<Ty<'tcx>>> {
-        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.fru_field_types }
-    }
-
-    pub fn is_coercion_cast(&self, hir_id: hir::HirId) -> bool {
-        validate_hir_id_for_typeck_results(self.hir_owner, hir_id);
-        self.coercion_casts.contains(&hir_id.local_id)
-    }
-
-    pub fn set_coercion_cast(&mut self, id: ItemLocalId) {
-        self.coercion_casts.insert(id);
-    }
-
-    pub fn coercion_casts(&self) -> &ItemLocalSet {
-        &self.coercion_casts
-    }
-}
-
-rustc_index::newtype_index! {
-    pub struct UserTypeAnnotationIndex {
-        derive [HashStable]
-        DEBUG_FORMAT = "UserType({})",
-        const START_INDEX = 0,
-    }
-}
-
-/// Mapping of type annotation indices to canonical user type annotations.
-pub type CanonicalUserTypeAnnotations<'tcx> =
-    IndexVec<UserTypeAnnotationIndex, CanonicalUserTypeAnnotation<'tcx>>;
-
-#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable, Lift)]
-pub struct CanonicalUserTypeAnnotation<'tcx> {
-    pub user_ty: Box<CanonicalUserType<'tcx>>,
-    pub span: Span,
-    pub inferred_ty: Ty<'tcx>,
-}
-
-/// Canonicalized user type annotation.
-pub type CanonicalUserType<'tcx> = Canonical<'tcx, UserType<'tcx>>;
-
-impl<'tcx> CanonicalUserType<'tcx> {
-    /// Returns `true` if this represents a substitution of the form `[?0, ?1, ?2]`,
-    /// i.e., each thing is mapped to a canonical variable with the same index.
-    pub fn is_identity(&self) -> bool {
-        match self.value {
-            UserType::Ty(_) => false,
-            UserType::TypeOf(_, user_substs) => {
-                if user_substs.user_self_ty.is_some() {
-                    return false;
-                }
-
-                iter::zip(user_substs.substs, BoundVar::new(0)..).all(|(kind, cvar)| {
-                    match kind.unpack() {
-                        GenericArgKind::Type(ty) => match ty.kind() {
-                            ty::Bound(debruijn, b) => {
-                                // We only allow a `ty::INNERMOST` index in substitutions.
-                                assert_eq!(*debruijn, ty::INNERMOST);
-                                cvar == b.var
-                            }
-                            _ => false,
-                        },
-
-                        GenericArgKind::Lifetime(r) => match *r {
-                            ty::ReLateBound(debruijn, br) => {
-                                // We only allow a `ty::INNERMOST` index in substitutions.
-                                assert_eq!(debruijn, ty::INNERMOST);
-                                cvar == br.var
-                            }
-                            _ => false,
-                        },
-
-                        GenericArgKind::Const(ct) => match ct.kind() {
-                            ty::ConstKind::Bound(debruijn, b) => {
-                                // We only allow a `ty::INNERMOST` index in substitutions.
-                                assert_eq!(debruijn, ty::INNERMOST);
-                                cvar == b
-                            }
-                            _ => false,
-                        },
-                    }
-                })
-            }
-        }
-    }
-}
-
-/// A user-given type annotation attached to a constant. These arise
-/// from constants that are named via paths, like `Foo::<A>::new` and
-/// so forth.
-#[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
-pub enum UserType<'tcx> {
-    Ty(Ty<'tcx>),
-
-    /// The canonical type is the result of `type_of(def_id)` with the
-    /// given substitutions applied.
-    TypeOf(DefId, UserSubsts<'tcx>),
-}
-
 impl<'tcx> CommonTypes<'tcx> {
     fn new(
         interners: &CtxtInterners<'tcx>,
@@ -2321,7 +1652,7 @@ pub fn trait_may_define_assoc_type(self, trait_def_id: DefId, assoc_name: Ident)
 
     /// Given a `ty`, return whether it's an `impl Future<...>`.
     pub fn ty_is_opaque_future(self, ty: Ty<'_>) -> bool {
-        let ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs: _ }) = ty.kind() else { return false };
+        let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = ty.kind() else { return false };
         let future_trait = self.require_lang_item(LangItem::Future, None);
 
         self.explicit_item_bounds(def_id).iter().any(|(predicate, _)| {
@@ -2565,15 +1896,35 @@ pub fn mk_diverging_default(self) -> Ty<'tcx> {
     }
 
     #[inline]
-    pub fn mk_fn_def(self, def_id: DefId, substs: SubstsRef<'tcx>) -> Ty<'tcx> {
-        debug_assert_eq!(
-            self.generics_of(def_id).count(),
-            substs.len(),
-            "wrong number of generic parameters for {def_id:?}: {substs:?}",
-        );
+    pub fn mk_fn_def(
+        self,
+        def_id: DefId,
+        substs: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
+    ) -> Ty<'tcx> {
+        let substs = self.check_substs(def_id, substs);
         self.mk_ty(FnDef(def_id, substs))
     }
 
+    #[inline(always)]
+    fn check_substs(
+        self,
+        _def_id: DefId,
+        substs: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
+    ) -> SubstsRef<'tcx> {
+        let substs = substs.into_iter().map(Into::into);
+        #[cfg(debug_assertions)]
+        {
+            let n = self.generics_of(_def_id).count();
+            assert_eq!(
+                (n, Some(n)),
+                substs.size_hint(),
+                "wrong number of generic parameters for {_def_id:?}: {:?}",
+                substs.collect::<Vec<_>>(),
+            );
+        }
+        self.mk_substs(substs)
+    }
+
     #[inline]
     pub fn mk_fn_ptr(self, fty: PolyFnSig<'tcx>) -> Ty<'tcx> {
         self.mk_ty(FnPtr(fty))
@@ -2590,13 +1941,12 @@ pub fn mk_dynamic(
     }
 
     #[inline]
-    pub fn mk_projection(self, item_def_id: DefId, substs: SubstsRef<'tcx>) -> Ty<'tcx> {
-        debug_assert_eq!(
-            self.generics_of(item_def_id).count(),
-            substs.len(),
-            "wrong number of generic parameters for {item_def_id:?}: {substs:?}",
-        );
-        self.mk_ty(Alias(ty::Projection, AliasTy { def_id: item_def_id, substs }))
+    pub fn mk_projection(
+        self,
+        item_def_id: DefId,
+        substs: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
+    ) -> Ty<'tcx> {
+        self.mk_ty(Alias(ty::Projection, self.mk_alias_ty(item_def_id, substs)))
     }
 
     #[inline]
@@ -2666,7 +2016,7 @@ pub fn mk_param_from_def(self, param: &ty::GenericParamDef) -> GenericArg<'tcx>
 
     #[inline]
     pub fn mk_opaque(self, def_id: DefId, substs: SubstsRef<'tcx>) -> Ty<'tcx> {
-        self.mk_ty(Alias(ty::Opaque, ty::AliasTy { def_id, substs }))
+        self.mk_ty(Alias(ty::Opaque, self.mk_alias_ty(def_id, substs)))
     }
 
     pub fn mk_place_field(self, place: Place<'tcx>, f: Field, ty: Ty<'tcx>) -> Place<'tcx> {
@@ -2855,16 +2205,17 @@ pub fn mk_trait_ref(
         trait_def_id: DefId,
         substs: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
     ) -> ty::TraitRef<'tcx> {
-        let substs = substs.into_iter().map(Into::into);
-        let n = self.generics_of(trait_def_id).count();
-        debug_assert_eq!(
-            (n, Some(n)),
-            substs.size_hint(),
-            "wrong number of generic parameters for {trait_def_id:?}: {:?} \nDid you accidentally include the self-type in the params list?",
-            substs.collect::<Vec<_>>(),
-        );
-        let substs = self.mk_substs(substs);
-        ty::TraitRef::new(trait_def_id, substs)
+        let substs = self.check_substs(trait_def_id, substs);
+        ty::TraitRef { def_id: trait_def_id, substs, _use_mk_trait_ref_instead: () }
+    }
+
+    pub fn mk_alias_ty(
+        self,
+        def_id: DefId,
+        substs: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
+    ) -> ty::AliasTy<'tcx> {
+        let substs = self.check_substs(def_id, substs);
+        ty::AliasTy { def_id, substs, _use_mk_alias_ty_instead: () }
     }
 
     pub fn mk_bound_variable_kinds<
index d7880a32ea9cd8f141b70ecadad0c5fca95836bd..8c22df7395f1052669ad14f2e36cc7e187bf4b23 100644 (file)
@@ -3,8 +3,8 @@
 use std::ops::ControlFlow;
 
 use crate::ty::{
-    visit::TypeVisitable, AliasTy, Const, ConstKind, DefIdTree, ExistentialPredicate, InferConst,
-    InferTy, Opaque, PolyTraitPredicate, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor,
+    visit::TypeVisitable, AliasTy, Const, ConstKind, DefIdTree, InferConst, InferTy, Opaque,
+    PolyTraitPredicate, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor,
 };
 
 use rustc_data_structures::fx::FxHashMap;
@@ -457,10 +457,10 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                 return ControlFlow::Break(());
             }
 
-            Alias(Opaque, AliasTy { def_id, substs: _ }) => {
+            Alias(Opaque, AliasTy { def_id, .. }) => {
                 let parent = self.tcx.parent(*def_id);
                 if let hir::def::DefKind::TyAlias | hir::def::DefKind::AssocTy = self.tcx.def_kind(parent)
-                    && let Alias(Opaque, AliasTy { def_id: parent_opaque_def_id, substs: _ }) = self.tcx.type_of(parent).kind()
+                    && let Alias(Opaque, AliasTy { def_id: parent_opaque_def_id, .. }) = self.tcx.type_of(parent).kind()
                     && parent_opaque_def_id == def_id
                 {
                     // Okay
@@ -469,17 +469,6 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                 }
             }
 
-            Dynamic(dty, _, _) => {
-                for pred in *dty {
-                    match pred.skip_binder() {
-                        ExistentialPredicate::Trait(_) | ExistentialPredicate::Projection(_) => {
-                            // Okay
-                        }
-                        _ => return ControlFlow::Break(()),
-                    }
-                }
-            }
-
             Param(param) => {
                 // FIXME: It would be nice to make this not use string manipulation,
                 // but it's pretty hard to do this, since `ty::ParamTy` is missing
index 22dc921aba1ca13fd53a7604c6eafeb9b6eb6f08..14d07608a780e6c5b33b6dbae204401251b39088 100644 (file)
@@ -779,8 +779,7 @@ fn suggest_constraining_opaque_associated_type(
         ty: Ty<'tcx>,
     ) -> bool {
         let assoc = self.associated_item(proj_ty.def_id);
-        if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs: _ }) = *proj_ty.self_ty().kind()
-        {
+        if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *proj_ty.self_ty().kind() {
             let opaque_local_def_id = def_id.as_local();
             let opaque_hir_ty = if let Some(opaque_local_def_id) = opaque_local_def_id {
                 match &self.hir().expect_item(opaque_local_def_id).kind {
index 44650827810abf11095901cb7907f433098996b6..f785fb5c4b9be5b5c57f78104e7895b029bcbabf 100644 (file)
@@ -6,28 +6,18 @@
 use std::hash::Hash;
 use std::iter;
 
-use self::SimplifiedTypeGen::*;
+use self::SimplifiedType::*;
 
-pub type SimplifiedType = SimplifiedTypeGen<DefId>;
-
-/// See `simplify_type`
-///
-/// Note that we keep this type generic over the type of identifier it uses
-/// because we sometimes need to use SimplifiedTypeGen values as stable sorting
-/// keys (in which case we use a DefPathHash as id-type) but in the general case
-/// the non-stable but fast to construct DefId-version is the better choice.
+/// See `simplify_type`.
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
-pub enum SimplifiedTypeGen<D>
-where
-    D: Copy + Debug + Eq,
-{
+pub enum SimplifiedType {
     BoolSimplifiedType,
     CharSimplifiedType,
     IntSimplifiedType(ty::IntTy),
     UintSimplifiedType(ty::UintTy),
     FloatSimplifiedType(ty::FloatTy),
-    AdtSimplifiedType(D),
-    ForeignSimplifiedType(D),
+    AdtSimplifiedType(DefId),
+    ForeignSimplifiedType(DefId),
     StrSimplifiedType,
     ArraySimplifiedType,
     SliceSimplifiedType,
@@ -38,9 +28,9 @@ pub enum SimplifiedTypeGen<D>
     /// A trait object, all of whose components are markers
     /// (e.g., `dyn Send + Sync`).
     MarkerTraitObjectSimplifiedType,
-    TraitSimplifiedType(D),
-    ClosureSimplifiedType(D),
-    GeneratorSimplifiedType(D),
+    TraitSimplifiedType(DefId),
+    ClosureSimplifiedType(DefId),
+    GeneratorSimplifiedType(DefId),
     GeneratorWitnessSimplifiedType(usize),
     FunctionSimplifiedType(usize),
     PlaceholderSimplifiedType,
@@ -142,8 +132,8 @@ pub fn simplify_type<'tcx>(
     }
 }
 
-impl<D: Copy + Debug + Eq> SimplifiedTypeGen<D> {
-    pub fn def(self) -> Option<D> {
+impl SimplifiedType {
+    pub fn def(self) -> Option<DefId> {
         match self {
             AdtSimplifiedType(d)
             | ForeignSimplifiedType(d)
@@ -153,36 +143,6 @@ pub fn def(self) -> Option<D> {
             _ => None,
         }
     }
-
-    pub fn map_def<U, F>(self, map: F) -> SimplifiedTypeGen<U>
-    where
-        F: Fn(D) -> U,
-        U: Copy + Debug + Eq,
-    {
-        match self {
-            BoolSimplifiedType => BoolSimplifiedType,
-            CharSimplifiedType => CharSimplifiedType,
-            IntSimplifiedType(t) => IntSimplifiedType(t),
-            UintSimplifiedType(t) => UintSimplifiedType(t),
-            FloatSimplifiedType(t) => FloatSimplifiedType(t),
-            AdtSimplifiedType(d) => AdtSimplifiedType(map(d)),
-            ForeignSimplifiedType(d) => ForeignSimplifiedType(map(d)),
-            StrSimplifiedType => StrSimplifiedType,
-            ArraySimplifiedType => ArraySimplifiedType,
-            SliceSimplifiedType => SliceSimplifiedType,
-            RefSimplifiedType(m) => RefSimplifiedType(m),
-            PtrSimplifiedType(m) => PtrSimplifiedType(m),
-            NeverSimplifiedType => NeverSimplifiedType,
-            MarkerTraitObjectSimplifiedType => MarkerTraitObjectSimplifiedType,
-            TupleSimplifiedType(n) => TupleSimplifiedType(n),
-            TraitSimplifiedType(d) => TraitSimplifiedType(map(d)),
-            ClosureSimplifiedType(d) => ClosureSimplifiedType(map(d)),
-            GeneratorSimplifiedType(d) => GeneratorSimplifiedType(map(d)),
-            GeneratorWitnessSimplifiedType(n) => GeneratorWitnessSimplifiedType(n),
-            FunctionSimplifiedType(n) => FunctionSimplifiedType(n),
-            PlaceholderSimplifiedType => PlaceholderSimplifiedType,
-        }
-    }
 }
 
 /// Given generic arguments from an obligation and an impl,
index 174ac74fc9e61f6e5b3cdaec8fc1b54491605092..d283ccc3ad8a29435035c2c6bc4fc1fe9b0b3454 100644 (file)
@@ -160,7 +160,7 @@ fn add_kind(&mut self, kind: &ty::TyKind<'_>) {
                 self.add_projection_ty(data);
             }
 
-            &ty::Alias(ty::Opaque, ty::AliasTy { def_id: _, substs }) => {
+            &ty::Alias(ty::Opaque, ty::AliasTy { substs, .. }) => {
                 self.add_flags(TypeFlags::HAS_TY_OPAQUE);
                 self.add_substs(substs);
             }
index 6cb28a0fd8077984dc8a3306034962b647cbd00c..7290f0ae7c0350f4d34b3e08be5303af6da875d1 100644 (file)
     Const, ConstInt, ConstKind, ConstS, Expr, InferConst, ScalarInt, UnevaluatedConst, ValTree,
 };
 pub use self::context::{
-    tls, CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations,
-    CtxtInterners, DeducedParamAttrs, FreeRegionInfo, GeneratorDiagnosticData,
-    GeneratorInteriorTypeCause, GlobalCtxt, Lift, OnDiskCache, TyCtxt, TyCtxtFeed, TypeckResults,
-    UserType, UserTypeAnnotationIndex,
+    tls, CtxtInterners, DeducedParamAttrs, FreeRegionInfo, GlobalCtxt, Lift, OnDiskCache, TyCtxt,
+    TyCtxtFeed,
 };
 pub use self::instance::{Instance, InstanceDef, ShortInstance};
 pub use self::list::List;
     Region, RegionKind, RegionVid, TraitRef, TyKind, TypeAndMut, UpvarSubsts, VarianceDiagInfo,
 };
 pub use self::trait_def::TraitDef;
+pub use self::typeck_results::{
+    CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations,
+    GeneratorDiagnosticData, GeneratorInteriorTypeCause, TypeckResults, UserType,
+    UserTypeAnnotationIndex,
+};
 
 pub mod _match;
 pub mod abstract_const;
 mod rvalue_scopes;
 mod structural_impls;
 mod sty;
+mod typeck_results;
 
 // Data types
 
@@ -781,8 +785,8 @@ pub fn remap_constness_diag(&mut self, param_env: ParamEnv<'tcx>) {
         }
     }
 
-    pub fn with_self_type(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
-        Self { trait_ref: self.trait_ref.with_self_type(tcx, self_ty), ..self }
+    pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
+        Self { trait_ref: self.trait_ref.with_self_ty(tcx, self_ty), ..self }
     }
 
     pub fn def_id(self) -> DefId {
@@ -1050,6 +1054,18 @@ pub fn projection_def_id(&self) -> DefId {
     }
 }
 
+impl<'tcx> ProjectionPredicate<'tcx> {
+    pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
+        Self {
+            projection_ty: tcx.mk_alias_ty(
+                self.projection_ty.def_id,
+                [self_ty.into()].into_iter().chain(self.projection_ty.substs.iter().skip(1)),
+            ),
+            ..self
+        }
+    }
+}
+
 pub trait ToPolyTraitRef<'tcx> {
     fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx>;
 }
index c7d6c6abd1c22ebe153c37ae240e8f572058eee3..a21e3961cb627341211579f1a8528bb3a39b34c3 100644 (file)
@@ -1,15 +1,10 @@
 use rustc_data_structures::fx::FxHashMap;
-use rustc_hir::def_id::{DefId, DefIndex};
+use rustc_hir::def_id::DefIndex;
 use rustc_index::vec::{Idx, IndexVec};
 
-use crate::middle::exported_symbols::ExportedSymbol;
-use crate::mir::Body;
-use crate::ty::{
-    self, Clause, Const, FnSig, GeneratorDiagnosticData, GenericPredicates, Predicate, TraitRef, Ty,
-};
+use crate::ty;
 
 pub trait ParameterizedOverTcx: 'static {
-    #[allow(unused_lifetimes)]
     type Value<'tcx>;
 }
 
@@ -67,7 +62,7 @@ impl $crate::ty::ParameterizedOverTcx for $ty {
     ty::TraitDef,
     ty::Visibility<DefIndex>,
     ty::adjustment::CoerceUnsizedInfo,
-    ty::fast_reject::SimplifiedTypeGen<DefId>,
+    ty::fast_reject::SimplifiedType,
     rustc_ast::Attribute,
     rustc_ast::DelimArgs,
     rustc_attr::ConstStability,
@@ -100,29 +95,28 @@ impl $crate::ty::ParameterizedOverTcx for $ty {
     rustc_type_ir::Variance,
 }
 
-// HACK(compiler-errors): This macro rule can only take an ident,
-// not a path, due to parsing ambiguity reasons. That means we gotta
-// import all of these types above.
+// HACK(compiler-errors): This macro rule can only take a fake path,
+// not a real, due to parsing ambiguity reasons.
 #[macro_export]
 macro_rules! parameterized_over_tcx {
-    ($($ident:ident),+ $(,)?) => {
+    ($($($fake_path:ident)::+),+ $(,)?) => {
         $(
-            impl $crate::ty::ParameterizedOverTcx for $ident<'static> {
-                type Value<'tcx> = $ident<'tcx>;
+            impl $crate::ty::ParameterizedOverTcx for $($fake_path)::+<'static> {
+                type Value<'tcx> = $($fake_path)::+<'tcx>;
             }
         )*
     }
 }
 
 parameterized_over_tcx! {
-    Ty,
-    FnSig,
-    GenericPredicates,
-    TraitRef,
-    Const,
-    Predicate,
-    Clause,
-    GeneratorDiagnosticData,
-    Body,
-    ExportedSymbol,
+    crate::middle::exported_symbols::ExportedSymbol,
+    crate::mir::Body,
+    ty::Ty,
+    ty::FnSig,
+    ty::GenericPredicates,
+    ty::TraitRef,
+    ty::Const,
+    ty::Predicate,
+    ty::Clause,
+    ty::GeneratorDiagnosticData,
 }
index 3fad349bff8124a2f474dd73bcf105729175e9ce..29bad33e4bc0f36aa5ef8f955e1ec30da54ef19a 100644 (file)
@@ -169,10 +169,8 @@ fn default_print_def_path(
                 self.path_append(
                     |cx: Self| {
                         if trait_qualify_parent {
-                            let trait_ref = ty::TraitRef::new(
-                                parent_def_id,
-                                cx.tcx().intern_substs(parent_substs),
-                            );
+                            let trait_ref =
+                                cx.tcx().mk_trait_ref(parent_def_id, parent_substs.iter().copied());
                             cx.path_qualified(trait_ref.self_ty(), Some(trait_ref))
                         } else {
                             cx.print_def_path(parent_def_id, parent_substs)
index 6acc2dc65d36942c7f7e53b5f8d28e12952af228..a1d53506707c9a2938749623d087c314bad761a6 100644 (file)
@@ -16,6 +16,7 @@
 use rustc_session::cstore::{ExternCrate, ExternCrateSource};
 use rustc_session::Limit;
 use rustc_span::symbol::{kw, Ident, Symbol};
+use rustc_span::FileNameDisplayPreference;
 use rustc_target::abi::Size;
 use rustc_target::spec::abi::Abi;
 use smallvec::SmallVec;
@@ -728,7 +729,7 @@ fn pretty_print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error>
                 }
             }
             ty::Placeholder(placeholder) => p!(write("Placeholder({:?})", placeholder)),
-            ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs }) => {
+            ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
                 // FIXME(eddyb) print this with `print_def_path`.
                 // We use verbose printing in 'NO_QUERIES' mode, to
                 // avoid needing to call `predicates_of`. This should
@@ -743,7 +744,7 @@ fn pretty_print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error>
                 let parent = self.tcx().parent(def_id);
                 match self.tcx().def_kind(parent) {
                     DefKind::TyAlias | DefKind::AssocTy => {
-                        if let ty::Alias(ty::Opaque, ty::AliasTy { def_id: d, substs: _ }) =
+                        if let ty::Alias(ty::Opaque, ty::AliasTy { def_id: d, .. }) =
                             *self.tcx().type_of(parent).kind()
                         {
                             if d == def_id {
@@ -818,11 +819,16 @@ fn pretty_print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error>
                             p!("@", print_def_path(did.to_def_id(), substs));
                         } else {
                             let span = self.tcx().def_span(did);
+                            let preference = if FORCE_TRIMMED_PATH.with(|flag| flag.get()) {
+                                FileNameDisplayPreference::Short
+                            } else {
+                                FileNameDisplayPreference::Remapped
+                            };
                             p!(write(
                                 "@{}",
                                 // This may end up in stderr diagnostics but it may also be emitted
                                 // into MIR. Hence we use the remapped path if available
-                                self.tcx().sess.source_map().span_to_embeddable_string(span)
+                                self.tcx().sess.source_map().span_to_string(span, preference)
                             ));
                         }
                     } else {
index 1eac8859ca93487bed32fdf2d088805b2603431d..c4116558bd27b262b6aebdc3ccdb0ee587213d0c 100644 (file)
@@ -280,7 +280,7 @@ fn relate<R: TypeRelation<'tcx>>(
             Err(TypeError::ProjectionMismatched(expected_found(relation, a.def_id, b.def_id)))
         } else {
             let substs = relation.relate(a.substs, b.substs)?;
-            Ok(ty::AliasTy { def_id: a.def_id, substs: &substs })
+            Ok(relation.tcx().mk_alias_ty(a.def_id, substs))
         }
     }
 }
@@ -322,7 +322,7 @@ fn relate<R: TypeRelation<'tcx>>(
             Err(TypeError::Traits(expected_found(relation, a.def_id, b.def_id)))
         } else {
             let substs = relate_substs(relation, a.substs, b.substs)?;
-            Ok(ty::TraitRef { def_id: a.def_id, substs })
+            Ok(relation.tcx().mk_trait_ref(a.def_id, substs))
         }
     }
 }
@@ -557,8 +557,8 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>(
         }
 
         (
-            &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, substs: a_substs }),
-            &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, substs: b_substs }),
+            &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, substs: a_substs, .. }),
+            &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, substs: b_substs, .. }),
         ) if a_def_id == b_def_id => {
             if relation.intercrate() {
                 // During coherence, opaque types should be treated as equal to each other, even if their generic params
index 27de48c1f83454e78f93baea50359551e127af32..66aeebab88ba017d24bfd90895e1d1f7b58d4d94 100644 (file)
@@ -816,14 +816,13 @@ pub fn auto_traits<'a>(&'a self) -> impl Iterator<Item = DefId> + Captures<'tcx>
 pub struct TraitRef<'tcx> {
     pub def_id: DefId,
     pub substs: SubstsRef<'tcx>,
+    /// This field exists to prevent the creation of `TraitRef` without
+    /// calling [TyCtxt::mk_trait_ref].
+    pub(super) _use_mk_trait_ref_instead: (),
 }
 
 impl<'tcx> TraitRef<'tcx> {
-    pub fn new(def_id: DefId, substs: SubstsRef<'tcx>) -> TraitRef<'tcx> {
-        TraitRef { def_id, substs }
-    }
-
-    pub fn with_self_type(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
+    pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
         tcx.mk_trait_ref(
             self.def_id,
             [self_ty.into()].into_iter().chain(self.substs.iter().skip(1)),
@@ -833,10 +832,7 @@ pub fn with_self_type(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
     /// Returns a `TraitRef` of the form `P0: Foo<P1..Pn>` where `Pi`
     /// are the parameters defined on trait.
     pub fn identity(tcx: TyCtxt<'tcx>, def_id: DefId) -> Binder<'tcx, TraitRef<'tcx>> {
-        ty::Binder::dummy(TraitRef {
-            def_id,
-            substs: InternalSubsts::identity_for_item(tcx, def_id),
-        })
+        ty::Binder::dummy(tcx.mk_trait_ref(def_id, InternalSubsts::identity_for_item(tcx, def_id)))
     }
 
     #[inline]
@@ -850,7 +846,7 @@ pub fn from_method(
         substs: SubstsRef<'tcx>,
     ) -> ty::TraitRef<'tcx> {
         let defs = tcx.generics_of(trait_id);
-        ty::TraitRef { def_id: trait_id, substs: tcx.intern_substs(&substs[..defs.params.len()]) }
+        tcx.mk_trait_ref(trait_id, tcx.intern_substs(&substs[..defs.params.len()]))
     }
 }
 
@@ -1166,6 +1162,10 @@ pub struct AliasTy<'tcx> {
     /// `TraitRef` containing this associated type, which is in `tcx.associated_item(def_id).container`,
     /// aka. `tcx.parent(def_id)`.
     pub def_id: DefId,
+
+    /// This field exists to prevent the creation of `ProjectionTy` without using
+    /// [TyCtxt::mk_alias_ty].
+    pub(super) _use_mk_alias_ty_instead: (),
 }
 
 impl<'tcx> AliasTy<'tcx> {
@@ -1190,10 +1190,7 @@ pub fn trait_ref_and_own_substs(
         let trait_def_id = self.trait_def_id(tcx);
         let trait_generics = tcx.generics_of(trait_def_id);
         (
-            ty::TraitRef {
-                def_id: trait_def_id,
-                substs: self.substs.truncate_to(tcx, trait_generics),
-            },
+            tcx.mk_trait_ref(trait_def_id, self.substs.truncate_to(tcx, trait_generics)),
             &self.substs[trait_generics.count()..],
         )
     }
@@ -1207,7 +1204,7 @@ pub fn trait_ref_and_own_substs(
     /// as well.
     pub fn trait_ref(&self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> {
         let def_id = self.trait_def_id(tcx);
-        ty::TraitRef { def_id, substs: self.substs.truncate_to(tcx, tcx.generics_of(def_id)) }
+        tcx.mk_trait_ref(def_id, self.substs.truncate_to(tcx, tcx.generics_of(def_id)))
     }
 
     pub fn self_ty(&self) -> Ty<'tcx> {
@@ -1449,10 +1446,8 @@ pub fn with_self_ty(
         debug_assert!(!self_ty.has_escaping_bound_vars());
 
         ty::ProjectionPredicate {
-            projection_ty: ty::AliasTy {
-                def_id: self.def_id,
-                substs: tcx.mk_substs_trait(self_ty, self.substs),
-            },
+            projection_ty: tcx
+                .mk_alias_ty(self.def_id, [self_ty.into()].into_iter().chain(self.substs)),
             term: self.term,
         }
     }
diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs
new file mode 100644 (file)
index 0000000..4fe85d4
--- /dev/null
@@ -0,0 +1,689 @@
+use crate::{
+    hir::place::Place as HirPlace,
+    infer::canonical::Canonical,
+    ty::{
+        self, tls, BindingMode, BoundVar, CanonicalPolyFnSig, ClosureSizeProfileData,
+        GenericArgKind, InternalSubsts, SubstsRef, Ty, UserSubsts,
+    },
+};
+use rustc_data_structures::{fx::FxHashMap, sync::Lrc, unord::UnordSet, vec_map::VecMap};
+use rustc_errors::ErrorGuaranteed;
+use rustc_hir as hir;
+use rustc_hir::{
+    def::{DefKind, Res},
+    def_id::{DefId, LocalDefId, LocalDefIdMap},
+    hir_id::OwnerId,
+    HirId, ItemLocalId, ItemLocalMap, ItemLocalSet,
+};
+use rustc_index::vec::{Idx, IndexVec};
+use rustc_macros::HashStable;
+use rustc_middle::mir::FakeReadCause;
+use rustc_session::Session;
+use rustc_span::Span;
+use std::{
+    collections::hash_map::{self, Entry},
+    hash::Hash,
+    iter,
+};
+
+use super::RvalueScopes;
+
+#[derive(TyEncodable, TyDecodable, Debug, HashStable)]
+pub struct TypeckResults<'tcx> {
+    /// The `HirId::owner` all `ItemLocalId`s in this table are relative to.
+    pub hir_owner: OwnerId,
+
+    /// Resolved definitions for `<T>::X` associated paths and
+    /// method calls, including those of overloaded operators.
+    type_dependent_defs: ItemLocalMap<Result<(DefKind, DefId), ErrorGuaranteed>>,
+
+    /// Resolved field indices for field accesses in expressions (`S { field }`, `obj.field`)
+    /// or patterns (`S { field }`). The index is often useful by itself, but to learn more
+    /// about the field you also need definition of the variant to which the field
+    /// belongs, but it may not exist if it's a tuple field (`tuple.0`).
+    field_indices: ItemLocalMap<usize>,
+
+    /// Stores the types for various nodes in the AST. Note that this table
+    /// is not guaranteed to be populated outside inference. See
+    /// typeck::check::fn_ctxt for details.
+    node_types: ItemLocalMap<Ty<'tcx>>,
+
+    /// Stores the type parameters which were substituted to obtain the type
+    /// of this node. This only applies to nodes that refer to entities
+    /// parameterized by type parameters, such as generic fns, types, or
+    /// other items.
+    node_substs: ItemLocalMap<SubstsRef<'tcx>>,
+
+    /// This will either store the canonicalized types provided by the user
+    /// or the substitutions that the user explicitly gave (if any) attached
+    /// to `id`. These will not include any inferred values. The canonical form
+    /// is used to capture things like `_` or other unspecified values.
+    ///
+    /// For example, if the user wrote `foo.collect::<Vec<_>>()`, then the
+    /// canonical substitutions would include only `for<X> { Vec<X> }`.
+    ///
+    /// See also `AscribeUserType` statement in MIR.
+    user_provided_types: ItemLocalMap<CanonicalUserType<'tcx>>,
+
+    /// Stores the canonicalized types provided by the user. See also
+    /// `AscribeUserType` statement in MIR.
+    pub user_provided_sigs: LocalDefIdMap<CanonicalPolyFnSig<'tcx>>,
+
+    adjustments: ItemLocalMap<Vec<ty::adjustment::Adjustment<'tcx>>>,
+
+    /// Stores the actual binding mode for all instances of hir::BindingAnnotation.
+    pat_binding_modes: ItemLocalMap<BindingMode>,
+
+    /// Stores the types which were implicitly dereferenced in pattern binding modes
+    /// for later usage in THIR lowering. For example,
+    ///
+    /// ```
+    /// match &&Some(5i32) {
+    ///     Some(n) => {},
+    ///     _ => {},
+    /// }
+    /// ```
+    /// leads to a `vec![&&Option<i32>, &Option<i32>]`. Empty vectors are not stored.
+    ///
+    /// See:
+    /// <https://github.com/rust-lang/rfcs/blob/master/text/2005-match-ergonomics.md#definitions>
+    pat_adjustments: ItemLocalMap<Vec<Ty<'tcx>>>,
+
+    /// Records the reasons that we picked the kind of each closure;
+    /// not all closures are present in the map.
+    closure_kind_origins: ItemLocalMap<(Span, HirPlace<'tcx>)>,
+
+    /// For each fn, records the "liberated" types of its arguments
+    /// and return type. Liberated means that all bound regions
+    /// (including late-bound regions) are replaced with free
+    /// equivalents. This table is not used in codegen (since regions
+    /// are erased there) and hence is not serialized to metadata.
+    ///
+    /// This table also contains the "revealed" values for any `impl Trait`
+    /// that appear in the signature and whose values are being inferred
+    /// by this function.
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// # use std::fmt::Debug;
+    /// fn foo(x: &u32) -> impl Debug { *x }
+    /// ```
+    ///
+    /// The function signature here would be:
+    ///
+    /// ```ignore (illustrative)
+    /// for<'a> fn(&'a u32) -> Foo
+    /// ```
+    ///
+    /// where `Foo` is an opaque type created for this function.
+    ///
+    ///
+    /// The *liberated* form of this would be
+    ///
+    /// ```ignore (illustrative)
+    /// fn(&'a u32) -> u32
+    /// ```
+    ///
+    /// Note that `'a` is not bound (it would be an `ReFree`) and
+    /// that the `Foo` opaque type is replaced by its hidden type.
+    liberated_fn_sigs: ItemLocalMap<ty::FnSig<'tcx>>,
+
+    /// For each FRU expression, record the normalized types of the fields
+    /// of the struct - this is needed because it is non-trivial to
+    /// normalize while preserving regions. This table is used only in
+    /// MIR construction and hence is not serialized to metadata.
+    fru_field_types: ItemLocalMap<Vec<Ty<'tcx>>>,
+
+    /// For every coercion cast we add the HIR node ID of the cast
+    /// expression to this set.
+    coercion_casts: ItemLocalSet,
+
+    /// Set of trait imports actually used in the method resolution.
+    /// This is used for warning unused imports. During type
+    /// checking, this `Lrc` should not be cloned: it must have a ref-count
+    /// of 1 so that we can insert things into the set mutably.
+    pub used_trait_imports: Lrc<UnordSet<LocalDefId>>,
+
+    /// If any errors occurred while type-checking this body,
+    /// this field will be set to `Some(ErrorGuaranteed)`.
+    pub tainted_by_errors: Option<ErrorGuaranteed>,
+
+    /// All the opaque types that have hidden types set
+    /// by this function. We also store the
+    /// type here, so that mir-borrowck can use it as a hint for figuring out hidden types,
+    /// even if they are only set in dead code (which doesn't show up in MIR).
+    pub concrete_opaque_types: VecMap<LocalDefId, ty::OpaqueHiddenType<'tcx>>,
+
+    /// Tracks the minimum captures required for a closure;
+    /// see `MinCaptureInformationMap` for more details.
+    pub closure_min_captures: ty::MinCaptureInformationMap<'tcx>,
+
+    /// Tracks the fake reads required for a closure and the reason for the fake read.
+    /// When performing pattern matching for closures, there are times we don't end up
+    /// reading places that are mentioned in a closure (because of _ patterns). However,
+    /// to ensure the places are initialized, we introduce fake reads.
+    /// Consider these two examples:
+    /// ``` (discriminant matching with only wildcard arm)
+    /// let x: u8;
+    /// let c = || match x { _ => () };
+    /// ```
+    /// In this example, we don't need to actually read/borrow `x` in `c`, and so we don't
+    /// want to capture it. However, we do still want an error here, because `x` should have
+    /// to be initialized at the point where c is created. Therefore, we add a "fake read"
+    /// instead.
+    /// ``` (destructured assignments)
+    /// let c = || {
+    ///     let (t1, t2) = t;
+    /// }
+    /// ```
+    /// In the second example, we capture the disjoint fields of `t` (`t.0` & `t.1`), but
+    /// we never capture `t`. This becomes an issue when we build MIR as we require
+    /// information on `t` in order to create place `t.0` and `t.1`. We can solve this
+    /// issue by fake reading `t`.
+    pub closure_fake_reads: FxHashMap<LocalDefId, Vec<(HirPlace<'tcx>, FakeReadCause, hir::HirId)>>,
+
+    /// Tracks the rvalue scoping rules which defines finer scoping for rvalue expressions
+    /// by applying extended parameter rules.
+    /// Details may be find in `rustc_hir_analysis::check::rvalue_scopes`.
+    pub rvalue_scopes: RvalueScopes,
+
+    /// Stores the type, expression, span and optional scope span of all types
+    /// that are live across the yield of this generator (if a generator).
+    pub generator_interior_types: ty::Binder<'tcx, Vec<GeneratorInteriorTypeCause<'tcx>>>,
+
+    /// We sometimes treat byte string literals (which are of type `&[u8; N]`)
+    /// as `&[u8]`, depending on the pattern  in which they are used.
+    /// This hashset records all instances where we behave
+    /// like this to allow `const_to_pat` to reliably handle this situation.
+    pub treat_byte_string_as_slice: ItemLocalSet,
+
+    /// Contains the data for evaluating the effect of feature `capture_disjoint_fields`
+    /// on closure size.
+    pub closure_size_eval: FxHashMap<LocalDefId, ClosureSizeProfileData<'tcx>>,
+}
+
+/// Whenever a value may be live across a generator yield, the type of that value winds up in the
+/// `GeneratorInteriorTypeCause` struct. This struct adds additional information about such
+/// captured types that can be useful for diagnostics. In particular, it stores the span that
+/// caused a given type to be recorded, along with the scope that enclosed the value (which can
+/// be used to find the await that the value is live across).
+///
+/// For example:
+///
+/// ```ignore (pseudo-Rust)
+/// async move {
+///     let x: T = expr;
+///     foo.await
+///     ...
+/// }
+/// ```
+///
+/// Here, we would store the type `T`, the span of the value `x`, the "scope-span" for
+/// the scope that contains `x`, the expr `T` evaluated from, and the span of `foo.await`.
+#[derive(TyEncodable, TyDecodable, Clone, Debug, Eq, Hash, PartialEq, HashStable)]
+#[derive(TypeFoldable, TypeVisitable)]
+pub struct GeneratorInteriorTypeCause<'tcx> {
+    /// Type of the captured binding.
+    pub ty: Ty<'tcx>,
+    /// Span of the binding that was captured.
+    pub span: Span,
+    /// Span of the scope of the captured binding.
+    pub scope_span: Option<Span>,
+    /// Span of `.await` or `yield` expression.
+    pub yield_span: Span,
+    /// Expr which the type evaluated from.
+    pub expr: Option<hir::HirId>,
+}
+
+// This type holds diagnostic information on generators and async functions across crate boundaries
+// and is used to provide better error messages
+#[derive(TyEncodable, TyDecodable, Clone, Debug, HashStable)]
+pub struct GeneratorDiagnosticData<'tcx> {
+    pub generator_interior_types: ty::Binder<'tcx, Vec<GeneratorInteriorTypeCause<'tcx>>>,
+    pub hir_owner: DefId,
+    pub nodes_types: ItemLocalMap<Ty<'tcx>>,
+    pub adjustments: ItemLocalMap<Vec<ty::adjustment::Adjustment<'tcx>>>,
+}
+
+impl<'tcx> TypeckResults<'tcx> {
+    pub fn new(hir_owner: OwnerId) -> TypeckResults<'tcx> {
+        TypeckResults {
+            hir_owner,
+            type_dependent_defs: Default::default(),
+            field_indices: Default::default(),
+            user_provided_types: Default::default(),
+            user_provided_sigs: Default::default(),
+            node_types: Default::default(),
+            node_substs: Default::default(),
+            adjustments: Default::default(),
+            pat_binding_modes: Default::default(),
+            pat_adjustments: Default::default(),
+            closure_kind_origins: Default::default(),
+            liberated_fn_sigs: Default::default(),
+            fru_field_types: Default::default(),
+            coercion_casts: Default::default(),
+            used_trait_imports: Lrc::new(Default::default()),
+            tainted_by_errors: None,
+            concrete_opaque_types: Default::default(),
+            closure_min_captures: Default::default(),
+            closure_fake_reads: Default::default(),
+            rvalue_scopes: Default::default(),
+            generator_interior_types: ty::Binder::dummy(Default::default()),
+            treat_byte_string_as_slice: Default::default(),
+            closure_size_eval: Default::default(),
+        }
+    }
+
+    /// Returns the final resolution of a `QPath` in an `Expr` or `Pat` node.
+    pub fn qpath_res(&self, qpath: &hir::QPath<'_>, id: hir::HirId) -> Res {
+        match *qpath {
+            hir::QPath::Resolved(_, ref path) => path.res,
+            hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => self
+                .type_dependent_def(id)
+                .map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)),
+        }
+    }
+
+    pub fn type_dependent_defs(
+        &self,
+    ) -> LocalTableInContext<'_, Result<(DefKind, DefId), ErrorGuaranteed>> {
+        LocalTableInContext { hir_owner: self.hir_owner, data: &self.type_dependent_defs }
+    }
+
+    pub fn type_dependent_def(&self, id: HirId) -> Option<(DefKind, DefId)> {
+        validate_hir_id_for_typeck_results(self.hir_owner, id);
+        self.type_dependent_defs.get(&id.local_id).cloned().and_then(|r| r.ok())
+    }
+
+    pub fn type_dependent_def_id(&self, id: HirId) -> Option<DefId> {
+        self.type_dependent_def(id).map(|(_, def_id)| def_id)
+    }
+
+    pub fn type_dependent_defs_mut(
+        &mut self,
+    ) -> LocalTableInContextMut<'_, Result<(DefKind, DefId), ErrorGuaranteed>> {
+        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.type_dependent_defs }
+    }
+
+    pub fn field_indices(&self) -> LocalTableInContext<'_, usize> {
+        LocalTableInContext { hir_owner: self.hir_owner, data: &self.field_indices }
+    }
+
+    pub fn field_indices_mut(&mut self) -> LocalTableInContextMut<'_, usize> {
+        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.field_indices }
+    }
+
+    pub fn field_index(&self, id: hir::HirId) -> usize {
+        self.field_indices().get(id).cloned().expect("no index for a field")
+    }
+
+    pub fn opt_field_index(&self, id: hir::HirId) -> Option<usize> {
+        self.field_indices().get(id).cloned()
+    }
+
+    pub fn user_provided_types(&self) -> LocalTableInContext<'_, CanonicalUserType<'tcx>> {
+        LocalTableInContext { hir_owner: self.hir_owner, data: &self.user_provided_types }
+    }
+
+    pub fn user_provided_types_mut(
+        &mut self,
+    ) -> LocalTableInContextMut<'_, CanonicalUserType<'tcx>> {
+        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.user_provided_types }
+    }
+
+    pub fn node_types(&self) -> LocalTableInContext<'_, Ty<'tcx>> {
+        LocalTableInContext { hir_owner: self.hir_owner, data: &self.node_types }
+    }
+
+    pub fn node_types_mut(&mut self) -> LocalTableInContextMut<'_, Ty<'tcx>> {
+        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.node_types }
+    }
+
+    pub fn get_generator_diagnostic_data(&self) -> GeneratorDiagnosticData<'tcx> {
+        let generator_interior_type = self.generator_interior_types.map_bound_ref(|vec| {
+            vec.iter()
+                .map(|item| {
+                    GeneratorInteriorTypeCause {
+                        ty: item.ty,
+                        span: item.span,
+                        scope_span: item.scope_span,
+                        yield_span: item.yield_span,
+                        expr: None, //FIXME: Passing expression over crate boundaries is impossible at the moment
+                    }
+                })
+                .collect::<Vec<_>>()
+        });
+        GeneratorDiagnosticData {
+            generator_interior_types: generator_interior_type,
+            hir_owner: self.hir_owner.to_def_id(),
+            nodes_types: self.node_types.clone(),
+            adjustments: self.adjustments.clone(),
+        }
+    }
+
+    pub fn node_type(&self, id: hir::HirId) -> Ty<'tcx> {
+        self.node_type_opt(id).unwrap_or_else(|| {
+            bug!("node_type: no type for node `{}`", tls::with(|tcx| tcx.hir().node_to_string(id)))
+        })
+    }
+
+    pub fn node_type_opt(&self, id: hir::HirId) -> Option<Ty<'tcx>> {
+        validate_hir_id_for_typeck_results(self.hir_owner, id);
+        self.node_types.get(&id.local_id).cloned()
+    }
+
+    pub fn node_substs_mut(&mut self) -> LocalTableInContextMut<'_, SubstsRef<'tcx>> {
+        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.node_substs }
+    }
+
+    pub fn node_substs(&self, id: hir::HirId) -> SubstsRef<'tcx> {
+        validate_hir_id_for_typeck_results(self.hir_owner, id);
+        self.node_substs.get(&id.local_id).cloned().unwrap_or_else(|| InternalSubsts::empty())
+    }
+
+    pub fn node_substs_opt(&self, id: hir::HirId) -> Option<SubstsRef<'tcx>> {
+        validate_hir_id_for_typeck_results(self.hir_owner, id);
+        self.node_substs.get(&id.local_id).cloned()
+    }
+
+    /// Returns the type of a pattern as a monotype. Like [`expr_ty`], this function
+    /// doesn't provide type parameter substitutions.
+    ///
+    /// [`expr_ty`]: TypeckResults::expr_ty
+    pub fn pat_ty(&self, pat: &hir::Pat<'_>) -> Ty<'tcx> {
+        self.node_type(pat.hir_id)
+    }
+
+    /// Returns the type of an expression as a monotype.
+    ///
+    /// NB (1): This is the PRE-ADJUSTMENT TYPE for the expression.  That is, in
+    /// some cases, we insert `Adjustment` annotations such as auto-deref or
+    /// auto-ref.  The type returned by this function does not consider such
+    /// adjustments.  See `expr_ty_adjusted()` instead.
+    ///
+    /// NB (2): This type doesn't provide type parameter substitutions; e.g., if you
+    /// ask for the type of `id` in `id(3)`, it will return `fn(&isize) -> isize`
+    /// instead of `fn(ty) -> T with T = isize`.
+    pub fn expr_ty(&self, expr: &hir::Expr<'_>) -> Ty<'tcx> {
+        self.node_type(expr.hir_id)
+    }
+
+    pub fn expr_ty_opt(&self, expr: &hir::Expr<'_>) -> Option<Ty<'tcx>> {
+        self.node_type_opt(expr.hir_id)
+    }
+
+    pub fn adjustments(&self) -> LocalTableInContext<'_, Vec<ty::adjustment::Adjustment<'tcx>>> {
+        LocalTableInContext { hir_owner: self.hir_owner, data: &self.adjustments }
+    }
+
+    pub fn adjustments_mut(
+        &mut self,
+    ) -> LocalTableInContextMut<'_, Vec<ty::adjustment::Adjustment<'tcx>>> {
+        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.adjustments }
+    }
+
+    pub fn expr_adjustments(&self, expr: &hir::Expr<'_>) -> &[ty::adjustment::Adjustment<'tcx>] {
+        validate_hir_id_for_typeck_results(self.hir_owner, expr.hir_id);
+        self.adjustments.get(&expr.hir_id.local_id).map_or(&[], |a| &a[..])
+    }
+
+    /// Returns the type of `expr`, considering any `Adjustment`
+    /// entry recorded for that expression.
+    pub fn expr_ty_adjusted(&self, expr: &hir::Expr<'_>) -> Ty<'tcx> {
+        self.expr_adjustments(expr).last().map_or_else(|| self.expr_ty(expr), |adj| adj.target)
+    }
+
+    pub fn expr_ty_adjusted_opt(&self, expr: &hir::Expr<'_>) -> Option<Ty<'tcx>> {
+        self.expr_adjustments(expr).last().map(|adj| adj.target).or_else(|| self.expr_ty_opt(expr))
+    }
+
+    pub fn is_method_call(&self, expr: &hir::Expr<'_>) -> bool {
+        // Only paths and method calls/overloaded operators have
+        // entries in type_dependent_defs, ignore the former here.
+        if let hir::ExprKind::Path(_) = expr.kind {
+            return false;
+        }
+
+        matches!(self.type_dependent_defs().get(expr.hir_id), Some(Ok((DefKind::AssocFn, _))))
+    }
+
+    pub fn extract_binding_mode(&self, s: &Session, id: HirId, sp: Span) -> Option<BindingMode> {
+        self.pat_binding_modes().get(id).copied().or_else(|| {
+            s.delay_span_bug(sp, "missing binding mode");
+            None
+        })
+    }
+
+    pub fn pat_binding_modes(&self) -> LocalTableInContext<'_, BindingMode> {
+        LocalTableInContext { hir_owner: self.hir_owner, data: &self.pat_binding_modes }
+    }
+
+    pub fn pat_binding_modes_mut(&mut self) -> LocalTableInContextMut<'_, BindingMode> {
+        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_binding_modes }
+    }
+
+    pub fn pat_adjustments(&self) -> LocalTableInContext<'_, Vec<Ty<'tcx>>> {
+        LocalTableInContext { hir_owner: self.hir_owner, data: &self.pat_adjustments }
+    }
+
+    pub fn pat_adjustments_mut(&mut self) -> LocalTableInContextMut<'_, Vec<Ty<'tcx>>> {
+        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_adjustments }
+    }
+
+    /// For a given closure, returns the iterator of `ty::CapturedPlace`s that are captured
+    /// by the closure.
+    pub fn closure_min_captures_flattened(
+        &self,
+        closure_def_id: LocalDefId,
+    ) -> impl Iterator<Item = &ty::CapturedPlace<'tcx>> {
+        self.closure_min_captures
+            .get(&closure_def_id)
+            .map(|closure_min_captures| closure_min_captures.values().flat_map(|v| v.iter()))
+            .into_iter()
+            .flatten()
+    }
+
+    pub fn closure_kind_origins(&self) -> LocalTableInContext<'_, (Span, HirPlace<'tcx>)> {
+        LocalTableInContext { hir_owner: self.hir_owner, data: &self.closure_kind_origins }
+    }
+
+    pub fn closure_kind_origins_mut(
+        &mut self,
+    ) -> LocalTableInContextMut<'_, (Span, HirPlace<'tcx>)> {
+        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.closure_kind_origins }
+    }
+
+    pub fn liberated_fn_sigs(&self) -> LocalTableInContext<'_, ty::FnSig<'tcx>> {
+        LocalTableInContext { hir_owner: self.hir_owner, data: &self.liberated_fn_sigs }
+    }
+
+    pub fn liberated_fn_sigs_mut(&mut self) -> LocalTableInContextMut<'_, ty::FnSig<'tcx>> {
+        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.liberated_fn_sigs }
+    }
+
+    pub fn fru_field_types(&self) -> LocalTableInContext<'_, Vec<Ty<'tcx>>> {
+        LocalTableInContext { hir_owner: self.hir_owner, data: &self.fru_field_types }
+    }
+
+    pub fn fru_field_types_mut(&mut self) -> LocalTableInContextMut<'_, Vec<Ty<'tcx>>> {
+        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.fru_field_types }
+    }
+
+    pub fn is_coercion_cast(&self, hir_id: hir::HirId) -> bool {
+        validate_hir_id_for_typeck_results(self.hir_owner, hir_id);
+        self.coercion_casts.contains(&hir_id.local_id)
+    }
+
+    pub fn set_coercion_cast(&mut self, id: ItemLocalId) {
+        self.coercion_casts.insert(id);
+    }
+
+    pub fn coercion_casts(&self) -> &ItemLocalSet {
+        &self.coercion_casts
+    }
+}
+
+/// Validate that the given HirId (respectively its `local_id` part) can be
+/// safely used as a key in the maps of a TypeckResults. For that to be
+/// the case, the HirId must have the same `owner` as all the other IDs in
+/// this table (signified by `hir_owner`). Otherwise the HirId
+/// would be in a different frame of reference and using its `local_id`
+/// would result in lookup errors, or worse, in silently wrong data being
+/// stored/returned.
+#[inline]
+fn validate_hir_id_for_typeck_results(hir_owner: OwnerId, hir_id: hir::HirId) {
+    if hir_id.owner != hir_owner {
+        invalid_hir_id_for_typeck_results(hir_owner, hir_id);
+    }
+}
+
+#[cold]
+#[inline(never)]
+fn invalid_hir_id_for_typeck_results(hir_owner: OwnerId, hir_id: hir::HirId) {
+    ty::tls::with(|tcx| {
+        bug!(
+            "node {} with HirId::owner {:?} cannot be placed in TypeckResults with hir_owner {:?}",
+            tcx.hir().node_to_string(hir_id),
+            hir_id.owner,
+            hir_owner
+        )
+    });
+}
+
+pub struct LocalTableInContext<'a, V> {
+    hir_owner: OwnerId,
+    data: &'a ItemLocalMap<V>,
+}
+
+impl<'a, V> LocalTableInContext<'a, V> {
+    pub fn contains_key(&self, id: hir::HirId) -> bool {
+        validate_hir_id_for_typeck_results(self.hir_owner, id);
+        self.data.contains_key(&id.local_id)
+    }
+
+    pub fn get(&self, id: hir::HirId) -> Option<&V> {
+        validate_hir_id_for_typeck_results(self.hir_owner, id);
+        self.data.get(&id.local_id)
+    }
+
+    pub fn iter(&self) -> hash_map::Iter<'_, hir::ItemLocalId, V> {
+        self.data.iter()
+    }
+}
+
+impl<'a, V> ::std::ops::Index<hir::HirId> for LocalTableInContext<'a, V> {
+    type Output = V;
+
+    fn index(&self, key: hir::HirId) -> &V {
+        self.get(key).expect("LocalTableInContext: key not found")
+    }
+}
+
+pub struct LocalTableInContextMut<'a, V> {
+    hir_owner: OwnerId,
+    data: &'a mut ItemLocalMap<V>,
+}
+
+impl<'a, V> LocalTableInContextMut<'a, V> {
+    pub fn get_mut(&mut self, id: hir::HirId) -> Option<&mut V> {
+        validate_hir_id_for_typeck_results(self.hir_owner, id);
+        self.data.get_mut(&id.local_id)
+    }
+
+    pub fn entry(&mut self, id: hir::HirId) -> Entry<'_, hir::ItemLocalId, V> {
+        validate_hir_id_for_typeck_results(self.hir_owner, id);
+        self.data.entry(id.local_id)
+    }
+
+    pub fn insert(&mut self, id: hir::HirId, val: V) -> Option<V> {
+        validate_hir_id_for_typeck_results(self.hir_owner, id);
+        self.data.insert(id.local_id, val)
+    }
+
+    pub fn remove(&mut self, id: hir::HirId) -> Option<V> {
+        validate_hir_id_for_typeck_results(self.hir_owner, id);
+        self.data.remove(&id.local_id)
+    }
+}
+
+rustc_index::newtype_index! {
+    pub struct UserTypeAnnotationIndex {
+        derive [HashStable]
+        DEBUG_FORMAT = "UserType({})",
+        const START_INDEX = 0,
+    }
+}
+
+/// Mapping of type annotation indices to canonical user type annotations.
+pub type CanonicalUserTypeAnnotations<'tcx> =
+    IndexVec<UserTypeAnnotationIndex, CanonicalUserTypeAnnotation<'tcx>>;
+
+#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable, Lift)]
+pub struct CanonicalUserTypeAnnotation<'tcx> {
+    pub user_ty: Box<CanonicalUserType<'tcx>>,
+    pub span: Span,
+    pub inferred_ty: Ty<'tcx>,
+}
+
+/// Canonicalized user type annotation.
+pub type CanonicalUserType<'tcx> = Canonical<'tcx, UserType<'tcx>>;
+
+impl<'tcx> CanonicalUserType<'tcx> {
+    /// Returns `true` if this represents a substitution of the form `[?0, ?1, ?2]`,
+    /// i.e., each thing is mapped to a canonical variable with the same index.
+    pub fn is_identity(&self) -> bool {
+        match self.value {
+            UserType::Ty(_) => false,
+            UserType::TypeOf(_, user_substs) => {
+                if user_substs.user_self_ty.is_some() {
+                    return false;
+                }
+
+                iter::zip(user_substs.substs, BoundVar::new(0)..).all(|(kind, cvar)| {
+                    match kind.unpack() {
+                        GenericArgKind::Type(ty) => match ty.kind() {
+                            ty::Bound(debruijn, b) => {
+                                // We only allow a `ty::INNERMOST` index in substitutions.
+                                assert_eq!(*debruijn, ty::INNERMOST);
+                                cvar == b.var
+                            }
+                            _ => false,
+                        },
+
+                        GenericArgKind::Lifetime(r) => match *r {
+                            ty::ReLateBound(debruijn, br) => {
+                                // We only allow a `ty::INNERMOST` index in substitutions.
+                                assert_eq!(debruijn, ty::INNERMOST);
+                                cvar == br.var
+                            }
+                            _ => false,
+                        },
+
+                        GenericArgKind::Const(ct) => match ct.kind() {
+                            ty::ConstKind::Bound(debruijn, b) => {
+                                // We only allow a `ty::INNERMOST` index in substitutions.
+                                assert_eq!(debruijn, ty::INNERMOST);
+                                cvar == b
+                            }
+                            _ => false,
+                        },
+                    }
+                })
+            }
+        }
+    }
+}
+
+/// A user-given type annotation attached to a constant. These arise
+/// from constants that are named via paths, like `Foo::<A>::new` and
+/// so forth.
+#[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
+pub enum UserType<'tcx> {
+    Ty(Ty<'tcx>),
+
+    /// The canonical type is the result of `type_of(def_id)` with the
+    /// given substitutions applied.
+    TypeOf(DefId, UserSubsts<'tcx>),
+}
index b8a19e582c9dcf3fa9aec79f1fed5e16005b96fd..857f52c8a245612ddc9d164207681e8c15a7f4aa 100644 (file)
@@ -825,7 +825,7 @@ fn tcx(&self) -> TyCtxt<'tcx> {
     }
 
     fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
-        if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs }) = *t.kind() {
+        if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) = *t.kind() {
             self.expand_opaque_ty(def_id, substs).unwrap_or(t)
         } else if t.has_opaque_types() {
             t.super_fold_with(self)
index 1fd2e40c187e0487eb761156caa852a091d45b98..34fefb99e09c25c1b034a2f431ce38dafbf3e39c 100644 (file)
@@ -25,7 +25,7 @@
 use rustc_middle::{
     mir::*,
     thir::*,
-    ty::{Ty, TyCtxt},
+    ty::{ParamEnv, Ty, TyCtxt},
 };
 use rustc_span::Span;
 
@@ -78,6 +78,7 @@ pub(super) fn build_custom_mir<'tcx>(
 
     let mut pctxt = ParseCtxt {
         tcx,
+        param_env: tcx.param_env(did),
         thir,
         source_scope: OUTERMOST_SOURCE_SCOPE,
         body: &mut body,
@@ -132,6 +133,7 @@ fn parse_attribute(attr: &Attribute) -> MirPhase {
 
 struct ParseCtxt<'tcx, 'body> {
     tcx: TyCtxt<'tcx>,
+    param_env: ParamEnv<'tcx>,
     thir: &'body Thir<'tcx>,
     source_scope: SourceScope,
 
index 03206af33bfb5dc927da6348f64b84f7d4074a08..2f26499a3b6e937c8acc0a1bfb2bdc48ba855b05 100644 (file)
@@ -1,5 +1,11 @@
 use rustc_middle::mir::interpret::{ConstValue, Scalar};
+use rustc_middle::mir::tcx::PlaceTy;
 use rustc_middle::{mir::*, thir::*, ty};
+use rustc_span::Span;
+use rustc_target::abi::VariantIdx;
+
+use crate::build::custom::ParseError;
+use crate::build::expr::as_constant::as_constant_inner;
 
 use super::{parse_by_kind, PResult, ParseCtxt};
 
@@ -12,6 +18,14 @@ pub fn parse_statement(&self, expr_id: ExprId) -> PResult<StatementKind<'tcx>> {
             @call("mir_retag_raw", args) => {
                 Ok(StatementKind::Retag(RetagKind::Raw, Box::new(self.parse_place(args[0])?)))
             },
+            @call("mir_set_discriminant", args) => {
+                let place = self.parse_place(args[0])?;
+                let var = self.parse_integer_literal(args[1])? as u32;
+                Ok(StatementKind::SetDiscriminant {
+                    place: Box::new(place),
+                    variant_index: VariantIdx::from_u32(var),
+                })
+            },
             ExprKind::Assign { lhs, rhs } => {
                 let lhs = self.parse_place(*lhs)?;
                 let rhs = self.parse_rvalue(*rhs)?;
@@ -21,18 +35,60 @@ pub fn parse_statement(&self, expr_id: ExprId) -> PResult<StatementKind<'tcx>> {
     }
 
     pub fn parse_terminator(&self, expr_id: ExprId) -> PResult<TerminatorKind<'tcx>> {
-        parse_by_kind!(self, expr_id, _, "terminator",
+        parse_by_kind!(self, expr_id, expr, "terminator",
             @call("mir_return", _args) => {
                 Ok(TerminatorKind::Return)
             },
             @call("mir_goto", args) => {
                 Ok(TerminatorKind::Goto { target: self.parse_block(args[0])? } )
             },
+            ExprKind::Match { scrutinee, arms } => {
+                let discr = self.parse_operand(*scrutinee)?;
+                self.parse_match(arms, expr.span).map(|t| TerminatorKind::SwitchInt { discr, targets: t })
+            },
         )
     }
 
+    fn parse_match(&self, arms: &[ArmId], span: Span) -> PResult<SwitchTargets> {
+        let Some((otherwise, rest)) = arms.split_last() else {
+            return Err(ParseError {
+                span,
+                item_description: format!("no arms"),
+                expected: "at least one arm".to_string(),
+            })
+        };
+
+        let otherwise = &self.thir[*otherwise];
+        let PatKind::Wild = otherwise.pattern.kind else {
+            return Err(ParseError {
+                span: otherwise.span,
+                item_description: format!("{:?}", otherwise.pattern.kind),
+                expected: "wildcard pattern".to_string(),
+            })
+        };
+        let otherwise = self.parse_block(otherwise.body)?;
+
+        let mut values = Vec::new();
+        let mut targets = Vec::new();
+        for arm in rest {
+            let arm = &self.thir[*arm];
+            let PatKind::Constant { value } = arm.pattern.kind else {
+                return Err(ParseError {
+                    span: arm.pattern.span,
+                    item_description: format!("{:?}", arm.pattern.kind),
+                    expected: "constant pattern".to_string(),
+                })
+            };
+            values.push(value.eval_bits(self.tcx, self.param_env, arm.pattern.ty));
+            targets.push(self.parse_block(arm.body)?);
+        }
+
+        Ok(SwitchTargets::new(values.into_iter().zip(targets), otherwise))
+    }
+
     fn parse_rvalue(&self, expr_id: ExprId) -> PResult<Rvalue<'tcx>> {
         parse_by_kind!(self, expr_id, _, "rvalue",
+            @call("mir_discriminant", args) => self.parse_place(args[0]).map(Rvalue::Discriminant),
             ExprKind::Borrow { borrow_kind, arg } => Ok(
                 Rvalue::Ref(self.tcx.lifetimes.re_erased, *borrow_kind, self.parse_place(*arg)?)
             ),
@@ -55,7 +111,7 @@ fn parse_operand(&self, expr_id: ExprId) -> PResult<Operand<'tcx>> {
             | ExprKind::ConstParam { .. }
             | ExprKind::ConstBlock { .. } => {
                 Ok(Operand::Constant(Box::new(
-                    crate::build::expr::as_constant::as_constant_inner(expr, |_| None, self.tcx)
+                    as_constant_inner(expr, |_| None, self.tcx)
                 )))
             },
             _ => self.parse_place(expr_id).map(Operand::Copy),
@@ -63,12 +119,42 @@ fn parse_operand(&self, expr_id: ExprId) -> PResult<Operand<'tcx>> {
     }
 
     fn parse_place(&self, expr_id: ExprId) -> PResult<Place<'tcx>> {
-        parse_by_kind!(self, expr_id, _, "place",
-            ExprKind::Deref { arg } => Ok(
-                self.parse_place(*arg)?.project_deeper(&[PlaceElem::Deref], self.tcx)
-            ),
-            _ => self.parse_local(expr_id).map(Place::from),
-        )
+        self.parse_place_inner(expr_id).map(|(x, _)| x)
+    }
+
+    fn parse_place_inner(&self, expr_id: ExprId) -> PResult<(Place<'tcx>, PlaceTy<'tcx>)> {
+        let (parent, proj) = parse_by_kind!(self, expr_id, expr, "place",
+            @call("mir_field", args) => {
+                let (parent, ty) = self.parse_place_inner(args[0])?;
+                let field = Field::from_u32(self.parse_integer_literal(args[1])? as u32);
+                let field_ty = ty.field_ty(self.tcx, field);
+                let proj = PlaceElem::Field(field, field_ty);
+                let place = parent.project_deeper(&[proj], self.tcx);
+                return Ok((place, PlaceTy::from_ty(field_ty)));
+            },
+            @call("mir_variant", args) => {
+                (args[0], PlaceElem::Downcast(
+                    None,
+                    VariantIdx::from_u32(self.parse_integer_literal(args[1])? as u32)
+                ))
+            },
+            ExprKind::Deref { arg } => {
+                parse_by_kind!(self, *arg, _, "does not matter",
+                    @call("mir_make_place", args) => return self.parse_place_inner(args[0]),
+                    _ => (*arg, PlaceElem::Deref),
+                )
+            },
+            ExprKind::Index { lhs, index } => (*lhs, PlaceElem::Index(self.parse_local(*index)?)),
+            ExprKind::Field { lhs, name: field, .. } => (*lhs, PlaceElem::Field(*field, expr.ty)),
+            _ => {
+                let place = self.parse_local(expr_id).map(Place::from)?;
+                return Ok((place, PlaceTy::from_ty(expr.ty)))
+            },
+        );
+        let (parent, ty) = self.parse_place_inner(parent)?;
+        let place = parent.project_deeper(&[proj], self.tcx);
+        let ty = ty.projection_ty(self.tcx, proj);
+        Ok((place, ty))
     }
 
     fn parse_local(&self, expr_id: ExprId) -> PResult<Local> {
@@ -102,4 +188,16 @@ fn parse_static(&self, expr_id: ExprId) -> PResult<Operand<'tcx>> {
             },
         )
     }
+
+    fn parse_integer_literal(&self, expr_id: ExprId) -> PResult<u128> {
+        parse_by_kind!(self, expr_id, expr, "constant",
+            ExprKind::Literal { .. }
+            | ExprKind::NamedConst { .. }
+            | ExprKind::NonHirLiteral { .. }
+            | ExprKind::ConstBlock { .. } => Ok({
+                let value = as_constant_inner(expr, |_| None, self.tcx);
+                value.literal.eval_bits(self.tcx, self.param_env, value.ty())
+            }),
+        )
+    }
 }
index 0814793f27790159dd3aa6400fe3a6e28b6b3b4f..c7b3eb44dc5fb52318b716a2d1c53ce3ae483b10 100644 (file)
@@ -142,7 +142,7 @@ pub(crate) fn as_rvalue(
                 let exchange_malloc = Operand::function_handle(
                     tcx,
                     tcx.require_lang_item(LangItem::ExchangeMalloc, Some(expr_span)),
-                    ty::List::empty(),
+                    [],
                     expr_span,
                 );
                 let storage = this.temp(tcx.mk_mut_ptr(tcx.types.u8), expr_span);
index 6d5a98342d2936730549754f62fcacdadd06bcae..de6a48f7cc411c4c7afb830f729c5bcb95227dfe 100644 (file)
@@ -838,8 +838,6 @@ fn trait_method<'tcx>(
     method_name: Symbol,
     substs: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
 ) -> ConstantKind<'tcx> {
-    let substs = tcx.mk_substs(substs.into_iter().map(Into::into));
-
     // The unhygienic comparison here is acceptable because this is only
     // used on known traits.
     let item = tcx
index 8610792c0eb5d24be0eced169c40d1d141ec3a4e..7836ae2e7b76f9959107eceb12875c9da02fdd63 100644 (file)
@@ -614,7 +614,6 @@ fn destructor_call_block(&mut self, (succ, unwind): (BasicBlock, Unwind)) -> Bas
         let drop_trait = tcx.require_lang_item(LangItem::Drop, None);
         let drop_fn = tcx.associated_item_def_ids(drop_trait)[0];
         let ty = self.place_ty(self.place);
-        let substs = tcx.mk_substs_trait(ty, []);
 
         let ref_ty =
             tcx.mk_ref(tcx.lifetimes.re_erased, ty::TypeAndMut { ty, mutbl: hir::Mutability::Mut });
@@ -632,7 +631,12 @@ fn destructor_call_block(&mut self, (succ, unwind): (BasicBlock, Unwind)) -> Bas
             )],
             terminator: Some(Terminator {
                 kind: TerminatorKind::Call {
-                    func: Operand::function_handle(tcx, drop_fn, substs, self.source_info.span),
+                    func: Operand::function_handle(
+                        tcx,
+                        drop_fn,
+                        [ty.into()],
+                        self.source_info.span,
+                    ),
                     args: vec![Operand::Move(Place::from(ref_place))],
                     destination: unit_temp,
                     target: Some(succ),
index 782abd7804d5d0f66ed7175a141d42fe41bb6e2d..9c22b5df73ce85ea2423352c4c8d55ed0ea20abe 100644 (file)
@@ -500,7 +500,7 @@ fn unsafety_check_result<'tcx>(
     // `mir_built` force this.
     let body = &tcx.mir_built(def).borrow();
 
-    if body.should_skip() {
+    if body.is_custom_mir() {
         return tcx.arena.alloc(UnsafetyCheckResult {
             violations: Vec::new(),
             used_unsafe_blocks: FxHashSet::default(),
index b0514e033566c9a65ebe8f5484a41d74ddb39898..044b7ce65bd71cd65ed54597d246e1e4efc01cac 100644 (file)
@@ -6,6 +6,7 @@
 use either::Right;
 
 use rustc_ast::Mutability;
+use rustc_const_eval::const_eval::CheckAlignment;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def::DefKind;
 use rustc_index::bit_set::BitSet;
@@ -22,7 +23,7 @@
 use rustc_middle::ty::InternalSubsts;
 use rustc_middle::ty::{self, ConstKind, Instance, ParamEnv, Ty, TyCtxt, TypeVisitable};
 use rustc_span::{def_id::DefId, Span};
-use rustc_target::abi::{self, HasDataLayout, Size, TargetDataLayout};
+use rustc_target::abi::{self, Align, HasDataLayout, Size, TargetDataLayout};
 use rustc_target::spec::abi::Abi as CallAbi;
 use rustc_trait_selection::traits;
 
@@ -186,16 +187,27 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
     type MemoryKind = !;
 
     #[inline(always)]
-    fn enforce_alignment(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
+    fn enforce_alignment(_ecx: &InterpCx<'mir, 'tcx, Self>) -> CheckAlignment {
         // We do not check for alignment to avoid having to carry an `Align`
         // in `ConstValue::ByRef`.
-        false
+        CheckAlignment::No
     }
 
     #[inline(always)]
     fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
         false // for now, we don't enforce validity
     }
+    fn alignment_check_failed(
+        ecx: &InterpCx<'mir, 'tcx, Self>,
+        _has: Align,
+        _required: Align,
+        _check: CheckAlignment,
+    ) -> InterpResult<'tcx, ()> {
+        span_bug!(
+            ecx.cur_span(),
+            "`alignment_check_failed` called when no alignment check requested"
+        )
+    }
 
     fn load_mir(
         _ecx: &InterpCx<'mir, 'tcx, Self>,
index e9027387413cfe1e97425a7992e74e33384fbfb3..c75fe2327de3eb0b52e35f0cbebfe02fc9282838 100644 (file)
@@ -2,6 +2,7 @@
 //!
 //! Currently, this pass only propagates scalar values.
 
+use rustc_const_eval::const_eval::CheckAlignment;
 use rustc_const_eval::interpret::{ConstValue, ImmTy, Immediate, InterpCx, Scalar};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_middle::mir::visit::{MutVisitor, Visitor};
@@ -10,6 +11,7 @@
 use rustc_mir_dataflow::value_analysis::{Map, State, TrackElem, ValueAnalysis, ValueOrPlace};
 use rustc_mir_dataflow::{lattice::FlatSet, Analysis, ResultsVisitor, SwitchIntEdgeEffects};
 use rustc_span::DUMMY_SP;
+use rustc_target::abi::Align;
 
 use crate::MirPass;
 
@@ -448,13 +450,21 @@ impl<'mir, 'tcx> rustc_const_eval::interpret::Machine<'mir, 'tcx> for DummyMachi
     type MemoryKind = !;
     const PANIC_ON_ALLOC_FAIL: bool = true;
 
-    fn enforce_alignment(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
+    fn enforce_alignment(_ecx: &InterpCx<'mir, 'tcx, Self>) -> CheckAlignment {
         unimplemented!()
     }
 
     fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
         unimplemented!()
     }
+    fn alignment_check_failed(
+        _ecx: &InterpCx<'mir, 'tcx, Self>,
+        _has: Align,
+        _required: Align,
+        _check: CheckAlignment,
+    ) -> interpret::InterpResult<'tcx, ()> {
+        unimplemented!()
+    }
 
     fn find_mir_or_eval_fn(
         _ecx: &mut InterpCx<'mir, 'tcx, Self>,
index 97485c4f57b12ea872de807daf68c6ca9fe7ec8a..3e45319431cec0e9de6816ed78310c892d09d461 100644 (file)
 use crate::MirPass;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_index::bit_set::BitSet;
+use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
 use rustc_middle::mir::{dump_mir, PassWhere};
 use rustc_middle::mir::{
     traversal, BasicBlock, Body, InlineAsmOperand, Local, LocalKind, Location, Operand, Place,
     Rvalue, Statement, StatementKind, TerminatorKind,
 };
-use rustc_middle::mir::{
-    visit::{MutVisitor, PlaceContext, Visitor},
-    ProjectionElem,
-};
 use rustc_middle::ty::TyCtxt;
 use rustc_mir_dataflow::impls::MaybeLiveLocals;
 use rustc_mir_dataflow::{Analysis, ResultsCursor};
@@ -359,40 +356,45 @@ struct FilterInformation<'a, 'body, 'alloc, 'tcx> {
 // through these methods, and not directly.
 impl<'alloc> Candidates<'alloc> {
     /// Just `Vec::retain`, but the condition is inverted and we add debugging output
-    fn vec_remove_debug(
+    fn vec_filter_candidates(
         src: Local,
         v: &mut Vec<Local>,
-        mut f: impl FnMut(Local) -> bool,
+        mut f: impl FnMut(Local) -> CandidateFilter,
         at: Location,
     ) {
         v.retain(|dest| {
             let remove = f(*dest);
-            if remove {
+            if remove == CandidateFilter::Remove {
                 trace!("eliminating {:?} => {:?} due to conflict at {:?}", src, dest, at);
             }
-            !remove
+            remove == CandidateFilter::Keep
         });
     }
 
-    /// `vec_remove_debug` but for an `Entry`
-    fn entry_remove(
+    /// `vec_filter_candidates` but for an `Entry`
+    fn entry_filter_candidates(
         mut entry: OccupiedEntry<'_, Local, Vec<Local>>,
         p: Local,
-        f: impl FnMut(Local) -> bool,
+        f: impl FnMut(Local) -> CandidateFilter,
         at: Location,
     ) {
         let candidates = entry.get_mut();
-        Self::vec_remove_debug(p, candidates, f, at);
+        Self::vec_filter_candidates(p, candidates, f, at);
         if candidates.len() == 0 {
             entry.remove();
         }
     }
 
-    /// Removes all candidates `(p, q)` or `(q, p)` where `p` is the indicated local and `f(q)` is true.
-    fn remove_candidates_if(&mut self, p: Local, mut f: impl FnMut(Local) -> bool, at: Location) {
+    /// For all candidates `(p, q)` or `(q, p)` removes the candidate if `f(q)` says to do so
+    fn filter_candidates_by(
+        &mut self,
+        p: Local,
+        mut f: impl FnMut(Local) -> CandidateFilter,
+        at: Location,
+    ) {
         // Cover the cases where `p` appears as a `src`
         if let Entry::Occupied(entry) = self.c.entry(p) {
-            Self::entry_remove(entry, p, &mut f, at);
+            Self::entry_filter_candidates(entry, p, &mut f, at);
         }
         // And the cases where `p` appears as a `dest`
         let Some(srcs) = self.reverse.get_mut(&p) else {
@@ -401,18 +403,31 @@ fn remove_candidates_if(&mut self, p: Local, mut f: impl FnMut(Local) -> bool, a
         // We use `retain` here to remove the elements from the reverse set if we've removed the
         // matching candidate in the forward set.
         srcs.retain(|src| {
-            if !f(*src) {
+            if f(*src) == CandidateFilter::Keep {
                 return true;
             }
             let Entry::Occupied(entry) = self.c.entry(*src) else {
                 return false;
             };
-            Self::entry_remove(entry, *src, |dest| dest == p, at);
+            Self::entry_filter_candidates(
+                entry,
+                *src,
+                |dest| {
+                    if dest == p { CandidateFilter::Remove } else { CandidateFilter::Keep }
+                },
+                at,
+            );
             false
         });
     }
 }
 
+#[derive(Copy, Clone, PartialEq, Eq)]
+enum CandidateFilter {
+    Keep,
+    Remove,
+}
+
 impl<'a, 'body, 'alloc, 'tcx> FilterInformation<'a, 'body, 'alloc, 'tcx> {
     /// Filters the set of candidates to remove those that conflict.
     ///
@@ -460,7 +475,7 @@ fn internal_filter_liveness(&mut self) {
             for (i, statement) in data.statements.iter().enumerate().rev() {
                 self.at = Location { block, statement_index: i };
                 self.live.seek_after_primary_effect(self.at);
-                self.get_statement_write_info(&statement.kind);
+                self.write_info.for_statement(&statement.kind, self.body);
                 self.apply_conflicts();
             }
         }
@@ -469,80 +484,59 @@ fn internal_filter_liveness(&mut self) {
     fn apply_conflicts(&mut self) {
         let writes = &self.write_info.writes;
         for p in writes {
-            self.candidates.remove_candidates_if(
+            let other_skip = self.write_info.skip_pair.and_then(|(a, b)| {
+                if a == *p {
+                    Some(b)
+                } else if b == *p {
+                    Some(a)
+                } else {
+                    None
+                }
+            });
+            self.candidates.filter_candidates_by(
                 *p,
-                // It is possible that a local may be live for less than the
-                // duration of a statement This happens in the case of function
-                // calls or inline asm. Because of this, we also mark locals as
-                // conflicting when both of them are written to in the same
-                // statement.
-                |q| self.live.contains(q) || writes.contains(&q),
+                |q| {
+                    if Some(q) == other_skip {
+                        return CandidateFilter::Keep;
+                    }
+                    // It is possible that a local may be live for less than the
+                    // duration of a statement This happens in the case of function
+                    // calls or inline asm. Because of this, we also mark locals as
+                    // conflicting when both of them are written to in the same
+                    // statement.
+                    if self.live.contains(q) || writes.contains(&q) {
+                        CandidateFilter::Remove
+                    } else {
+                        CandidateFilter::Keep
+                    }
+                },
                 self.at,
             );
         }
     }
-
-    /// Gets the write info for the `statement`.
-    fn get_statement_write_info(&mut self, statement: &StatementKind<'tcx>) {
-        self.write_info.writes.clear();
-        match statement {
-            StatementKind::Assign(box (lhs, rhs)) => match rhs {
-                Rvalue::Use(op) => {
-                    if !lhs.is_indirect() {
-                        self.get_assign_use_write_info(*lhs, op);
-                        return;
-                    }
-                }
-                _ => (),
-            },
-            _ => (),
-        }
-
-        self.write_info.for_statement(statement);
-    }
-
-    fn get_assign_use_write_info(&mut self, lhs: Place<'tcx>, rhs: &Operand<'tcx>) {
-        // We register the writes for the operand unconditionally
-        self.write_info.add_operand(rhs);
-        // However, we cannot do the same thing for the `lhs` as that would always block the
-        // optimization. Instead, we consider removing candidates manually.
-        let Some(rhs) = rhs.place() else {
-            self.write_info.add_place(lhs);
-            return;
-        };
-        // Find out which candidate pair we should skip, if any
-        let Some((src, dest)) = places_to_candidate_pair(lhs, rhs, self.body) else {
-            self.write_info.add_place(lhs);
-            return;
-        };
-        self.candidates.remove_candidates_if(
-            lhs.local,
-            |other| {
-                // Check if this is the candidate pair that should not be removed
-                if (lhs.local == src && other == dest) || (lhs.local == dest && other == src) {
-                    return false;
-                }
-                // Otherwise, do the "standard" thing
-                self.live.contains(other)
-            },
-            self.at,
-        )
-    }
 }
 
 /// Describes where a statement/terminator writes to
 #[derive(Default, Debug)]
 struct WriteInfo {
     writes: Vec<Local>,
+    /// If this pair of locals is a candidate pair, completely skip processing it during this
+    /// statement. All other candidates are unaffected.
+    skip_pair: Option<(Local, Local)>,
 }
 
 impl WriteInfo {
-    fn for_statement<'tcx>(&mut self, statement: &StatementKind<'tcx>) {
+    fn for_statement<'tcx>(&mut self, statement: &StatementKind<'tcx>, body: &Body<'tcx>) {
+        self.reset();
         match statement {
             StatementKind::Assign(box (lhs, rhs)) => {
                 self.add_place(*lhs);
                 match rhs {
-                    Rvalue::Use(op) | Rvalue::Repeat(op, _) => {
+                    Rvalue::Use(op) => {
+                        self.add_operand(op);
+                        self.consider_skipping_for_assign_use(*lhs, op, body);
+                    }
+                    Rvalue::Repeat(op, _) => {
                         self.add_operand(op);
                     }
                     Rvalue::Cast(_, op, _)
@@ -586,8 +580,22 @@ fn for_statement<'tcx>(&mut self, statement: &StatementKind<'tcx>) {
         }
     }
 
+    fn consider_skipping_for_assign_use<'tcx>(
+        &mut self,
+        lhs: Place<'tcx>,
+        rhs: &Operand<'tcx>,
+        body: &Body<'tcx>,
+    ) {
+        let Some(rhs) = rhs.place() else {
+            return
+        };
+        if let Some(pair) = places_to_candidate_pair(lhs, rhs, body) {
+            self.skip_pair = Some(pair);
+        }
+    }
+
     fn for_terminator<'tcx>(&mut self, terminator: &TerminatorKind<'tcx>) {
-        self.writes.clear();
+        self.reset();
         match terminator {
             TerminatorKind::SwitchInt { discr: op, .. }
             | TerminatorKind::Assert { cond: op, .. } => {
@@ -657,15 +665,16 @@ fn add_operand<'tcx>(&mut self, op: &Operand<'tcx>) {
             Operand::Copy(_) | Operand::Constant(_) => (),
         }
     }
+
+    fn reset(&mut self) {
+        self.writes.clear();
+        self.skip_pair = None;
+    }
 }
 
 /////////////////////////////////////////////////////
 // Candidate accumulation
 
-fn is_constant<'tcx>(place: Place<'tcx>) -> bool {
-    place.projection.iter().all(|p| !matches!(p, ProjectionElem::Deref | ProjectionElem::Index(_)))
-}
-
 /// If the pair of places is being considered for merging, returns the candidate which would be
 /// merged in order to accomplish this.
 ///
@@ -741,10 +750,6 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, _: Location) {
             Rvalue::Use(Operand::Copy(rhs) | Operand::Move(rhs)),
         )) = &statement.kind
         {
-            if !is_constant(*lhs) || !is_constant(*rhs) {
-                return;
-            }
-
             let Some((src, dest)) = places_to_candidate_pair(*lhs, *rhs, self.body) else {
                 return;
             };
index ef7589d3ef2315f9bbf21e9c880c5f03e4e39122..9d560f5c837e2d75e75f6899d65199bdef8fe710 100644 (file)
@@ -849,7 +849,7 @@ fn visit_projection_elem(
             };
 
             let kind = match parent_ty.ty.kind() {
-                &ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs }) => {
+                &ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
                     self.tcx.bound_type_of(def_id).subst(self.tcx, substs).kind()
                 }
                 kind => kind,
index f92a0e826dcdfb6dcf55e264235d07e360a5137f..f8b55c862875e06796968c7cc1bbc0d9de190570 100644 (file)
@@ -336,8 +336,7 @@ fn new(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -> Self {
         // we must subst the self_ty because it's
         // otherwise going to be TySelf and we can't index
         // or access fields of a Place of type TySelf.
-        let substs = tcx.mk_substs_trait(self_ty, []);
-        let sig = tcx.bound_fn_sig(def_id).subst(tcx, substs);
+        let sig = tcx.bound_fn_sig(def_id).subst(tcx, &[self_ty.into()]);
         let sig = tcx.erase_late_bound_regions(sig);
         let span = tcx.def_span(def_id);
 
@@ -417,10 +416,8 @@ fn make_clone_call(
     ) {
         let tcx = self.tcx;
 
-        let substs = tcx.mk_substs_trait(ty, []);
-
         // `func == Clone::clone(&ty) -> ty`
-        let func_ty = tcx.mk_fn_def(self.def_id, substs);
+        let func_ty = tcx.mk_fn_def(self.def_id, [ty]);
         let func = Operand::Constant(Box::new(Constant {
             span: self.span,
             user_ty: None,
@@ -575,9 +572,8 @@ fn build_call_shim<'tcx>(
 
         // Create substitutions for the `Self` and `Args` generic parameters of the shim body.
         let arg_tup = tcx.mk_tup(untuple_args.iter());
-        let sig_substs = tcx.mk_substs_trait(ty, [ty::subst::GenericArg::from(arg_tup)]);
 
-        (Some(sig_substs), Some(untuple_args))
+        (Some([ty.into(), arg_tup.into()]), Some(untuple_args))
     } else {
         (None, None)
     };
@@ -588,7 +584,7 @@ fn build_call_shim<'tcx>(
 
     assert_eq!(sig_substs.is_some(), !instance.has_polymorphic_mir_body());
     let mut sig =
-        if let Some(sig_substs) = sig_substs { sig.subst(tcx, sig_substs) } else { sig.0 };
+        if let Some(sig_substs) = sig_substs { sig.subst(tcx, &sig_substs) } else { sig.0 };
 
     if let CallKind::Indirect(fnty) = call_kind {
         // `sig` determines our local decls, and thus the callee type in the `Call` terminator. This
index f1ca72de8dbe47d934cc8b8c197c5ed4b4d11ff7..f15cf54718e2b7221bbb70fb9261f36af32fd525 100644 (file)
@@ -77,3 +77,9 @@ pub struct SymbolAlreadyDefined {
     pub span: Option<Span>,
     pub symbol: String,
 }
+
+#[derive(Diagnostic)]
+#[diag(monomorphize_couldnt_dump_mono_stats)]
+pub struct CouldntDumpMonoStats {
+    pub error: String,
+}
index 932edc6675f5900cb6dd04d9678d7847345f0f9b..38e1d98e44e13f0d72af80666004b666fb21835c 100644 (file)
 mod default;
 mod merging;
 
+use std::cmp;
+use std::fs::{self, File};
+use std::io::{BufWriter, Write};
+use std::path::{Path, PathBuf};
+
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::sync;
 use rustc_hir::def_id::DefIdSet;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
+use rustc_session::config::SwitchWithOptPath;
 use rustc_span::symbol::Symbol;
 
 use crate::collector::InliningMap;
 use crate::collector::{self, MonoItemCollectionMode};
-use crate::errors::{SymbolAlreadyDefined, UnknownPartitionStrategy};
+use crate::errors::{CouldntDumpMonoStats, SymbolAlreadyDefined, UnknownPartitionStrategy};
 
 pub struct PartitioningCx<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
@@ -411,6 +417,15 @@ fn collect_and_partition_mono_items<'tcx>(
         })
         .collect();
 
+    // Output monomorphization stats per def_id
+    if let SwitchWithOptPath::Enabled(ref path) = tcx.sess.opts.unstable_opts.dump_mono_stats {
+        if let Err(err) =
+            dump_mono_items_stats(tcx, &codegen_units, path, tcx.sess.opts.crate_name.as_deref())
+        {
+            tcx.sess.emit_fatal(CouldntDumpMonoStats { error: err.to_string() });
+        }
+    }
+
     if tcx.sess.opts.unstable_opts.print_mono_items.is_some() {
         let mut item_to_cgus: FxHashMap<_, Vec<_>> = Default::default();
 
@@ -465,6 +480,67 @@ fn collect_and_partition_mono_items<'tcx>(
     (tcx.arena.alloc(mono_items), codegen_units)
 }
 
+/// Outputs stats about instantation counts and estimated size, per `MonoItem`'s
+/// def, to a file in the given output directory.
+fn dump_mono_items_stats<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    codegen_units: &[CodegenUnit<'tcx>],
+    output_directory: &Option<PathBuf>,
+    crate_name: Option<&str>,
+) -> Result<(), Box<dyn std::error::Error>> {
+    let output_directory = if let Some(ref directory) = output_directory {
+        fs::create_dir_all(directory)?;
+        directory
+    } else {
+        Path::new(".")
+    };
+
+    let filename = format!("{}.mono_items.md", crate_name.unwrap_or("unknown-crate"));
+    let output_path = output_directory.join(&filename);
+    let file = File::create(output_path)?;
+    let mut file = BufWriter::new(file);
+
+    // Gather instantiated mono items grouped by def_id
+    let mut items_per_def_id: FxHashMap<_, Vec<_>> = Default::default();
+    for cgu in codegen_units {
+        for (&mono_item, _) in cgu.items() {
+            // Avoid variable-sized compiler-generated shims
+            if mono_item.is_user_defined() {
+                items_per_def_id.entry(mono_item.def_id()).or_default().push(mono_item);
+            }
+        }
+    }
+
+    // Output stats sorted by total instantiated size, from heaviest to lightest
+    let mut stats: Vec<_> = items_per_def_id
+        .into_iter()
+        .map(|(def_id, items)| {
+            let instantiation_count = items.len();
+            let size_estimate = items[0].size_estimate(tcx);
+            let total_estimate = instantiation_count * size_estimate;
+            (def_id, instantiation_count, size_estimate, total_estimate)
+        })
+        .collect();
+    stats.sort_unstable_by_key(|(_, _, _, total_estimate)| cmp::Reverse(*total_estimate));
+
+    if !stats.is_empty() {
+        writeln!(
+            file,
+            "| Item | Instantiation count | Estimated Cost Per Instantiation | Total Estimated Cost |"
+        )?;
+        writeln!(file, "| --- | ---: | ---: | ---: |")?;
+        for (def_id, instantiation_count, size_estimate, total_estimate) in stats {
+            let item = with_no_trimmed_paths!(tcx.def_path_str(def_id));
+            writeln!(
+                file,
+                "| {item} | {instantiation_count} | {size_estimate} | {total_estimate} |"
+            )?;
+        }
+    }
+
+    Ok(())
+}
+
 fn codegened_and_inlined_items<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> &'tcx DefIdSet {
     let (items, cgus) = tcx.collect_and_partition_mono_items(());
     let mut visited = DefIdSet::default();
index d80c05d6b38268d734924a5b7d5a95732eb3be40..72d38aeac7a0c0647f176fe451143d3cc1611354 100644 (file)
@@ -110,26 +110,25 @@ impl<'tcx, V> DefIdVisitorSkeleton<'_, 'tcx, V>
     V: DefIdVisitor<'tcx> + ?Sized,
 {
     fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> ControlFlow<V::BreakTy> {
-        let TraitRef { def_id, substs } = trait_ref;
+        let TraitRef { def_id, substs, .. } = trait_ref;
         self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref.print_only_trait_path())?;
         if self.def_id_visitor.shallow() { ControlFlow::CONTINUE } else { substs.visit_with(self) }
     }
 
     fn visit_projection_ty(&mut self, projection: ty::AliasTy<'tcx>) -> ControlFlow<V::BreakTy> {
         let tcx = self.def_id_visitor.tcx();
-        let (trait_ref, assoc_substs) = if tcx.def_kind(projection.def_id)
-            != DefKind::ImplTraitPlaceholder
-        {
-            projection.trait_ref_and_own_substs(tcx)
-        } else {
-            // HACK(RPITIT): Remove this when RPITITs are lowered to regular assoc tys
-            let def_id = tcx.impl_trait_in_trait_parent(projection.def_id);
-            let trait_generics = tcx.generics_of(def_id);
-            (
-                ty::TraitRef { def_id, substs: projection.substs.truncate_to(tcx, trait_generics) },
-                &projection.substs[trait_generics.count()..],
-            )
-        };
+        let (trait_ref, assoc_substs) =
+            if tcx.def_kind(projection.def_id) != DefKind::ImplTraitPlaceholder {
+                projection.trait_ref_and_own_substs(tcx)
+            } else {
+                // HACK(RPITIT): Remove this when RPITITs are lowered to regular assoc tys
+                let def_id = tcx.impl_trait_in_trait_parent(projection.def_id);
+                let trait_generics = tcx.generics_of(def_id);
+                (
+                    tcx.mk_trait_ref(def_id, projection.substs.truncate_to(tcx, trait_generics)),
+                    &projection.substs[trait_generics.count()..],
+                )
+            };
         self.visit_trait(trait_ref)?;
         if self.def_id_visitor.shallow() {
             ControlFlow::CONTINUE
@@ -235,7 +234,7 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<V::BreakTy> {
                     self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref)?;
                 }
             }
-            ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs: _ }) => {
+            ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => {
                 // Skip repeated `Opaque`s to avoid infinite recursion.
                 if self.visited_opaque_tys.insert(def_id) {
                     // The intent is to treat `impl Trait1 + Trait2` identically to
index 7a20eaceba0247682a7ae74451ddcbf3eeeb7772..cf2f04c7486b846c0609109998fc8daedc75b8db 100644 (file)
@@ -49,7 +49,7 @@ pub struct Cycle {
     #[primary_span]
     pub span: Span,
     pub stack_bottom: String,
-    #[subdiagnostic(eager)]
+    #[subdiagnostic]
     pub cycle_stack: Vec<CycleStack>,
     #[subdiagnostic]
     pub stack_count: StackCount,
index 6de564a3a069225ebee1f06be5418c9de0e1cac1..3bafd3730bd79d2db4cb31d95bda50d7e756a492 100644 (file)
@@ -875,18 +875,12 @@ pub struct PacRet {
     pub key: PAuthKey,
 }
 
-#[derive(Clone, Copy, Hash, Debug, PartialEq)]
+#[derive(Clone, Copy, Hash, Debug, PartialEq, Default)]
 pub struct BranchProtection {
     pub bti: bool,
     pub pac_ret: Option<PacRet>,
 }
 
-impl Default for BranchProtection {
-    fn default() -> Self {
-        BranchProtection { bti: false, pac_ret: None }
-    }
-}
-
 pub const fn default_lib_output() -> CrateType {
     CrateType::Rlib
 }
@@ -1875,7 +1869,7 @@ fn parse_opt_level(
         .into_iter()
         .flat_map(|(i, s)| {
             // NB: This can match a string without `=`.
-            if let Some("opt-level") = s.splitn(2, '=').next() { Some(i) } else { None }
+            if let Some("opt-level") = s.split('=').next() { Some(i) } else { None }
         })
         .max();
     if max_o > max_c {
@@ -1912,7 +1906,7 @@ fn select_debuginfo(
         .into_iter()
         .flat_map(|(i, s)| {
             // NB: This can match a string without `=`.
-            if let Some("debuginfo") = s.splitn(2, '=').next() { Some(i) } else { None }
+            if let Some("debuginfo") = s.split('=').next() { Some(i) } else { None }
         })
         .max();
     if max_g > max_c {
index 4266430c4c68067788d1f2af53e96f2ed4d88fd1..25d84506efaf0df5477c34bbab0392fc5b9fa20a 100644 (file)
@@ -176,7 +176,7 @@ pub fn surrounding(s: Span) -> Self {
 #[derive(Diagnostic)]
 #[diag(session_skipping_const_checks)]
 pub struct SkippingConstChecks {
-    #[subdiagnostic(eager)]
+    #[subdiagnostic]
     pub unleashed_features: Vec<UnleashedFeatureHelp>,
 }
 
index dab9c736d14d59d496f8bbed8b2e2d52f57a5980..9e130287104f9b1edd38a3d47e3dc11701c14e7f 100644 (file)
@@ -1294,6 +1294,9 @@ pub(crate) fn parse_proc_macro_execution_strategy(
         computed `block` spans (one span encompassing a block's terminator and \
         all statements). If `-Z instrument-coverage` is also enabled, create \
         an additional `.html` file showing the computed coverage spans."),
+    dump_mono_stats: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
+        parse_switch_with_opt_path, [UNTRACKED],
+        "output statistics about monomorphization collection (format: markdown)"),
     dwarf_version: Option<u32> = (None, parse_opt_number, [TRACKED],
         "version of DWARF debug information to emit (default: 2 or 4, depending on platform)"),
     dylib_lto: bool = (false, parse_bool, [UNTRACKED],
index d3c2c5113bcdec663f1b00fb9d873d316d7bccae..26cd54210d0bbb9c33134c7876269f4f7a336006 100644 (file)
@@ -175,7 +175,7 @@ unsafe fn analyze_source_file_sse2(src: &str,
             // There might still be a tail left to analyze
             let tail_start = chunk_count * CHUNK_SIZE + intra_chunk_offset;
             if tail_start < src.len() {
-                analyze_source_file_generic(&src[tail_start as usize ..],
+                analyze_source_file_generic(&src[tail_start ..],
                                         src.len() - tail_start,
                                         output_offset + BytePos::from_usize(tail_start),
                                         lines,
@@ -219,7 +219,7 @@ fn analyze_source_file_generic(
     while i < scan_len {
         let byte = unsafe {
             // We verified that i < scan_len <= src.len()
-            *src_bytes.get_unchecked(i as usize)
+            *src_bytes.get_unchecked(i)
         };
 
         // How much to advance in order to get to the next UTF-8 char in the
index 335bfc3302f27c34bd0dada4f2e93840574a55f0..2181c090027b535819aec1eb8afeb1851c0f4841 100644 (file)
@@ -259,6 +259,10 @@ pub fn to_string_lossy(&self, display_pref: FileNameDisplayPreference) -> Cow<'_
             FileNameDisplayPreference::Remapped => {
                 self.remapped_path_if_available().to_string_lossy()
             }
+            FileNameDisplayPreference::Short => self
+                .local_path_if_available()
+                .file_name()
+                .map_or_else(|| "".into(), |f| f.to_string_lossy()),
         }
     }
 }
@@ -302,6 +306,9 @@ pub enum FileNameDisplayPreference {
     /// Display the path before the application of rewrite rules provided via `--remap-path-prefix`.
     /// This is appropriate for use in user-facing output (such as diagnostics).
     Local,
+    /// Display only the filename, as a way to reduce the verbosity of the output.
+    /// This is appropriate for use in user-facing output (such as diagnostics).
+    Short,
 }
 
 pub struct FileNameDisplay<'a> {
@@ -1381,7 +1388,7 @@ fn encode(&self, s: &mut S) {
                     4 => {
                         raw_diffs = Vec::with_capacity(bytes_per_diff * num_diffs);
                         for diff in diff_iter {
-                            raw_diffs.extend_from_slice(&(diff.0 as u32).to_le_bytes());
+                            raw_diffs.extend_from_slice(&(diff.0).to_le_bytes());
                         }
                     }
                     _ => unreachable!(),
index a4e0f54d27670d474a8e96a5db415c25ae090b3d..d9c87ac0ba82bfb6ecb0c9b3991dc6dee752ea44 100644 (file)
@@ -438,7 +438,11 @@ pub fn lookup_line(&self, pos: BytePos) -> Result<SourceFileAndLine, Lrc<SourceF
         }
     }
 
-    fn span_to_string(&self, sp: Span, filename_display_pref: FileNameDisplayPreference) -> String {
+    pub fn span_to_string(
+        &self,
+        sp: Span,
+        filename_display_pref: FileNameDisplayPreference,
+    ) -> String {
         if self.files.borrow().source_files.is_empty() || sp.is_dummy() {
             return "no-location".to_string();
         }
@@ -446,12 +450,15 @@ fn span_to_string(&self, sp: Span, filename_display_pref: FileNameDisplayPrefere
         let lo = self.lookup_char_pos(sp.lo());
         let hi = self.lookup_char_pos(sp.hi());
         format!(
-            "{}:{}:{}: {}:{}",
+            "{}:{}:{}{}",
             lo.file.name.display(filename_display_pref),
             lo.line,
             lo.col.to_usize() + 1,
-            hi.line,
-            hi.col.to_usize() + 1,
+            if let FileNameDisplayPreference::Short = filename_display_pref {
+                String::new()
+            } else {
+                format!(": {}:{}", hi.line, hi.col.to_usize() + 1)
+            }
         )
     }
 
@@ -941,7 +948,7 @@ pub fn next_point(&self, sp: Span) -> Span {
     /// Otherwise, the span reached to limit is returned.
     pub fn span_look_ahead(&self, span: Span, expect: Option<&str>, limit: Option<usize>) -> Span {
         let mut sp = span;
-        for _ in 0..limit.unwrap_or(100 as usize) {
+        for _ in 0..limit.unwrap_or(100_usize) {
             sp = self.next_point(sp);
             if let Ok(ref snippet) = self.span_to_snippet(sp) {
                 if expect.map_or(false, |es| snippet == es) {
index 281b2d88f483bd66bd16e2994fad7df908f79619..a59c9011ab21a4116e4452b206392781e0ab0e25 100644 (file)
@@ -216,7 +216,7 @@ fn print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> {
         match *ty.kind() {
             // Print all nominal types as paths (unlike `pretty_print_type`).
             ty::FnDef(def_id, substs)
-            | ty::Alias(_, ty::AliasTy { def_id, substs })
+            | ty::Alias(_, ty::AliasTy { def_id, substs, .. })
             | ty::Closure(def_id, substs)
             | ty::Generator(def_id, substs, _) => self.print_def_path(def_id, substs),
 
index b7f055d9146a05c30dc41af17d8c5ebe0e34c938..4285aa62cb96307991169be15b067839e36c2686 100644 (file)
@@ -439,7 +439,7 @@ fn print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> {
             // Mangle all nominal types as paths.
             ty::Adt(ty::AdtDef(Interned(&ty::AdtDefData { did: def_id, .. }, _)), substs)
             | ty::FnDef(def_id, substs)
-            | ty::Alias(_, ty::AliasTy { def_id, substs })
+            | ty::Alias(_, ty::AliasTy { def_id, substs, .. })
             | ty::Closure(def_id, substs)
             | ty::Generator(def_id, substs, _) => {
                 self = self.print_def_path(def_id, substs)?;
index fc6a2edabb763c89de1dad368dfecf7b17154b2a..44644c4733e8726b33c886394631744352af4a04 100644 (file)
@@ -81,7 +81,7 @@ fn pre_link_args(os: &'static str, arch: Arch, abi: &'static str) -> LinkArgs {
         _ => os.into(),
     };
 
-    let platform_version: StaticCow<str> = match os.as_ref() {
+    let platform_version: StaticCow<str> = match os {
         "ios" => ios_lld_platform_version(),
         "tvos" => tvos_lld_platform_version(),
         "watchos" => watchos_lld_platform_version(),
index e3eb9bccd5ed78d5001471c83cec143a3586d02c..34934379c7e84a468abfe4995612c6bbb80aa579 100644 (file)
@@ -5,12 +5,7 @@ pub fn target() -> Target {
     base.max_atomic_width = Some(64);
     base.add_pre_link_args(
         LinkerFlavor::Unix(Cc::No),
-        &[
-            "-b64".into(),
-            "-bpT:0x100000000".into(),
-            "-bpD:0x110000000".into(),
-            "-bcdtors:all:0:s".into(),
-        ],
+        &["-b64", "-bpT:0x100000000", "-bpD:0x110000000", "-bcdtors:all:0:s"],
     );
 
     Target {
index 752b53fbc3f9a2011c5cfa90afc2e32d2fbfb8b0..0c1717cff332c40e79bede7a633994be3c054155 100644 (file)
 use rustc_hir::def_id::DefId;
-use rustc_infer::infer::InferCtxt;
+use rustc_infer::infer::{InferCtxt, LateBoundRegionConversionTime};
+use rustc_infer::traits::util::elaborate_predicates_with_span;
 use rustc_infer::traits::{Obligation, ObligationCause, TraitObligation};
-use rustc_span::DUMMY_SP;
+use rustc_middle::ty;
+use rustc_span::{Span, DUMMY_SP};
 
 use crate::traits::ObligationCtxt;
 
+pub enum Ambiguity {
+    DefId(DefId),
+    ParamEnv(Span),
+}
+
 pub fn recompute_applicable_impls<'tcx>(
     infcx: &InferCtxt<'tcx>,
     obligation: &TraitObligation<'tcx>,
-) -> Vec<DefId> {
+) -> Vec<Ambiguity> {
     let tcx = infcx.tcx;
     let param_env = obligation.param_env;
-    let dummy_cause = ObligationCause::dummy();
+
     let impl_may_apply = |impl_def_id| {
         let ocx = ObligationCtxt::new_in_snapshot(infcx);
         let placeholder_obligation =
             infcx.replace_bound_vars_with_placeholders(obligation.predicate);
         let obligation_trait_ref =
-            ocx.normalize(&dummy_cause, param_env, placeholder_obligation.trait_ref);
+            ocx.normalize(&ObligationCause::dummy(), param_env, placeholder_obligation.trait_ref);
 
         let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id);
         let impl_trait_ref = tcx.bound_impl_trait_ref(impl_def_id).unwrap().subst(tcx, impl_substs);
         let impl_trait_ref = ocx.normalize(&ObligationCause::dummy(), param_env, impl_trait_ref);
 
-        if let Err(_) = ocx.eq(&dummy_cause, param_env, obligation_trait_ref, impl_trait_ref) {
+        if let Err(_) =
+            ocx.eq(&ObligationCause::dummy(), param_env, obligation_trait_ref, impl_trait_ref)
+        {
             return false;
         }
 
         let impl_predicates = tcx.predicates_of(impl_def_id).instantiate(tcx, impl_substs);
-        ocx.register_obligations(
-            impl_predicates
-                .predicates
-                .iter()
-                .map(|&predicate| Obligation::new(tcx, dummy_cause.clone(), param_env, predicate)),
+        ocx.register_obligations(impl_predicates.predicates.iter().map(|&predicate| {
+            Obligation::new(tcx, ObligationCause::dummy(), param_env, predicate)
+        }));
+
+        ocx.select_where_possible().is_empty()
+    };
+
+    let param_env_candidate_may_apply = |poly_trait_predicate: ty::PolyTraitPredicate<'tcx>| {
+        let ocx = ObligationCtxt::new_in_snapshot(infcx);
+        let placeholder_obligation =
+            infcx.replace_bound_vars_with_placeholders(obligation.predicate);
+        let obligation_trait_ref =
+            ocx.normalize(&ObligationCause::dummy(), param_env, placeholder_obligation.trait_ref);
+
+        let param_env_predicate = infcx.replace_bound_vars_with_fresh_vars(
+            DUMMY_SP,
+            LateBoundRegionConversionTime::HigherRankedType,
+            poly_trait_predicate,
         );
+        let param_env_trait_ref =
+            ocx.normalize(&ObligationCause::dummy(), param_env, param_env_predicate.trait_ref);
+
+        if let Err(_) =
+            ocx.eq(&ObligationCause::dummy(), param_env, obligation_trait_ref, param_env_trait_ref)
+        {
+            return false;
+        }
 
         ocx.select_where_possible().is_empty()
     };
 
-    let mut impls = Vec::new();
+    let mut ambiguities = Vec::new();
+
     tcx.for_each_relevant_impl(
         obligation.predicate.def_id(),
         obligation.predicate.skip_binder().trait_ref.self_ty(),
         |impl_def_id| {
-            if infcx.probe(move |_snapshot| impl_may_apply(impl_def_id)) {
-                impls.push(impl_def_id)
+            if infcx.probe(|_| impl_may_apply(impl_def_id)) {
+                ambiguities.push(Ambiguity::DefId(impl_def_id))
             }
         },
     );
-    impls
+
+    let predicates =
+        tcx.predicates_of(obligation.cause.body_id.owner.to_def_id()).instantiate_identity(tcx);
+    for obligation in
+        elaborate_predicates_with_span(tcx, std::iter::zip(predicates.predicates, predicates.spans))
+    {
+        let kind = obligation.predicate.kind();
+        if let ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) = kind.skip_binder()
+            && param_env_candidate_may_apply(kind.rebind(trait_pred))
+        {
+            if kind.rebind(trait_pred.trait_ref) == ty::TraitRef::identity(tcx, trait_pred.def_id()) {
+                ambiguities.push(Ambiguity::ParamEnv(tcx.def_span(trait_pred.def_id())))
+            } else {
+                ambiguities.push(Ambiguity::ParamEnv(obligation.cause.span))
+            }
+        }
+    }
+
+    ambiguities
 }
index 8ee31e4b498af42b1f5bf32f55759cb8928e2428..2dd2c568bab97be6f3a78f2cd894ba695adadeec 100644 (file)
@@ -35,7 +35,7 @@
 use rustc_middle::ty::abstract_const::NotConstEvaluatable;
 use rustc_middle::ty::error::ExpectedFound;
 use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
-use rustc_middle::ty::print::{FmtPrinter, Print};
+use rustc_middle::ty::print::{with_forced_trimmed_paths, FmtPrinter, Print};
 use rustc_middle::ty::{
     self, SubtypePredicate, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeFoldable,
     TypeVisitable,
@@ -1036,7 +1036,7 @@ fn report_selection_error(
                             && self.fallback_has_occurred
                         {
                             let predicate = trait_predicate.map_bound(|trait_pred| {
-                                trait_pred.with_self_type(self.tcx, self.tcx.mk_unit())
+                                trait_pred.with_self_ty(self.tcx, self.tcx.mk_unit())
                             });
                             let unit_obligation = obligation.with(tcx, predicate);
                             if self.predicate_may_hold(&unit_obligation) {
@@ -1487,7 +1487,7 @@ fn suggest_unsized_bound_if_applicable(
     fn annotate_source_of_ambiguity(
         &self,
         err: &mut Diagnostic,
-        impls: &[DefId],
+        impls: &[ambiguity::Ambiguity],
         predicate: ty::Predicate<'tcx>,
     );
 
@@ -1636,17 +1636,30 @@ fn report_projection_error(
                     infer::LateBoundRegionConversionTime::HigherRankedType,
                     bound_predicate.rebind(data),
                 );
-                let normalized_ty = ocx.normalize(
-                    &obligation.cause,
-                    obligation.param_env,
-                    self.tcx.mk_projection(data.projection_ty.def_id, data.projection_ty.substs),
-                );
+                let unnormalized_term = match data.term.unpack() {
+                    ty::TermKind::Ty(_) => self
+                        .tcx
+                        .mk_projection(data.projection_ty.def_id, data.projection_ty.substs)
+                        .into(),
+                    ty::TermKind::Const(ct) => self
+                        .tcx
+                        .mk_const(
+                            ty::UnevaluatedConst {
+                                def: ty::WithOptConstParam::unknown(data.projection_ty.def_id),
+                                substs: data.projection_ty.substs,
+                            },
+                            ct.ty(),
+                        )
+                        .into(),
+                };
+                let normalized_term =
+                    ocx.normalize(&obligation.cause, obligation.param_env, unnormalized_term);
 
                 debug!(?obligation.cause, ?obligation.param_env);
 
-                debug!(?normalized_ty, data.ty = ?data.term);
+                debug!(?normalized_term, data.ty = ?data.term);
 
-                let is_normalized_ty_expected = !matches!(
+                let is_normalized_term_expected = !matches!(
                     obligation.cause.code().peel_derives(),
                     ObligationCauseCode::ItemObligation(_)
                         | ObligationCauseCode::BindingObligation(_, _)
@@ -1655,7 +1668,6 @@ fn report_projection_error(
                         | ObligationCauseCode::ObjectCastObligation(..)
                         | ObligationCauseCode::OpaqueType
                 );
-                let expected_ty = data.term.ty().unwrap_or_else(|| self.tcx.ty_error());
 
                 // constrain inference variables a bit more to nested obligations from normalize so
                 // we can have more helpful errors.
@@ -1664,11 +1676,11 @@ fn report_projection_error(
                 if let Err(new_err) = ocx.eq_exp(
                     &obligation.cause,
                     obligation.param_env,
-                    is_normalized_ty_expected,
-                    normalized_ty,
-                    expected_ty,
+                    is_normalized_term_expected,
+                    normalized_term,
+                    data.term,
                 ) {
-                    (Some((data, is_normalized_ty_expected, normalized_ty, expected_ty)), new_err)
+                    (Some((data, is_normalized_term_expected, normalized_term, data.term)), new_err)
                 } else {
                     (None, error.err)
                 }
@@ -1677,12 +1689,8 @@ fn report_projection_error(
             };
 
             let msg = values
-                .and_then(|(predicate, _, normalized_ty, expected_ty)| {
-                    self.maybe_detailed_projection_msg(
-                        predicate,
-                        normalized_ty.into(),
-                        expected_ty.into(),
-                    )
+                .and_then(|(predicate, _, normalized_term, expected_term)| {
+                    self.maybe_detailed_projection_msg(predicate, normalized_term, expected_term)
                 })
                 .unwrap_or_else(|| format!("type mismatch resolving `{}`", predicate));
             let mut diag = struct_span_err!(self.tcx.sess, obligation.cause.span, E0271, "{msg}");
@@ -1749,21 +1757,26 @@ fn maybe_detailed_projection_msg(
         let trait_def_id = pred.projection_ty.trait_def_id(self.tcx);
         let self_ty = pred.projection_ty.self_ty();
 
-        if Some(pred.projection_ty.def_id) == self.tcx.lang_items().fn_once_output() {
-            Some(format!(
-                "expected `{self_ty}` to be a {fn_kind} that returns `{expected_ty}`, but it returns `{normalized_ty}`",
-                fn_kind = self_ty.prefix_string(self.tcx)
-            ))
-        } else if Some(trait_def_id) == self.tcx.lang_items().future_trait() {
-            Some(format!(
-                "expected `{self_ty}` to be a future that resolves to `{expected_ty}`, but it resolves to `{normalized_ty}`"
-            ))
-        } else if Some(trait_def_id) == self.tcx.get_diagnostic_item(sym::Iterator) {
-            Some(format!(
-                "expected `{self_ty}` to be an iterator that yields `{expected_ty}`, but it yields `{normalized_ty}`"
-            ))
-        } else {
-            None
+        with_forced_trimmed_paths! {
+            if Some(pred.projection_ty.def_id) == self.tcx.lang_items().fn_once_output() {
+                Some(format!(
+                    "expected `{self_ty}` to be a {fn_kind} that returns `{expected_ty}`, but it \
+                     returns `{normalized_ty}`",
+                    fn_kind = self_ty.prefix_string(self.tcx)
+                ))
+            } else if Some(trait_def_id) == self.tcx.lang_items().future_trait() {
+                Some(format!(
+                    "expected `{self_ty}` to be a future that resolves to `{expected_ty}`, but it \
+                     resolves to `{normalized_ty}`"
+                ))
+            } else if Some(trait_def_id) == self.tcx.get_diagnostic_item(sym::Iterator) {
+                Some(format!(
+                    "expected `{self_ty}` to be an iterator that yields `{expected_ty}`, but it \
+                     yields `{normalized_ty}`"
+                ))
+            } else {
+                None
+            }
         }
     }
 
@@ -2085,8 +2098,8 @@ fn mk_trait_obligation_with_new_self_ty(
         param_env: ty::ParamEnv<'tcx>,
         trait_ref_and_ty: ty::Binder<'tcx, (ty::TraitPredicate<'tcx>, Ty<'tcx>)>,
     ) -> PredicateObligation<'tcx> {
-        let trait_pred = trait_ref_and_ty
-            .map_bound(|(tr, new_self_ty)| tr.with_self_type(self.tcx, new_self_ty));
+        let trait_pred =
+            trait_ref_and_ty.map_bound(|(tr, new_self_ty)| tr.with_self_ty(self.tcx, new_self_ty));
 
         Obligation::new(self.tcx, ObligationCause::dummy(), param_env, trait_pred)
     }
@@ -2180,13 +2193,22 @@ fn maybe_report_ambiguity(
                 let mut selcx = SelectionContext::new(&self);
                 match selcx.select_from_obligation(&obligation) {
                     Ok(None) => {
-                        let impls = ambiguity::recompute_applicable_impls(self.infcx, &obligation);
+                        let ambiguities =
+                            ambiguity::recompute_applicable_impls(self.infcx, &obligation);
                         let has_non_region_infer =
                             trait_ref.skip_binder().substs.types().any(|t| !t.is_ty_infer());
                         // It doesn't make sense to talk about applicable impls if there are more
                         // than a handful of them.
-                        if impls.len() > 1 && impls.len() < 10 && has_non_region_infer {
-                            self.annotate_source_of_ambiguity(&mut err, &impls, predicate);
+                        if ambiguities.len() > 1 && ambiguities.len() < 10 && has_non_region_infer {
+                            if self.tainted_by_errors().is_some() && subst.is_none() {
+                                // If `subst.is_none()`, then this is probably two param-env
+                                // candidates or impl candidates that are equal modulo lifetimes.
+                                // Therefore, if we've already emitted an error, just skip this
+                                // one, since it's not particularly actionable.
+                                err.cancel();
+                                return;
+                            }
+                            self.annotate_source_of_ambiguity(&mut err, &ambiguities, predicate);
                         } else {
                             if self.tainted_by_errors().is_some() {
                                 err.cancel();
@@ -2435,21 +2457,30 @@ fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
     fn annotate_source_of_ambiguity(
         &self,
         err: &mut Diagnostic,
-        impls: &[DefId],
+        ambiguities: &[ambiguity::Ambiguity],
         predicate: ty::Predicate<'tcx>,
     ) {
         let mut spans = vec![];
         let mut crates = vec![];
         let mut post = vec![];
-        for def_id in impls {
-            match self.tcx.span_of_impl(*def_id) {
-                Ok(span) => spans.push(span),
-                Err(name) => {
-                    crates.push(name);
-                    if let Some(header) = to_pretty_impl_header(self.tcx, *def_id) {
-                        post.push(header);
+        let mut has_param_env = false;
+        for ambiguity in ambiguities {
+            match ambiguity {
+                ambiguity::Ambiguity::DefId(impl_def_id) => {
+                    match self.tcx.span_of_impl(*impl_def_id) {
+                        Ok(span) => spans.push(span),
+                        Err(name) => {
+                            crates.push(name);
+                            if let Some(header) = to_pretty_impl_header(self.tcx, *impl_def_id) {
+                                post.push(header);
+                            }
+                        }
                     }
                 }
+                ambiguity::Ambiguity::ParamEnv(span) => {
+                    has_param_env = true;
+                    spans.push(*span);
+                }
             }
         }
         let mut crate_names: Vec<_> = crates.iter().map(|n| format!("`{}`", n)).collect();
@@ -2473,7 +2504,11 @@ fn annotate_source_of_ambiguity(
             return;
         }
 
-        let msg = format!("multiple `impl`s satisfying `{}` found", predicate);
+        let msg = format!(
+            "multiple `impl`s{} satisfying `{}` found",
+            if has_param_env { " or `where` clauses" } else { "" },
+            predicate
+        );
         let post = if post.len() > 1 || (post.len() == 1 && post[0].contains('\n')) {
             format!(":\n{}", post.iter().map(|p| format!("- {}", p)).collect::<Vec<_>>().join("\n"),)
         } else if post.len() == 1 {
index 55a05df763fe621b73b54a91c9b32af1054481bf..057b0a368bf9b7f8ff48b3277d4e412791c4a497 100644 (file)
@@ -352,6 +352,14 @@ fn point_at_chain(
         param_env: ty::ParamEnv<'tcx>,
         err: &mut Diagnostic,
     );
+    fn probe_assoc_types_at_expr(
+        &self,
+        type_diffs: &[TypeError<'tcx>],
+        span: Span,
+        prev_ty: Ty<'tcx>,
+        body_id: hir::HirId,
+        param_env: ty::ParamEnv<'tcx>,
+    ) -> Vec<Option<(Span, (DefId, Ty<'tcx>))>>;
 }
 
 fn predicate_constraint(generics: &hir::Generics<'_>, pred: ty::Predicate<'_>) -> (Span, String) {
@@ -878,7 +886,7 @@ fn suggest_fn_call(
                     fn_sig.inputs().map_bound(|inputs| &inputs[1..]),
                 ))
             }
-            ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs }) => {
+            ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
                 self.tcx.bound_item_bounds(def_id).subst(self.tcx, substs).iter().find_map(|pred| {
                     if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = pred.kind().skip_binder()
                     && Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output()
@@ -1618,7 +1626,7 @@ fn suggest_impl_trait(
         let trait_obj = if has_dyn { &snippet[4..] } else { &snippet };
         if only_never_return {
             // No return paths, probably using `panic!()` or similar.
-            // Suggest `-> T`, `-> impl Trait`, and if `Trait` is object safe, `-> Box<dyn Trait>`.
+            // Suggest `-> impl Trait`, and if `Trait` is object safe, `-> Box<dyn Trait>`.
             suggest_trait_object_return_type_alternatives(
                 err,
                 ret_ty.span,
@@ -2540,6 +2548,25 @@ fn note_obligation_cause_code<T>(
             }
             ObligationCauseCode::SizedArgumentType(sp) => {
                 if let Some(span) = sp {
+                    if let ty::PredicateKind::Clause(clause) = predicate.kind().skip_binder()
+                        && let ty::Clause::Trait(trait_pred) = clause
+                        && let ty::Dynamic(..) = trait_pred.self_ty().kind()
+                    {
+                        let span = if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
+                            && snippet.starts_with("dyn ")
+                        {
+                            let pos = snippet.len() - snippet[3..].trim_start().len();
+                            span.with_hi(span.lo() + BytePos(pos as u32))
+                        } else {
+                            span.shrink_to_lo()
+                        };
+                        err.span_suggestion_verbose(
+                            span,
+                            "you can use `impl Trait` as the argument type",
+                            "impl ".to_string(),
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
                     err.span_suggestion_verbose(
                         span.shrink_to_lo(),
                         "function arguments must have a statically known size, borrowed types \
@@ -2662,7 +2689,7 @@ fn note_obligation_cause_code<T>(
                                 Some(ident) => err.span_note(ident.span, &msg),
                                 None => err.note(&msg),
                             },
-                            ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs: _ }) => {
+                            ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => {
                                 // Avoid printing the future from `core::future::identity_future`, it's not helpful
                                 if tcx.parent(*def_id) == identity_future {
                                     break 'print;
@@ -2975,7 +3002,7 @@ fn suggest_await_before_try(
                     self.tcx.mk_projection(
                         item_def_id,
                         // Future::Output has no substs
-                        self.tcx.mk_substs_trait(trait_pred.self_ty(), []),
+                        [trait_pred.self_ty()],
                     )
                 });
                 let InferOk { value: projection_ty, .. } =
@@ -3152,23 +3179,37 @@ fn function_argument_obligation(
             if let ObligationCauseCode::ExprBindingObligation(def_id, _, _, idx) = parent_code.deref()
                 && let predicates = self.tcx.predicates_of(def_id).instantiate_identity(self.tcx)
                 && let Some(pred) = predicates.predicates.get(*idx)
-                && let Ok(trait_pred) = pred.kind().try_map_bound(|pred| match pred {
-                    ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) => Ok(trait_pred),
-                    _ => Err(()),
-                })
             {
-                let mut c = CollectAllMismatches {
-                    infcx: self.infcx,
-                    param_env,
-                    errors: vec![],
-                };
-                if let Ok(trait_predicate) = predicate.kind().try_map_bound(|pred| match pred {
+                if let Ok(trait_pred) = pred.kind().try_map_bound(|pred| match pred {
                     ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) => Ok(trait_pred),
                     _ => Err(()),
-                }) {
+                })
+                    && let Ok(trait_predicate) = predicate.kind().try_map_bound(|pred| match pred {
+                        ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) => Ok(trait_pred),
+                        _ => Err(()),
+                    })
+                {
+                    let mut c = CollectAllMismatches {
+                        infcx: self.infcx,
+                        param_env,
+                        errors: vec![],
+                    };
                     if let Ok(_) = c.relate(trait_pred, trait_predicate) {
                         type_diffs = c.errors;
                     }
+                } else if let ty::PredicateKind::Clause(
+                    ty::Clause::Projection(proj)
+                ) = pred.kind().skip_binder()
+                    && let ty::PredicateKind::Clause(
+                        ty::Clause::Projection(projection)
+                    ) = predicate.kind().skip_binder()
+                {
+                    type_diffs = vec![
+                        Sorts(ty::error::ExpectedFound {
+                            expected: self.tcx.mk_ty(ty::Alias(ty::Projection, proj.projection_ty)),
+                            found: projection.term.ty().unwrap(),
+                        }),
+                    ];
                 }
             }
             if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
@@ -3221,10 +3262,8 @@ fn point_at_chain(
 
         let tcx = self.tcx;
 
+        let mut print_root_expr = true;
         let mut assocs = vec![];
-        // We still want to point at the different methods even if there hasn't
-        // been a change of assoc type.
-        let mut call_spans = vec![];
         let mut expr = expr;
         let mut prev_ty = self.resolve_vars_if_possible(
             typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(tcx.ty_error()),
@@ -3234,63 +3273,8 @@ fn point_at_chain(
             // vec![1, 2, 3].iter().map(mapper).sum<i32>()
             //               ^^^^^^ ^^^^^^^^^^^
             expr = rcvr_expr;
-            let mut assocs_in_this_method = Vec::with_capacity(type_diffs.len());
-            call_spans.push(span);
-
-            let ocx = ObligationCtxt::new_in_snapshot(self.infcx);
-            for diff in &type_diffs {
-                let Sorts(expected_found) = diff else { continue; };
-                let ty::Alias(ty::Projection, proj) = expected_found.expected.kind() else { continue; };
-
-                let origin =
-                    TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span };
-                let trait_def_id = proj.trait_def_id(self.tcx);
-                // Make `Self` be equivalent to the type of the call chain
-                // expression we're looking at now, so that we can tell what
-                // for example `Iterator::Item` is at this point in the chain.
-                let substs = InternalSubsts::for_item(self.tcx, trait_def_id, |param, _| {
-                    match param.kind {
-                        ty::GenericParamDefKind::Type { .. } => {
-                            if param.index == 0 {
-                                return prev_ty.into();
-                            }
-                        }
-                        ty::GenericParamDefKind::Lifetime
-                        | ty::GenericParamDefKind::Const { .. } => {}
-                    }
-                    self.var_for_def(span, param)
-                });
-                // This will hold the resolved type of the associated type, if the
-                // current expression implements the trait that associated type is
-                // in. For example, this would be what `Iterator::Item` is here.
-                let ty_var = self.infcx.next_ty_var(origin);
-                // This corresponds to `<ExprTy as Iterator>::Item = _`.
-                let trait_ref = ty::Binder::dummy(ty::PredicateKind::Clause(
-                    ty::Clause::Projection(ty::ProjectionPredicate {
-                        projection_ty: ty::AliasTy { substs, def_id: proj.def_id },
-                        term: ty_var.into(),
-                    }),
-                ));
-                // Add `<ExprTy as Iterator>::Item = _` obligation.
-                ocx.register_obligation(Obligation::misc(
-                    self.tcx,
-                    span,
-                    expr.hir_id,
-                    param_env,
-                    trait_ref,
-                ));
-                if ocx.select_where_possible().is_empty() {
-                    // `ty_var` now holds the type that `Item` is for `ExprTy`.
-                    let ty_var = self.resolve_vars_if_possible(ty_var);
-                    assocs_in_this_method.push(Some((span, (proj.def_id, ty_var))));
-                } else {
-                    // `<ExprTy as Iterator>` didn't select, so likely we've
-                    // reached the end of the iterator chain, like the originating
-                    // `Vec<_>`.
-                    // Keep the space consistent for later zipping.
-                    assocs_in_this_method.push(None);
-                }
-            }
+            let assocs_in_this_method =
+                self.probe_assoc_types_at_expr(&type_diffs, span, prev_ty, expr.hir_id, param_env);
             assocs.push(assocs_in_this_method);
             prev_ty = self.resolve_vars_if_possible(
                 typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(tcx.ty_error()),
@@ -3300,17 +3284,32 @@ fn point_at_chain(
                 && let hir::Path { res: hir::def::Res::Local(hir_id), .. } = path
                 && let Some(hir::Node::Pat(binding)) = self.tcx.hir().find(*hir_id)
                 && let parent_hir_id = self.tcx.hir().get_parent_node(binding.hir_id)
-                && let Some(hir::Node::Local(local)) = self.tcx.hir().find(parent_hir_id)
-                && let Some(binding_expr) = local.init
+                && let Some(parent) = self.tcx.hir().find(parent_hir_id)
             {
-                // We've reached the root of the method call chain and it is a
-                // binding. Get the binding creation and try to continue the chain.
-                expr = binding_expr;
+                // We've reached the root of the method call chain...
+                if let hir::Node::Local(local) = parent
+                    && let Some(binding_expr) = local.init
+                {
+                    // ...and it is a binding. Get the binding creation and continue the chain.
+                    expr = binding_expr;
+                }
+                if let hir::Node::Param(param) = parent {
+                    // ...and it is a an fn argument.
+                    let prev_ty = self.resolve_vars_if_possible(
+                        typeck_results.node_type_opt(param.hir_id).unwrap_or(tcx.ty_error()),
+                    );
+                    let assocs_in_this_method = self.probe_assoc_types_at_expr(&type_diffs, param.ty_span, prev_ty, param.hir_id, param_env);
+                    if assocs_in_this_method.iter().any(|a| a.is_some()) {
+                        assocs.push(assocs_in_this_method);
+                        print_root_expr = false;
+                    }
+                    break;
+                }
             }
         }
         // We want the type before deref coercions, otherwise we talk about `&[_]`
         // instead of `Vec<_>`.
-        if let Some(ty) = typeck_results.expr_ty_opt(expr) {
+        if let Some(ty) = typeck_results.expr_ty_opt(expr) && print_root_expr {
             let ty = with_forced_trimmed_paths!(self.ty_to_string(ty));
             // Point at the root expression
             // vec![1, 2, 3].iter().map(mapper).sum<i32>()
@@ -3324,7 +3323,7 @@ fn point_at_chain(
             let Some(prev_assoc_in_method) = assocs.peek() else {
                 for entry in assocs_in_method {
                     let Some((span, (assoc, ty))) = entry else { continue; };
-                    if type_diffs.iter().any(|diff| {
+                    if primary_spans.is_empty() || type_diffs.iter().any(|diff| {
                         let Sorts(expected_found) = diff else { return false; };
                         self.can_eq(param_env, expected_found.found, ty).is_ok()
                     }) {
@@ -3353,7 +3352,7 @@ fn point_at_chain(
                         let ty_str = with_forced_trimmed_paths!(self.ty_to_string(ty));
 
                         let assoc = with_forced_trimmed_paths!(self.tcx.def_path_str(assoc));
-                        if ty != *prev_ty {
+                        if self.can_eq(param_env, ty, *prev_ty).is_err() {
                             if type_diffs.iter().any(|diff| {
                                 let Sorts(expected_found) = diff else { return false; };
                                 self.can_eq(param_env, expected_found.found, ty).is_ok()
@@ -3380,13 +3379,6 @@ fn point_at_chain(
                 }
             }
         }
-        for span in call_spans {
-            if span_labels.iter().find(|(s, _)| *s == span).is_none() {
-                // Ensure we are showing the entire chain, even if the assoc types
-                // haven't changed.
-                span_labels.push((span, String::new()));
-            }
-        }
         if !primary_spans.is_empty() {
             let mut multi_span: MultiSpan = primary_spans.into();
             for (span, label) in span_labels {
@@ -3394,13 +3386,70 @@ fn point_at_chain(
             }
             err.span_note(
                 multi_span,
-                format!(
-                    "the method call chain might not have had the expected \
-                                     associated types",
-                ),
+                format!("the method call chain might not have had the expected associated types"),
             );
         }
     }
+
+    fn probe_assoc_types_at_expr(
+        &self,
+        type_diffs: &[TypeError<'tcx>],
+        span: Span,
+        prev_ty: Ty<'tcx>,
+        body_id: hir::HirId,
+        param_env: ty::ParamEnv<'tcx>,
+    ) -> Vec<Option<(Span, (DefId, Ty<'tcx>))>> {
+        let ocx = ObligationCtxt::new_in_snapshot(self.infcx);
+        let mut assocs_in_this_method = Vec::with_capacity(type_diffs.len());
+        for diff in type_diffs {
+            let Sorts(expected_found) = diff else { continue; };
+            let ty::Alias(ty::Projection, proj) = expected_found.expected.kind() else { continue; };
+
+            let origin = TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span };
+            let trait_def_id = proj.trait_def_id(self.tcx);
+            // Make `Self` be equivalent to the type of the call chain
+            // expression we're looking at now, so that we can tell what
+            // for example `Iterator::Item` is at this point in the chain.
+            let substs = InternalSubsts::for_item(self.tcx, trait_def_id, |param, _| {
+                match param.kind {
+                    ty::GenericParamDefKind::Type { .. } => {
+                        if param.index == 0 {
+                            return prev_ty.into();
+                        }
+                    }
+                    ty::GenericParamDefKind::Lifetime | ty::GenericParamDefKind::Const { .. } => {}
+                }
+                self.var_for_def(span, param)
+            });
+            // This will hold the resolved type of the associated type, if the
+            // current expression implements the trait that associated type is
+            // in. For example, this would be what `Iterator::Item` is here.
+            let ty_var = self.infcx.next_ty_var(origin);
+            // This corresponds to `<ExprTy as Iterator>::Item = _`.
+            let projection = ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::Projection(
+                ty::ProjectionPredicate {
+                    projection_ty: self.tcx.mk_alias_ty(proj.def_id, substs),
+                    term: ty_var.into(),
+                },
+            )));
+            // Add `<ExprTy as Iterator>::Item = _` obligation.
+            ocx.register_obligation(Obligation::misc(
+                self.tcx, span, body_id, param_env, projection,
+            ));
+            if ocx.select_where_possible().is_empty() {
+                // `ty_var` now holds the type that `Item` is for `ExprTy`.
+                let ty_var = self.resolve_vars_if_possible(ty_var);
+                assocs_in_this_method.push(Some((span, (proj.def_id, ty_var))));
+            } else {
+                // `<ExprTy as Iterator>` didn't select, so likely we've
+                // reached the end of the iterator chain, like the originating
+                // `Vec<_>`.
+                // Keep the space consistent for later zipping.
+                assocs_in_this_method.push(None);
+            }
+        }
+        assocs_in_this_method
+    }
 }
 
 /// Add a hint to add a missing borrow or remove an unnecessary one.
@@ -3580,13 +3629,6 @@ fn suggest_trait_object_return_type_alternatives(
     trait_obj: &str,
     is_object_safe: bool,
 ) {
-    err.span_suggestion(
-        ret_ty,
-        "use some type `T` that is `T: Sized` as the return type if all return paths have the \
-            same type",
-        "T",
-        Applicability::MaybeIncorrect,
-    );
     err.span_suggestion(
         ret_ty,
         &format!(
index ea4bf42c515b5fb5a7aa83413b4d3eca80236736..2566d793d78daa53e4a5b5be00e880ad0dd96b02 100644 (file)
@@ -425,13 +425,8 @@ pub fn fully_solve_bound<'tcx>(
     bound: DefId,
 ) -> Vec<FulfillmentError<'tcx>> {
     let tcx = infcx.tcx;
-    let trait_ref = ty::TraitRef { def_id: bound, substs: tcx.mk_substs_trait(ty, []) };
-    let obligation = Obligation {
-        cause,
-        recursion_depth: 0,
-        param_env,
-        predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(tcx),
-    };
+    let trait_ref = tcx.mk_trait_ref(bound, [ty]);
+    let obligation = Obligation::new(tcx, cause, param_env, ty::Binder::dummy(trait_ref));
 
     fully_solve_obligation(infcx, obligation)
 }
index 3e85ea69635e645c953b4e3eec401e1f3390e318..8b1ced78f4e8a06fe4a69ed1d0a4f49c8e043935 100644 (file)
@@ -694,18 +694,12 @@ fn receiver_is_dispatchable<'tcx>(
 
         // U: Trait<Arg1, ..., ArgN>
         let trait_predicate = {
-            let substs =
-                InternalSubsts::for_item(tcx, method.trait_container(tcx).unwrap(), |param, _| {
-                    if param.index == 0 {
-                        unsized_self_ty.into()
-                    } else {
-                        tcx.mk_param_from_def(param)
-                    }
-                });
+            let trait_def_id = method.trait_container(tcx).unwrap();
+            let substs = InternalSubsts::for_item(tcx, trait_def_id, |param, _| {
+                if param.index == 0 { unsized_self_ty.into() } else { tcx.mk_param_from_def(param) }
+            });
 
-            ty::Binder::dummy(ty::TraitRef { def_id: unsize_did, substs })
-                .without_const()
-                .to_predicate(tcx)
+            ty::Binder::dummy(tcx.mk_trait_ref(trait_def_id, substs)).to_predicate(tcx)
         };
 
         let caller_bounds: Vec<Predicate<'tcx>> =
index ca9ee04c58c10d2b1811ab8c172615d4ba1bfabf..84d7244c1db786a6144c32e6fdf6be92e2e1c3c2 100644 (file)
@@ -496,7 +496,7 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
             // This is really important. While we *can* handle this, this has
             // severe performance implications for large opaque types with
             // late-bound regions. See `issue-88862` benchmark.
-            ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs })
+            ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. })
                 if !substs.has_escaping_bound_vars() =>
             {
                 // Only normalize `impl Trait` outside of type inference, usually in codegen.
@@ -1309,8 +1309,7 @@ fn assemble_candidate_for_impl_trait_in_trait<'cx, 'tcx>(
         let trait_substs =
             obligation.predicate.substs.truncate_to(tcx, tcx.generics_of(trait_def_id));
         // FIXME(named-returns): Binders
-        let trait_predicate =
-            ty::Binder::dummy(ty::TraitRef { def_id: trait_def_id, substs: trait_substs });
+        let trait_predicate = ty::Binder::dummy(tcx.mk_trait_ref(trait_def_id, trait_substs));
 
         let _ = selcx.infcx.commit_if_ok(|_| {
             match selcx.select(&obligation.with(tcx, trait_predicate)) {
@@ -1867,10 +1866,7 @@ fn confirm_generator_candidate<'cx, 'tcx>(
         };
 
         ty::ProjectionPredicate {
-            projection_ty: ty::AliasTy {
-                substs: trait_ref.substs,
-                def_id: obligation.predicate.def_id,
-            },
+            projection_ty: tcx.mk_alias_ty(obligation.predicate.def_id, trait_ref.substs),
             term: ty.into(),
         }
     });
@@ -1909,10 +1905,7 @@ fn confirm_future_candidate<'cx, 'tcx>(
         debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name, sym::Output);
 
         ty::ProjectionPredicate {
-            projection_ty: ty::AliasTy {
-                substs: trait_ref.substs,
-                def_id: obligation.predicate.def_id,
-            },
+            projection_ty: tcx.mk_alias_ty(obligation.predicate.def_id, trait_ref.substs),
             term: return_ty.into(),
         }
     });
@@ -1965,10 +1958,8 @@ fn confirm_builtin_candidate<'cx, 'tcx>(
         bug!("unexpected builtin trait with associated type: {:?}", obligation.predicate);
     };
 
-    let predicate = ty::ProjectionPredicate {
-        projection_ty: ty::AliasTy { substs, def_id: item_def_id },
-        term,
-    };
+    let predicate =
+        ty::ProjectionPredicate { projection_ty: tcx.mk_alias_ty(item_def_id, substs), term };
 
     confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false)
         .with_addl_obligations(obligations)
@@ -2037,7 +2028,7 @@ fn confirm_callable_candidate<'cx, 'tcx>(
         flag,
     )
     .map_bound(|(trait_ref, ret_type)| ty::ProjectionPredicate {
-        projection_ty: ty::AliasTy { substs: trait_ref.substs, def_id: fn_once_output_def_id },
+        projection_ty: tcx.mk_alias_ty(fn_once_output_def_id, trait_ref.substs),
         term: ret_type.into(),
     });
 
index 777de195895b89de6c9f1e50c422de074b842bed..c6ef13e185b2d7526e6870397a3932e451e6a49c 100644 (file)
@@ -205,7 +205,7 @@ fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
             // This is really important. While we *can* handle this, this has
             // severe performance implications for large opaque types with
             // late-bound regions. See `issue-88862` benchmark.
-            ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs })
+            ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. })
                 if !substs.has_escaping_bound_vars() =>
             {
                 // Only normalize `impl Trait` outside of type inference, usually in codegen.
index bfa318787e546869e2c0efe8ebcbb679579feaf0..34b5fc4891eb36643e65c2412e8ac70330559e55 100644 (file)
@@ -26,7 +26,7 @@ pub(crate) fn update<'tcx, T>(
                 .kind()
                 .rebind(
                     // (*) binder moved here
-                    ty::PredicateKind::Clause(ty::Clause::Trait(tpred.with_self_type(infcx.tcx, new_self_ty)))
+                    ty::PredicateKind::Clause(ty::Clause::Trait(tpred.with_self_ty(infcx.tcx, new_self_ty)))
                 ),
         );
         // Don't report overflow errors. Otherwise equivalent to may_hold.
index 829d4f60986054141a68d95400b1f34746e3df28..c54d901e9b10aff43f7e9106632beef59ae3e495 100644 (file)
@@ -536,7 +536,7 @@ fn need_migrate_deref_output_trait_object(
             let ty = traits::normalize_projection_type(
                 self,
                 param_env,
-                ty::AliasTy { def_id: tcx.lang_items().deref_target()?, substs: trait_ref.substs },
+                tcx.mk_alias_ty(tcx.lang_items().deref_target()?, trait_ref.substs),
                 cause.clone(),
                 0,
                 // We're *intentionally* throwing these away,
index 85456853ce08c66cffd744c7112974852a37b043..f6fe71fbd4f889ce18c08f0c08b890b4939363c1 100644 (file)
@@ -155,7 +155,7 @@ fn confirm_projection_candidate(
         let placeholder_self_ty = placeholder_trait_predicate.self_ty();
         let placeholder_trait_predicate = ty::Binder::dummy(placeholder_trait_predicate);
         let (def_id, substs) = match *placeholder_self_ty.kind() {
-            ty::Alias(_, ty::AliasTy { def_id, substs }) => (def_id, substs),
+            ty::Alias(_, ty::AliasTy { def_id, substs, .. }) => (def_id, substs),
             _ => bug!("projection candidate for unexpected type: {:?}", placeholder_self_ty),
         };
 
index 115897851d67317e8ad4670714e864e4ae28131c..792933096b15c61a731b3a2e1cee0d87c1347926 100644 (file)
@@ -1595,7 +1595,7 @@ fn match_projection_obligation_against_definition_bounds(
 
         let tcx = self.infcx.tcx;
         let (def_id, substs) = match *placeholder_trait_predicate.trait_ref.self_ty().kind() {
-            ty::Alias(_, ty::AliasTy { def_id, substs }) => (def_id, substs),
+            ty::Alias(_, ty::AliasTy { def_id, substs, .. }) => (def_id, substs),
             _ => {
                 span_bug!(
                     obligation.cause.span,
@@ -2259,7 +2259,7 @@ fn constituent_types_for_ty(
                 t.rebind(def.all_fields().map(|f| f.ty(self.tcx(), substs)).collect())
             }
 
-            ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs }) => {
+            ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
                 // We can resolve the `impl Trait` to its concrete type,
                 // which enforces a DAG between the functions requiring
                 // the auto trait bounds in question.
index 74c4ae8854c34e4d9fb628808f5523a4f4707c65..0e0a883d9f5908ffcf0dfe5c41a34daa5c1639e2 100644 (file)
@@ -451,19 +451,21 @@ fn compute(&mut self, arg: GenericArg<'tcx>) {
                 GenericArgKind::Const(ct) => {
                     match ct.kind() {
                         ty::ConstKind::Unevaluated(uv) => {
-                            let obligations = self.nominal_obligations(uv.def.did, uv.substs);
-                            self.out.extend(obligations);
-
-                            let predicate =
-                                ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(ct));
-                            let cause = self.cause(traits::WellFormed(None));
-                            self.out.push(traits::Obligation::with_depth(
-                                self.tcx(),
-                                cause,
-                                self.recursion_depth,
-                                self.param_env,
-                                predicate,
-                            ));
+                            if !ct.has_escaping_bound_vars() {
+                                let obligations = self.nominal_obligations(uv.def.did, uv.substs);
+                                self.out.extend(obligations);
+
+                                let predicate =
+                                    ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(ct));
+                                let cause = self.cause(traits::WellFormed(None));
+                                self.out.push(traits::Obligation::with_depth(
+                                    self.tcx(),
+                                    cause,
+                                    self.recursion_depth,
+                                    self.param_env,
+                                    predicate,
+                                ));
+                            }
                         }
                         ty::ConstKind::Infer(_) => {
                             let cause = self.cause(traits::WellFormed(None));
@@ -648,7 +650,7 @@ fn compute(&mut self, arg: GenericArg<'tcx>) {
                     // types appearing in the fn signature
                 }
 
-                ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs }) => {
+                ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
                     // All of the requirements on type parameters
                     // have already been checked for `impl Trait` in
                     // return position. We do need to check type-alias-impl-trait though.
index 53bafde0ea20e9fdcc52f63b587bb4d223185ea2..bc4a52c5040d1fa5f2647d6acd6c7105a814009c 100644 (file)
@@ -433,7 +433,7 @@ fn impl_provided_for(
                     }
                 }
                 (
-                    &ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs: _ }),
+                    &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }),
                     OpaqueType(opaque_ty_id, ..),
                 ) => def_id == opaque_ty_id.0,
                 (&ty::FnDef(def_id, ..), FnDef(fn_def_id, ..)) => def_id == fn_def_id.0,
@@ -789,7 +789,7 @@ fn fold_binder<T: TypeFoldable<'tcx>>(
     }
 
     fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
-        if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs }) = *ty.kind() {
+        if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) = *ty.kind() {
             if def_id == self.opaque_ty_id.0 && substs == self.identity_substs {
                 return self.tcx.mk_ty(ty::Bound(
                     self.binder_index,
index f3fd315c71ee5fa43aaf47771f94849e399ac3a4..9712abb708f2762c61c6c2b0b922e642c681fb83 100644 (file)
@@ -347,13 +347,13 @@ fn lower_into(self, interner: RustInterner<'tcx>) -> chalk_ir::Ty<RustInterner<'
             ty::Tuple(types) => {
                 chalk_ir::TyKind::Tuple(types.len(), types.as_substs().lower_into(interner))
             }
-            ty::Alias(ty::Projection, ty::AliasTy { def_id, substs }) => {
+            ty::Alias(ty::Projection, ty::AliasTy { def_id, substs, .. }) => {
                 chalk_ir::TyKind::Alias(chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy {
                     associated_ty_id: chalk_ir::AssocTypeId(def_id),
                     substitution: substs.lower_into(interner),
                 }))
             }
-            ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs }) => {
+            ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
                 chalk_ir::TyKind::Alias(chalk_ir::AliasTy::Opaque(chalk_ir::OpaqueTy {
                     opaque_ty_id: chalk_ir::OpaqueTyId(def_id),
                     substitution: substs.lower_into(interner),
@@ -443,11 +443,11 @@ fn lower_into(self, interner: RustInterner<'tcx>) -> Ty<'tcx> {
             TyKind::Str => ty::Str,
             TyKind::OpaqueType(opaque_ty, substitution) => ty::Alias(
                 ty::Opaque,
-                ty::AliasTy { def_id: opaque_ty.0, substs: substitution.lower_into(interner) },
+                interner.tcx.mk_alias_ty(opaque_ty.0, substitution.lower_into(interner)),
             ),
             TyKind::AssociatedType(assoc_ty, substitution) => ty::Alias(
                 ty::Projection,
-                ty::AliasTy { substs: substitution.lower_into(interner), def_id: assoc_ty.0 },
+                interner.tcx.mk_alias_ty(assoc_ty.0, substitution.lower_into(interner)),
             ),
             TyKind::Foreign(def_id) => ty::Foreign(def_id.0),
             TyKind::Error => return interner.tcx.ty_error(),
@@ -458,17 +458,17 @@ fn lower_into(self, interner: RustInterner<'tcx>) -> Ty<'tcx> {
             TyKind::Alias(alias_ty) => match alias_ty {
                 chalk_ir::AliasTy::Projection(projection) => ty::Alias(
                     ty::Projection,
-                    ty::AliasTy {
-                        def_id: projection.associated_ty_id.0,
-                        substs: projection.substitution.lower_into(interner),
-                    },
+                    interner.tcx.mk_alias_ty(
+                        projection.associated_ty_id.0,
+                        projection.substitution.lower_into(interner),
+                    ),
                 ),
                 chalk_ir::AliasTy::Opaque(opaque) => ty::Alias(
                     ty::Opaque,
-                    ty::AliasTy {
-                        def_id: opaque.opaque_ty_id.0,
-                        substs: opaque.substitution.lower_into(interner),
-                    },
+                    interner.tcx.mk_alias_ty(
+                        opaque.opaque_ty_id.0,
+                        opaque.substitution.lower_into(interner),
+                    ),
                 ),
             },
             TyKind::Function(_quantified_ty) => unimplemented!(),
index 9589342b3c73f6cf981055828db383b439eba538..c761a4dbe4500bfbc78b9576bbfabb873a4de662 100644 (file)
@@ -919,7 +919,7 @@ fn variant_info_for_generator<'tcx>(
     def_id: DefId,
     substs: ty::SubstsRef<'tcx>,
 ) -> (Vec<VariantInfo>, Option<Size>) {
-    let Variants::Multiple { tag, ref tag_encoding, .. } = layout.variants else {
+    let Variants::Multiple { tag, ref tag_encoding, tag_field, .. } = layout.variants else {
         return (vec![], None);
     };
 
@@ -975,12 +975,28 @@ fn variant_info_for_generator<'tcx>(
             if variant_size == Size::ZERO {
                 variant_size = upvars_size;
             }
-            // We need to add the discriminant size back into min_size, since it is subtracted
-            // later during printing.
-            variant_size += match tag_encoding {
-                TagEncoding::Direct => tag.size(cx),
-                _ => Size::ZERO,
-            };
+
+            // This `if` deserves some explanation.
+            //
+            // The layout code has a choice of where to place the discriminant of this generator.
+            // If the discriminant of the generator is placed early in the layout (before the
+            // variant's own fields), then it'll implicitly be counted towards the size of the
+            // variant, since we use the maximum offset to calculate size.
+            //    (side-note: I know this is a bit problematic given upvars placement, etc).
+            //
+            // This is important, since the layout printing code always subtracts this discriminant
+            // size from the variant size if the struct is "enum"-like, so failing to account for it
+            // will either lead to numerical underflow, or an underreported variant size...
+            //
+            // However, if the discriminant is placed past the end of the variant, then we need
+            // to factor in the size of the discriminant manually. This really should be refactored
+            // better, but this "works" for now.
+            if layout.fields.offset(tag_field) >= variant_size {
+                variant_size += match tag_encoding {
+                    TagEncoding::Direct => tag.size(cx),
+                    _ => Size::ZERO,
+                };
+            }
 
             VariantInfo {
                 name: Some(Symbol::intern(&ty::GeneratorSubsts::variant_name(variant_idx))),
index e9ffbca96280d85503651104987002c0d733310e..f30ae82d7cdd2b4fd4d596c0e207f016efa4aada 100644 (file)
@@ -250,9 +250,9 @@ fn clone(&self) -> Self {
         match self {
             Bool => Bool,
             Char => Char,
-            Int(i) => Int(i.clone()),
-            Uint(u) => Uint(u.clone()),
-            Float(f) => Float(f.clone()),
+            Int(i) => Int(*i),
+            Uint(u) => Uint(*u),
+            Float(f) => Float(*f),
             Adt(d, s) => Adt(d.clone(), s.clone()),
             Foreign(d) => Foreign(d.clone()),
             Str => Str,
@@ -262,7 +262,7 @@ fn clone(&self) -> Self {
             Ref(r, t, m) => Ref(r.clone(), t.clone(), m.clone()),
             FnDef(d, s) => FnDef(d.clone(), s.clone()),
             FnPtr(s) => FnPtr(s.clone()),
-            Dynamic(p, r, repr) => Dynamic(p.clone(), r.clone(), repr.clone()),
+            Dynamic(p, r, repr) => Dynamic(p.clone(), r.clone(), *repr),
             Closure(d, s) => Closure(d.clone(), s.clone()),
             Generator(d, s, m) => Generator(d.clone(), s.clone(), m.clone()),
             GeneratorWitness(g) => GeneratorWitness(g.clone()),
@@ -270,7 +270,7 @@ fn clone(&self) -> Self {
             Tuple(t) => Tuple(t.clone()),
             Alias(k, p) => Alias(*k, p.clone()),
             Param(p) => Param(p.clone()),
-            Bound(d, b) => Bound(d.clone(), b.clone()),
+            Bound(d, b) => Bound(*d, b.clone()),
             Placeholder(p) => Placeholder(p.clone()),
             Infer(t) => Infer(t.clone()),
             Error(e) => Error(e.clone()),
@@ -936,7 +936,7 @@ impl<I: Interner> Clone for RegionKind<I> {
     fn clone(&self) -> Self {
         match self {
             ReEarlyBound(r) => ReEarlyBound(r.clone()),
-            ReLateBound(d, r) => ReLateBound(d.clone(), r.clone()),
+            ReLateBound(d, r) => ReLateBound(*d, r.clone()),
             ReFree(r) => ReFree(r.clone()),
             ReStatic => ReStatic,
             ReVar(r) => ReVar(r.clone()),
index 8ba1c122884ca431173cc28a77d33b6282e7169d..0910ce599b7c00fe41cf17a12b489c8b0609692c 100644 (file)
 //! #[custom_mir(dialect = "built")]
 //! pub fn simple(x: i32) -> i32 {
 //!     mir!(
-//!         let temp1: i32;
-//!         let temp2: _;
+//!         let temp2: i32;
 //!
 //!         {
-//!             temp1 = x;
-//!             Goto(exit)
+//!             let temp1 = x;
+//!             Goto(my_second_block)
 //!         }
 //!
-//!         exit = {
+//!         my_second_block = {
 //!             temp2 = Move(temp1);
 //!             RET = temp2;
 //!             Return()
 //! }
 //! ```
 //!
-//! Hopefully most of this is fairly self-explanatory. Expanding on some notable details:
+//! The `custom_mir` attribute tells the compiler to treat the function as being custom MIR. This
+//! attribute only works on functions - there is no way to insert custom MIR into the middle of
+//! another function. The `dialect` and `phase` parameters indicate which [version of MIR][dialect
+//! docs] you are inserting here. Generally you'll want to use `#![custom_mir(dialect = "built")]`
+//! if you want your MIR to be modified by the full MIR pipeline, or `#![custom_mir(dialect =
+//! "runtime", phase = "optimized")] if you don't.
 //!
-//!  - The `custom_mir` attribute tells the compiler to treat the function as being custom MIR. This
-//!    attribute only works on functions - there is no way to insert custom MIR into the middle of
-//!    another function.
-//!  - The `dialect` and `phase` parameters indicate which version of MIR you are inserting here.
-//!    This will normally be the phase that corresponds to the thing you are trying to test. The
-//!    phase can be omitted for dialects that have just one.
-//!  - You should define your function signature like you normally would. Externally, this function
-//!    can be called like any other function.
-//!  - Type inference works - you don't have to spell out the type of all of your locals.
+//! [dialect docs]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/enum.MirPhase.html
 //!
-//! For now, all statements and terminators are parsed from nested invocations of the special
-//! functions provided in this module. We additionally want to (but do not yet) support more
-//! "normal" Rust syntax in places where it makes sense. Also, most kinds of instructions are not
-//! supported yet.
+//! The input to the [`mir!`] macro is:
+//!
+//!  - A possibly empty list of local declarations. Locals can also be declared inline on
+//!    assignments via `let`. Type inference generally works. Shadowing does not.
+//!  - A list of basic blocks. The first of these is the start block and is where execution begins.
+//!    All blocks other than the start block need to be given a name, so that they can be referred
+//!    to later.
+//!     - Each block is a list of semicolon terminated statements, followed by a terminator. The
+//!       syntax for the various statements and terminators is designed to be as similar as possible
+//!       to the syntax for analogous concepts in native Rust. See below for a list.
+//!
+//! # Examples
+//!
+//! ```rust
+//! #![feature(core_intrinsics, custom_mir)]
+//!
+//! extern crate core;
+//! use core::intrinsics::mir::*;
+//!
+//! #[custom_mir(dialect = "built")]
+//! pub fn choose_load(a: &i32, b: &i32, c: bool) -> i32 {
+//!     mir!(
+//!         {
+//!             match c {
+//!                 true => t,
+//!                 _ => f,
+//!             }
+//!         }
+//!
+//!         t = {
+//!             let temp = a;
+//!             Goto(load_and_exit)
+//!         }
+//!
+//!         f = {
+//!             temp = b;
+//!             Goto(load_and_exit)
+//!         }
+//!
+//!         load_and_exit = {
+//!             RET = *temp;
+//!             Return()
+//!         }
+//!     )
+//! }
+//!
+//! #[custom_mir(dialect = "built")]
+//! fn unwrap_unchecked<T>(opt: Option<T>) -> T {
+//!     mir!({
+//!         RET = Move(Field(Variant(opt, 1), 0));
+//!         Return()
+//!     })
+//! }
+//! ```
+//!
+//! We can also set off compilation failures that happen in sufficiently late stages of the
+//! compiler:
+//!
+//! ```rust,compile_fail
+//! #![feature(core_intrinsics, custom_mir)]
+//!
+//! extern crate core;
+//! use core::intrinsics::mir::*;
+//!
+//! #[custom_mir(dialect = "built")]
+//! fn borrow_error(should_init: bool) -> i32 {
+//!     mir!(
+//!         let temp: i32;
+//!
+//!         {
+//!             match should_init {
+//!                 true => init,
+//!                 _ => use_temp,
+//!             }
+//!         }
+//!
+//!         init = {
+//!             temp = 0;
+//!             Goto(use_temp)
+//!         }
+//!
+//!         use_temp = {
+//!             RET = temp;
+//!             Return()
+//!         }
+//!     )
+//! }
+//! ```
+//!
+//! ```text
+//! error[E0381]: used binding is possibly-uninitialized
+//!   --> test.rs:24:13
+//!    |
+//! 8  | /     mir!(
+//! 9  | |         let temp: i32;
+//! 10 | |
+//! 11 | |         {
+//! ...  |
+//! 19 | |             temp = 0;
+//!    | |             -------- binding initialized here in some conditions
+//! ...  |
+//! 24 | |             RET = temp;
+//!    | |             ^^^^^^^^^^ value used here but it is possibly-uninitialized
+//! 25 | |             Return()
+//! 26 | |         }
+//! 27 | |     )
+//!    | |_____- binding declared here but left uninitialized
+//!
+//! error: aborting due to previous error
+//!
+//! For more information about this error, try `rustc --explain E0381`.
+//! ```
+//!
+//! # Syntax
+//!
+//! The lists below are an exhaustive description of how various MIR constructs can be created.
+//! Anything missing from the list should be assumed to not be supported, PRs welcome.
+//!
+//! #### Locals
+//!
+//!  - The `_0` return local can always be accessed via `RET`.
+//!  - Arguments can be accessed via their regular name.
+//!  - All other locals need to be declared with `let` somewhere and then can be accessed by name.
+//!
+//! #### Places
+//!  - Locals implicit convert to places.
+//!  - Field accesses, derefs, and indexing work normally.
+//!  - Fields in variants can be accessed via the [`Variant`] and [`Field`] associated functions,
+//!    see their documentation for details.
+//!
+//! #### Operands
+//!  - Places implicitly convert to `Copy` operands.
+//!  - `Move` operands can be created via [`Move`].
+//!  - Const blocks, literals, named constants, and const params all just work.
+//!  - [`Static`] and [`StaticMut`] can be used to create `&T` and `*mut T`s to statics. These are
+//!    constants in MIR and the only way to access statics.
+//!
+//! #### Statements
+//!  - Assign statements work via normal Rust assignment.
+//!  - [`Retag`] statements have an associated function.
+//!
+//! #### Rvalues
+//!
+//!  - Operands implicitly convert to `Use` rvalues.
+//!  - `&`, `&mut`, `addr_of!`, and `addr_of_mut!` all work to create their associated rvalue.
+//!  - [`Discriminant`] has an associated function.
+//!
+//! #### Terminators
+//!
+//!  - [`Goto`] and [`Return`] have associated functions.
+//!  - `match some_int_operand` becomes a `SwitchInt`. Each arm should be `literal => basic_block`
+//!     - The exception is the last arm, which must be `_ => basic_block` and corresponds to the
+//!       otherwise branch.
 //!
 
 #![unstable(
 pub struct BasicBlock;
 
 macro_rules! define {
-    ($name:literal, $($sig:tt)*) => {
+    ($name:literal, $( #[ $meta:meta ] )* fn $($sig:tt)*) => {
         #[rustc_diagnostic_item = $name]
-        pub $($sig)* { panic!() }
+        $( #[ $meta ] )*
+        pub fn $($sig)* { panic!() }
     }
 }
 
@@ -82,8 +228,73 @@ macro_rules! define {
 define!("mir_move", fn Move<T>(place: T) -> T);
 define!("mir_static", fn Static<T>(s: T) -> &'static T);
 define!("mir_static_mut", fn StaticMut<T>(s: T) -> *mut T);
+define!(
+    "mir_discriminant",
+    /// Gets the discriminant of a place.
+    fn Discriminant<T>(place: T) -> <T as ::core::marker::DiscriminantKind>::Discriminant
+);
+define!("mir_set_discriminant", fn SetDiscriminant<T>(place: T, index: u32));
+define!(
+    "mir_field",
+    /// Access the field with the given index of some place.
+    ///
+    /// This only makes sense to use in conjunction with [`Variant`]. If the type you are looking to
+    /// access the field of does not have variants, you can use normal field projection syntax.
+    ///
+    /// There is no proper way to do a place projection to a variant in Rust, and so these two
+    /// functions are a workaround. You can access a field of a variant via `Field(Variant(place,
+    /// var_idx), field_idx)`, where `var_idx` and `field_idx` are appropriate literals. Some
+    /// caveats:
+    ///
+    ///  - The return type of `Variant` is always `()`. Don't worry about that, the correct MIR will
+    ///    still be generated.
+    ///  - In some situations, the return type of `Field` cannot be inferred. You may need to
+    ///    annotate it on the function in these cases.
+    ///  - Since `Field` is a function call which is not a place expression, using this on the left
+    ///    hand side of an expression is rejected by the compiler. [`place!`] is a macro provided to
+    ///    work around that issue. Wrap the left hand side of an assignment in the macro to convince
+    ///    the compiler that it's ok.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// #![feature(custom_mir, core_intrinsics)]
+    ///
+    /// extern crate core;
+    /// use core::intrinsics::mir::*;
+    ///
+    /// #[custom_mir(dialect = "built")]
+    /// fn unwrap_deref(opt: Option<&i32>) -> i32 {
+    ///     mir!({
+    ///         RET = *Field::<&i32>(Variant(opt, 1), 0);
+    ///         Return()
+    ///     })
+    /// }
+    ///
+    /// #[custom_mir(dialect = "built")]
+    /// fn set(opt: &mut Option<i32>) {
+    ///     mir!({
+    ///         place!(Field(Variant(*opt, 1), 0)) = 5;
+    ///         Return()
+    ///     })
+    /// }
+    /// ```
+    fn Field<F>(place: (), field: u32) -> F
+);
+define!(
+    "mir_variant",
+    /// Adds a variant projection with the given index to the place.
+    ///
+    /// See [`Field`] for documentation.
+    fn Variant<T>(place: T, index: u32) -> ()
+);
+define!(
+    "mir_make_place",
+    #[doc(hidden)]
+    fn __internal_make_place<T>(place: T) -> *mut T
+);
 
-/// Convenience macro for generating custom MIR.
+/// Macro for generating custom MIR.
 ///
 /// See the module documentation for syntax details. This macro is not magic - it only transforms
 /// your MIR into something that is easier to parse in the compiler.
@@ -139,6 +350,13 @@ macro_rules! define {
     }}
 }
 
+/// Helper macro that allows you to treat a value expression like a place expression.
+///
+/// See the documentation on [`Variant`] for why this is necessary and how to use it.
+pub macro place($e:expr) {
+    (*::core::intrinsics::mir::__internal_make_place($e))
+}
+
 /// Helper macro that extracts the `let` declarations out of a bunch of statements.
 ///
 /// This macro is written using the "statement muncher" strategy. Each invocation parses the first
index fb8d06c66820cf0b47a41a48cfdfd8064d3c7f5f..818914a2df074d3f3d0ba46a57ef805f42dc6347 100644 (file)
@@ -1759,8 +1759,13 @@ mod remove_dir_impl {
     use crate::sys::common::small_c_string::run_path_with_cstr;
     use crate::sys::{cvt, cvt_r};
 
-    #[cfg(not(all(target_os = "macos", not(target_arch = "aarch64")),))]
+    #[cfg(not(any(
+        target_os = "linux",
+        all(target_os = "macos", not(target_arch = "aarch64"))
+    )))]
     use libc::{fdopendir, openat, unlinkat};
+    #[cfg(target_os = "linux")]
+    use libc::{fdopendir, openat64 as openat, unlinkat};
     #[cfg(all(target_os = "macos", not(target_arch = "aarch64")))]
     use macos_weak::{fdopendir, openat, unlinkat};
 
index 94546ca09d00d859bdf3863eb4cead3f9223d120..6fa85e859c05b303495ac8e2d808832a13fd0e5b 100644 (file)
 use crate::sync::atomic::{AtomicBool, AtomicU8, Ordering};
 use crate::sys::cvt;
 use crate::sys::weak::syscall;
+#[cfg(not(target_os = "linux"))]
+use libc::sendfile as sendfile64;
+#[cfg(target_os = "linux")]
+use libc::sendfile64;
 use libc::{EBADF, EINVAL, ENOSYS, EOPNOTSUPP, EOVERFLOW, EPERM, EXDEV};
 
 #[cfg(test)]
@@ -647,7 +651,7 @@ fn splice(
 
         let result = match mode {
             SpliceMode::Sendfile => {
-                cvt(unsafe { libc::sendfile(writer, reader, ptr::null_mut(), chunk_size) })
+                cvt(unsafe { sendfile64(writer, reader, ptr::null_mut(), chunk_size) })
             }
             SpliceMode::Splice => cvt(unsafe {
                 splice(reader, ptr::null_mut(), writer, ptr::null_mut(), chunk_size, 0)
index 9055a011c515e18bd33b44953477220266f17f23..3d60941e84e393c0a7fac39d1fb70f736ed448db 100644 (file)
@@ -95,6 +95,10 @@ unsafe fn sanitize_standard_fds() {
         )))]
         'poll: {
             use crate::sys::os::errno;
+            #[cfg(not(target_os = "linux"))]
+            use libc::open as open64;
+            #[cfg(target_os = "linux")]
+            use libc::open64;
             let pfds: &mut [_] = &mut [
                 libc::pollfd { fd: 0, events: 0, revents: 0 },
                 libc::pollfd { fd: 1, events: 0, revents: 0 },
@@ -116,7 +120,7 @@ unsafe fn sanitize_standard_fds() {
                 if pfd.revents & libc::POLLNVAL == 0 {
                     continue;
                 }
-                if libc::open("/dev/null\0".as_ptr().cast(), libc::O_RDWR, 0) == -1 {
+                if open64("/dev/null\0".as_ptr().cast(), libc::O_RDWR, 0) == -1 {
                     // If the stream is closed but we failed to reopen it, abort the
                     // process. Otherwise we wouldn't preserve the safety of
                     // operations on the corresponding Rust object Stdin, Stdout, or
@@ -139,9 +143,13 @@ unsafe fn sanitize_standard_fds() {
         )))]
         {
             use crate::sys::os::errno;
+            #[cfg(not(target_os = "linux"))]
+            use libc::open as open64;
+            #[cfg(target_os = "linux")]
+            use libc::open64;
             for fd in 0..3 {
                 if libc::fcntl(fd, libc::F_GETFD) == -1 && errno() == libc::EBADF {
-                    if libc::open("/dev/null\0".as_ptr().cast(), libc::O_RDWR, 0) == -1 {
+                    if open64("/dev/null\0".as_ptr().cast(), libc::O_RDWR, 0) == -1 {
                         // If the stream is closed but we failed to reopen it, abort the
                         // process. Otherwise we wouldn't preserve the safety of
                         // operations on the corresponding Rust object Stdin, Stdout, or
index 56a805cef7318fe8e6ed00f57997d90647a03b22..c0716a089bc38b1b2b3be521c41165e259daeb46 100644 (file)
@@ -66,14 +66,15 @@ pub fn spawn(
         //
         // Note that as soon as we're done with the fork there's no need to hold
         // a lock any more because the parent won't do anything and the child is
-        // in its own process. Thus the parent drops the lock guard while the child
-        // forgets it to avoid unlocking it on a new thread, which would be invalid.
+        // in its own process. Thus the parent drops the lock guard immediately.
+        // The child calls `mem::forget` to leak the lock, which is crucial because
+        // releasing a lock is not async-signal-safe.
         let env_lock = sys::os::env_read_lock();
         let (pid, pidfd) = unsafe { self.do_fork()? };
 
         if pid == 0 {
             crate::panic::always_abort();
-            mem::forget(env_lock);
+            mem::forget(env_lock); // avoid non-async-signal-safe unlocking
             drop(input);
             let Err(err) = unsafe { self.do_exec(theirs, envp.as_ref()) };
             let errno = err.raw_os_error().unwrap_or(libc::EINVAL) as u32;
index 75a5c0f927982b3e8b542048839b7e9a0a8e7278..957e086798fd3cd786acd7f01970f42b813f2231 100644 (file)
@@ -45,7 +45,10 @@ mod imp {
     use crate::thread;
 
     use libc::MAP_FAILED;
-    use libc::{mmap, munmap};
+    #[cfg(not(target_os = "linux"))]
+    use libc::{mmap as mmap64, munmap};
+    #[cfg(target_os = "linux")]
+    use libc::{mmap64, munmap};
     use libc::{sigaction, sighandler_t, SA_ONSTACK, SA_SIGINFO, SIGBUS, SIG_DFL};
     use libc::{sigaltstack, SIGSTKSZ, SS_DISABLE};
     use libc::{MAP_ANON, MAP_PRIVATE, PROT_NONE, PROT_READ, PROT_WRITE, SIGSEGV};
@@ -135,7 +138,7 @@ unsafe fn get_stackp() -> *mut libc::c_void {
         #[cfg(not(any(target_os = "openbsd", target_os = "netbsd", target_os = "linux",)))]
         let flags = MAP_PRIVATE | MAP_ANON;
         let stackp =
-            mmap(ptr::null_mut(), SIGSTKSZ + page_size(), PROT_READ | PROT_WRITE, flags, -1, 0);
+            mmap64(ptr::null_mut(), SIGSTKSZ + page_size(), PROT_READ | PROT_WRITE, flags, -1, 0);
         if stackp == MAP_FAILED {
             panic!("failed to allocate an alternative stack: {}", io::Error::last_os_error());
         }
index 6ecf5bdcf86d2bf792695eb1720f3c10c403eadf..d454a2a717c0639a326555d3dc8b21a60450b1dd 100644 (file)
@@ -653,7 +653,10 @@ pub unsafe fn init() -> Option<Guard> {
 ))]
 #[cfg_attr(test, allow(dead_code))]
 pub mod guard {
-    use libc::{mmap, mprotect};
+    #[cfg(not(target_os = "linux"))]
+    use libc::{mmap as mmap64, mprotect};
+    #[cfg(target_os = "linux")]
+    use libc::{mmap64, mprotect};
     use libc::{MAP_ANON, MAP_FAILED, MAP_FIXED, MAP_PRIVATE, PROT_NONE, PROT_READ, PROT_WRITE};
 
     use crate::io;
@@ -803,7 +806,7 @@ pub unsafe fn init() -> Option<Guard> {
             // read/write permissions and only then mprotect() it to
             // no permissions at all. See issue #50313.
             let stackptr = get_stack_start_aligned()?;
-            let result = mmap(
+            let result = mmap64(
                 stackptr,
                 page_size,
                 PROT_READ | PROT_WRITE,
index be5c9bb07880891cbe23550c952f2aed26a93c9a..05f25af68ea8fe5985e11370df9bbe03c2951e01 100644 (file)
@@ -89,16 +89,16 @@ fn hash<H: Hasher>(&self, state: &mut H) {
 
 impl<T: Internable + Deref> Deref for Interned<T> {
     type Target = T::Target;
-    fn deref(&self) -> &'static Self::Target {
+    fn deref(&self) -> &Self::Target {
         let l = T::intern_cache().lock().unwrap();
-        unsafe { mem::transmute::<&Self::Target, &'static Self::Target>(l.get(*self)) }
+        unsafe { mem::transmute::<&Self::Target, &Self::Target>(l.get(*self)) }
     }
 }
 
 impl<T: Internable + AsRef<U>, U: ?Sized> AsRef<U> for Interned<T> {
-    fn as_ref(&self) -> &'static U {
+    fn as_ref(&self) -> &U {
         let l = T::intern_cache().lock().unwrap();
-        unsafe { mem::transmute::<&U, &'static U>(l.get(*self).as_ref()) }
+        unsafe { mem::transmute::<&U, &U>(l.get(*self).as_ref()) }
     }
 }
 
index 50caef3553fdaf5f47d8e2248762494b06229750..d1601272af7596e709ab607294aa430b953ca4c0 100644 (file)
@@ -325,7 +325,7 @@ pub(crate) fn build_impls(
     // * https://github.com/rust-lang/rust/pull/99917 â€” where the feature got used
     // * https://github.com/rust-lang/rust/issues/53487 â€” overall tracking issue for Error
     if tcx.has_attr(did, sym::rustc_has_incoherent_inherent_impls) {
-        use rustc_middle::ty::fast_reject::SimplifiedTypeGen::*;
+        use rustc_middle::ty::fast_reject::SimplifiedType::*;
         let type_ =
             if tcx.is_trait(did) { TraitSimplifiedType(did) } else { AdtSimplifiedType(did) };
         for &did in tcx.incoherent_impls(type_) {
index 4a4dc899ba9a379279fa6e0e1d7ea50002dee894..92886bbfe26b4e5d03953f9eb3362bfe03bd3ae9 100644 (file)
@@ -1835,7 +1835,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
             }
         }
 
-        ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs }) => {
+        ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
             // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
             // by looking up the bounds associated with the def_id.
             let bounds = cx
index 7a7313c4bc99d90e5987fa6d2864d7fedfea3a17..7a13e7e36d169c3c50cb31561469381a9414b651 100644 (file)
@@ -1870,7 +1870,7 @@ pub(crate) fn from_symbol(s: Symbol) -> Option<PrimitiveType> {
     }
 
     pub(crate) fn simplified_types() -> &'static SimplifiedTypes {
-        use ty::fast_reject::SimplifiedTypeGen::*;
+        use ty::fast_reject::SimplifiedType::*;
         use ty::{FloatTy, IntTy, UintTy};
         use PrimitiveType::*;
         static CELL: OnceCell<SimplifiedTypes> = OnceCell::new();
index 1e1c657b0bf22f7d71306f57099be4ac8d9c3145..b141820fe423c549217a41e58745f56d763009b6 100644 (file)
@@ -236,12 +236,12 @@ fn next(&mut self) -> Option<Self::Item> {
             return event;
         };
 
-        let mut origtext = String::new();
+        let mut original_text = String::new();
         for event in &mut self.inner {
             match event {
                 Event::End(Tag::CodeBlock(..)) => break,
                 Event::Text(ref s) => {
-                    origtext.push_str(s);
+                    original_text.push_str(s);
                 }
                 _ => {}
             }
@@ -258,7 +258,7 @@ fn next(&mut self) -> Option<Self::Item> {
                                  <pre class=\"language-{}\"><code>{}</code></pre>\
                              </div>",
                             lang,
-                            Escape(&origtext),
+                            Escape(&original_text),
                         )
                         .into(),
                     ));
@@ -268,7 +268,7 @@ fn next(&mut self) -> Option<Self::Item> {
             CodeBlockKind::Indented => Default::default(),
         };
 
-        let lines = origtext.lines().filter_map(|l| map_line(l).for_html());
+        let lines = original_text.lines().filter_map(|l| map_line(l).for_html());
         let text = lines.intersperse("\n".into()).collect::<String>();
 
         compile_fail = parse_result.compile_fail;
@@ -285,7 +285,7 @@ fn next(&mut self) -> Option<Self::Item> {
             if url.is_empty() {
                 return None;
             }
-            let test = origtext
+            let test = original_text
                 .lines()
                 .map(|l| map_line(l).for_code())
                 .intersperse("\n".into())
index c485ac9ddb8c1b2fd2252e4562d7d6f631d908cd..a527e9feaec3758a6c5e104272c5bbb2d0011b12 100644 (file)
@@ -1071,6 +1071,10 @@ pre.rust .doccomment {
        color: var(--code-highlight-doc-comment-color);
 }
 
+.rustdoc.source .example-wrap pre.rust a {
+       background: var(--codeblock-link-background);
+}
+
 .example-wrap.compile_fail,
 .example-wrap.should_panic {
        border-left: 2px solid var(--codeblock-error-color);
@@ -1396,7 +1400,6 @@ kbd {
        vertical-align: middle;
        border: solid 1px var(--border-color);
        border-radius: 3px;
-       cursor: default;
        color: var(--kbd--color);
        background-color: var(--kbd-background);
        box-shadow: inset 0 -1px 0 var(--kbd-box-shadow-color);
@@ -1970,7 +1973,6 @@ in storage.js
 }
 
 .scraped-example .code-wrapper .src-line-numbers {
-       margin: 0;
        padding: 14px 0;
 }
 
index eba845bf5a91565f2219f56f71c9eeb8701526a2..de0dfcd469045e74c94e3037f60500bfbc2d50e4 100644 (file)
@@ -88,6 +88,7 @@ Original by Dempfi (https://github.com/dempfi/ayu)
        --source-sidebar-background-selected: #14191f;
        --source-sidebar-background-hover: #14191f;
        --table-alt-row-background-color: #191f26;
+       --codeblock-link-background: #333;
 }
 
 h1, h2, h3, h4 {
@@ -150,15 +151,10 @@ pre, .rustdoc.source .example-wrap {
        color: #c5c5c5;
 }
 
-.content .item-info::before { color: #ccc; }
-
 .sidebar h2 a,
 .sidebar h3 a {
        color: white;
 }
-body.source .example-wrap pre.rust a {
-       background: #333;
-}
 
 .result-name .primitive > i, .result-name .keyword > i {
        color: #788797;
index d945e956c533e20b52fea54d922924363acd449d..dd7fc6892537c35b57a5e12ce63cfc1a71b3e545 100644 (file)
        --source-sidebar-background-selected: #333;
        --source-sidebar-background-hover: #444;
        --table-alt-row-background-color: #2A2A2A;
-}
-
-.content .item-info::before { color: #ccc; }
-
-body.source .example-wrap pre.rust a {
-       background: #333;
+       --codeblock-link-background: #333;
 }
 
 #titles > button:not(.selected) {
index 58955a79316af3f2485c68e681ba9ac247454934..b69d8a1cff95753f1255550bc5d87be641af01f0 100644 (file)
        --source-sidebar-background-selected: #fff;
        --source-sidebar-background-hover: #e0e0e0;
        --table-alt-row-background-color: #F5F5F5;
-}
-
-.content .item-info::before { color: #ccc; }
-
-body.source .example-wrap pre.rust a {
-       background: #eee;
+       --codeblock-link-background: #eee;
 }
 
 #titles > button:not(.selected) {
index cbbcfad3ef4833016debbc3b8ad3eb299f0fb5b5..e9740e30da483d6a5231c8e47a17fe2a678d015a 100644 (file)
@@ -9,7 +9,7 @@
 // It also validates that functions can be called through function pointers
 // through traits.
 
-#![feature(no_core, lang_items, unboxed_closures, arbitrary_self_types)]
+#![feature(no_core, lang_items, intrinsics, unboxed_closures, arbitrary_self_types)]
 #![crate_type = "lib"]
 #![no_core]
 
@@ -49,6 +49,10 @@ pub trait Fn<Args: Tuple>: FnOnce<Args> {
     extern "rust-call" fn call(&self, args: Args) -> Self::Output;
 }
 
+extern "rust-intrinsic" {
+    pub fn transmute<Src, Dst>(src: Src) -> Dst;
+}
+
 pub static mut STORAGE_FOO: fn(&usize, &mut u32) -> Result<(), ()> = arbitrary_black_box;
 pub static mut STORAGE_BAR: u32 = 12;
 
@@ -87,3 +91,21 @@ pub extern "C" fn test() {
         STORAGE_FOO(&1, &mut buf);
     }
 }
+
+// Validate that we can codegen transmutes between data ptrs and fn ptrs.
+
+// CHECK: define{{.+}}{{void \(\) addrspace\(1\)\*|ptr addrspace\(1\)}} @transmute_data_ptr_to_fn({{\{\}\*|ptr}}{{.*}} %x)
+#[no_mangle]
+pub unsafe fn transmute_data_ptr_to_fn(x: *const ()) -> fn() {
+    // It doesn't matter precisely how this is codegenned (through memory or an addrspacecast),
+    // as long as it doesn't cause a verifier error by using `bitcast`.
+    transmute(x)
+}
+
+// CHECK: define{{.+}}{{\{\}\*|ptr}} @transmute_fn_ptr_to_data({{void \(\) addrspace\(1\)\*|ptr addrspace\(1\)}}{{.*}} %x)
+#[no_mangle]
+pub unsafe fn transmute_fn_ptr_to_data(x: fn()) -> *const () {
+    // It doesn't matter precisely how this is codegenned (through memory or an addrspacecast),
+    // as long as it doesn't cause a verifier error by using `bitcast`.
+    transmute(x)
+}
diff --git a/src/test/mir-opt/building/custom/enums.rs b/src/test/mir-opt/building/custom/enums.rs
new file mode 100644 (file)
index 0000000..e5cd456
--- /dev/null
@@ -0,0 +1,120 @@
+#![feature(custom_mir, core_intrinsics)]
+
+extern crate core;
+use core::intrinsics::mir::*;
+
+// EMIT_MIR enums.switch_bool.built.after.mir
+#[custom_mir(dialect = "built")]
+pub fn switch_bool(b: bool) -> u32 {
+    mir!(
+        {
+            match b {
+                true => t,
+                false => f,
+                _ => f,
+            }
+        }
+
+        t = {
+            RET = 5;
+            Return()
+        }
+
+        f = {
+            RET = 10;
+            Return()
+        }
+    )
+}
+
+// EMIT_MIR enums.switch_option.built.after.mir
+#[custom_mir(dialect = "built")]
+pub fn switch_option(option: Option<()>) -> bool {
+    mir!(
+        {
+            let discr = Discriminant(option);
+            match discr {
+                0 => n,
+                1 => s,
+                _ => s,
+            }
+        }
+
+        n = {
+            RET = false;
+            Return()
+        }
+
+        s = {
+            RET = true;
+            Return()
+        }
+    )
+}
+
+#[repr(u8)]
+enum Bool {
+    False = 0,
+    True = 1,
+}
+
+// EMIT_MIR enums.switch_option_repr.built.after.mir
+#[custom_mir(dialect = "built")]
+fn switch_option_repr(option: Bool) -> bool {
+    mir!(
+        {
+            let discr = Discriminant(option);
+            match discr {
+                0 => f,
+                _ => t,
+            }
+        }
+
+        t = {
+            RET = true;
+            Return()
+        }
+
+        f = {
+            RET = false;
+            Return()
+        }
+    )
+}
+
+// EMIT_MIR enums.set_discr.built.after.mir
+#[custom_mir(dialect = "runtime", phase = "initial")]
+fn set_discr(option: &mut Option<()>) {
+    mir!({
+        SetDiscriminant(*option, 0);
+        Return()
+    })
+}
+
+// EMIT_MIR enums.set_discr_repr.built.after.mir
+#[custom_mir(dialect = "runtime", phase = "initial")]
+fn set_discr_repr(b: &mut Bool) {
+    mir!({
+        SetDiscriminant(*b, 0);
+        Return()
+    })
+}
+
+fn main() {
+    assert_eq!(switch_bool(true), 5);
+    assert_eq!(switch_bool(false), 10);
+
+    assert_eq!(switch_option(Some(())), true);
+    assert_eq!(switch_option(None), false);
+
+    assert_eq!(switch_option_repr(Bool::True), true);
+    assert_eq!(switch_option_repr(Bool::False), false);
+
+    let mut opt = Some(());
+    set_discr(&mut opt);
+    assert_eq!(opt, None);
+
+    let mut b = Bool::True;
+    set_discr_repr(&mut b);
+    assert!(matches!(b, Bool::False));
+}
diff --git a/src/test/mir-opt/building/custom/enums.set_discr.built.after.mir b/src/test/mir-opt/building/custom/enums.set_discr.built.after.mir
new file mode 100644 (file)
index 0000000..7de9ed0
--- /dev/null
@@ -0,0 +1,10 @@
+// MIR for `set_discr` after built
+
+fn set_discr(_1: &mut Option<()>) -> () {
+    let mut _0: ();                      // return place in scope 0 at $DIR/enums.rs:+0:39: +0:39
+
+    bb0: {
+        discriminant((*_1)) = 0;         // scope 0 at $DIR/enums.rs:+2:9: +2:36
+        return;                          // scope 0 at $DIR/enums.rs:+3:9: +3:17
+    }
+}
diff --git a/src/test/mir-opt/building/custom/enums.set_discr_repr.built.after.mir b/src/test/mir-opt/building/custom/enums.set_discr_repr.built.after.mir
new file mode 100644 (file)
index 0000000..6fdc3d0
--- /dev/null
@@ -0,0 +1,10 @@
+// MIR for `set_discr_repr` after built
+
+fn set_discr_repr(_1: &mut Bool) -> () {
+    let mut _0: ();                      // return place in scope 0 at $DIR/enums.rs:+0:33: +0:33
+
+    bb0: {
+        discriminant((*_1)) = 0;         // scope 0 at $DIR/enums.rs:+2:9: +2:31
+        return;                          // scope 0 at $DIR/enums.rs:+3:9: +3:17
+    }
+}
diff --git a/src/test/mir-opt/building/custom/enums.switch_bool.built.after.mir b/src/test/mir-opt/building/custom/enums.switch_bool.built.after.mir
new file mode 100644 (file)
index 0000000..95c57d2
--- /dev/null
@@ -0,0 +1,19 @@
+// MIR for `switch_bool` after built
+
+fn switch_bool(_1: bool) -> u32 {
+    let mut _0: u32;                     // return place in scope 0 at $DIR/enums.rs:+0:32: +0:35
+
+    bb0: {
+        switchInt(_1) -> [1: bb1, 0: bb2, otherwise: bb2]; // scope 0 at $DIR/enums.rs:+3:13: +7:14
+    }
+
+    bb1: {
+        _0 = const 5_u32;                // scope 0 at $DIR/enums.rs:+11:13: +11:20
+        return;                          // scope 0 at $DIR/enums.rs:+12:13: +12:21
+    }
+
+    bb2: {
+        _0 = const 10_u32;               // scope 0 at $DIR/enums.rs:+16:13: +16:21
+        return;                          // scope 0 at $DIR/enums.rs:+17:13: +17:21
+    }
+}
diff --git a/src/test/mir-opt/building/custom/enums.switch_option.built.after.mir b/src/test/mir-opt/building/custom/enums.switch_option.built.after.mir
new file mode 100644 (file)
index 0000000..a659ba7
--- /dev/null
@@ -0,0 +1,21 @@
+// MIR for `switch_option` after built
+
+fn switch_option(_1: Option<()>) -> bool {
+    let mut _0: bool;                    // return place in scope 0 at $DIR/enums.rs:+0:45: +0:49
+    let mut _2: isize;                   // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+
+    bb0: {
+        _2 = discriminant(_1);           // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+        switchInt(_2) -> [0: bb1, 1: bb2, otherwise: bb2]; // scope 0 at $DIR/enums.rs:+4:13: +8:14
+    }
+
+    bb1: {
+        _0 = const false;                // scope 0 at $DIR/enums.rs:+12:13: +12:24
+        return;                          // scope 0 at $DIR/enums.rs:+13:13: +13:21
+    }
+
+    bb2: {
+        _0 = const true;                 // scope 0 at $DIR/enums.rs:+17:13: +17:23
+        return;                          // scope 0 at $DIR/enums.rs:+18:13: +18:21
+    }
+}
diff --git a/src/test/mir-opt/building/custom/enums.switch_option_repr.built.after.mir b/src/test/mir-opt/building/custom/enums.switch_option_repr.built.after.mir
new file mode 100644 (file)
index 0000000..d60e4b1
--- /dev/null
@@ -0,0 +1,21 @@
+// MIR for `switch_option_repr` after built
+
+fn switch_option_repr(_1: Bool) -> bool {
+    let mut _0: bool;                    // return place in scope 0 at $DIR/enums.rs:+0:40: +0:44
+    let mut _2: u8;                      // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+
+    bb0: {
+        _2 = discriminant(_1);           // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+        switchInt(_2) -> [0: bb2, otherwise: bb1]; // scope 0 at $DIR/enums.rs:+4:13: +7:14
+    }
+
+    bb1: {
+        _0 = const true;                 // scope 0 at $DIR/enums.rs:+11:13: +11:23
+        return;                          // scope 0 at $DIR/enums.rs:+12:13: +12:21
+    }
+
+    bb2: {
+        _0 = const false;                // scope 0 at $DIR/enums.rs:+16:13: +16:24
+        return;                          // scope 0 at $DIR/enums.rs:+17:13: +17:21
+    }
+}
diff --git a/src/test/mir-opt/building/custom/projections.rs b/src/test/mir-opt/building/custom/projections.rs
new file mode 100644 (file)
index 0000000..5e472e5
--- /dev/null
@@ -0,0 +1,85 @@
+#![feature(custom_mir, core_intrinsics)]
+
+extern crate core;
+use core::intrinsics::mir::*;
+
+union U {
+    a: i32,
+    b: u32,
+}
+
+// EMIT_MIR projections.unions.built.after.mir
+#[custom_mir(dialect = "built")]
+fn unions(u: U) -> i32 {
+    mir!({
+        RET = u.a;
+        Return()
+    })
+}
+
+// EMIT_MIR projections.tuples.built.after.mir
+#[custom_mir(dialect = "analysis", phase = "post-cleanup")]
+fn tuples(i: (u32, i32)) -> (u32, i32) {
+    mir!(
+        // FIXME(JakobDegen): This is necessary because we can't give type hints for `RET`
+        let temp: (u32, i32);
+        {
+            temp.0 = i.0;
+            temp.1 = i.1;
+
+            RET = temp;
+            Return()
+        }
+    )
+}
+
+// EMIT_MIR projections.unwrap.built.after.mir
+#[custom_mir(dialect = "built")]
+fn unwrap(opt: Option<i32>) -> i32 {
+    mir!({
+        RET = Field(Variant(opt, 1), 0);
+        Return()
+    })
+}
+
+// EMIT_MIR projections.unwrap_deref.built.after.mir
+#[custom_mir(dialect = "built")]
+fn unwrap_deref(opt: Option<&i32>) -> i32 {
+    mir!({
+        RET = *Field::<&i32>(Variant(opt, 1), 0);
+        Return()
+    })
+}
+
+// EMIT_MIR projections.set.built.after.mir
+#[custom_mir(dialect = "built")]
+fn set(opt: &mut Option<i32>) {
+    mir!({
+        place!(Field(Variant(*opt, 1), 0)) = 10;
+        Return()
+    })
+}
+
+// EMIT_MIR projections.simple_index.built.after.mir
+#[custom_mir(dialect = "built")]
+fn simple_index(a: [i32; 10], b: &[i32]) -> i32 {
+    mir!({
+        let temp = 3;
+        RET = a[temp];
+        RET = (*b)[temp];
+        Return()
+    })
+}
+
+fn main() {
+    assert_eq!(unions(U { a: 5 }), 5);
+    assert_eq!(tuples((5, 6)), (5, 6));
+
+    assert_eq!(unwrap(Some(5)), 5);
+    assert_eq!(unwrap_deref(Some(&5)), 5);
+    let mut o = Some(5);
+    set(&mut o);
+    assert_eq!(o, Some(10));
+
+    assert_eq!(simple_index([0; 10], &[0; 10]), 0);
+}
diff --git a/src/test/mir-opt/building/custom/projections.set.built.after.mir b/src/test/mir-opt/building/custom/projections.set.built.after.mir
new file mode 100644 (file)
index 0000000..2f15176
--- /dev/null
@@ -0,0 +1,10 @@
+// MIR for `set` after built
+
+fn set(_1: &mut Option<i32>) -> () {
+    let mut _0: ();                      // return place in scope 0 at $DIR/projections.rs:+0:31: +0:31
+
+    bb0: {
+        (((*_1) as variant#1).0: i32) = const 10_i32; // scope 0 at $DIR/projections.rs:+2:9: +2:48
+        return;                          // scope 0 at $DIR/projections.rs:+3:9: +3:17
+    }
+}
diff --git a/src/test/mir-opt/building/custom/projections.simple_index.built.after.mir b/src/test/mir-opt/building/custom/projections.simple_index.built.after.mir
new file mode 100644 (file)
index 0000000..fc422e4
--- /dev/null
@@ -0,0 +1,13 @@
+// MIR for `simple_index` after built
+
+fn simple_index(_1: [i32; 10], _2: &[i32]) -> i32 {
+    let mut _0: i32;                     // return place in scope 0 at $DIR/projections.rs:+0:45: +0:48
+    let mut _3: usize;                   // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+
+    bb0: {
+        _3 = const 3_usize;              // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+        _0 = _1[_3];                     // scope 0 at $DIR/projections.rs:+3:9: +3:22
+        _0 = (*_2)[_3];                  // scope 0 at $DIR/projections.rs:+4:9: +4:25
+        return;                          // scope 0 at $DIR/projections.rs:+5:9: +5:17
+    }
+}
diff --git a/src/test/mir-opt/building/custom/projections.tuples.built.after.mir b/src/test/mir-opt/building/custom/projections.tuples.built.after.mir
new file mode 100644 (file)
index 0000000..65487d3
--- /dev/null
@@ -0,0 +1,13 @@
+// MIR for `tuples` after built
+
+fn tuples(_1: (u32, i32)) -> (u32, i32) {
+    let mut _0: (u32, i32);              // return place in scope 0 at $DIR/projections.rs:+0:29: +0:39
+    let mut _2: (u32, i32);              // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+
+    bb0: {
+        (_2.0: u32) = (_1.0: u32);       // scope 0 at $DIR/projections.rs:+5:13: +5:25
+        (_2.1: i32) = (_1.1: i32);       // scope 0 at $DIR/projections.rs:+6:13: +6:25
+        _0 = _2;                         // scope 0 at $DIR/projections.rs:+8:13: +8:23
+        return;                          // scope 0 at $DIR/projections.rs:+9:13: +9:21
+    }
+}
diff --git a/src/test/mir-opt/building/custom/projections.unions.built.after.mir b/src/test/mir-opt/building/custom/projections.unions.built.after.mir
new file mode 100644 (file)
index 0000000..922538a
--- /dev/null
@@ -0,0 +1,10 @@
+// MIR for `unions` after built
+
+fn unions(_1: U) -> i32 {
+    let mut _0: i32;                     // return place in scope 0 at $DIR/projections.rs:+0:20: +0:23
+
+    bb0: {
+        _0 = (_1.0: i32);                // scope 0 at $DIR/projections.rs:+2:9: +2:18
+        return;                          // scope 0 at $DIR/projections.rs:+3:9: +3:17
+    }
+}
diff --git a/src/test/mir-opt/building/custom/projections.unwrap.built.after.mir b/src/test/mir-opt/building/custom/projections.unwrap.built.after.mir
new file mode 100644 (file)
index 0000000..75b03a3
--- /dev/null
@@ -0,0 +1,10 @@
+// MIR for `unwrap` after built
+
+fn unwrap(_1: Option<i32>) -> i32 {
+    let mut _0: i32;                     // return place in scope 0 at $DIR/projections.rs:+0:32: +0:35
+
+    bb0: {
+        _0 = ((_1 as variant#1).0: i32); // scope 0 at $DIR/projections.rs:+2:9: +2:40
+        return;                          // scope 0 at $DIR/projections.rs:+3:9: +3:17
+    }
+}
diff --git a/src/test/mir-opt/building/custom/projections.unwrap_deref.built.after.mir b/src/test/mir-opt/building/custom/projections.unwrap_deref.built.after.mir
new file mode 100644 (file)
index 0000000..c6b0f7e
--- /dev/null
@@ -0,0 +1,10 @@
+// MIR for `unwrap_deref` after built
+
+fn unwrap_deref(_1: Option<&i32>) -> i32 {
+    let mut _0: i32;                     // return place in scope 0 at $DIR/projections.rs:+0:39: +0:42
+
+    bb0: {
+        _0 = (*((_1 as variant#1).0: &i32)); // scope 0 at $DIR/projections.rs:+2:9: +2:49
+        return;                          // scope 0 at $DIR/projections.rs:+3:9: +3:17
+    }
+}
diff --git a/src/test/mir-opt/building/custom/references.raw_pointer.built.after.mir b/src/test/mir-opt/building/custom/references.raw_pointer.built.after.mir
new file mode 100644 (file)
index 0000000..775e5e3
--- /dev/null
@@ -0,0 +1,10 @@
+// MIR for `raw_pointer` after built
+
+fn raw_pointer(_1: *const i32) -> *const i32 {
+    let mut _0: *const i32;              // return place in scope 0 at $DIR/references.rs:+0:38: +0:48
+
+    bb0: {
+        _0 = &raw const (*_1);           // scope 0 at $DIR/references.rs:+4:9: +4:27
+        return;                          // scope 0 at $DIR/references.rs:+5:9: +5:17
+    }
+}
index dee85722e8656daaffc42780c5d8ef5946dc0023..c93f6ec624b3551784c67643d449ce3a4bce8c7c 100644 (file)
@@ -36,8 +36,22 @@ pub fn immut_ref(x: &i32) -> &i32 {
     )
 }
 
+// EMIT_MIR references.raw_pointer.built.after.mir
+#[custom_mir(dialect = "built")]
+pub fn raw_pointer(x: *const i32) -> *const i32 {
+    // Regression test for a bug in which unsafetyck was not correctly turned off for
+    // `dialect = "built"`
+    mir!({
+        RET = addr_of!(*x);
+        Return()
+    })
+}
+
 fn main() {
     let mut x = 5;
     assert_eq!(*mut_ref(&mut x), 5);
     assert_eq!(*immut_ref(&x), 5);
+    unsafe {
+        assert_eq!(*raw_pointer(addr_of!(x)), 5);
+    }
 }
index 799ba851c92f9a1aaa7892c758e87bba78d5b182..80203901ed3c4c5c4678d48cd7a3461e4a3f1ca5 100644 (file)
@@ -27,7 +27,6 @@ define-function: (
             "color": |color|,
             "background-color": |background|,
             "box-shadow": |box_shadow| + " 0px -1px 0px 0px inset",
-            "cursor": "default",
         }, ALL)),
     ],
 )
index 94cf7b94241df8d79144969b852f538de8ccfa88..3537e669608d15faf6afbcc26b5410b865225720 100644 (file)
@@ -35,6 +35,7 @@
     -Z            dump-mir-exclude-pass-number=val -- exclude the pass number when dumping MIR (used in tests) (default: no)
     -Z                       dump-mir-graphviz=val -- in addition to `.mir` files, create graphviz `.dot` files (and with `-Z instrument-coverage`, also create a `.dot` file for the MIR-derived coverage graph) (default: no)
     -Z                       dump-mir-spanview=val -- in addition to `.mir` files, create `.html` files to view spans for all `statement`s (including terminators), only `terminator` spans, or computed `block` spans (one span encompassing a block's terminator and all statements). If `-Z instrument-coverage` is also enabled, create an additional `.html` file showing the computed coverage spans.
+    -Z                         dump-mono-stats=val -- output statistics about monomorphization collection (format: markdown)
     -Z                           dwarf-version=val -- version of DWARF debug information to emit (default: 2 or 4, depending on platform)
     -Z                               dylib-lto=val -- enables LTO for dylib crate type
     -Z                        emit-stack-sizes=val -- emit a section containing stack size metadata (default: no)
index cb4cd466590b626e5e2553dacda2df9e2047af42..c19b639a8d5819d1f84a23f9330cbd7a4f02f03d 100644 (file)
@@ -683,7 +683,7 @@ struct RawIdentDiagnosticArg {
 #[diag(compiletest_example)]
 struct SubdiagnosticBad {
     #[subdiagnostic(bad)]
-    //~^ ERROR `#[subdiagnostic(bad)]` is not a valid attribute
+    //~^ ERROR `#[subdiagnostic(...)]` is not a valid attribute
     note: Note,
 }
 
@@ -707,7 +707,7 @@ struct SubdiagnosticBadTwice {
 #[diag(compiletest_example)]
 struct SubdiagnosticBadLitStr {
     #[subdiagnostic("bad")]
-    //~^ ERROR `#[subdiagnostic("...")]` is not a valid attribute
+    //~^ ERROR `#[subdiagnostic(...)]` is not a valid attribute
     note: Note,
 }
 
@@ -723,6 +723,7 @@ struct SubdiagnosticEagerLint {
 #[diag(compiletest_example)]
 struct SubdiagnosticEagerCorrect {
     #[subdiagnostic(eager)]
+    //~^ ERROR `#[subdiagnostic(...)]` is not a valid attribute
     note: Note,
 }
 
@@ -743,6 +744,7 @@ pub(crate) struct SubdiagnosticWithSuggestion {
 #[diag(compiletest_example)]
 struct SubdiagnosticEagerSuggestion {
     #[subdiagnostic(eager)]
+    //~^ ERROR `#[subdiagnostic(...)]` is not a valid attribute
     sub: SubdiagnosticWithSuggestion,
 }
 
index 1b7ef4e4f19cfc193c26ee6aa643adbb99c720c5..f39d32a221cacc1084bbecd15b635a1ef43a7fb9 100644 (file)
@@ -533,21 +533,19 @@ LL | #[label]
    |
    = help: `#[label]` and `#[suggestion]` can only be applied to fields
 
-error: `#[subdiagnostic(bad)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:685:21
+error: `#[subdiagnostic(...)]` is not a valid attribute
+  --> $DIR/diagnostic-derive.rs:685:5
    |
 LL |     #[subdiagnostic(bad)]
-   |                     ^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: `eager` is the only supported nested attribute for `subdiagnostic`
+   = help: `subdiagnostic` does not support nested attributes
 
 error: `#[subdiagnostic = ...]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:693:5
    |
 LL |     #[subdiagnostic = "bad"]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: `eager` is the only supported nested attribute for `subdiagnostic`
 
 error: `#[subdiagnostic(...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:701:5
@@ -555,15 +553,15 @@ error: `#[subdiagnostic(...)]` is not a valid attribute
 LL |     #[subdiagnostic(bad, bad)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: `eager` is the only supported nested attribute for `subdiagnostic`
+   = help: `subdiagnostic` does not support nested attributes
 
-error: `#[subdiagnostic("...")]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:709:21
+error: `#[subdiagnostic(...)]` is not a valid attribute
+  --> $DIR/diagnostic-derive.rs:709:5
    |
 LL |     #[subdiagnostic("bad")]
-   |                     ^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: `eager` is the only supported nested attribute for `subdiagnostic`
+   = help: `subdiagnostic` does not support nested attributes
 
 error: `#[subdiagnostic(...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:717:5
@@ -571,22 +569,38 @@ error: `#[subdiagnostic(...)]` is not a valid attribute
 LL |     #[subdiagnostic(eager)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: eager subdiagnostics are not supported on lints
+   = help: `subdiagnostic` does not support nested attributes
+
+error: `#[subdiagnostic(...)]` is not a valid attribute
+  --> $DIR/diagnostic-derive.rs:725:5
+   |
+LL |     #[subdiagnostic(eager)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: `subdiagnostic` does not support nested attributes
+
+error: `#[subdiagnostic(...)]` is not a valid attribute
+  --> $DIR/diagnostic-derive.rs:746:5
+   |
+LL |     #[subdiagnostic(eager)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: `subdiagnostic` does not support nested attributes
 
 error: expected at least one string literal for `code(...)`
-  --> $DIR/diagnostic-derive.rs:775:18
+  --> $DIR/diagnostic-derive.rs:777:18
    |
 LL |     #[suggestion(code())]
    |                  ^^^^^^
 
 error: `code(...)` must contain only string literals
-  --> $DIR/diagnostic-derive.rs:783:23
+  --> $DIR/diagnostic-derive.rs:785:23
    |
 LL |     #[suggestion(code(foo))]
    |                       ^^^
 
 error: `code = "..."`/`code(...)` must contain only string literals
-  --> $DIR/diagnostic-derive.rs:791:18
+  --> $DIR/diagnostic-derive.rs:793:18
    |
 LL |     #[suggestion(code = 3)]
    |                  ^^^^^^^^
@@ -662,7 +676,7 @@ note: required by a bound in `DiagnosticBuilder::<'a, G>::set_arg`
   --> $COMPILER_DIR/rustc_errors/src/diagnostic_builder.rs:LL:CC
    = note: this error originates in the derive macro `Diagnostic` which comes from the expansion of the macro `forward` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 83 previous errors
+error: aborting due to 85 previous errors
 
 Some errors have detailed explanations: E0277, E0425.
 For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/argument-suggestions/display-is-suggestable.rs b/src/test/ui/argument-suggestions/display-is-suggestable.rs
new file mode 100644 (file)
index 0000000..d765bc4
--- /dev/null
@@ -0,0 +1,8 @@
+use std::fmt::Display;
+
+fn foo(x: &(dyn Display + Send)) {}
+
+fn main() {
+    foo();
+    //~^ ERROR this function takes 1 argument but 0 arguments were supplied
+}
diff --git a/src/test/ui/argument-suggestions/display-is-suggestable.stderr b/src/test/ui/argument-suggestions/display-is-suggestable.stderr
new file mode 100644 (file)
index 0000000..edd72b5
--- /dev/null
@@ -0,0 +1,19 @@
+error[E0061]: this function takes 1 argument but 0 arguments were supplied
+  --> $DIR/display-is-suggestable.rs:6:5
+   |
+LL |     foo();
+   |     ^^^-- an argument of type `&dyn std::fmt::Display + Send` is missing
+   |
+note: function defined here
+  --> $DIR/display-is-suggestable.rs:3:4
+   |
+LL | fn foo(x: &(dyn Display + Send)) {}
+   |    ^^^ ------------------------
+help: provide the argument
+   |
+LL |     foo(/* &dyn std::fmt::Display + Send */);
+   |        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0061`.
diff --git a/src/test/ui/associated-type-bounds/const-projection-err.gce.stderr b/src/test/ui/associated-type-bounds/const-projection-err.gce.stderr
new file mode 100644 (file)
index 0000000..0f1ec9a
--- /dev/null
@@ -0,0 +1,24 @@
+warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/const-projection-err.rs:4:26
+   |
+LL | #![cfg_attr(gce, feature(generic_const_exprs))]
+   |                          ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0271]: type mismatch resolving `<T as TraitWAssocConst>::A == 1`
+  --> $DIR/const-projection-err.rs:14:11
+   |
+LL |     foo::<T>();
+   |           ^ expected `0`, found `1`
+   |
+note: required by a bound in `foo`
+  --> $DIR/const-projection-err.rs:11:28
+   |
+LL | fn foo<T: TraitWAssocConst<A = 1>>() {}
+   |                            ^^^^^ required by this bound in `foo`
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0271`.
diff --git a/src/test/ui/associated-type-bounds/const-projection-err.rs b/src/test/ui/associated-type-bounds/const-projection-err.rs
new file mode 100644 (file)
index 0000000..bead856
--- /dev/null
@@ -0,0 +1,18 @@
+// revisions: stock gce
+
+#![feature(associated_const_equality)]
+#![cfg_attr(gce, feature(generic_const_exprs))]
+//[gce]~^ WARN the feature `generic_const_exprs` is incomplete
+
+trait TraitWAssocConst {
+    const A: usize;
+}
+
+fn foo<T: TraitWAssocConst<A = 1>>() {}
+
+fn bar<T: TraitWAssocConst<A = 0>>() {
+    foo::<T>();
+    //~^ ERROR type mismatch resolving `<T as TraitWAssocConst>::A == 1`
+}
+
+fn main() {}
diff --git a/src/test/ui/associated-type-bounds/const-projection-err.stock.stderr b/src/test/ui/associated-type-bounds/const-projection-err.stock.stderr
new file mode 100644 (file)
index 0000000..bf08242
--- /dev/null
@@ -0,0 +1,17 @@
+error[E0271]: type mismatch resolving `<T as TraitWAssocConst>::A == 1`
+  --> $DIR/const-projection-err.rs:14:11
+   |
+LL |     foo::<T>();
+   |           ^ expected `1`, found `<T as TraitWAssocConst>::A`
+   |
+   = note: expected constant `1`
+              found constant `<T as TraitWAssocConst>::A`
+note: required by a bound in `foo`
+  --> $DIR/const-projection-err.rs:11:28
+   |
+LL | fn foo<T: TraitWAssocConst<A = 1>>() {}
+   |                            ^^^^^ required by this bound in `foo`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0271`.
index 26b9f4b3a92660ea78b923adb3884545ea4eb81a..fed60ccf089d05c85288a7ef3774506f7d2dbd96 100644 (file)
@@ -4,5 +4,5 @@
 
 fn main() {
     let _: &dyn I32Iterator<Item = u32> = &vec![42].into_iter();
-    //~^ ERROR expected `std::vec::IntoIter<u32>` to be an iterator that yields `i32`, but it yields `u32`
+    //~^ ERROR expected `IntoIter<u32>` to be an iterator that yields `i32`, but it yields `u32`
 }
index 2d25f68de44ad1c34a7c36976ce21a9300699deb..a28a0b74e4accd98c47bbf6f001d9562560f4ff8 100644 (file)
@@ -1,4 +1,4 @@
-error[E0271]: expected `std::vec::IntoIter<u32>` to be an iterator that yields `i32`, but it yields `u32`
+error[E0271]: expected `IntoIter<u32>` to be an iterator that yields `i32`, but it yields `u32`
   --> $DIR/associated-types-overridden-binding-2.rs:6:43
    |
 LL |     let _: &dyn I32Iterator<Item = u32> = &vec![42].into_iter();
index 61d7e2520eab7a8cea7c3f8f97fd2a932aa4d5bd..1b1b3cffd58f3d81f2eccfd6d53a374a64c272aa 100644 (file)
@@ -1,4 +1,3 @@
-// check-pass
 // edition: 2021
 
 #![feature(async_fn_in_trait)]
@@ -13,11 +12,9 @@ trait MyTrait {
 }
 
 impl MyTrait for i32 {
-    // This will break once a PR that implements #102745 is merged
     fn foo(&self) -> Pin<Box<dyn Future<Output = i32> + '_>> {
-        Box::pin(async {
-            *self
-        })
+        //~^ ERROR method `foo` should be async
+        Box::pin(async { *self })
     }
 }
 
diff --git a/src/test/ui/async-await/in-trait/async-example-desugared-boxed.stderr b/src/test/ui/async-await/in-trait/async-example-desugared-boxed.stderr
new file mode 100644 (file)
index 0000000..60fa534
--- /dev/null
@@ -0,0 +1,11 @@
+error: method `foo` should be async because the method from the trait is async
+  --> $DIR/async-example-desugared-boxed.rs:15:5
+   |
+LL |     async fn foo(&self) -> i32;
+   |     --------------------------- required because the trait method is async
+...
+LL |     fn foo(&self) -> Pin<Box<dyn Future<Output = i32> + '_>> {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/async-await/in-trait/async-example-desugared-extra.rs b/src/test/ui/async-await/in-trait/async-example-desugared-extra.rs
new file mode 100644 (file)
index 0000000..81e1e59
--- /dev/null
@@ -0,0 +1,37 @@
+// check-pass
+// edition: 2021
+
+#![feature(async_fn_in_trait)]
+#![feature(return_position_impl_trait_in_trait)]
+#![allow(incomplete_features)]
+
+use std::future::Future;
+use std::pin::Pin;
+use std::task::Poll;
+
+trait MyTrait {
+    async fn foo(&self) -> i32;
+}
+
+#[derive(Clone)]
+struct MyFuture(i32);
+
+impl Future for MyFuture {
+    type Output = i32;
+    fn poll(
+        self: Pin<&mut Self>,
+        _: &mut std::task::Context<'_>,
+    ) -> Poll<<Self as Future>::Output> {
+        Poll::Ready(self.0)
+    }
+}
+
+impl MyTrait for i32 {
+    // FIXME: this should eventually require `#[refine]` to compile, because it also provides
+    // `Clone`.
+    fn foo(&self) -> impl Future<Output = i32> + Clone {
+        MyFuture(*self)
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/async-await/in-trait/async-example-desugared-manual.rs b/src/test/ui/async-await/in-trait/async-example-desugared-manual.rs
new file mode 100644 (file)
index 0000000..71473e7
--- /dev/null
@@ -0,0 +1,29 @@
+// edition: 2021
+
+#![feature(async_fn_in_trait)]
+#![feature(return_position_impl_trait_in_trait)]
+#![allow(incomplete_features)]
+
+use std::future::Future;
+use std::task::Poll;
+
+trait MyTrait {
+    async fn foo(&self) -> i32;
+}
+
+struct MyFuture;
+impl Future for MyFuture {
+    type Output = i32;
+    fn poll(self: std::pin::Pin<&mut Self>, _: &mut std::task::Context<'_>) -> Poll<Self::Output> {
+        Poll::Ready(0)
+    }
+}
+
+impl MyTrait for u32 {
+    fn foo(&self) -> MyFuture {
+        //~^ ERROR method `foo` should be async
+        MyFuture
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/async-await/in-trait/async-example-desugared-manual.stderr b/src/test/ui/async-await/in-trait/async-example-desugared-manual.stderr
new file mode 100644 (file)
index 0000000..567a36a
--- /dev/null
@@ -0,0 +1,11 @@
+error: method `foo` should be async because the method from the trait is async
+  --> $DIR/async-example-desugared-manual.rs:23:5
+   |
+LL |     async fn foo(&self) -> i32;
+   |     --------------------------- required because the trait method is async
+...
+LL |     fn foo(&self) -> MyFuture {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
index 1313c9edd861c213850af2725cadc84f52146fed..fb92ec786746f9cb9ba3c18b0c9a239da183fa1e 100644 (file)
@@ -12,11 +12,8 @@ trait MyTrait {
 }
 
 impl MyTrait for i32 {
-    // This will break once a PR that implements #102745 is merged
     fn foo(&self) -> impl Future<Output = i32> + '_ {
-        async {
-            *self
-        }
+        async { *self }
     }
 }
 
index f94d32145a290297c1750035ba89297ecf8220eb..9598d53bce8b2ec02cd2f6e91086eb8560b90595 100644 (file)
@@ -9,7 +9,7 @@ trait MyTrait {
 
 impl MyTrait for i32 {
     fn foo(&self) -> i32 {
-        //~^ ERROR: `i32` is not a future [E0277]
+        //~^ ERROR: method `foo` should be async
         *self
     }
 }
index 03321dc5b5af16a4ccbd9baa3f78fb005151201b..579801d0f3975cf89a8bbe03eae3dd7f9837fadc 100644 (file)
@@ -1,17 +1,11 @@
-error[E0277]: `i32` is not a future
-  --> $DIR/fn-not-async-err.rs:11:22
-   |
-LL |     fn foo(&self) -> i32 {
-   |                      ^^^ `i32` is not a future
-   |
-   = help: the trait `Future` is not implemented for `i32`
-   = note: i32 must be a future or must implement `IntoFuture` to be awaited
-note: required by a bound in `MyTrait::foo::{opaque#0}`
-  --> $DIR/fn-not-async-err.rs:7:28
+error: method `foo` should be async because the method from the trait is async
+  --> $DIR/fn-not-async-err.rs:11:5
    |
 LL |     async fn foo(&self) -> i32;
-   |                            ^^^ required by this bound in `MyTrait::foo::{opaque#0}`
+   |     --------------------------- required because the trait method is async
+...
+LL |     fn foo(&self) -> i32 {
+   |     ^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0277`.
index 594baa91ad8ba61c21eb6914ae4c0b24e5fedd0b..2c4ed5535801e95db3c17300b6784db11b3fbeb4 100644 (file)
@@ -12,9 +12,7 @@ trait MyTrait {
 impl MyTrait for i32 {
     fn foo(&self) -> impl Future<Output = i32> {
         //~^ ERROR `impl Trait` only allowed in function and inherent method return types, not in `impl` method return [E0562]
-        async {
-            *self
-        }
+        async { *self }
     }
 }
 
diff --git a/src/test/ui/async-await/in-trait/issue-104678.rs b/src/test/ui/async-await/in-trait/issue-104678.rs
new file mode 100644 (file)
index 0000000..e396df4
--- /dev/null
@@ -0,0 +1,31 @@
+// edition:2021
+// check-pass
+
+#![feature(async_fn_in_trait)]
+#![allow(incomplete_features)]
+
+use std::future::Future;
+pub trait Pool {
+    type Conn;
+
+    async fn async_callback<'a, F: FnOnce(&'a Self::Conn) -> Fut, Fut: Future<Output = ()>>(
+        &'a self,
+        callback: F,
+    ) -> ();
+}
+
+pub struct PoolImpl;
+pub struct ConnImpl;
+
+impl Pool for PoolImpl {
+    type Conn = ConnImpl;
+
+    async fn async_callback<'a, F: FnOnce(&'a Self::Conn) -> Fut, Fut: Future<Output = ()>>(
+        &'a self,
+        _callback: F,
+    ) -> () {
+        todo!()
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/borrowck/issue-104639-lifetime-order.rs b/src/test/ui/borrowck/issue-104639-lifetime-order.rs
new file mode 100644 (file)
index 0000000..db1f8f8
--- /dev/null
@@ -0,0 +1,10 @@
+// edition:2018
+// check-pass
+
+#![allow(dead_code)]
+async fn fail<'a, 'b, 'c>(_: &'static str) where 'a: 'c, 'b: 'c, {}
+async fn pass<'a, 'c, 'b>(_: &'static str) where 'a: 'c, 'b: 'c, {}
+async fn pass2<'a, 'b, 'c>(_: &'static str) where 'a: 'c, 'b: 'c, 'c: 'a, {}
+async fn pass3<'a, 'b, 'c>(_: &'static str) where 'a: 'b, 'b: 'c, 'c: 'a, {}
+
+fn main() { }
index 34debb6831734568330e7b6d8ccfaa32ae753e3f..3906d64c9462453682f8edf42d47332c5619b14f 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `closure` found for reference `&Obj<[closure@$DIR/issue-33784.rs:25:43: 25:45]>` in the current scope
+error[E0599]: no method named `closure` found for reference `&Obj<[closure@issue-33784.rs:25:43]>` in the current scope
   --> $DIR/issue-33784.rs:27:7
    |
 LL |     p.closure();
@@ -9,7 +9,7 @@ help: to call the function stored in `closure`, surround the field access with p
 LL |     (p.closure)();
    |     +         +
 
-error[E0599]: no method named `fn_ptr` found for reference `&&Obj<[closure@$DIR/issue-33784.rs:25:43: 25:45]>` in the current scope
+error[E0599]: no method named `fn_ptr` found for reference `&&Obj<[closure@issue-33784.rs:25:43]>` in the current scope
   --> $DIR/issue-33784.rs:29:7
    |
 LL |     q.fn_ptr();
index e0444042614bb683f4a6d0cd8c213b8d4f95977a..0af5493f81675502ced616895b8f4bf9b1ccc503 100644 (file)
@@ -40,8 +40,17 @@ error[E0283]: type annotations needed: cannot satisfy `IsLessOrEqual<I, 8>: True
 LL |     IsLessOrEqual<I, 8>: True,
    |                          ^^^^
    |
-   = note: cannot satisfy `IsLessOrEqual<I, 8>: True`
-   = help: the trait `True` is implemented for `IsLessOrEqual<LHS, RHS>`
+note: multiple `impl`s or `where` clauses satisfying `IsLessOrEqual<I, 8>: True` found
+  --> $DIR/issue-72787.rs:10:1
+   |
+LL | impl<const LHS: u32, const RHS: u32> True for IsLessOrEqual<LHS, RHS> where
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL |     IsLessOrEqual<I, 8>: True,
+   |                          ^^^^
+...
+LL |     IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
+   |                                          ^^^^
 
 error[E0283]: type annotations needed: cannot satisfy `IsLessOrEqual<I, 8>: True`
   --> $DIR/issue-72787.rs:21:26
@@ -49,8 +58,17 @@ error[E0283]: type annotations needed: cannot satisfy `IsLessOrEqual<I, 8>: True
 LL |     IsLessOrEqual<I, 8>: True,
    |                          ^^^^
    |
-   = note: cannot satisfy `IsLessOrEqual<I, 8>: True`
-   = help: the trait `True` is implemented for `IsLessOrEqual<LHS, RHS>`
+note: multiple `impl`s or `where` clauses satisfying `IsLessOrEqual<I, 8>: True` found
+  --> $DIR/issue-72787.rs:10:1
+   |
+LL | impl<const LHS: u32, const RHS: u32> True for IsLessOrEqual<LHS, RHS> where
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL |     IsLessOrEqual<I, 8>: True,
+   |                          ^^^^
+...
+LL |     IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
+   |                                          ^^^^
 
 error: aborting due to 6 previous errors
 
diff --git a/src/test/ui/const-generics/issue-105689.rs b/src/test/ui/const-generics/issue-105689.rs
new file mode 100644 (file)
index 0000000..4237b3c
--- /dev/null
@@ -0,0 +1,14 @@
+// check-pass
+// edition:2021
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+#[allow(unused)]
+async fn foo<'a>() {
+    let _data = &mut [0u8; { 1 + 4 }];
+    bar().await
+}
+
+async fn bar() {}
+
+fn main() {}
index 3a58a7cd7ef05b5670b01b8514e158b0e3dd528f..0079bb3aad6df5b72e8fb68ff9f1d7844c5a581b 100644 (file)
@@ -27,7 +27,7 @@ LL | pub static S1: &[()] = unsafe { from_raw_parts(ptr::null(), 0) };
 error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
    |
-   = note: dereferencing pointer failed: ALLOC_ID has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
+   = note: dereferencing pointer failed: allocN has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
    |
 note: inside `std::slice::from_raw_parts::<'_, u32>`
   --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
@@ -45,7 +45,7 @@ LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) }
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
-               â•¾â”€ALLOC_ID─╼ 01 00 00 00                         â”‚ â•¾â”€â”€â•¼....
+               â•¾ALLOC_ID╼ 01 00 00 00                         â”‚ â•¾â”€â”€â•¼....
            }
 
 error[E0080]: it is undefined behavior to use this value
@@ -57,7 +57,7 @@ LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, size
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
    = note: the raw bytes of the constant (size: 8, align: 4) {
-               â•¾â”€ALLOC_ID─╼ 04 00 00 00                         â”‚ â•¾â”€â”€â•¼....
+               â•¾ALLOC_ID╼ 04 00 00 00                         â”‚ â•¾â”€â”€â•¼....
            }
 
 error[E0080]: it is undefined behavior to use this value
@@ -68,24 +68,24 @@ LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4)
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
-               â•¾â”€ALLOC_ID─╼ 04 00 00 00                         â”‚ â•¾â”€â”€â•¼....
+               â•¾ALLOC_ID╼ 04 00 00 00                         â”‚ â•¾â”€â”€â•¼....
            }
 
 error[E0080]: it is undefined behavior to use this value
   --> $DIR/forbidden_slices.rs:32:1
    |
 LL | pub static S7: &[u16] = unsafe {
-   | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1)
+   | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[1]: encountered uninitialized bytes
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
-               â•¾â”€A_ID+0x1─╼ 04 00 00 00                         â”‚ â•¾â”€â”€â•¼....
+               â•¾ALLOC_ID+0x2╼ 04 00 00 00                         â”‚ â•¾â”€â”€â•¼....
            }
 
 error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
    |
-   = note: dereferencing pointer failed: ALLOC_ID has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
+   = note: dereferencing pointer failed: allocN has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
    |
 note: inside `std::slice::from_raw_parts::<'_, u64>`
   --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
@@ -129,7 +129,7 @@ LL | pub static R1: &[()] = unsafe { from_ptr_range(ptr::null()..ptr::null()) };
 error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
-   = note: out-of-bounds pointer arithmetic: ALLOC_ID has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
+   = note: out-of-bounds pointer arithmetic: allocN has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
    |
 note: inside `ptr::const_ptr::<impl *const u32>::offset`
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
@@ -149,7 +149,7 @@ LL | pub static R4: &[u8] = unsafe {
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
-               Ã¢\95¾ALLOC_IDâ\94\80â\95¼ 01 00 00 00                         Ã¢\94\82 Ã¢\95¾â\94\80â\94\80â\95¼....
+               â•¾ALLOC_ID╼ 01 00 00 00                         â”‚ â•¾â”€â”€â•¼....
            }
 
 error[E0080]: it is undefined behavior to use this value
@@ -161,7 +161,7 @@ LL | pub static R5: &[u8] = unsafe {
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
    = note: the raw bytes of the constant (size: 8, align: 4) {
-               Ã¢\95¾ALLOC_IDâ\94\80â\95¼ 04 00 00 00                         Ã¢\94\82 Ã¢\95¾â\94\80â\94\80â\95¼....
+               â•¾ALLOC_ID╼ 04 00 00 00                         â”‚ â•¾â”€â”€â•¼....
            }
 
 error[E0080]: it is undefined behavior to use this value
@@ -172,31 +172,35 @@ LL | pub static R6: &[bool] = unsafe {
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
-               Ã¢\95¾ALLOC_IDâ\94\80â\95¼ 04 00 00 00                         Ã¢\94\82 Ã¢\95¾â\94\80â\94\80â\95¼....
+               â•¾ALLOC_ID╼ 04 00 00 00                         â”‚ â•¾â”€â”€â•¼....
            }
 
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/forbidden_slices.rs:67:1
+error[E0080]: could not evaluate static initializer
+  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
    |
-LL | pub static R7: &[u16] = unsafe {
-   | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1)
+   = note: accessing memory with alignment 1, but alignment 2 is required
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 4) {
-               â•¾A_ID+0x1─╼ 04 00 00 00                         â”‚ â•¾â”€â”€â•¼....
-           }
+note: inside `std::slice::from_raw_parts::<'_, u16>`
+  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+note: inside `from_ptr_range::<'_, u16>`
+  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+note: inside `R7`
+  --> $DIR/forbidden_slices.rs:69:5
+   |
+LL |     from_ptr_range(ptr..ptr.add(4))
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
-   = note: out-of-bounds pointer arithmetic: ALLOC_ID has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
+   = note: out-of-bounds pointer arithmetic: allocN has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
    |
 note: inside `ptr::const_ptr::<impl *const u64>::offset`
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
 note: inside `ptr::const_ptr::<impl *const u64>::add`
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
 note: inside `R8`
-  --> $DIR/forbidden_slices.rs:74:25
+  --> $DIR/forbidden_slices.rs:73:25
    |
 LL |     from_ptr_range(ptr..ptr.add(1))
    |                         ^^^^^^^^^^
@@ -211,7 +215,7 @@ note: inside `ptr::const_ptr::<impl *const u32>::sub_ptr`
 note: inside `from_ptr_range::<'_, u32>`
   --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
 note: inside `R9`
-  --> $DIR/forbidden_slices.rs:79:34
+  --> $DIR/forbidden_slices.rs:78:34
    |
 LL | pub static R9: &[u32] = unsafe { from_ptr_range(&D0..(&D0 as *const u32).add(1)) };
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -226,7 +230,7 @@ note: inside `ptr::const_ptr::<impl *const u32>::sub_ptr`
 note: inside `from_ptr_range::<'_, u32>`
   --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
 note: inside `R10`
-  --> $DIR/forbidden_slices.rs:80:35
+  --> $DIR/forbidden_slices.rs:79:35
    |
 LL | pub static R10: &[u32] = unsafe { from_ptr_range(&D0..&D0) };
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^
index 4e929e3525c20dc78aec81d9af1ac7a5e5efbd86..f4f9fe69516a6a258a1abb022c7c35b5b135d37a 100644 (file)
@@ -27,7 +27,7 @@ LL | pub static S1: &[()] = unsafe { from_raw_parts(ptr::null(), 0) };
 error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
    |
-   = note: dereferencing pointer failed: ALLOC_ID has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
+   = note: dereferencing pointer failed: allocN has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
    |
 note: inside `std::slice::from_raw_parts::<'_, u32>`
   --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
@@ -45,7 +45,7 @@ LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) }
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               â•¾â”€â”€â”€â”€â”€â”€â”€ALLOC_ID───────╼ 01 00 00 00 00 00 00 00 â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
+               â•¾ALLOC_ID╼ 01 00 00 00 00 00 00 00 â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
            }
 
 error[E0080]: it is undefined behavior to use this value
@@ -57,7 +57,7 @@ LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, size
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               â•¾â”€â”€â”€â”€â”€â”€â”€ALLOC_ID───────╼ 08 00 00 00 00 00 00 00 â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
+               â•¾ALLOC_ID╼ 08 00 00 00 00 00 00 00 â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
            }
 
 error[E0080]: it is undefined behavior to use this value
@@ -68,24 +68,24 @@ LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4)
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               â•¾â”€â”€â”€â”€â”€â”€â”€ALLOC_ID───────╼ 04 00 00 00 00 00 00 00 â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
+               â•¾ALLOC_ID╼ 04 00 00 00 00 00 00 00 â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
            }
 
 error[E0080]: it is undefined behavior to use this value
   --> $DIR/forbidden_slices.rs:32:1
    |
 LL | pub static S7: &[u16] = unsafe {
-   | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1)
+   | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[1]: encountered uninitialized bytes
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               â•¾â”€â”€â”€â”€â”€ALLOC_ID+0x1─────╼ 04 00 00 00 00 00 00 00 â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
+               â•¾ALLOC_ID+0x2╼ 04 00 00 00 00 00 00 00 â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
            }
 
 error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
    |
-   = note: dereferencing pointer failed: ALLOC_ID has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
+   = note: dereferencing pointer failed: allocN has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
    |
 note: inside `std::slice::from_raw_parts::<'_, u64>`
   --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
@@ -129,7 +129,7 @@ LL | pub static R1: &[()] = unsafe { from_ptr_range(ptr::null()..ptr::null()) };
 error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
-   = note: out-of-bounds pointer arithmetic: ALLOC_ID has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
+   = note: out-of-bounds pointer arithmetic: allocN has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
    |
 note: inside `ptr::const_ptr::<impl *const u32>::offset`
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
@@ -149,7 +149,7 @@ LL | pub static R4: &[u8] = unsafe {
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               â•¾â”€â”€â”€â”€â”€â”€ALLOC_ID───────╼ 01 00 00 00 00 00 00 00 â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
+               â•¾ALLOC_ID╼ 01 00 00 00 00 00 00 00 â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
            }
 
 error[E0080]: it is undefined behavior to use this value
@@ -161,7 +161,7 @@ LL | pub static R5: &[u8] = unsafe {
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               â•¾â”€â”€â”€â”€â”€â”€ALLOC_ID───────╼ 08 00 00 00 00 00 00 00 â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
+               â•¾ALLOC_ID╼ 08 00 00 00 00 00 00 00 â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
            }
 
 error[E0080]: it is undefined behavior to use this value
@@ -172,31 +172,35 @@ LL | pub static R6: &[bool] = unsafe {
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               â•¾â”€â”€â”€â”€â”€â”€ALLOC_ID───────╼ 04 00 00 00 00 00 00 00 â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
+               â•¾ALLOC_ID╼ 04 00 00 00 00 00 00 00 â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
            }
 
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/forbidden_slices.rs:67:1
+error[E0080]: could not evaluate static initializer
+  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
    |
-LL | pub static R7: &[u16] = unsafe {
-   | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1)
+   = note: accessing memory with alignment 1, but alignment 2 is required
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 16, align: 8) {
-               â•¾â”€â”€â”€â”€ALLOC_ID+0x1─────╼ 04 00 00 00 00 00 00 00 â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
-           }
+note: inside `std::slice::from_raw_parts::<'_, u16>`
+  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+note: inside `from_ptr_range::<'_, u16>`
+  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+note: inside `R7`
+  --> $DIR/forbidden_slices.rs:69:5
+   |
+LL |     from_ptr_range(ptr..ptr.add(4))
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
-   = note: out-of-bounds pointer arithmetic: ALLOC_ID has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
+   = note: out-of-bounds pointer arithmetic: allocN has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
    |
 note: inside `ptr::const_ptr::<impl *const u64>::offset`
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
 note: inside `ptr::const_ptr::<impl *const u64>::add`
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
 note: inside `R8`
-  --> $DIR/forbidden_slices.rs:74:25
+  --> $DIR/forbidden_slices.rs:73:25
    |
 LL |     from_ptr_range(ptr..ptr.add(1))
    |                         ^^^^^^^^^^
@@ -211,7 +215,7 @@ note: inside `ptr::const_ptr::<impl *const u32>::sub_ptr`
 note: inside `from_ptr_range::<'_, u32>`
   --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
 note: inside `R9`
-  --> $DIR/forbidden_slices.rs:79:34
+  --> $DIR/forbidden_slices.rs:78:34
    |
 LL | pub static R9: &[u32] = unsafe { from_ptr_range(&D0..(&D0 as *const u32).add(1)) };
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -226,7 +230,7 @@ note: inside `ptr::const_ptr::<impl *const u32>::sub_ptr`
 note: inside `from_ptr_range::<'_, u32>`
   --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
 note: inside `R10`
-  --> $DIR/forbidden_slices.rs:80:35
+  --> $DIR/forbidden_slices.rs:79:35
    |
 LL | pub static R10: &[u32] = unsafe { from_ptr_range(&D0..&D0) };
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^
index e2184911f422c47cfe2318fd641c688e7d4cc90a..cc6100226dc1c00794ec90bbaf9524e9489f5f88 100644 (file)
@@ -1,6 +1,6 @@
 // stderr-per-bitwidth
-// normalize-stderr-test "alloc[0-9]+" -> "ALLOC_ID"
-// normalize-stderr-test "a[0-9]+\+0x" -> "A_ID+0x"
+// normalize-stderr-test "╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼" -> "╾ALLOC_ID$2╼"
+// normalize-stderr-test "alloc\d+" -> "allocN"
 // error-pattern: could not evaluate static initializer
 #![feature(
     slice_from_ptr_range,
@@ -31,7 +31,7 @@
 // Reading padding is not ok
 pub static S7: &[u16] = unsafe {
     //~^ ERROR: it is undefined behavior to use this value
-    let ptr = (&D2 as *const Struct as *const u16).byte_add(1);
+    let ptr = (&D2 as *const Struct as *const u16).add(1);
 
     from_raw_parts(ptr, 4)
 };
     from_ptr_range(ptr..ptr.add(4))
 };
 pub static R7: &[u16] = unsafe {
-    //~^ ERROR: it is undefined behavior to use this value
     let ptr = (&D2 as *const Struct as *const u16).byte_add(1);
-    from_ptr_range(ptr..ptr.add(4))
+    from_ptr_range(ptr..ptr.add(4)) //~ inside `R7`
 };
 pub static R8: &[u64] = unsafe {
     let ptr = (&D4 as *const [u32; 2] as *const u32).byte_add(1).cast::<u64>();
-    from_ptr_range(ptr..ptr.add(1))
+    from_ptr_range(ptr..ptr.add(1)) //~ inside `R8`
 };
 
 // This is sneaky: &D0 and &D0 point to different objects
index e5b5c7a846c116f0cd6092036eed1473f323254c..a0a8d76d10d2d9b86e6fbd6733ddd3662f0b6026 100644 (file)
@@ -1,5 +1,5 @@
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:13:1
+  --> $DIR/ub-ref-ptr.rs:14:1
    |
 LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) };
    | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1)
@@ -10,7 +10,7 @@ LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) };
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:17:1
+  --> $DIR/ub-ref-ptr.rs:18:1
    |
 LL | const UNALIGNED_BOX: Box<u16> = unsafe { mem::transmute(&[0u8; 4]) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned box (required 2 byte alignment but found 1)
@@ -21,7 +21,7 @@ LL | const UNALIGNED_BOX: Box<u16> = unsafe { mem::transmute(&[0u8; 4]) };
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:21:1
+  --> $DIR/ub-ref-ptr.rs:22:1
    |
 LL | const NULL: &u16 = unsafe { mem::transmute(0usize) };
    | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference
@@ -32,7 +32,7 @@ LL | const NULL: &u16 = unsafe { mem::transmute(0usize) };
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:24:1
+  --> $DIR/ub-ref-ptr.rs:25:1
    |
 LL | const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null box
@@ -43,7 +43,7 @@ LL | const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) };
            }
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-ref-ptr.rs:31:1
+  --> $DIR/ub-ref-ptr.rs:32:1
    |
 LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -52,7 +52,7 @@ LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) };
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-ref-ptr.rs:34:39
+  --> $DIR/ub-ref-ptr.rs:35:39
    |
 LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
    |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -61,13 +61,13 @@ LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 note: erroneous constant used
-  --> $DIR/ub-ref-ptr.rs:34:38
+  --> $DIR/ub-ref-ptr.rs:35:38
    |
 LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-ref-ptr.rs:37:86
+  --> $DIR/ub-ref-ptr.rs:38:86
    |
 LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) };
    |                                                                                      ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -76,13 +76,13 @@ LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[us
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 note: erroneous constant used
-  --> $DIR/ub-ref-ptr.rs:37:85
+  --> $DIR/ub-ref-ptr.rs:38:85
    |
 LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) };
    |                                                                                     ^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:40:1
+  --> $DIR/ub-ref-ptr.rs:41:1
    |
 LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (address 0x539 is unallocated)
@@ -93,7 +93,7 @@ LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) };
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:43:1
+  --> $DIR/ub-ref-ptr.rs:44:1
    |
 LL | const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (address 0x539 is unallocated)
@@ -104,13 +104,13 @@ LL | const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) };
            }
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-ref-ptr.rs:46:41
+  --> $DIR/ub-ref-ptr.rs:47:41
    |
 LL | const UNINIT_PTR: *const i32 = unsafe { MaybeUninit { uninit: () }.init };
    |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:50:1
+  --> $DIR/ub-ref-ptr.rs:51:1
    |
 LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a function pointer
@@ -121,13 +121,13 @@ LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) };
            }
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-ref-ptr.rs:52:38
+  --> $DIR/ub-ref-ptr.rs:53:38
    |
 LL | const UNINIT_FN_PTR: fn() = unsafe { MaybeUninit { uninit: () }.init };
    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:55:1
+  --> $DIR/ub-ref-ptr.rs:56:1
    |
 LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0xd[noalloc], but expected a function pointer
@@ -138,7 +138,7 @@ LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) };
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:57:1
+  --> $DIR/ub-ref-ptr.rs:58:1
    |
 LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
    | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered alloc41, but expected a function pointer
@@ -148,6 +148,39 @@ LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
                â•¾â”€alloc41─╼                                     â”‚ â•¾â”€â”€â•¼
            }
 
-error: aborting due to 14 previous errors
+error: accessing memory with alignment 1, but alignment 4 is required
+  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #68585 <https://github.com/rust-lang/rust/issues/104616>
+note: inside `std::ptr::read::<u32>`
+  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+note: inside `ptr::const_ptr::<impl *const u32>::read`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+note: inside `UNALIGNED_READ`
+  --> $DIR/ub-ref-ptr.rs:65:5
+   |
+LL |     ptr.read();
+   |     ^^^^^^^^^^
+   = note: `#[deny(invalid_alignment)]` on by default
+
+error: aborting due to 15 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
+Future incompatibility report: Future breakage diagnostic:
+error: accessing memory with alignment 1, but alignment 4 is required
+  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #68585 <https://github.com/rust-lang/rust/issues/104616>
+note: inside `std::ptr::read::<u32>`
+  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+note: inside `ptr::const_ptr::<impl *const u32>::read`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+note: inside `UNALIGNED_READ`
+  --> $DIR/ub-ref-ptr.rs:65:5
+   |
+LL |     ptr.read();
+   |     ^^^^^^^^^^
+   = note: `#[deny(invalid_alignment)]` on by default
+
index 607366cabc4e9d30c5a2ba70964fe4eb69854d61..d53b44671e3f48eb53a2c6f1c3a085cb95b92d7b 100644 (file)
@@ -1,5 +1,5 @@
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:13:1
+  --> $DIR/ub-ref-ptr.rs:14:1
    |
 LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) };
    | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1)
@@ -10,7 +10,7 @@ LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) };
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:17:1
+  --> $DIR/ub-ref-ptr.rs:18:1
    |
 LL | const UNALIGNED_BOX: Box<u16> = unsafe { mem::transmute(&[0u8; 4]) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned box (required 2 byte alignment but found 1)
@@ -21,7 +21,7 @@ LL | const UNALIGNED_BOX: Box<u16> = unsafe { mem::transmute(&[0u8; 4]) };
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:21:1
+  --> $DIR/ub-ref-ptr.rs:22:1
    |
 LL | const NULL: &u16 = unsafe { mem::transmute(0usize) };
    | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference
@@ -32,7 +32,7 @@ LL | const NULL: &u16 = unsafe { mem::transmute(0usize) };
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:24:1
+  --> $DIR/ub-ref-ptr.rs:25:1
    |
 LL | const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null box
@@ -43,7 +43,7 @@ LL | const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) };
            }
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-ref-ptr.rs:31:1
+  --> $DIR/ub-ref-ptr.rs:32:1
    |
 LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -52,7 +52,7 @@ LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) };
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-ref-ptr.rs:34:39
+  --> $DIR/ub-ref-ptr.rs:35:39
    |
 LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
    |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -61,13 +61,13 @@ LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 note: erroneous constant used
-  --> $DIR/ub-ref-ptr.rs:34:38
+  --> $DIR/ub-ref-ptr.rs:35:38
    |
 LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-ref-ptr.rs:37:86
+  --> $DIR/ub-ref-ptr.rs:38:86
    |
 LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) };
    |                                                                                      ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -76,13 +76,13 @@ LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[us
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 note: erroneous constant used
-  --> $DIR/ub-ref-ptr.rs:37:85
+  --> $DIR/ub-ref-ptr.rs:38:85
    |
 LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) };
    |                                                                                     ^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:40:1
+  --> $DIR/ub-ref-ptr.rs:41:1
    |
 LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (address 0x539 is unallocated)
@@ -93,7 +93,7 @@ LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) };
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:43:1
+  --> $DIR/ub-ref-ptr.rs:44:1
    |
 LL | const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (address 0x539 is unallocated)
@@ -104,13 +104,13 @@ LL | const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) };
            }
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-ref-ptr.rs:46:41
+  --> $DIR/ub-ref-ptr.rs:47:41
    |
 LL | const UNINIT_PTR: *const i32 = unsafe { MaybeUninit { uninit: () }.init };
    |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:50:1
+  --> $DIR/ub-ref-ptr.rs:51:1
    |
 LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a function pointer
@@ -121,13 +121,13 @@ LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) };
            }
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-ref-ptr.rs:52:38
+  --> $DIR/ub-ref-ptr.rs:53:38
    |
 LL | const UNINIT_FN_PTR: fn() = unsafe { MaybeUninit { uninit: () }.init };
    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:55:1
+  --> $DIR/ub-ref-ptr.rs:56:1
    |
 LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0xd[noalloc], but expected a function pointer
@@ -138,7 +138,7 @@ LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) };
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:57:1
+  --> $DIR/ub-ref-ptr.rs:58:1
    |
 LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
    | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered alloc41, but expected a function pointer
@@ -148,6 +148,39 @@ LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
                â•¾â”€â”€â”€â”€â”€â”€â”€alloc41───────╼                         â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼
            }
 
-error: aborting due to 14 previous errors
+error: accessing memory with alignment 1, but alignment 4 is required
+  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #68585 <https://github.com/rust-lang/rust/issues/104616>
+note: inside `std::ptr::read::<u32>`
+  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+note: inside `ptr::const_ptr::<impl *const u32>::read`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+note: inside `UNALIGNED_READ`
+  --> $DIR/ub-ref-ptr.rs:65:5
+   |
+LL |     ptr.read();
+   |     ^^^^^^^^^^
+   = note: `#[deny(invalid_alignment)]` on by default
+
+error: aborting due to 15 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
+Future incompatibility report: Future breakage diagnostic:
+error: accessing memory with alignment 1, but alignment 4 is required
+  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #68585 <https://github.com/rust-lang/rust/issues/104616>
+note: inside `std::ptr::read::<u32>`
+  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+note: inside `ptr::const_ptr::<impl *const u32>::read`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+note: inside `UNALIGNED_READ`
+  --> $DIR/ub-ref-ptr.rs:65:5
+   |
+LL |     ptr.read();
+   |     ^^^^^^^^^^
+   = note: `#[deny(invalid_alignment)]` on by default
+
index a1c81239009ac0569e45d8217764ccf07ad9c81a..b0fc3c196a49fc3457915955dd277d352d6154c0 100644 (file)
@@ -1,6 +1,7 @@
 // ignore-tidy-linelength
 // stderr-per-bitwidth
 #![allow(invalid_value)]
+#![feature(const_ptr_read)]
 
 use std::mem;
 
@@ -57,4 +58,12 @@ union MaybeUninit<T: Copy> {
 const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
 //~^ ERROR it is undefined behavior to use this value
 
+
+const UNALIGNED_READ: () = unsafe {
+    let x = &[0u8; 4];
+    let ptr = x.as_ptr().cast::<u32>();
+    ptr.read(); //~ inside `UNALIGNED_READ`
+};
+
+
 fn main() {}
index 9994c2e5a83458c27cb6e3ad8ee66071eeabad14..90a3dcada058d691ec0dfee66edc0e1e87ad53da 100644 (file)
@@ -1,27 +1,27 @@
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:36:1
+  --> $DIR/ub-wide-ptr.rs:37:1
    |
 LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation)
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
-               â•¾â”€allocN──╼ e7 03 00 00                         â”‚ â•¾â”€â”€â•¼....
+               â•¾ALLOC_ID╼ e7 03 00 00                         â”‚ â•¾â”€â”€â•¼....
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:38:1
+  --> $DIR/ub-wide-ptr.rs:39:1
    |
 LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid reference metadata: slice is bigger than largest supported object
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
-               â•¾â”€allocN─╼ ff ff ff ff                         â”‚ â•¾â”€â”€â•¼....
+               â•¾ALLOC_ID╼ ff ff ff ff                         â”‚ â•¾â”€â”€â•¼....
            }
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:41:1
+  --> $DIR/ub-wide-ptr.rs:42:1
    |
 LL | const STR_LENGTH_PTR: &str = unsafe { mem::transmute((&42u8, &3)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -30,7 +30,7 @@ LL | const STR_LENGTH_PTR: &str = unsafe { mem::transmute((&42u8, &3)) };
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:44:1
+  --> $DIR/ub-wide-ptr.rs:45:1
    |
 LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -39,68 +39,68 @@ LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) };
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:46:1
+  --> $DIR/ub-wide-ptr.rs:47:1
    |
 LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
-               â•¾â”€allocN─╼ ff ff ff ff                         â”‚ â•¾â”€â”€â•¼....
+               â•¾ALLOC_ID╼ ff ff ff ff                         â”‚ â•¾â”€â”€â•¼....
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:50:1
+  --> $DIR/ub-wide-ptr.rs:51:1
    |
 LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
    | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered uninitialized data in `str`
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
-               â•¾â”€allocN─╼ 01 00 00 00                         â”‚ â•¾â”€â”€â•¼....
+               â•¾ALLOC_ID╼ 01 00 00 00                         â”‚ â•¾â”€â”€â•¼....
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:53:1
+  --> $DIR/ub-wide-ptr.rs:54:1
    |
 LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered uninitialized data in `str`
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
-               â•¾â”€allocN─╼ 01 00 00 00                         â”‚ â•¾â”€â”€â•¼....
+               â•¾ALLOC_ID╼ 01 00 00 00                         â”‚ â•¾â”€â”€â•¼....
            }
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:60:1
+  --> $DIR/ub-wide-ptr.rs:61:1
    |
 LL | const SLICE_LENGTH_UNINIT: &[u8] = unsafe {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:67:1
+  --> $DIR/ub-wide-ptr.rs:68:1
    |
 LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation)
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
-               â•¾â”€allocN─╼ e7 03 00 00                         â”‚ â•¾â”€â”€â•¼....
+               â•¾ALLOC_ID╼ e7 03 00 00                         â”‚ â•¾â”€â”€â•¼....
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:70:1
+  --> $DIR/ub-wide-ptr.rs:71:1
    |
 LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
-               â•¾â”€allocN─╼ ff ff ff 7f                         â”‚ â•¾â”€â”€â•¼....
+               â•¾ALLOC_ID╼ ff ff ff 7f                         â”‚ â•¾â”€â”€â•¼....
            }
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:73:1
+  --> $DIR/ub-wide-ptr.rs:74:1
    |
 LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -109,18 +109,18 @@ LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) };
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:76:1
+  --> $DIR/ub-wide-ptr.rs:77:1
    |
 LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (going beyond the bounds of its allocation)
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
-               â•¾â”€allocN─╼ e7 03 00 00                         â”‚ â•¾â”€â”€â•¼....
+               â•¾ALLOC_ID╼ e7 03 00 00                         â”‚ â•¾â”€â”€â•¼....
            }
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:79:1
+  --> $DIR/ub-wide-ptr.rs:80:1
    |
 LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -129,165 +129,165 @@ LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3)
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:83:1
+  --> $DIR/ub-wide-ptr.rs:84:1
    |
 LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x03, but expected a boolean
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
-               â•¾â”€allocN─╼                                     â”‚ â•¾â”€â”€â•¼
+               â•¾ALLOC_ID╼                                     â”‚ â•¾â”€â”€â•¼
            }
 
 note: erroneous constant used
-  --> $DIR/ub-wide-ptr.rs:83:40
+  --> $DIR/ub-wide-ptr.rs:84:40
    |
 LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
    |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:90:1
+  --> $DIR/ub-wide-ptr.rs:91:1
    |
 LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered 0x03, but expected a boolean
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
-               â•¾allocN─╼                                     â”‚ â•¾â”€â”€â•¼
+               â•¾ALLOC_ID╼                                     â”‚ â•¾â”€â”€â•¼
            }
 
 note: erroneous constant used
-  --> $DIR/ub-wide-ptr.rs:90:42
+  --> $DIR/ub-wide-ptr.rs:91:42
    |
 LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
    |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:94:1
+  --> $DIR/ub-wide-ptr.rs:95:1
    |
 LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.1[0]: encountered 0x03, but expected a boolean
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
-               â•¾allocN─╼                                     â”‚ â•¾â”€â”€â•¼
+               â•¾ALLOC_ID╼                                     â”‚ â•¾â”€â”€â•¼
            }
 
 note: erroneous constant used
-  --> $DIR/ub-wide-ptr.rs:94:42
+  --> $DIR/ub-wide-ptr.rs:95:42
    |
 LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
    |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:102:1
+  --> $DIR/ub-wide-ptr.rs:103:1
    |
 LL | const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:111:1
+  --> $DIR/ub-wide-ptr.rs:112:1
    |
 LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
-               â•¾allocN─╼ â•¾allocN─╼                         â”‚ â•¾â”€â”€â•¼â•¾â”€â”€â•¼
+               â•¾ALLOC_ID╼ â•¾ALLOC_ID╼                         â”‚ â•¾â”€â”€â•¼â•¾â”€â”€â•¼
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:115:1
+  --> $DIR/ub-wide-ptr.rs:116:1
    |
 LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
-               â•¾allocN─╼ â•¾allocN─╼                         â”‚ â•¾â”€â”€â•¼â•¾â”€â”€â•¼
+               â•¾ALLOC_ID╼ â•¾ALLOC_ID╼                         â”‚ â•¾â”€â”€â•¼â•¾â”€â”€â•¼
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:119:1
+  --> $DIR/ub-wide-ptr.rs:120:1
    |
 LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0x4[noalloc], but expected a vtable pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
-               â•¾allocN─╼ 04 00 00 00                         â”‚ â•¾â”€â”€â•¼....
+               â•¾ALLOC_ID╼ 04 00 00 00                         â”‚ â•¾â”€â”€â•¼....
            }
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:122:57
+  --> $DIR/ub-wide-ptr.rs:123:57
    |
 LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) };
    |                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:125:57
+  --> $DIR/ub-wide-ptr.rs:126:57
    |
 LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) };
    |                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:128:56
+  --> $DIR/ub-wide-ptr.rs:129:56
    |
 LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) };
    |                                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:131:1
+  --> $DIR/ub-wide-ptr.rs:132:1
    |
 LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
-               â•¾allocN─╼ â•¾allocN─╼                         â”‚ â•¾â”€â”€â•¼â•¾â”€â”€â•¼
+               â•¾ALLOC_ID╼ â•¾ALLOC_ID╼                         â”‚ â•¾â”€â”€â•¼â•¾â”€â”€â•¼
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:136:1
+  --> $DIR/ub-wide-ptr.rs:137:1
    |
 LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.<dyn-downcast>: encountered 0x03, but expected a boolean
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
-               â•¾allocN─╼ â•¾allocN─╼                         â”‚ â•¾â”€â”€â•¼â•¾â”€â”€â•¼
+               â•¾ALLOC_ID╼ â•¾ALLOC_ID╼                         â”‚ â•¾â”€â”€â•¼â•¾â”€â”€â•¼
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:141:1
+  --> $DIR/ub-wide-ptr.rs:142:1
    |
 LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a vtable pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
-               â•¾allocN─╼ 00 00 00 00                         â”‚ â•¾â”€â”€â•¼....
+               â•¾ALLOC_ID╼ 00 00 00 00                         â”‚ â•¾â”€â”€â•¼....
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:143:1
+  --> $DIR/ub-wide-ptr.rs:144:1
    |
 LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered allocN, but expected a vtable pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
-               â•¾allocN─╼ â•¾allocN─╼                         â”‚ â•¾â”€â”€â•¼â•¾â”€â”€â•¼
+               â•¾ALLOC_ID╼ â•¾ALLOC_ID╼                         â”‚ â•¾â”€â”€â•¼â•¾â”€â”€â•¼
            }
 
 error[E0080]: could not evaluate static initializer
-  --> $DIR/ub-wide-ptr.rs:149:5
+  --> $DIR/ub-wide-ptr.rs:150:5
    |
 LL |     mem::transmute::<_, &dyn Trait>((&92u8, 0usize))
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance)
 
 error[E0080]: could not evaluate static initializer
-  --> $DIR/ub-wide-ptr.rs:153:5
+  --> $DIR/ub-wide-ptr.rs:154:5
    |
 LL |     mem::transmute::<_, &dyn Trait>((&92u8, &3u64))
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
index 06a377d9f7c97982b8d7c29cac7a628b6eee2832..ab25303ddc0cf611df2a306a549d4fde936f52e0 100644 (file)
@@ -1,27 +1,27 @@
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:36:1
+  --> $DIR/ub-wide-ptr.rs:37:1
    |
 LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation)
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               â•¾â”€â”€â”€â”€â”€â”€â”€allocN────────╼ e7 03 00 00 00 00 00 00 â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
+               â•¾ALLOC_ID╼ e7 03 00 00 00 00 00 00 â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:38:1
+  --> $DIR/ub-wide-ptr.rs:39:1
    |
 LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid reference metadata: slice is bigger than largest supported object
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               â•¾â”€â”€â”€â”€â”€â”€â”€allocN───────╼ ff ff ff ff ff ff ff ff â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
+               â•¾ALLOC_ID╼ ff ff ff ff ff ff ff ff â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
            }
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:41:1
+  --> $DIR/ub-wide-ptr.rs:42:1
    |
 LL | const STR_LENGTH_PTR: &str = unsafe { mem::transmute((&42u8, &3)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -30,7 +30,7 @@ LL | const STR_LENGTH_PTR: &str = unsafe { mem::transmute((&42u8, &3)) };
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:44:1
+  --> $DIR/ub-wide-ptr.rs:45:1
    |
 LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -39,68 +39,68 @@ LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) };
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:46:1
+  --> $DIR/ub-wide-ptr.rs:47:1
    |
 LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               â•¾â”€â”€â”€â”€â”€â”€â”€allocN───────╼ ff ff ff ff ff ff ff ff â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
+               â•¾ALLOC_ID╼ ff ff ff ff ff ff ff ff â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:50:1
+  --> $DIR/ub-wide-ptr.rs:51:1
    |
 LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
    | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered uninitialized data in `str`
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               â•¾â”€â”€â”€â”€â”€â”€â”€allocN───────╼ 01 00 00 00 00 00 00 00 â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
+               â•¾ALLOC_ID╼ 01 00 00 00 00 00 00 00 â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:53:1
+  --> $DIR/ub-wide-ptr.rs:54:1
    |
 LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered uninitialized data in `str`
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               â•¾â”€â”€â”€â”€â”€â”€â”€allocN───────╼ 01 00 00 00 00 00 00 00 â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
+               â•¾ALLOC_ID╼ 01 00 00 00 00 00 00 00 â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
            }
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:60:1
+  --> $DIR/ub-wide-ptr.rs:61:1
    |
 LL | const SLICE_LENGTH_UNINIT: &[u8] = unsafe {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:67:1
+  --> $DIR/ub-wide-ptr.rs:68:1
    |
 LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation)
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               â•¾â”€â”€â”€â”€â”€â”€â”€allocN───────╼ e7 03 00 00 00 00 00 00 â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
+               â•¾ALLOC_ID╼ e7 03 00 00 00 00 00 00 â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:70:1
+  --> $DIR/ub-wide-ptr.rs:71:1
    |
 LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               â•¾â”€â”€â”€â”€â”€â”€â”€allocN───────╼ ff ff ff ff ff ff ff 7f â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
+               â•¾ALLOC_ID╼ ff ff ff ff ff ff ff 7f â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
            }
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:73:1
+  --> $DIR/ub-wide-ptr.rs:74:1
    |
 LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -109,18 +109,18 @@ LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) };
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:76:1
+  --> $DIR/ub-wide-ptr.rs:77:1
    |
 LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (going beyond the bounds of its allocation)
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               â•¾â”€â”€â”€â”€â”€â”€â”€allocN───────╼ e7 03 00 00 00 00 00 00 â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
+               â•¾ALLOC_ID╼ e7 03 00 00 00 00 00 00 â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
            }
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:79:1
+  --> $DIR/ub-wide-ptr.rs:80:1
    |
 LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -129,165 +129,165 @@ LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3)
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:83:1
+  --> $DIR/ub-wide-ptr.rs:84:1
    |
 LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x03, but expected a boolean
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
-               â•¾â”€â”€â”€â”€â”€â”€â”€allocN───────╼                         â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼
+               â•¾ALLOC_ID╼                         â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼
            }
 
 note: erroneous constant used
-  --> $DIR/ub-wide-ptr.rs:83:40
+  --> $DIR/ub-wide-ptr.rs:84:40
    |
 LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
    |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:90:1
+  --> $DIR/ub-wide-ptr.rs:91:1
    |
 LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered 0x03, but expected a boolean
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
-               â•¾â”€â”€â”€â”€â”€â”€allocN───────╼                         â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼
+               â•¾ALLOC_ID╼                         â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼
            }
 
 note: erroneous constant used
-  --> $DIR/ub-wide-ptr.rs:90:42
+  --> $DIR/ub-wide-ptr.rs:91:42
    |
 LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
    |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:94:1
+  --> $DIR/ub-wide-ptr.rs:95:1
    |
 LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.1[0]: encountered 0x03, but expected a boolean
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
-               â•¾â”€â”€â”€â”€â”€â”€allocN───────╼                         â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼
+               â•¾ALLOC_ID╼                         â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼
            }
 
 note: erroneous constant used
-  --> $DIR/ub-wide-ptr.rs:94:42
+  --> $DIR/ub-wide-ptr.rs:95:42
    |
 LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
    |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:102:1
+  --> $DIR/ub-wide-ptr.rs:103:1
    |
 LL | const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:111:1
+  --> $DIR/ub-wide-ptr.rs:112:1
    |
 LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               â•¾â”€â”€â”€â”€â”€â”€allocN───────╼ â•¾â”€â”€â”€â”€â”€â”€allocN───────╼ â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼â•¾â”€â”€â”€â”€â”€â”€â•¼
+               â•¾ALLOC_ID╼ â•¾ALLOC_ID╼ â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼â•¾â”€â”€â”€â”€â”€â”€â•¼
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:115:1
+  --> $DIR/ub-wide-ptr.rs:116:1
    |
 LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               â•¾â”€â”€â”€â”€â”€â”€allocN───────╼ â•¾â”€â”€â”€â”€â”€â”€allocN───────╼ â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼â•¾â”€â”€â”€â”€â”€â”€â•¼
+               â•¾ALLOC_ID╼ â•¾ALLOC_ID╼ â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼â•¾â”€â”€â”€â”€â”€â”€â•¼
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:119:1
+  --> $DIR/ub-wide-ptr.rs:120:1
    |
 LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0x4[noalloc], but expected a vtable pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               â•¾â”€â”€â”€â”€â”€â”€allocN───────╼ 04 00 00 00 00 00 00 00 â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
+               â•¾ALLOC_ID╼ 04 00 00 00 00 00 00 00 â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
            }
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:122:57
+  --> $DIR/ub-wide-ptr.rs:123:57
    |
 LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) };
    |                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:125:57
+  --> $DIR/ub-wide-ptr.rs:126:57
    |
 LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) };
    |                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:128:56
+  --> $DIR/ub-wide-ptr.rs:129:56
    |
 LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) };
    |                                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:131:1
+  --> $DIR/ub-wide-ptr.rs:132:1
    |
 LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               â•¾â”€â”€â”€â”€â”€â”€allocN───────╼ â•¾â”€â”€â”€â”€â”€â”€allocN───────╼ â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼â•¾â”€â”€â”€â”€â”€â”€â•¼
+               â•¾ALLOC_ID╼ â•¾ALLOC_ID╼ â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼â•¾â”€â”€â”€â”€â”€â”€â•¼
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:136:1
+  --> $DIR/ub-wide-ptr.rs:137:1
    |
 LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.<dyn-downcast>: encountered 0x03, but expected a boolean
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               â•¾â”€â”€â”€â”€â”€â”€allocN───────╼ â•¾â”€â”€â”€â”€â”€â”€allocN───────╼ â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼â•¾â”€â”€â”€â”€â”€â”€â•¼
+               â•¾ALLOC_ID╼ â•¾ALLOC_ID╼ â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼â•¾â”€â”€â”€â”€â”€â”€â•¼
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:141:1
+  --> $DIR/ub-wide-ptr.rs:142:1
    |
 LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a vtable pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               â•¾â”€â”€â”€â”€â”€â”€allocN───────╼ 00 00 00 00 00 00 00 00 â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
+               â•¾ALLOC_ID╼ 00 00 00 00 00 00 00 00 â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:143:1
+  --> $DIR/ub-wide-ptr.rs:144:1
    |
 LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered allocN, but expected a vtable pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               â•¾â”€â”€â”€â”€â”€â”€allocN───────╼ â•¾â”€â”€â”€â”€â”€â”€allocN───────╼ â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼â•¾â”€â”€â”€â”€â”€â”€â•¼
+               â•¾ALLOC_ID╼ â•¾ALLOC_ID╼ â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼â•¾â”€â”€â”€â”€â”€â”€â•¼
            }
 
 error[E0080]: could not evaluate static initializer
-  --> $DIR/ub-wide-ptr.rs:149:5
+  --> $DIR/ub-wide-ptr.rs:150:5
    |
 LL |     mem::transmute::<_, &dyn Trait>((&92u8, 0usize))
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance)
 
 error[E0080]: could not evaluate static initializer
-  --> $DIR/ub-wide-ptr.rs:153:5
+  --> $DIR/ub-wide-ptr.rs:154:5
    |
 LL |     mem::transmute::<_, &dyn Trait>((&92u8, &3u64))
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
index 2894ef831884cda462a4acbf9bbd9d643bd9fb6d..d12e5e2bed93ef20daa6f5b98b4cb27b3920146a 100644 (file)
@@ -4,6 +4,7 @@
 
 use std::mem;
 
+// normalize-stderr-test "╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼" -> "╾ALLOC_ID$2╼"
 // normalize-stderr-test "offset \d+" -> "offset N"
 // normalize-stderr-test "alloc\d+" -> "allocN"
 // normalize-stderr-test "size \d+" -> "size N"
index 249bbb5991cc98dc6da6f19feff3bdb06b4bff36..94d7bdc6bae9ff6222411821a5a3b912f6728fbf 100644 (file)
@@ -17,7 +17,7 @@
     // Since we are not copying anything, this should be allowed.
     let src = ();
     let mut dst = ();
-    copy_nonoverlapping(&src as *const _ as *const i32, &mut dst as *mut _ as *mut i32, 0);
+    copy_nonoverlapping(&src as *const _ as *const u8, &mut dst as *mut _ as *mut u8, 0);
 };
 
 const COPY_OOB_1: () = unsafe {
index 9c239c8a100f991e60176a3364a15478940bf252..e2f8149883b1d980978e431889112462f1dd4e85 100644 (file)
     //[with_flag]~| invalid value
 };
 
-const UNALIGNED_READ: () = {
-    INNER; //[with_flag]~ constant
-    // There is an error here but its span is in the standard library so we cannot match it...
-    // so we have this in a *nested* const, such that the *outer* const fails to use it.
-    const INNER: () = unsafe {
-        let x = &[0u8; 4];
-        let ptr = x.as_ptr().cast::<u32>();
-        ptr.read();
-    };
-};
-
 fn main() {}
index 51eec78336565ac9b518ff1b1c875507f74be822..b2a5fd90149a3eee815afc6625507556b9a01c45 100644 (file)
@@ -28,27 +28,6 @@ error[E0080]: evaluation of constant value failed
 LL |     let _x: &u32 = transmute(&[0u8; 4]);
    |                    ^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 4 byte alignment but found 1)
 
-error[E0080]: evaluation of constant value failed
-  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-   |
-   = note: accessing memory with alignment 1, but alignment 4 is required
-   |
-note: inside `std::ptr::read::<u32>`
-  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-note: inside `ptr::const_ptr::<impl *const u32>::read`
-  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-note: inside `INNER`
-  --> $DIR/detect-extra-ub.rs:38:9
-   |
-LL |         ptr.read();
-   |         ^^^^^^^^^^
-
-note: erroneous constant used
-  --> $DIR/detect-extra-ub.rs:32:5
-   |
-LL |     INNER;
-   |     ^^^^^
-
-error: aborting due to 5 previous errors
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
index e1a7a02a56869ad056ca3a15f05c57805b31c2eb..0e580aedeaa921e7fd548624dc075a660864600d 100644 (file)
@@ -100,22 +100,22 @@ help: a unit struct with a similar name exists
 LL |     let xe1 = XEmpty2();
    |               ~~~~~~~
 
-error[E0599]: no variant or associated item named `Empty3` found for enum `empty_struct::XE` in the current scope
+error[E0599]: no variant or associated item named `Empty3` found for enum `XE` in the current scope
   --> $DIR/empty-struct-braces-expr.rs:25:19
    |
 LL |     let xe3 = XE::Empty3;
    |                   ^^^^^^
    |                   |
-   |                   variant or associated item not found in `empty_struct::XE`
+   |                   variant or associated item not found in `XE`
    |                   help: there is a variant with a similar name: `XEmpty3`
 
-error[E0599]: no variant or associated item named `Empty3` found for enum `empty_struct::XE` in the current scope
+error[E0599]: no variant or associated item named `Empty3` found for enum `XE` in the current scope
   --> $DIR/empty-struct-braces-expr.rs:26:19
    |
 LL |     let xe3 = XE::Empty3();
    |                   ^^^^^^
    |                   |
-   |                   variant or associated item not found in `empty_struct::XE`
+   |                   variant or associated item not found in `XE`
    |                   help: there is a variant with a similar name: `XEmpty3`
 
 error[E0599]: no variant named `Empty1` found for enum `empty_struct::XE`
index 9b868ed7a9e93868b712ac46ca19482e99839947..c04e57843d4b21f4d16e5205630273d4f199cc37 100644 (file)
@@ -1,5 +1,5 @@
+#![allow(unused, bare_trait_objects)]
 #[repr(align(256))]
-#[allow(dead_code)]
 struct A {
     v: u8,
 }
@@ -14,13 +14,17 @@ fn foo(&self) {
     }
 }
 
-fn foo(x: dyn Foo) {
-    //~^ ERROR [E0277]
+fn foo(x: dyn Foo) { //~ ERROR [E0277]
     x.foo()
 }
 
+fn bar(x: Foo) { //~ ERROR [E0277]
+    x.foo()
+}
+
+fn qux(_: [()]) {} //~ ERROR [E0277]
+
 fn main() {
     let x: Box<dyn Foo> = Box::new(A { v: 22 });
-    foo(*x);
-    //~^ ERROR [E0277]
+    foo(*x); //~ ERROR [E0277]
 }
index 0f7520ef7f8a95a80644466eedf36a0a5902a143..92c71392672e197537c6a72525b9059a31c19852 100644 (file)
@@ -6,13 +6,47 @@ LL | fn foo(x: dyn Foo) {
    |
    = help: the trait `Sized` is not implemented for `(dyn Foo + 'static)`
    = help: unsized fn params are gated as an unstable feature
+help: you can use `impl Trait` as the argument type
+   |
+LL | fn foo(x: impl Foo) {
+   |           ~~~~
 help: function arguments must have a statically known size, borrowed types always have a known size
    |
 LL | fn foo(x: &dyn Foo) {
    |           +
 
 error[E0277]: the size for values of type `(dyn Foo + 'static)` cannot be known at compilation time
-  --> $DIR/feature-gate-unsized_fn_params.rs:24:9
+  --> $DIR/feature-gate-unsized_fn_params.rs:21:8
+   |
+LL | fn bar(x: Foo) {
+   |        ^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `(dyn Foo + 'static)`
+   = help: unsized fn params are gated as an unstable feature
+help: you can use `impl Trait` as the argument type
+   |
+LL | fn bar(x: impl Foo) {
+   |           ++++
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL | fn bar(x: &Foo) {
+   |           +
+
+error[E0277]: the size for values of type `[()]` cannot be known at compilation time
+  --> $DIR/feature-gate-unsized_fn_params.rs:25:8
+   |
+LL | fn qux(_: [()]) {}
+   |        ^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[()]`
+   = help: unsized fn params are gated as an unstable feature
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL | fn qux(_: &[()]) {}
+   |           +
+
+error[E0277]: the size for values of type `(dyn Foo + 'static)` cannot be known at compilation time
+  --> $DIR/feature-gate-unsized_fn_params.rs:29:9
    |
 LL |     foo(*x);
    |         ^^ doesn't have a size known at compile-time
@@ -21,6 +55,6 @@ LL |     foo(*x);
    = note: all function arguments must have a statically known size
    = help: unsized fn params are gated as an unstable feature
 
-error: aborting due to 2 previous errors
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
index c4507843e366e06896824d284114ac97951075ed..9aeeb88cf04f2befd08f101afdb57860769e220d 100644 (file)
@@ -6,6 +6,10 @@ LL | fn f(f: dyn FnOnce()) {}
    |
    = help: the trait `Sized` is not implemented for `(dyn FnOnce() + 'static)`
    = help: unsized fn params are gated as an unstable feature
+help: you can use `impl Trait` as the argument type
+   |
+LL | fn f(f: impl FnOnce()) {}
+   |         ~~~~
 help: function arguments must have a statically known size, borrowed types always have a known size
    |
 LL | fn f(f: &dyn FnOnce()) {}
index 2296666219eef2fbb284e11e7699db91b4adb20d..463ac7684ecdfea3a73122953e24915249278b66 100644 (file)
@@ -17,11 +17,11 @@ note: `Bar` defines an item `bar`, perhaps you need to implement it
 LL | trait Bar {
    | ^^^^^^^^^
 
-error[E0599]: no method named `bar` found for struct `Arc<[closure@$DIR/fn-help-with-err.rs:22:36: 22:38]>` in the current scope
+error[E0599]: no method named `bar` found for struct `Arc<[closure@fn-help-with-err.rs:22:36]>` in the current scope
   --> $DIR/fn-help-with-err.rs:23:10
    |
 LL |     arc2.bar();
-   |          ^^^ method not found in `Arc<[closure@$DIR/fn-help-with-err.rs:22:36: 22:38]>`
+   |          ^^^ method not found in `Arc<[closure@fn-help-with-err.rs:22:36]>`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
 note: `Bar` defines an item `bar`, perhaps you need to implement it
index c1e235441d65df68f775e99f1de85b897185d040..0458d2535f2f56ad83eac2b0d3be6ceaaf28c22b 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: the method `filterx` exists for struct `Map<Repeat, [closure@$DIR/issue-30786.rs:117:27: 117:34]>`, but its trait bounds were not satisfied
+error[E0599]: the method `filterx` exists for struct `Map<Repeat, [closure@issue-30786.rs:117:27]>`, but its trait bounds were not satisfied
   --> $DIR/issue-30786.rs:118:22
    |
 LL | pub struct Map<S, F> {
@@ -8,7 +8,7 @@ LL | pub struct Map<S, F> {
    | doesn't satisfy `_: StreamExt`
 ...
 LL |     let filter = map.filterx(|x: &_| true);
-   |                      ^^^^^^^ method cannot be called on `Map<Repeat, [closure@$DIR/issue-30786.rs:117:27: 117:34]>` due to unsatisfied trait bounds
+   |                      ^^^^^^^ method cannot be called on `Map<Repeat, [closure@issue-30786.rs:117:27]>` due to unsatisfied trait bounds
    |
 note: the following trait bounds were not satisfied:
       `&'a mut &Map<Repeat, [closure@$DIR/issue-30786.rs:117:27: 117:34]>: Stream`
@@ -19,7 +19,7 @@ note: the following trait bounds were not satisfied:
 LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
    |         ---------     -                          ^^^^^^ unsatisfied trait bound introduced here
 
-error[E0599]: the method `countx` exists for struct `Filter<Map<Repeat, for<'a> fn(&'a u64) -> &'a u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:129:30: 129:37]>`, but its trait bounds were not satisfied
+error[E0599]: the method `countx` exists for struct `Filter<Map<Repeat, for<'a> fn(&'a u64) -> &'a u64 {identity::<u64>}>, [closure@issue-30786.rs:129:30]>`, but its trait bounds were not satisfied
   --> $DIR/issue-30786.rs:130:24
    |
 LL | pub struct Filter<S, F> {
@@ -29,7 +29,7 @@ LL | pub struct Filter<S, F> {
    | doesn't satisfy `_: StreamExt`
 ...
 LL |     let count = filter.countx();
-   |                        ^^^^^^ method cannot be called on `Filter<Map<Repeat, for<'a> fn(&'a u64) -> &'a u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:129:30: 129:37]>` due to unsatisfied trait bounds
+   |                        ^^^^^^ method cannot be called due to unsatisfied trait bounds
    |
 note: the following trait bounds were not satisfied:
       `&'a mut &Filter<Map<Repeat, for<'a> fn(&'a u64) -> &'a u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:129:30: 129:37]>: Stream`
index ab5598e364fc4f522b95e66080a7196a1c0cba93..fdd192f43137067a274ebe008c03d2641a9fad0b 100644 (file)
@@ -30,7 +30,7 @@ LL |     where
 LL |         F: for<'r> T0<'r, (<Self as Ty<'r>>::V,), O = <B as Ty<'r>>::V>,
    |                                                   ^^^^^^^^^^^^^^^^^^^^ required by this bound in `T1::m`
 
-error[E0271]: expected `[closure@$DIR/issue-62203-hrtb-ice.rs:42:16: 42:19]` to be a closure that returns `Unit3`, but it returns `Unit4`
+error[E0271]: expected `[closure@issue-62203-hrtb-ice.rs:42:16]` to be a closure that returns `Unit3`, but it returns `Unit4`
   --> $DIR/issue-62203-hrtb-ice.rs:39:9
    |
 LL |       let v = Unit2.m(
index f90399b6b945888bad12c687d671387595b81093..7f73d5e12d1962a9288eb62d472d632b983b1ae4 100644 (file)
@@ -70,10 +70,6 @@ error[E0746]: return type cannot have an unboxed trait object
 LL | fn bak() -> dyn Trait { unimplemented!() }
    |             ^^^^^^^^^ doesn't have a size known at compile-time
    |
-help: use some type `T` that is `T: Sized` as the return type if all return paths have the same type
-   |
-LL | fn bak() -> T { unimplemented!() }
-   |             ~
 help: use `impl Trait` as the return type if all return paths have the same type but you want to expose only the trait in the signature
    |
 LL | fn bak() -> impl Trait { unimplemented!() }
index 3d4ae11e5767039ab3659d58f60c79c32545ad86..548c89d0a3871372e87270fd08b5ad3b2e1421a4 100644 (file)
@@ -145,11 +145,11 @@ note: `foo::Bar` defines an item `method2`, perhaps you need to implement it
 LL |     pub trait Bar {
    |     ^^^^^^^^^^^^^
 
-error[E0599]: no method named `method2` found for struct `no_method_suggested_traits::Foo` in the current scope
+error[E0599]: no method named `method2` found for struct `Foo` in the current scope
   --> $DIR/no-method-suggested-traits.rs:50:37
    |
 LL |     no_method_suggested_traits::Foo.method2();
-   |                                     ^^^^^^^ method not found in `no_method_suggested_traits::Foo`
+   |                                     ^^^^^^^ method not found in `Foo`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
 note: `foo::Bar` defines an item `method2`, perhaps you need to implement it
@@ -158,11 +158,11 @@ note: `foo::Bar` defines an item `method2`, perhaps you need to implement it
 LL |     pub trait Bar {
    |     ^^^^^^^^^^^^^
 
-error[E0599]: no method named `method2` found for struct `Rc<&mut Box<&no_method_suggested_traits::Foo>>` in the current scope
+error[E0599]: no method named `method2` found for struct `Rc<&mut Box<&Foo>>` in the current scope
   --> $DIR/no-method-suggested-traits.rs:52:71
    |
 LL |     std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Foo)).method2();
-   |                                                                       ^^^^^^^ method not found in `Rc<&mut Box<&no_method_suggested_traits::Foo>>`
+   |                                                                       ^^^^^^^ method not found in `Rc<&mut Box<&Foo>>`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
 note: `foo::Bar` defines an item `method2`, perhaps you need to implement it
@@ -171,11 +171,11 @@ note: `foo::Bar` defines an item `method2`, perhaps you need to implement it
 LL |     pub trait Bar {
    |     ^^^^^^^^^^^^^
 
-error[E0599]: no method named `method2` found for enum `no_method_suggested_traits::Bar` in the current scope
+error[E0599]: no method named `method2` found for enum `Bar` in the current scope
   --> $DIR/no-method-suggested-traits.rs:54:40
    |
 LL |     no_method_suggested_traits::Bar::X.method2();
-   |                                        ^^^^^^^ method not found in `no_method_suggested_traits::Bar`
+   |                                        ^^^^^^^ method not found in `Bar`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
 note: `foo::Bar` defines an item `method2`, perhaps you need to implement it
@@ -184,11 +184,11 @@ note: `foo::Bar` defines an item `method2`, perhaps you need to implement it
 LL |     pub trait Bar {
    |     ^^^^^^^^^^^^^
 
-error[E0599]: no method named `method2` found for struct `Rc<&mut Box<&no_method_suggested_traits::Bar>>` in the current scope
+error[E0599]: no method named `method2` found for struct `Rc<&mut Box<&Bar>>` in the current scope
   --> $DIR/no-method-suggested-traits.rs:56:74
    |
 LL |     std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Bar::X)).method2();
-   |                                                                          ^^^^^^^ method not found in `Rc<&mut Box<&no_method_suggested_traits::Bar>>`
+   |                                                                          ^^^^^^^ method not found in `Rc<&mut Box<&Bar>>`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
 note: `foo::Bar` defines an item `method2`, perhaps you need to implement it
@@ -255,29 +255,29 @@ error[E0599]: no method named `method3` found for struct `Rc<&mut Box<&usize>>`
 LL |     std::rc::Rc::new(&mut Box::new(&1_usize)).method3();
    |                                               ^^^^^^^ method not found in `Rc<&mut Box<&usize>>`
 
-error[E0599]: no method named `method3` found for struct `no_method_suggested_traits::Foo` in the current scope
+error[E0599]: no method named `method3` found for struct `Foo` in the current scope
   --> $DIR/no-method-suggested-traits.rs:71:37
    |
 LL |     no_method_suggested_traits::Foo.method3();
-   |                                     ^^^^^^^ method not found in `no_method_suggested_traits::Foo`
+   |                                     ^^^^^^^ method not found in `Foo`
 
-error[E0599]: no method named `method3` found for struct `Rc<&mut Box<&no_method_suggested_traits::Foo>>` in the current scope
+error[E0599]: no method named `method3` found for struct `Rc<&mut Box<&Foo>>` in the current scope
   --> $DIR/no-method-suggested-traits.rs:72:71
    |
 LL |     std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Foo)).method3();
-   |                                                                       ^^^^^^^ method not found in `Rc<&mut Box<&no_method_suggested_traits::Foo>>`
+   |                                                                       ^^^^^^^ method not found in `Rc<&mut Box<&Foo>>`
 
-error[E0599]: no method named `method3` found for enum `no_method_suggested_traits::Bar` in the current scope
+error[E0599]: no method named `method3` found for enum `Bar` in the current scope
   --> $DIR/no-method-suggested-traits.rs:74:40
    |
 LL |     no_method_suggested_traits::Bar::X.method3();
-   |                                        ^^^^^^^ method not found in `no_method_suggested_traits::Bar`
+   |                                        ^^^^^^^ method not found in `Bar`
 
-error[E0599]: no method named `method3` found for struct `Rc<&mut Box<&no_method_suggested_traits::Bar>>` in the current scope
+error[E0599]: no method named `method3` found for struct `Rc<&mut Box<&Bar>>` in the current scope
   --> $DIR/no-method-suggested-traits.rs:75:74
    |
 LL |     std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Bar::X)).method3();
-   |                                                                          ^^^^^^^ method not found in `Rc<&mut Box<&no_method_suggested_traits::Bar>>`
+   |                                                                          ^^^^^^^ method not found in `Rc<&mut Box<&Bar>>`
 
 error: aborting due to 24 previous errors
 
index 92f2ccb6544b10c2ba81744c921b4b945fd91d15..30c380152a5e6b88cf871a26dd82e1cf55f3403c 100644 (file)
@@ -55,8 +55,10 @@ error[E0271]: type mismatch resolving `<Demo as TraitWAssocConst>::A == 32`
   --> $DIR/issue-105330.rs:12:11
    |
 LL |     foo::<Demo>()();
-   |           ^^^^ types differ
+   |           ^^^^ expected `32`, found `<Demo as TraitWAssocConst>::A`
    |
+   = note: expected constant `32`
+              found constant `<Demo as TraitWAssocConst>::A`
 note: required by a bound in `foo`
   --> $DIR/issue-105330.rs:11:28
    |
@@ -89,8 +91,10 @@ error[E0271]: type mismatch resolving `<Demo as TraitWAssocConst>::A == 32`
   --> $DIR/issue-105330.rs:19:11
    |
 LL |     foo::<Demo>();
-   |           ^^^^ types differ
+   |           ^^^^ expected `32`, found `<Demo as TraitWAssocConst>::A`
    |
+   = note: expected constant `32`
+              found constant `<Demo as TraitWAssocConst>::A`
 note: required by a bound in `foo`
   --> $DIR/issue-105330.rs:11:28
    |
index 28478457b296db68779f5227322583c657f518b9..1669b550a9bafe26442e406d91bb02a980d135e7 100644 (file)
@@ -4,10 +4,6 @@ error[E0746]: return type cannot have an unboxed trait object
 LL |     dyn AbstractRenderer
    |     ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-help: use some type `T` that is `T: Sized` as the return type if all return paths have the same type
-   |
-LL |     T
-   |
 help: use `impl AbstractRenderer` as the return type if all return paths have the same type but you want to expose only the trait in the signature
    |
 LL |     impl AbstractRenderer
index 4e010a13653e7796c0723c35125c33bdb5ce60b1..2d60b18b1f208eae86ab14800e0e4053f93304d4 100644 (file)
@@ -4,7 +4,13 @@ error[E0283]: type annotations needed: cannot satisfy `&'a T: Foo`
 LL |     where &'a T : Foo,
    |                   ^^^
    |
-   = note: cannot satisfy `&'a T: Foo`
+note: multiple `impl`s or `where` clauses satisfying `&'a T: Foo` found
+  --> $DIR/issue-21974.rs:11:19
+   |
+LL |     where &'a T : Foo,
+   |                   ^^^
+LL |           &'b T : Foo
+   |                   ^^^
 
 error: aborting due to previous error
 
index 8f3b2ac73199ccec1afced236ae6f1c0f0452522..50d7f988e194cdcd30d2fc72c9dd6a639eaebcd4 100644 (file)
@@ -4,7 +4,11 @@ error[E0283]: type annotations needed: cannot satisfy `T0: Trait0<'l0>`
 LL | impl <'l0, 'l1, T0> Trait1<'l0, T0> for bool where T0 : Trait0<'l0>, T0 : Trait0<'l1> {}
    |                                                         ^^^^^^^^^^^
    |
-   = note: cannot satisfy `T0: Trait0<'l0>`
+note: multiple `impl`s or `where` clauses satisfying `T0: Trait0<'l0>` found
+  --> $DIR/issue-24424.rs:4:57
+   |
+LL | impl <'l0, 'l1, T0> Trait1<'l0, T0> for bool where T0 : Trait0<'l0>, T0 : Trait0<'l1> {}
+   |                                                         ^^^^^^^^^^^       ^^^^^^^^^^^
 
 error: aborting due to previous error
 
index e9d934332f171f6402a5f296c5bc780903aef40a..7808cbf8aa10840644bb7e85e8c9a81045adb8fc 100644 (file)
@@ -1,8 +1,8 @@
-error[E0599]: no function or associated item named `new_undirected` found for struct `issue_30123_aux::Graph<i32, i32>` in the current scope
+error[E0599]: no function or associated item named `new_undirected` found for struct `Graph<i32, i32>` in the current scope
   --> $DIR/issue-30123.rs:7:33
    |
 LL |     let ug = Graph::<i32, i32>::new_undirected();
-   |                                 ^^^^^^^^^^^^^^ function or associated item not found in `issue_30123_aux::Graph<i32, i32>`
+   |                                 ^^^^^^^^^^^^^^ function or associated item not found in `Graph<i32, i32>`
    |
    = note: the function or associated item was found for
            - `issue_30123_aux::Graph<N, E, Undirected>`
index b667ae0a789375cf62cf29eb460968793be24459..f3be99f9bcb4b3e09efcd9029b355d188c5ba5ec 100644 (file)
@@ -1,4 +1,4 @@
-error[E0271]: expected `TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]>` to be an iterator that yields `&_`, but it yields `u8`
+error[E0271]: expected `TakeWhile<&mut IntoIter<u8>, [closure@issue-31173.rs:7:21]>` to be an iterator that yields `&_`, but it yields `u8`
   --> $DIR/issue-31173.rs:11:10
    |
 LL |         .cloned()
@@ -6,14 +6,26 @@ LL |         .cloned()
    |
    = note: expected reference `&_`
                    found type `u8`
+note: the method call chain might not have had the expected associated types
+  --> $DIR/issue-31173.rs:3:20
+   |
+LL |   pub fn get_tok(it: &mut IntoIter<u8>) {
+   |                      ^^^^^^^^^^^^^^^^^ `Iterator::Item` is `u8` here
+...
+LL |           .take_while(|&x| {
+   |  __________-
+LL | |             found_e = true;
+LL | |             false
+LL | |         })
+   | |__________- `Iterator::Item` remains `u8` here
 note: required by a bound in `cloned`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
 
-error[E0599]: the method `collect` exists for struct `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]>>`, but its trait bounds were not satisfied
+error[E0599]: the method `collect` exists for struct `Cloned<TakeWhile<&mut IntoIter<u8>, [closure@issue-31173.rs:7:21]>>`, but its trait bounds were not satisfied
   --> $DIR/issue-31173.rs:12:10
    |
 LL |         .collect();
-   |          ^^^^^^^ method cannot be called on `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]>>` due to unsatisfied trait bounds
+   |          ^^^^^^^ method cannot be called due to unsatisfied trait bounds
   --> $SRC_DIR/core/src/iter/adapters/take_while.rs:LL:COL
    |
    = note: doesn't satisfy `<_ as Iterator>::Item = &_`
index 8430e85df871514f1269f49b6c7b9bccfe2b6efa..e3b6dcf55a7448296ea39c39de2c428b40e59ff2 100644 (file)
@@ -3,7 +3,7 @@
 use std::collections::HashMap;
 
 fn main() {
-    for _ in HashMap::new().iter().cloned() {} //~ ERROR expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
-    //~^ ERROR expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
-    //~| ERROR expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
+    for _ in HashMap::new().iter().cloned() {} //~ ERROR expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
+    //~^ ERROR expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
+    //~| ERROR expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
 }
index 49702c47658638bd28315df55d7b44ff327b5667..668eaabca4c463d450fbe59ed71e04280dd0c1e4 100644 (file)
@@ -1,4 +1,4 @@
-error[E0271]: expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
+error[E0271]: expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
   --> $DIR/issue-33941.rs:6:36
    |
 LL |     for _ in HashMap::new().iter().cloned() {}
@@ -6,10 +6,17 @@ LL |     for _ in HashMap::new().iter().cloned() {}
    |
    = note: expected reference `&_`
                   found tuple `(&_, &_)`
+note: the method call chain might not have had the expected associated types
+  --> $DIR/issue-33941.rs:6:29
+   |
+LL |     for _ in HashMap::new().iter().cloned() {}
+   |              -------------- ^^^^^^ `Iterator::Item` is `(&_, &_)` here
+   |              |
+   |              this expression has type `HashMap<_, _>`
 note: required by a bound in `cloned`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
 
-error[E0271]: expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
+error[E0271]: expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
   --> $DIR/issue-33941.rs:6:14
    |
 LL |     for _ in HashMap::new().iter().cloned() {}
@@ -20,7 +27,7 @@ LL |     for _ in HashMap::new().iter().cloned() {}
    = note: required for `Cloned<std::collections::hash_map::Iter<'_, _, _>>` to implement `Iterator`
    = note: required for `Cloned<std::collections::hash_map::Iter<'_, _, _>>` to implement `IntoIterator`
 
-error[E0271]: expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
+error[E0271]: expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
   --> $DIR/issue-33941.rs:6:14
    |
 LL |     for _ in HashMap::new().iter().cloned() {}
index fd694df30457ec11998188b8c0d61946cfaab133..00c375f8d2acfaad1da084e0f1b1e5a43c87b9e3 100644 (file)
@@ -5,7 +5,7 @@ LL | pub struct Iterate<T, F> {
    | ------------------------ method `iter` not found for this struct
 ...
 LL |     println!("{:?}", a.iter().take(10).collect::<Vec<usize>>());
-   |                        ^^^^ method not found in `Iterate<{integer}, [closure@$DIR/issue-41880.rs:26:24: 26:27]>`
+   |                        ^^^^ method not found in `Iterate<{integer}, [closure@issue-41880.rs:26:24]>`
 
 error: aborting due to previous error
 
index 6fe151622433a83050286b46287dd1d5d0b2b1b5..3ca6a2957e14b91768b6c421dc222634f5886677 100644 (file)
@@ -23,6 +23,10 @@ LL | pub fn f(_: dyn ToString) {}
    |
    = help: the trait `Sized` is not implemented for `(dyn ToString + 'static)`
    = help: unsized fn params are gated as an unstable feature
+help: you can use `impl Trait` as the argument type
+   |
+LL | pub fn f(_: impl ToString) {}
+   |             ~~~~
 help: function arguments must have a statically known size, borrowed types always have a known size
    |
 LL | pub fn f(_: &dyn ToString) {}
index 8a20a60853a63a3e952988cb055779c786cd8fc9..ffff403e0d4656508d4dbdbf3c4e7b32f6bb749f 100644 (file)
@@ -6,6 +6,10 @@ LL |     r: dyn A + 'static
    |
    = help: the trait `Sized` is not implemented for `(dyn A + 'static)`
    = help: unsized fn params are gated as an unstable feature
+help: you can use `impl Trait` as the argument type
+   |
+LL |     r: impl A + 'static
+   |        ~~~~
 help: function arguments must have a statically known size, borrowed types always have a known size
    |
 LL |     r: &dyn A + 'static
index 87116e49245703805c9867ac9db2dce04c287ac1..ebdf33303c982b311d80fb1b066cf82b52cc6946 100644 (file)
@@ -1,3 +1,11 @@
+use std::collections::hash_set::Iter;
+use std::collections::HashSet;
+
+fn iter_to_vec<'b, X>(i: Iter<'b, X>) -> Vec<X> {
+    let i = i.map(|x| x.clone());
+    i.collect() //~ ERROR E0277
+}
+
 fn main() {
     let scores = vec![(0, 0)]
         .iter()
@@ -38,4 +46,8 @@ fn main() {
     });
     let f = e.filter(|_| false);
     let g: Vec<i32> = f.collect(); //~ ERROR E0277
+
+    let mut s = HashSet::new();
+    s.insert(1u8);
+    println!("{:?}", iter_to_vec(s.iter()));
 }
index 84bac7833f67b029b56e09e1b5c54ac2d4eaf946..d76a4bfb7b3ea886c68b8e90b2593fb4e7c477ea 100644 (file)
@@ -1,5 +1,23 @@
+error[E0277]: a value of type `Vec<X>` cannot be built from an iterator over elements of type `&X`
+  --> $DIR/invalid-iterator-chain.rs:6:7
+   |
+LL |     i.collect()
+   |       ^^^^^^^ value of type `Vec<X>` cannot be built from `std::iter::Iterator<Item=&X>`
+   |
+   = help: the trait `FromIterator<&X>` is not implemented for `Vec<X>`
+   = help: the trait `FromIterator<T>` is implemented for `Vec<T>`
+note: the method call chain might not have had the expected associated types
+  --> $DIR/invalid-iterator-chain.rs:4:26
+   |
+LL | fn iter_to_vec<'b, X>(i: Iter<'b, X>) -> Vec<X> {
+   |                          ^^^^^^^^^^^ `Iterator::Item` is `&X` here
+LL |     let i = i.map(|x| x.clone());
+   |               ------------------ `Iterator::Item` remains `&X` here
+note: required by a bound in `collect`
+  --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+
 error[E0277]: a value of type `i32` cannot be made by summing an iterator over elements of type `()`
-  --> $DIR/invalid-iterator-chain.rs:7:27
+  --> $DIR/invalid-iterator-chain.rs:15:27
    |
 LL |     println!("{}", scores.sum::<i32>());
    |                           ^^^ value of type `i32` cannot be made by summing a `std::iter::Iterator<Item=()>`
@@ -9,7 +27,7 @@ LL |     println!("{}", scores.sum::<i32>());
              <i32 as Sum<&'a i32>>
              <i32 as Sum>
 note: the method call chain might not have had the expected associated types
-  --> $DIR/invalid-iterator-chain.rs:4:10
+  --> $DIR/invalid-iterator-chain.rs:12:10
    |
 LL |       let scores = vec![(0, 0)]
    |                    ------------ this expression has type `Vec<({integer}, {integer})>`
@@ -24,7 +42,7 @@ note: required by a bound in `std::iter::Iterator::sum`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
 
 error[E0277]: a value of type `i32` cannot be made by summing an iterator over elements of type `()`
-  --> $DIR/invalid-iterator-chain.rs:18:14
+  --> $DIR/invalid-iterator-chain.rs:26:14
    |
 LL |             .sum::<i32>(),
    |              ^^^ value of type `i32` cannot be made by summing a `std::iter::Iterator<Item=()>`
@@ -34,7 +52,7 @@ LL |             .sum::<i32>(),
              <i32 as Sum<&'a i32>>
              <i32 as Sum>
 note: the method call chain might not have had the expected associated types
-  --> $DIR/invalid-iterator-chain.rs:12:14
+  --> $DIR/invalid-iterator-chain.rs:20:14
    |
 LL |         vec![0, 1]
    |         ---------- this expression has type `Vec<{integer}>`
@@ -56,7 +74,7 @@ note: required by a bound in `std::iter::Iterator::sum`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
 
 error[E0277]: a value of type `i32` cannot be made by summing an iterator over elements of type `f64`
-  --> $DIR/invalid-iterator-chain.rs:28:14
+  --> $DIR/invalid-iterator-chain.rs:36:14
    |
 LL |             .sum::<i32>(),
    |              ^^^ value of type `i32` cannot be made by summing a `std::iter::Iterator<Item=f64>`
@@ -66,7 +84,7 @@ LL |             .sum::<i32>(),
              <i32 as Sum<&'a i32>>
              <i32 as Sum>
 note: the method call chain might not have had the expected associated types
-  --> $DIR/invalid-iterator-chain.rs:24:14
+  --> $DIR/invalid-iterator-chain.rs:32:14
    |
 LL |         vec![0, 1]
    |         ---------- this expression has type `Vec<{integer}>`
@@ -84,7 +102,7 @@ note: required by a bound in `std::iter::Iterator::sum`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
 
 error[E0277]: a value of type `i32` cannot be made by summing an iterator over elements of type `()`
-  --> $DIR/invalid-iterator-chain.rs:30:54
+  --> $DIR/invalid-iterator-chain.rs:38:54
    |
 LL |     println!("{}", vec![0, 1].iter().map(|x| { x; }).sum::<i32>());
    |                                                      ^^^ value of type `i32` cannot be made by summing a `std::iter::Iterator<Item=()>`
@@ -94,7 +112,7 @@ LL |     println!("{}", vec![0, 1].iter().map(|x| { x; }).sum::<i32>());
              <i32 as Sum<&'a i32>>
              <i32 as Sum>
 note: the method call chain might not have had the expected associated types
-  --> $DIR/invalid-iterator-chain.rs:30:38
+  --> $DIR/invalid-iterator-chain.rs:38:38
    |
 LL |     println!("{}", vec![0, 1].iter().map(|x| { x; }).sum::<i32>());
    |                    ---------- ------ ^^^^^^^^^^^^^^^ `Iterator::Item` changed to `()` here
@@ -105,7 +123,7 @@ note: required by a bound in `std::iter::Iterator::sum`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
 
 error[E0277]: a value of type `i32` cannot be made by summing an iterator over elements of type `&()`
-  --> $DIR/invalid-iterator-chain.rs:31:40
+  --> $DIR/invalid-iterator-chain.rs:39:40
    |
 LL |     println!("{}", vec![(), ()].iter().sum::<i32>());
    |                                        ^^^ value of type `i32` cannot be made by summing a `std::iter::Iterator<Item=&()>`
@@ -115,7 +133,7 @@ LL |     println!("{}", vec![(), ()].iter().sum::<i32>());
              <i32 as Sum<&'a i32>>
              <i32 as Sum>
 note: the method call chain might not have had the expected associated types
-  --> $DIR/invalid-iterator-chain.rs:31:33
+  --> $DIR/invalid-iterator-chain.rs:39:33
    |
 LL |     println!("{}", vec![(), ()].iter().sum::<i32>());
    |                    ------------ ^^^^^^ `Iterator::Item` is `&()` here
@@ -125,7 +143,7 @@ note: required by a bound in `std::iter::Iterator::sum`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
 
 error[E0277]: a value of type `Vec<i32>` cannot be built from an iterator over elements of type `()`
-  --> $DIR/invalid-iterator-chain.rs:40:25
+  --> $DIR/invalid-iterator-chain.rs:48:25
    |
 LL |     let g: Vec<i32> = f.collect();
    |                         ^^^^^^^ value of type `Vec<i32>` cannot be built from `std::iter::Iterator<Item=()>`
@@ -133,7 +151,7 @@ LL |     let g: Vec<i32> = f.collect();
    = help: the trait `FromIterator<()>` is not implemented for `Vec<i32>`
    = help: the trait `FromIterator<T>` is implemented for `Vec<T>`
 note: the method call chain might not have had the expected associated types
-  --> $DIR/invalid-iterator-chain.rs:36:15
+  --> $DIR/invalid-iterator-chain.rs:44:15
    |
 LL |       let a = vec![0];
    |               ------- this expression has type `Vec<{integer}>`
@@ -153,6 +171,6 @@ LL |       let f = e.filter(|_| false);
 note: required by a bound in `collect`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
 
-error: aborting due to 6 previous errors
+error: aborting due to 7 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/lifetimes/conflicting-bounds.rs b/src/test/ui/lifetimes/conflicting-bounds.rs
new file mode 100644 (file)
index 0000000..f37f163
--- /dev/null
@@ -0,0 +1,11 @@
+//~ type annotations needed: cannot satisfy `Self: Gen<'source>`
+
+pub trait Gen<'source> {
+    type Output;
+
+    fn gen<T>(&self) -> T
+    where
+        Self: for<'s> Gen<'s, Output = T>;
+}
+
+fn main() {}
diff --git a/src/test/ui/lifetimes/conflicting-bounds.stderr b/src/test/ui/lifetimes/conflicting-bounds.stderr
new file mode 100644 (file)
index 0000000..42aa393
--- /dev/null
@@ -0,0 +1,14 @@
+error[E0283]: type annotations needed: cannot satisfy `Self: Gen<'source>`
+   |
+note: multiple `impl`s or `where` clauses satisfying `Self: Gen<'source>` found
+  --> $DIR/conflicting-bounds.rs:3:1
+   |
+LL | pub trait Gen<'source> {
+   | ^^^^^^^^^^^^^^^^^^^^^^
+...
+LL |         Self: for<'s> Gen<'s, Output = T>;
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0283`.
index a332c6547b8390c36268abff095edfc39bbf8ee4..3d4208031cd06b9879de3326b066a2b0a81bec8a 100644 (file)
@@ -4,8 +4,16 @@ error[E0283]: type annotations needed: cannot satisfy `&'a (): Foo`
 LL |     &'a (): Foo,
    |             ^^^
    |
-   = note: cannot satisfy `&'a (): Foo`
-   = help: the trait `Foo` is implemented for `&'a T`
+note: multiple `impl`s or `where` clauses satisfying `&'a (): Foo` found
+  --> $DIR/issue-34979.rs:2:1
+   |
+LL | impl<'a, T> Foo for &'a T {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL |     &'a (): Foo,
+   |             ^^^
+LL |     &'static (): Foo;
+   |                  ^^^
 
 error: aborting due to previous error
 
index fc42d1a4dcd08136374b9ab6203cd4de854dbd23..8846efba871b9cd1f845b86b58dfbaa5a0880d1b 100644 (file)
@@ -23,7 +23,7 @@ error[E0599]: no method named `extend` found for struct `Map` in the current sco
   --> $DIR/method-not-found-generic-arg-elision.rs:87:29
    |
 LL |     v.iter().map(|x| x * x).extend(std::iter::once(100));
-   |                             ^^^^^^ method not found in `Map<std::slice::Iter<'_, i32>, [closure@$DIR/method-not-found-generic-arg-elision.rs:87:18: 87:21]>`
+   |                             ^^^^^^ method not found in `Map<Iter<'_, i32>, [closure@method-not-found-generic-arg-elision.rs:87:18]>`
 
 error[E0599]: no method named `method` found for struct `Wrapper<bool>` in the current scope
   --> $DIR/method-not-found-generic-arg-elision.rs:90:13
index b91f75b97f84a0ce4b1483ccafafc26751fd7f45..72fb0e4d774312780cb81e6e5f8fc1617f0d8113 100644 (file)
@@ -13,11 +13,11 @@ LL |     once::<&str>("str").fuse().filter(|a: &str| true).count();
 note: required by a bound in `filter`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
 
-error[E0599]: the method `count` exists for struct `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:48]>`, but its trait bounds were not satisfied
+error[E0599]: the method `count` exists for struct `Filter<Fuse<Once<&str>>, [closure@issue-36053-2.rs:7:39]>`, but its trait bounds were not satisfied
   --> $DIR/issue-36053-2.rs:7:55
    |
 LL |     once::<&str>("str").fuse().filter(|a: &str| true).count();
-   |                                       ---------       ^^^^^ method cannot be called on `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:48]>` due to unsatisfied trait bounds
+   |                                       ---------       ^^^^^ method cannot be called due to unsatisfied trait bounds
    |                                       |
    |                                       doesn't satisfy `<_ as FnOnce<(&&str,)>>::Output = bool`
    |                                       doesn't satisfy `_: FnMut<(&&str,)>`
index 45cf3723483f3a05f0ca60546bc6c949bb7df68a..a0f790dba15ed21adddebbcb5daf9faa8cd909ef 100644 (file)
@@ -1,4 +1,4 @@
-error[E0271]: expected `[closure@$DIR/fallback-closure-wrap.rs:18:40: 18:47]` to be a closure that returns `()`, but it returns `!`
+error[E0271]: expected `[closure@fallback-closure-wrap.rs:18:40]` to be a closure that returns `()`, but it returns `!`
   --> $DIR/fallback-closure-wrap.rs:18:31
    |
 LL |       let error = Closure::wrap(Box::new(move || {
index 3491ad5afbc1501100d192a234e567a7f892bf47..1598b0696913b6e18dc59a2ed556a3505b3f9367 100644 (file)
@@ -1,19 +1,11 @@
-// compile-flags: -Z print-type-sizes
+// compile-flags: -Z print-type-sizes --crate-type lib
 // edition:2021
 // build-pass
 // ignore-pass
 
-#![feature(start)]
-
 async fn wait() {}
 
-async fn test(arg: [u8; 8192]) {
+pub async fn test(arg: [u8; 8192]) {
     wait().await;
     drop(arg);
 }
-
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
-    let _ = test([0; 8192]);
-    0
-}
index 94ad09ef296d3b15b713c3e5dc68adf8596671eb..6e47bb4930dc5306e8666c1e8fb7d407706398bc 100644 (file)
@@ -1,4 +1,4 @@
-print-type-size type: `[async fn body@$DIR/async.rs:10:32: 13:2]`: 16386 bytes, alignment: 1 bytes
+print-type-size type: `[async fn body@$DIR/async.rs:8:36: 11:2]`: 16386 bytes, alignment: 1 bytes
 print-type-size     discriminant: 1 bytes
 print-type-size     variant `Suspend0`: 16385 bytes
 print-type-size         field `.arg`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes
@@ -16,14 +16,14 @@ print-type-size type: `std::mem::MaybeUninit<[u8; 8192]>`: 8192 bytes, alignment
 print-type-size     variant `MaybeUninit`: 8192 bytes
 print-type-size         field `.uninit`: 0 bytes
 print-type-size         field `.value`: 8192 bytes
-print-type-size type: `[async fn body@$DIR/async.rs:8:17: 8:19]`: 1 bytes, alignment: 1 bytes
+print-type-size type: `[async fn body@$DIR/async.rs:6:17: 6:19]`: 1 bytes, alignment: 1 bytes
 print-type-size     discriminant: 1 bytes
 print-type-size     variant `Unresumed`: 0 bytes
 print-type-size     variant `Returned`: 0 bytes
 print-type-size     variant `Panicked`: 0 bytes
-print-type-size type: `std::mem::ManuallyDrop<[async fn body@$DIR/async.rs:8:17: 8:19]>`: 1 bytes, alignment: 1 bytes
+print-type-size type: `std::mem::ManuallyDrop<[async fn body@$DIR/async.rs:6:17: 6:19]>`: 1 bytes, alignment: 1 bytes
 print-type-size     field `.value`: 1 bytes
-print-type-size type: `std::mem::MaybeUninit<[async fn body@$DIR/async.rs:8:17: 8:19]>`: 1 bytes, alignment: 1 bytes
+print-type-size type: `std::mem::MaybeUninit<[async fn body@$DIR/async.rs:6:17: 6:19]>`: 1 bytes, alignment: 1 bytes
 print-type-size     variant `MaybeUninit`: 1 bytes
 print-type-size         field `.uninit`: 0 bytes
 print-type-size         field `.value`: 1 bytes
index a46db6121046b999834f4ab76759263a687accc4..d1cd36274ef3e88970904b45708405415f0fa959 100644 (file)
@@ -1,8 +1,8 @@
-// compile-flags: -Z print-type-sizes
+// compile-flags: -Z print-type-sizes --crate-type=lib
 // build-pass
 // ignore-pass
 
-#![feature(start, generators, generator_trait)]
+#![feature(generators, generator_trait)]
 
 use std::ops::Generator;
 
@@ -13,8 +13,6 @@
     }
 }
 
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+pub fn foo() {
     let _ = generator([0; 8192]);
-    0
 }
diff --git a/src/test/ui/print_type_sizes/generator_discr_placement.rs b/src/test/ui/print_type_sizes/generator_discr_placement.rs
new file mode 100644 (file)
index 0000000..1a85fe9
--- /dev/null
@@ -0,0 +1,23 @@
+// compile-flags: -Z print-type-sizes --crate-type lib
+// build-pass
+// ignore-pass
+
+// Tests a generator that has its discriminant as the *final* field.
+
+// Avoid emitting panic handlers, like the rest of these tests...
+#![feature(generators)]
+
+pub fn foo() {
+    let a = || {
+        {
+            let w: i32 = 4;
+            yield;
+            drop(w);
+        }
+        {
+            let z: i32 = 7;
+            yield;
+            drop(z);
+        }
+    };
+}
diff --git a/src/test/ui/print_type_sizes/generator_discr_placement.stdout b/src/test/ui/print_type_sizes/generator_discr_placement.stdout
new file mode 100644 (file)
index 0000000..7f8f4cc
--- /dev/null
@@ -0,0 +1,11 @@
+print-type-size type: `[generator@$DIR/generator_discr_placement.rs:11:13: 11:15]`: 8 bytes, alignment: 4 bytes
+print-type-size     discriminant: 1 bytes
+print-type-size     variant `Suspend0`: 7 bytes
+print-type-size         padding: 3 bytes
+print-type-size         field `.w`: 4 bytes, alignment: 4 bytes
+print-type-size     variant `Suspend1`: 7 bytes
+print-type-size         padding: 3 bytes
+print-type-size         field `.z`: 4 bytes, alignment: 4 bytes
+print-type-size     variant `Unresumed`: 0 bytes
+print-type-size     variant `Returned`: 0 bytes
+print-type-size     variant `Panicked`: 0 bytes
index 3ef7b60db2caee840885f4631d0b169f90fc3757..05097087d5a811e1c07a8e36bb50b755aa0941e6 100644 (file)
@@ -1,4 +1,4 @@
-// compile-flags: -Z print-type-sizes
+// compile-flags: -Z print-type-sizes --crate-type=lib
 // build-pass
 // ignore-pass
 // ^-- needed because `--pass check` does not emit the output needed.
@@ -8,24 +8,6 @@
 // monomorphized, in the MIR of the original function in which they
 // occur, to have their size reported.
 
-#![feature(start)]
-
-// In an ad-hoc attempt to avoid the injection of unwinding code
-// (which clutters the output of `-Z print-type-sizes` with types from
-// `unwind::libunwind`):
-//
-//   * I am not using Default to build values because that seems to
-//     cause the injection of unwinding code. (Instead I just make `fn new`
-//     methods.)
-//
-//   * Pair derive Copy to ensure that we don't inject
-//     unwinding code into generic uses of Pair when T itself is also
-//     Copy.
-//
-//     (I suspect this reflect some naivety within the rust compiler
-//      itself; it should be checking for drop glue, i.e., a destructor
-//      somewhere in the monomorphized types. It should not matter whether
-//      the type is Copy.)
 #[derive(Copy, Clone)]
 pub struct Pair<T> {
     _car: T,
@@ -61,11 +43,9 @@ pub fn f1<T:Copy>(x: T) {
         Pair::new(FiftyBytes::new(), FiftyBytes::new());
 }
 
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+pub fn start() {
     let _b: Pair<u8> = Pair::new(0, 0);
     let _s: Pair<SevenBytes> = Pair::new(SevenBytes::new(), SevenBytes::new());
     let ref _z: ZeroSized = ZeroSized;
     f1::<SevenBytes>(SevenBytes::new());
-    0
 }
index f1ad27ec131371988f2e0810fc4c709646dfb28b..9159038924719f288091a30166a4a362b2a7fc07 100644 (file)
@@ -1,11 +1,9 @@
-// compile-flags: -Z print-type-sizes
+// compile-flags: -Z print-type-sizes --crate-type=lib
 // build-pass
 
 // This file illustrates that when multiple structural types occur in
 // a function, every one of them is included in the output.
 
-#![feature(start)]
-
 pub struct SevenBytes([u8;  7]);
 pub struct FiftyBytes([u8; 50]);
 
@@ -13,11 +11,3 @@ pub enum Enum {
     Small(SevenBytes),
     Large(FiftyBytes),
 }
-
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
-    let _e: Enum;
-    let _f: FiftyBytes;
-    let _s: SevenBytes;
-    0
-}
index 0716cee21c6626a71670081e752d2abdddc11775..5e620f248b65d35b1dd4243686249b7cb44aac46 100644 (file)
@@ -1,4 +1,4 @@
-// compile-flags: -Z print-type-sizes
+// compile-flags: -Z print-type-sizes --crate-type=lib
 // build-pass
 // ignore-pass
 // ^-- needed because `--pass check` does not emit the output needed.
@@ -14,7 +14,6 @@
 // aligned (while on most it is 8-byte aligned) and so the resulting
 // padding and overall computed sizes can be quite different.
 
-#![feature(start)]
 #![feature(rustc_attrs)]
 #![allow(dead_code)]
 
@@ -56,7 +55,7 @@ pub struct NestedNonZero {
 
 impl Default for NestedNonZero {
     fn default() -> Self {
-        NestedNonZero { pre: 0, val: NonZeroU32::new(1).unwrap(), post: 0 }
+        NestedNonZero { pre: 0, val: unsafe { NonZeroU32::new_unchecked(1) }, post: 0 }
     }
 }
 
@@ -76,8 +75,7 @@ pub union Union2<A: Copy, B: Copy> {
     b: B,
 }
 
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+pub fn test() {
     let _x: MyOption<NonZeroU32> = Default::default();
     let _y: EmbeddedDiscr = Default::default();
     let _z: MyOption<IndirectNonZero> = Default::default();
@@ -96,6 +94,4 @@ fn start(_: isize, _: *const *const u8) -> isize {
     // ...even when theoretically possible.
     let _j: MyOption<Union1<NonZeroU32>> = Default::default();
     let _k: MyOption<Union2<NonZeroU32, NonZeroU32>> = Default::default();
-
-    0
 }
index e45e4794a3526a754357c88511c647a8d5637677..2ec5d9e64bfbfbad3de1496e7cdf2773002d6194 100644 (file)
@@ -1,4 +1,4 @@
-// compile-flags: -Z print-type-sizes
+// compile-flags: -Z print-type-sizes --crate-type=lib
 // build-pass
 // ignore-pass
 // ^-- needed because `--pass check` does not emit the output needed.
@@ -8,16 +8,12 @@
 // (even if multiple functions), it is only printed once in the
 // print-type-sizes output.
 
-#![feature(start)]
-
 pub struct SevenBytes([u8; 7]);
 
 pub fn f1() {
     let _s: SevenBytes = SevenBytes([0; 7]);
 }
 
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+pub fn test() {
     let _s: SevenBytes = SevenBytes([0; 7]);
-    0
 }
index 269cc3cc2825fccc97c3991c15f7c61f43ba6705..5ddfe4bf4dbb0a9bfaed5ac3a2a0a95547de2da9 100644 (file)
@@ -1,4 +1,4 @@
-// compile-flags: -Z print-type-sizes
+// compile-flags: -Z print-type-sizes --crate-type=lib
 // build-pass
 // ignore-pass
 // ^-- needed because `--pass check` does not emit the output needed.
 // padding and overall computed sizes can be quite different.
 
 #![allow(dead_code)]
-#![feature(start)]
 
 #[derive(Default)]
 #[repr(packed)]
-struct Packed1 {
+pub struct Packed1 {
     a: u8,
     b: u8,
     g: i32,
@@ -28,7 +27,7 @@ struct Packed1 {
 
 #[derive(Default)]
 #[repr(packed(2))]
-struct Packed2 {
+pub struct Packed2 {
     a: u8,
     b: u8,
     g: i32,
@@ -40,7 +39,7 @@ struct Packed2 {
 #[derive(Default)]
 #[repr(packed(2))]
 #[repr(C)]
-struct Packed2C {
+pub struct Packed2C {
     a: u8,
     b: u8,
     g: i32,
@@ -50,7 +49,7 @@ struct Packed2C {
 }
 
 #[derive(Default)]
-struct Padded {
+pub struct Padded {
     a: u8,
     b: u8,
     g: i32,
@@ -58,12 +57,3 @@ struct Padded {
     h: i16,
     d: u8,
 }
-
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
-    let _c: Packed1 = Default::default();
-    let _d: Packed2 = Default::default();
-    let _e: Packed2C = Default::default();
-    let _f: Padded = Default::default();
-    0
-}
index d1acad16d7e1d3a60a13b290408b751f2f1ae406..f41c677dc6c08ff7bd0a0b61c489b677fbd89b2c 100644 (file)
@@ -1,4 +1,4 @@
-// compile-flags: -Z print-type-sizes
+// compile-flags: -Z print-type-sizes --crate-type=lib
 // build-pass
 
 // This file illustrates how padding is handled: alignment
@@ -9,7 +9,6 @@
 // aligned (while on most it is 8-byte aligned) and so the resulting
 // padding and overall computed sizes can be quite different.
 
-#![feature(start)]
 #![allow(dead_code)]
 
 struct S {
@@ -27,8 +26,3 @@ enum E2 {
     A(i8, i32),
     B(S),
 }
-
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
-    0
-}
index 07544935b2f828480eafeceff869d76898ff001b..0bd11ebc958433a3369b7addf8a8d2213be792d2 100644 (file)
@@ -1,4 +1,4 @@
-// compile-flags: -Z print-type-sizes
+// compile-flags: -Z print-type-sizes --crate-type=lib
 // build-pass
 // ignore-pass
 // ^-- needed because `--pass check` does not emit the output needed.
@@ -11,7 +11,7 @@
 // It avoids using u64/i64 because on some targets that is only 4-byte
 // aligned (while on most it is 8-byte aligned) and so the resulting
 // padding and overall computed sizes can be quite different.
-#![feature(start)]
+
 #![allow(dead_code)]
 
 #[repr(align(16))]
@@ -24,15 +24,9 @@ enum E {
 }
 
 #[derive(Default)]
-struct S {
+pub struct S {
     a: i32,
     b: i32,
     c: A,
     d: i8,
 }
-
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
-    let _s: S = Default::default();
-    0
-}
index b8067c112eef13c974e2d8f12afeba90feb80c40..6b103776a30d3c6c700a85cf3a242f4661edc8ee 100644 (file)
@@ -1,10 +1,9 @@
-// compile-flags: -Z print-type-sizes
+// compile-flags: -Z print-type-sizes --crate-type=lib
 // build-pass
 
 // This test makes sure that the tag is not grown for `repr(C)` or `repr(u8)`
 // variants (see https://github.com/rust-lang/rust/issues/50098 for the original bug).
 
-#![feature(start)]
 #![allow(dead_code)]
 
 #[repr(C, u8)]
@@ -18,8 +17,3 @@ enum Repru8 {
     A(u16),
     B,
 }
-
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
-    0
-}
index 06a62db4ebb0f37014d835f0e71fc2f2fe85ad25..86fab7b500af08030a7acca69d30b776a5724a3a 100644 (file)
@@ -1,14 +1,12 @@
-// compile-flags: -Z print-type-sizes
+// compile-flags: -Z print-type-sizes --crate-type=lib
 // build-pass
 // ignore-pass
 // ^-- needed because `--pass check` does not emit the output needed.
 //     FIXME: consider using an attribute instead of side-effects.
 
 #![feature(never_type)]
-#![feature(start)]
 
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+pub fn test() {
     let _x: Option<!> = None;
     let _y: Result<u32, !> = Ok(42);
     let _z: Result<!, !> = loop {};
index 6c8553cc23ded83bffdef6a0a643b9bd099970df..5a3020520265db95a15f4857f10cfa2f0655e1ba 100644 (file)
@@ -1,4 +1,4 @@
-// compile-flags: -Z print-type-sizes
+// compile-flags: -Z print-type-sizes --crate-type=lib
 // build-pass
 
 // This file illustrates two things:
@@ -9,8 +9,6 @@
 // 2. For an enum, the print-type-sizes output will also include the
 //    size of each variant.
 
-#![feature(start)]
-
 pub struct SevenBytes([u8;  7]);
 pub struct FiftyBytes([u8; 50]);
 
@@ -18,9 +16,3 @@ pub enum Enum {
     Small(SevenBytes),
     Large(FiftyBytes),
 }
-
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
-    let _e: Enum;
-    0
-}
index e02a33109e56af728bd6776cf7b576290a0e27df..09415824d5df00835f9cda3dabbd4f5b9c4bc467 100644 (file)
@@ -1,12 +1,10 @@
-// compile-flags: -Z print-type-sizes
+// compile-flags: -Z print-type-sizes --crate-type=lib
 // build-pass
 // ignore-pass
 
 // At one point, zero-sized fields such as those in this file were causing
 // incorrect output from `-Z print-type-sizes`.
 
-#![feature(start)]
-
 struct S1 {
     x: u32,
     y: u32,
@@ -28,8 +26,7 @@ struct S5<TagW, TagZ> {
     tagz: TagZ,
 }
 
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+pub fn test() {
     let _s1: S1 = S1 { x: 0, y: 0, tag: () };
 
     let _s5: S5<(), Empty> = S5 {
@@ -43,5 +40,4 @@ fn start(_: isize, _: *const *const u8) -> isize {
         z: 4,
         tagz: Empty {},
     };
-    0
 }
index 939392733f0e9659de281625967ee497f98f9eb1..558e6b7b118d8221125e8cdd953d2ac1b9834bdd 100644 (file)
@@ -6,6 +6,10 @@ LL | fn foo(_x: K) {}
    |
    = help: the trait `Sized` is not implemented for `(dyn I + 'static)`
    = help: unsized fn params are gated as an unstable feature
+help: you can use `impl Trait` as the argument type
+   |
+LL | fn foo(_x: impl K) {}
+   |            ++++
 help: function arguments must have a statically known size, borrowed types always have a known size
    |
 LL | fn foo(_x: &K) {}
diff --git a/src/test/ui/suggestions/clone-on-unconstrained-borrowed-type-param.fixed b/src/test/ui/suggestions/clone-on-unconstrained-borrowed-type-param.fixed
new file mode 100644 (file)
index 0000000..4f9e93a
--- /dev/null
@@ -0,0 +1,16 @@
+// run-rustfix
+fn wat<T: Clone>(t: &T) -> T {
+    t.clone() //~ ERROR E0308
+}
+
+#[derive(Clone)]
+struct Foo;
+
+fn wut(t: &Foo) -> Foo {
+    t.clone() //~ ERROR E0308
+}
+
+fn main() {
+    wat(&42);
+    wut(&Foo);
+}
diff --git a/src/test/ui/suggestions/clone-on-unconstrained-borrowed-type-param.rs b/src/test/ui/suggestions/clone-on-unconstrained-borrowed-type-param.rs
new file mode 100644 (file)
index 0000000..89b077d
--- /dev/null
@@ -0,0 +1,15 @@
+// run-rustfix
+fn wat<T>(t: &T) -> T {
+    t.clone() //~ ERROR E0308
+}
+
+struct Foo;
+
+fn wut(t: &Foo) -> Foo {
+    t.clone() //~ ERROR E0308
+}
+
+fn main() {
+    wat(&42);
+    wut(&Foo);
+}
diff --git a/src/test/ui/suggestions/clone-on-unconstrained-borrowed-type-param.stderr b/src/test/ui/suggestions/clone-on-unconstrained-borrowed-type-param.stderr
new file mode 100644 (file)
index 0000000..26ab515
--- /dev/null
@@ -0,0 +1,43 @@
+error[E0308]: mismatched types
+  --> $DIR/clone-on-unconstrained-borrowed-type-param.rs:3:5
+   |
+LL | fn wat<T>(t: &T) -> T {
+   |        -            - expected `T` because of return type
+   |        |
+   |        this type parameter
+LL |     t.clone()
+   |     ^^^^^^^^^ expected type parameter `T`, found `&T`
+   |
+   = note: expected type parameter `T`
+                   found reference `&T`
+note: `T` does not implement `Clone`, so `&T` was cloned instead
+  --> $DIR/clone-on-unconstrained-borrowed-type-param.rs:3:5
+   |
+LL |     t.clone()
+   |     ^
+help: consider restricting type parameter `T`
+   |
+LL | fn wat<T: Clone>(t: &T) -> T {
+   |         +++++++
+
+error[E0308]: mismatched types
+  --> $DIR/clone-on-unconstrained-borrowed-type-param.rs:9:5
+   |
+LL | fn wut(t: &Foo) -> Foo {
+   |                    --- expected `Foo` because of return type
+LL |     t.clone()
+   |     ^^^^^^^^^ expected struct `Foo`, found `&Foo`
+   |
+note: `Foo` does not implement `Clone`, so `&Foo` was cloned instead
+  --> $DIR/clone-on-unconstrained-borrowed-type-param.rs:9:5
+   |
+LL |     t.clone()
+   |     ^
+help: consider annotating `Foo` with `#[derive(Clone)]`
+   |
+LL | #[derive(Clone)]
+   |
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
index 2cb53ecce10408cff69354ca06b2bed9302e9464..6910b77d9bc3fa1874c69f464fba0e1b1444ef3b 100644 (file)
@@ -20,11 +20,11 @@ LL |     let fp = BufWriter::new(fp);
 note: required by a bound in `BufWriter`
   --> $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL
 
-error[E0599]: the method `write_fmt` exists for struct `BufWriter<&dyn std::io::Write>`, but its trait bounds were not satisfied
+error[E0599]: the method `write_fmt` exists for struct `BufWriter<&dyn Write>`, but its trait bounds were not satisfied
   --> $DIR/mut-borrow-needed-by-trait.rs:21:5
    |
 LL |     writeln!(fp, "hello world").unwrap();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ method cannot be called on `BufWriter<&dyn std::io::Write>` due to unsatisfied trait bounds
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ method cannot be called on `BufWriter<&dyn Write>` due to unsatisfied trait bounds
   --> $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL
    |
    = note: doesn't satisfy `BufWriter<&dyn std::io::Write>: std::io::Write`
index d7d6241ef708cda1a68a922940d7a3963417a6ba..65340b2a2092ff5cdf345a4c08703603d70c0ee1 100644 (file)
@@ -10,7 +10,7 @@ pub trait Foo: Iterator<Item = <Self as Foo>::Key> {
 
 impl Foo for IntoIter<i32> {
     type Key = u32;
-    //~^ ERROR expected `std::vec::IntoIter<i32>` to be an iterator that yields `u32`, but it yields `i32`
+    //~^ ERROR expected `IntoIter<i32>` to be an iterator that yields `u32`, but it yields `i32`
 }
 
 fn main() {}
index 3e2d9d9038aa7c1e6b8655cd3fdf668cc42f6190..7fa1d2c2eed67c8fd85f48d77f1aa019a3d36fb7 100644 (file)
@@ -1,4 +1,4 @@
-error[E0271]: expected `std::vec::IntoIter<i32>` to be an iterator that yields `u32`, but it yields `i32`
+error[E0271]: expected `IntoIter<i32>` to be an iterator that yields `u32`, but it yields `i32`
   --> $DIR/assoc-type-in-superbad.rs:12:16
    |
 LL |     type Key = u32;
index 8da0b6d6b85056198c76584c63492e85841f1dee..36b08a7d3093141c3ee61e6ff410794cc2092341 100644 (file)
@@ -20,6 +20,10 @@ LL | fn foo(_x: Foo + Send) {
    |
    = help: the trait `Sized` is not implemented for `(dyn Foo + Send + 'static)`
    = help: unsized fn params are gated as an unstable feature
+help: you can use `impl Trait` as the argument type
+   |
+LL | fn foo(_x: impl Foo + Send) {
+   |            ++++
 help: function arguments must have a statically known size, borrowed types always have a known size
    |
 LL | fn foo(_x: &Foo + Send) {
index 930708f9ad80c7d35ed8a153a869331f826a831e..9e80497ca6e92a1cf95c3f58df7ca752a728e388 100644 (file)
@@ -4,10 +4,14 @@ error[E0283]: type annotations needed: cannot satisfy `T: FnMut<(&'a (),)>`
 LL |     T: FnMut(&'a ()),
    |        ^^^^^^^^^^^^^
    |
-   = note: cannot satisfy `T: FnMut<(&'a (),)>`
-   = help: the following types implement trait `FnMut<Args>`:
-             &F
-             &mut F
+note: multiple `impl`s or `where` clauses satisfying `T: FnMut<(&'a (),)>` found
+  --> $DIR/issue-85735.rs:7:8
+   |
+LL |     T: FnMut(&'a ()),
+   |        ^^^^^^^^^^^^^
+LL |
+LL |     T: FnMut(&'b ()),
+   |        ^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
index 24b3a045856a6accd5656b25a2531e4afae89465..4aa5966ff25d4cedac7d9db5a84b39087a0ef0f9 100644 (file)
@@ -8,7 +8,7 @@ trait Foo {
 
 impl Foo for () {
     type Bar = std::vec::IntoIter<u32>;
-    //~^ ERROR expected `std::vec::IntoIter<u32>` to be an iterator that yields `X`, but it yields `u32`
+    //~^ ERROR expected `IntoIter<u32>` to be an iterator that yields `X`, but it yields `u32`
 }
 
 fn incoherent() {
index fb40895c49f15d13e28a81527f3ef4ac2e159014..8d11b48888947d91bce4b7039892a34a8cc72b15 100644 (file)
@@ -1,4 +1,4 @@
-error[E0271]: expected `std::vec::IntoIter<u32>` to be an iterator that yields `X`, but it yields `u32`
+error[E0271]: expected `IntoIter<u32>` to be an iterator that yields `X`, but it yields `u32`
   --> $DIR/issue-57961.rs:10:16
    |
 LL | type X = impl Sized;
index 75feb5698eb630ea2e868cfb5cf4ea6d0e0b1eb5..d15fd23418bb0be17020759ab5df157b6891b0b3 100644 (file)
@@ -4,7 +4,13 @@ error[E0283]: type annotations needed: cannot satisfy `&'a T: Foo`
 LL |     where &'a T : Foo,
    |                   ^^^
    |
-   = note: cannot satisfy `&'a T: Foo`
+note: multiple `impl`s or `where` clauses satisfying `&'a T: Foo` found
+  --> $DIR/issue-40294.rs:6:19
+   |
+LL |     where &'a T : Foo,
+   |                   ^^^
+LL |           &'b T : Foo
+   |                   ^^^
 
 error: aborting due to previous error
 
index faac680ea19318f02e674ec0e5ddb67ad34cf9eb..ff36e18d28301ef3b1934208e8ed2175a8ecbe9f 100644 (file)
@@ -12,6 +12,10 @@ note: `NotClone` does not implement `Clone`, so `&NotClone` was cloned instead
    |
 LL |     nc.clone()
    |     ^^
+help: consider annotating `NotClone` with `#[derive(Clone)]`
+   |
+LL | #[derive(Clone)]
+   |
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/typeck/issue-92481.rs b/src/test/ui/typeck/issue-92481.rs
new file mode 100644 (file)
index 0000000..0a6b184
--- /dev/null
@@ -0,0 +1,14 @@
+//check-fail
+
+#![crate_type="lib"]
+
+fn r({) {
+    Ok {             //~ ERROR mismatched types [E0308]
+        d..||_=m
+    }
+}
+//~^^^^^ ERROR expected parameter name, found `{`
+//~| ERROR expected one of `,`, `:`, or `}`, found `..`
+//~^^^^^ ERROR cannot find value `d` in this scope [E0425]
+//~| ERROR cannot find value `m` in this scope [E0425]
+//~| ERROR variant `Result<_, _>::Ok` has no field named `d` [E0559]
diff --git a/src/test/ui/typeck/issue-92481.stderr b/src/test/ui/typeck/issue-92481.stderr
new file mode 100644 (file)
index 0000000..cd778a6
--- /dev/null
@@ -0,0 +1,60 @@
+error: expected parameter name, found `{`
+  --> $DIR/issue-92481.rs:5:6
+   |
+LL | fn r({) {
+   |      ^ expected parameter name
+
+error: expected one of `,`, `:`, or `}`, found `..`
+  --> $DIR/issue-92481.rs:5:6
+   |
+LL | fn r({) {
+   |      ^ unclosed delimiter
+LL |     Ok {
+LL |         d..||_=m
+   |          -^
+   |          |
+   |          help: `}` may belong here
+
+error[E0425]: cannot find value `d` in this scope
+  --> $DIR/issue-92481.rs:7:9
+   |
+LL |         d..||_=m
+   |         ^ not found in this scope
+
+error[E0425]: cannot find value `m` in this scope
+  --> $DIR/issue-92481.rs:7:16
+   |
+LL |         d..||_=m
+   |                ^ not found in this scope
+
+error[E0559]: variant `Result<_, _>::Ok` has no field named `d`
+  --> $DIR/issue-92481.rs:7:9
+   |
+LL |         d..||_=m
+   |         ^ field does not exist
+  --> $SRC_DIR/core/src/result.rs:LL:COL
+   |
+   = note: `Result<_, _>::Ok` defined here
+   |
+help: `Result<_, _>::Ok` is a tuple variant, use the appropriate syntax
+   |
+LL |     Result<_, _>::Ok(/* fields */)
+   |
+
+error[E0308]: mismatched types
+  --> $DIR/issue-92481.rs:6:5
+   |
+LL |   fn r({) {
+   |           - help: a return type might be missing here: `-> _`
+LL | /     Ok {
+LL | |         d..||_=m
+LL | |     }
+   | |_____^ expected `()`, found enum `Result`
+   |
+   = note: expected unit type `()`
+                   found enum `Result<_, _>`
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0308, E0425, E0559.
+For more information about an error, try `rustc --explain E0308`.
index e5ca0edd7a91c62826aa111d4be9dada4161bb37..99ec5178340030d15ca4cac950f747182a9e36cc 100644 (file)
@@ -1,8 +1,8 @@
-error[E0599]: no method named `call` found for closure `[closure@$DIR/unboxed-closures-static-call-wrong-trait.rs:6:26: 6:29]` in the current scope
+error[E0599]: no method named `call` found for closure `[closure@unboxed-closures-static-call-wrong-trait.rs:6:26]` in the current scope
   --> $DIR/unboxed-closures-static-call-wrong-trait.rs:7:10
    |
 LL |     mut_.call((0, ));
-   |          ^^^^ method not found in `[closure@$DIR/unboxed-closures-static-call-wrong-trait.rs:6:26: 6:29]`
+   |          ^^^^ method not found in `[closure@unboxed-closures-static-call-wrong-trait.rs:6:26]`
 
 error: aborting due to previous error
 
index 70898e522116f6c23971e2a554b2dc85fd4c84cd..cc0a320879c17207bbfb96b5d778e28a2c62030d 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 70898e522116f6c23971e2a554b2dc85fd4c84cd
+Subproject commit cc0a320879c17207bbfb96b5d778e28a2c62030d
index 9e596ca8157eb93b58fc827d6c4d3eda261a116c..3f0b165f2b604a006e253bf4972c458611599212 100644 (file)
@@ -15,7 +15,7 @@
 use rustc_middle::traits::Reveal;
 use rustc_middle::ty::{
     self, Binder, BoundConstness, Clause, GenericParamDefKind, ImplPolarity, ParamEnv, PredicateKind, TraitPredicate,
-    TraitRef, Ty, TyCtxt,
+    Ty, TyCtxt,
 };
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
@@ -513,9 +513,9 @@ fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) ->
         tcx.mk_predicates(ty_predicates.iter().map(|&(p, _)| p).chain(
             params.iter().filter(|&&(_, needs_eq)| needs_eq).map(|&(param, _)| {
                 tcx.mk_predicate(Binder::dummy(PredicateKind::Clause(Clause::Trait(TraitPredicate {
-                    trait_ref: TraitRef::new(
+                    trait_ref: tcx.mk_trait_ref(
                         eq_trait_id,
-                        tcx.mk_substs(std::iter::once(tcx.mk_param_from_def(param))),
+                        [tcx.mk_param_from_def(param)],
                     ),
                     constness: BoundConstness::NotConst,
                     polarity: ImplPolarity::Positive,
index fcdac90fc237ae1a1a18bd7ffcf3e722e53bb545..989f83cf80d5972301fc06eef9604796f674a7b8 100644 (file)
@@ -62,7 +62,7 @@ fn check_fn(
             return;
         }
         let ret_ty = return_ty(cx, hir_id);
-        if let ty::Alias(ty::Opaque, AliasTy { def_id, substs }) = *ret_ty.kind() {
+        if let ty::Alias(ty::Opaque, AliasTy { def_id, substs, .. }) = *ret_ty.kind() {
             let preds = cx.tcx.explicit_item_bounds(def_id);
             let mut is_future = false;
             for &(p, _span) in preds {
index 90192f46cbfa09f416e88c94060d3962f5c9cfef..652f8b4d3c56ef7109668aface5f83bf35cc8514 100644 (file)
@@ -97,7 +97,7 @@
 use rustc_middle::ty as rustc_ty;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
 use rustc_middle::ty::binding::BindingMode;
-use rustc_middle::ty::fast_reject::SimplifiedTypeGen::{
+use rustc_middle::ty::fast_reject::SimplifiedType::{
     ArraySimplifiedType, BoolSimplifiedType, CharSimplifiedType, FloatSimplifiedType, IntSimplifiedType,
     PtrSimplifiedType, SliceSimplifiedType, StrSimplifiedType, UintSimplifiedType,
 };
index 33f3b3af3dc02d125223da58b3c9fc694805def0..a6bcb134d408096099ddd5d13263a68e28688fa1 100644 (file)
@@ -79,7 +79,7 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'
                 return true;
             }
 
-            if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs: _ }) = *inner_ty.kind() {
+            if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *inner_ty.kind() {
                 for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) {
                     match predicate.kind().skip_binder() {
                         // For `impl Trait<U>`, it will register a predicate of `T: Trait<U>`, so we go through
@@ -250,7 +250,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
             is_must_use_ty(cx, *ty)
         },
         ty::Tuple(substs) => substs.iter().any(|ty| is_must_use_ty(cx, ty)),
-        ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs: _ }) => {
+        ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => {
             for (predicate, _) in cx.tcx.explicit_item_bounds(*def_id) {
                 if let ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) = predicate.kind().skip_binder() {
                     if cx.tcx.has_attr(trait_predicate.trait_ref.def_id, sym::must_use) {
@@ -631,7 +631,7 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'t
             Some(ExprFnSig::Closure(decl, subs.as_closure().sig()))
         },
         ty::FnDef(id, subs) => Some(ExprFnSig::Sig(cx.tcx.bound_fn_sig(id).subst(cx.tcx, subs), Some(id))),
-        ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs: _ }) => sig_from_bounds(cx, ty, cx.tcx.item_bounds(def_id), cx.tcx.opt_parent(def_id)),
+        ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => sig_from_bounds(cx, ty, cx.tcx.item_bounds(def_id), cx.tcx.opt_parent(def_id)),
         ty::FnPtr(sig) => Some(ExprFnSig::Sig(sig, None)),
         ty::Dynamic(bounds, _, _) => {
             let lang_items = cx.tcx.lang_items();
@@ -1039,10 +1039,10 @@ fn helper<'tcx>(
             }
         }
 
-        Some(AliasTy {
+        Some(tcx.mk_alias_ty(
+            assoc_item.def_id,
             substs,
-            def_id: assoc_item.def_id,
-        })
+        ))
     }
     helper(
         tcx,
index e5b1eb2e4870696691a5f1672ea90f194665a865..ab629e4711b10c0e2ca8e5fec502336575f2ab9a 100644 (file)
@@ -22,8 +22,9 @@
 };
 use rustc_span::def_id::{CrateNum, DefId};
 use rustc_span::Symbol;
-use rustc_target::abi::Size;
+use rustc_target::abi::{Size, Align};
 use rustc_target::spec::abi::Abi;
+use rustc_const_eval::const_eval::CheckAlignment;
 
 use crate::{
     concurrency::{data_race, weak_memory},
@@ -752,8 +753,12 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
     const PANIC_ON_ALLOC_FAIL: bool = false;
 
     #[inline(always)]
-    fn enforce_alignment(ecx: &MiriInterpCx<'mir, 'tcx>) -> bool {
-        ecx.machine.check_alignment != AlignmentCheck::None
+    fn enforce_alignment(ecx: &MiriInterpCx<'mir, 'tcx>) -> CheckAlignment {
+        if ecx.machine.check_alignment == AlignmentCheck::None {
+            CheckAlignment::No
+        } else {
+            CheckAlignment::Error
+        }
     }
 
     #[inline(always)]
@@ -761,6 +766,15 @@ fn use_addr_for_alignment_check(ecx: &MiriInterpCx<'mir, 'tcx>) -> bool {
         ecx.machine.check_alignment == AlignmentCheck::Int
     }
 
+    fn alignment_check_failed(
+        _ecx: &InterpCx<'mir, 'tcx, Self>,
+        has: Align,
+        required: Align,
+        _check: CheckAlignment,
+    ) -> InterpResult<'tcx, ()> {
+        throw_ub!(AlignmentCheckFailed { has, required })
+    }
+
     #[inline(always)]
     fn enforce_validity(ecx: &MiriInterpCx<'mir, 'tcx>) -> bool {
         ecx.machine.validate
index 7ee8c5d3bad1510fe76e701e8c78671ffbb15a9d..75454cbdc5fe6a6f5288adda9f3ebc7399e0ce83 100644 (file)
@@ -57,6 +57,7 @@
     ("cranelift-codegen", "Apache-2.0 WITH LLVM-exception"),
     ("cranelift-codegen-meta", "Apache-2.0 WITH LLVM-exception"),
     ("cranelift-codegen-shared", "Apache-2.0 WITH LLVM-exception"),
+    ("cranelift-egraph", "Apache-2.0 WITH LLVM-exception"),
     ("cranelift-entity", "Apache-2.0 WITH LLVM-exception"),
     ("cranelift-frontend", "Apache-2.0 WITH LLVM-exception"),
     ("cranelift-isle", "Apache-2.0 WITH LLVM-exception"),
@@ -67,6 +68,7 @@
     ("mach", "BSD-2-Clause"),
     ("regalloc2", "Apache-2.0 WITH LLVM-exception"),
     ("target-lexicon", "Apache-2.0 WITH LLVM-exception"),
+    ("wasmtime-jit-icache-coherence", "Apache-2.0 WITH LLVM-exception"),
 ];
 
 const EXCEPTIONS_BOOTSTRAP: &[(&str, &str)] = &[
     "cranelift-codegen",
     "cranelift-codegen-meta",
     "cranelift-codegen-shared",
+    "cranelift-egraph",
     "cranelift-entity",
     "cranelift-frontend",
     "cranelift-isle",
     "cranelift-native",
     "cranelift-object",
     "crc32fast",
+    "fallible-iterator",
     "fxhash",
     "getrandom",
     "gimli",
     "region",
     "slice-group-by",
     "smallvec",
+    "stable_deref_trait",
     "target-lexicon",
     "version_check",
     "wasi",
+    "wasmtime-jit-icache-coherence",
     "winapi",
     "winapi-i686-pc-windows-gnu",
     "winapi-x86_64-pc-windows-gnu",
index 19e8334fc1aa30bf5d753edb1e5b8a94016824e2..46a3bab42a17e21364007d6c5657b206012a99e6 100644 (file)
@@ -467,7 +467,6 @@ compiler-team-contributors = [
     "@compiler-errors",
     "@eholk",
     "@jackh726",
-    "@fee1-dead",
     "@TaKO8Ki",
     "@Nilstrieb",
 ]